perf hists browser: Apply the dso and thread filters when merging new batches
[linux-flexiantxendom0.git] / tools / perf / util / hist.c
1 #include "annotate.h"
2 #include "util.h"
3 #include "build-id.h"
4 #include "hist.h"
5 #include "session.h"
6 #include "sort.h"
7 #include <math.h>
8
9 static bool hists__filter_entry_by_dso(struct hists *hists,
10                                        struct hist_entry *he);
11 static bool hists__filter_entry_by_thread(struct hists *hists,
12                                           struct hist_entry *he);
13
14 enum hist_filter {
15         HIST_FILTER__DSO,
16         HIST_FILTER__THREAD,
17         HIST_FILTER__PARENT,
18 };
19
20 struct callchain_param  callchain_param = {
21         .mode   = CHAIN_GRAPH_REL,
22         .min_percent = 0.5,
23         .order  = ORDER_CALLEE
24 };
25
26 u16 hists__col_len(struct hists *hists, enum hist_column col)
27 {
28         return hists->col_len[col];
29 }
30
31 void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
32 {
33         hists->col_len[col] = len;
34 }
35
36 bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
37 {
38         if (len > hists__col_len(hists, col)) {
39                 hists__set_col_len(hists, col, len);
40                 return true;
41         }
42         return false;
43 }
44
45 static void hists__reset_col_len(struct hists *hists)
46 {
47         enum hist_column col;
48
49         for (col = 0; col < HISTC_NR_COLS; ++col)
50                 hists__set_col_len(hists, col, 0);
51 }
52
53 static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
54 {
55         u16 len;
56
57         if (h->ms.sym)
58                 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
59         else {
60                 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
61
62                 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
63                     !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
64                     !symbol_conf.dso_list)
65                         hists__set_col_len(hists, HISTC_DSO,
66                                            unresolved_col_width);
67         }
68
69         len = thread__comm_len(h->thread);
70         if (hists__new_col_len(hists, HISTC_COMM, len))
71                 hists__set_col_len(hists, HISTC_THREAD, len + 6);
72
73         if (h->ms.map) {
74                 len = dso__name_len(h->ms.map->dso);
75                 hists__new_col_len(hists, HISTC_DSO, len);
76         }
77 }
78
79 static void hist_entry__add_cpumode_period(struct hist_entry *self,
80                                            unsigned int cpumode, u64 period)
81 {
82         switch (cpumode) {
83         case PERF_RECORD_MISC_KERNEL:
84                 self->period_sys += period;
85                 break;
86         case PERF_RECORD_MISC_USER:
87                 self->period_us += period;
88                 break;
89         case PERF_RECORD_MISC_GUEST_KERNEL:
90                 self->period_guest_sys += period;
91                 break;
92         case PERF_RECORD_MISC_GUEST_USER:
93                 self->period_guest_us += period;
94                 break;
95         default:
96                 break;
97         }
98 }
99
100 static void hist_entry__decay(struct hist_entry *he)
101 {
102         he->period = (he->period * 7) / 8;
103         he->nr_events = (he->nr_events * 7) / 8;
104 }
105
106 static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
107 {
108         if (he->period == 0)
109                 return true;
110         hists->stats.total_period -= he->period;
111         hist_entry__decay(he);
112         hists->stats.total_period += he->period;
113         return he->period == 0;
114 }
115
116 static void __hists__decay_entries(struct hists *hists, bool zap_user,
117                                    bool zap_kernel, bool threaded)
118 {
119         struct rb_node *next = rb_first(&hists->entries);
120         struct hist_entry *n;
121
122         while (next) {
123                 n = rb_entry(next, struct hist_entry, rb_node);
124                 next = rb_next(&n->rb_node);
125                 /*
126                  * We may be annotating this, for instance, so keep it here in
127                  * case some it gets new samples, we'll eventually free it when
128                  * the user stops browsing and it agains gets fully decayed.
129                  */
130                 if (((zap_user && n->level == '.') ||
131                      (zap_kernel && n->level != '.') ||
132                      hists__decay_entry(hists, n)) &&
133                     !n->used) {
134                         rb_erase(&n->rb_node, &hists->entries);
135
136                         if (sort__need_collapse || threaded)
137                                 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
138
139                         hist_entry__free(n);
140                         --hists->nr_entries;
141                 }
142         }
143 }
144
145 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
146 {
147         return __hists__decay_entries(hists, zap_user, zap_kernel, false);
148 }
149
150 void hists__decay_entries_threaded(struct hists *hists,
151                                    bool zap_user, bool zap_kernel)
152 {
153         return __hists__decay_entries(hists, zap_user, zap_kernel, true);
154 }
155
156 /*
157  * histogram, sorted on item, collects periods
158  */
159
160 static struct hist_entry *hist_entry__new(struct hist_entry *template)
161 {
162         size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
163         struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
164
165         if (self != NULL) {
166                 *self = *template;
167                 self->nr_events = 1;
168                 if (self->ms.map)
169                         self->ms.map->referenced = true;
170                 if (symbol_conf.use_callchain)
171                         callchain_init(self->callchain);
172         }
173
174         return self;
175 }
176
177 static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
178 {
179         if (!h->filtered) {
180                 hists__calc_col_len(hists, h);
181                 ++hists->nr_entries;
182                 hists->stats.total_period += h->period;
183         }
184 }
185
186 static u8 symbol__parent_filter(const struct symbol *parent)
187 {
188         if (symbol_conf.exclude_other && parent == NULL)
189                 return 1 << HIST_FILTER__PARENT;
190         return 0;
191 }
192
193 struct hist_entry *__hists__add_entry(struct hists *hists,
194                                       struct addr_location *al,
195                                       struct symbol *sym_parent, u64 period)
196 {
197         struct rb_node **p;
198         struct rb_node *parent = NULL;
199         struct hist_entry *he;
200         struct hist_entry entry = {
201                 .thread = al->thread,
202                 .ms = {
203                         .map    = al->map,
204                         .sym    = al->sym,
205                 },
206                 .cpu    = al->cpu,
207                 .ip     = al->addr,
208                 .level  = al->level,
209                 .period = period,
210                 .parent = sym_parent,
211                 .filtered = symbol__parent_filter(sym_parent),
212         };
213         int cmp;
214
215         pthread_mutex_lock(&hists->lock);
216
217         p = &hists->entries_in->rb_node;
218
219         while (*p != NULL) {
220                 parent = *p;
221                 he = rb_entry(parent, struct hist_entry, rb_node_in);
222
223                 cmp = hist_entry__cmp(&entry, he);
224
225                 if (!cmp) {
226                         he->period += period;
227                         ++he->nr_events;
228                         goto out;
229                 }
230
231                 if (cmp < 0)
232                         p = &(*p)->rb_left;
233                 else
234                         p = &(*p)->rb_right;
235         }
236
237         he = hist_entry__new(&entry);
238         if (!he)
239                 goto out_unlock;
240
241         rb_link_node(&he->rb_node_in, parent, p);
242         rb_insert_color(&he->rb_node_in, hists->entries_in);
243 out:
244         hist_entry__add_cpumode_period(he, al->cpumode, period);
245 out_unlock:
246         pthread_mutex_unlock(&hists->lock);
247         return he;
248 }
249
250 int64_t
251 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
252 {
253         struct sort_entry *se;
254         int64_t cmp = 0;
255
256         list_for_each_entry(se, &hist_entry__sort_list, list) {
257                 cmp = se->se_cmp(left, right);
258                 if (cmp)
259                         break;
260         }
261
262         return cmp;
263 }
264
265 int64_t
266 hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
267 {
268         struct sort_entry *se;
269         int64_t cmp = 0;
270
271         list_for_each_entry(se, &hist_entry__sort_list, list) {
272                 int64_t (*f)(struct hist_entry *, struct hist_entry *);
273
274                 f = se->se_collapse ?: se->se_cmp;
275
276                 cmp = f(left, right);
277                 if (cmp)
278                         break;
279         }
280
281         return cmp;
282 }
283
284 void hist_entry__free(struct hist_entry *he)
285 {
286         free(he);
287 }
288
289 /*
290  * collapse the histogram
291  */
292
293 static bool hists__collapse_insert_entry(struct hists *hists,
294                                          struct rb_root *root,
295                                          struct hist_entry *he)
296 {
297         struct rb_node **p = &root->rb_node;
298         struct rb_node *parent = NULL;
299         struct hist_entry *iter;
300         int64_t cmp;
301
302         while (*p != NULL) {
303                 parent = *p;
304                 iter = rb_entry(parent, struct hist_entry, rb_node_in);
305
306                 cmp = hist_entry__collapse(iter, he);
307
308                 if (!cmp) {
309                         iter->period += he->period;
310                         iter->nr_events += he->nr_events;
311                         if (symbol_conf.use_callchain) {
312                                 callchain_cursor_reset(&hists->callchain_cursor);
313                                 callchain_merge(&hists->callchain_cursor, iter->callchain,
314                                                 he->callchain);
315                         }
316                         hist_entry__free(he);
317                         return false;
318                 }
319
320                 if (cmp < 0)
321                         p = &(*p)->rb_left;
322                 else
323                         p = &(*p)->rb_right;
324         }
325
326         rb_link_node(&he->rb_node_in, parent, p);
327         rb_insert_color(&he->rb_node_in, root);
328         return true;
329 }
330
331 static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
332 {
333         struct rb_root *root;
334
335         pthread_mutex_lock(&hists->lock);
336
337         root = hists->entries_in;
338         if (++hists->entries_in > &hists->entries_in_array[1])
339                 hists->entries_in = &hists->entries_in_array[0];
340
341         pthread_mutex_unlock(&hists->lock);
342
343         return root;
344 }
345
346 static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
347 {
348         hists__filter_entry_by_dso(hists, he);
349         hists__filter_entry_by_thread(hists, he);
350 }
351
352 static void __hists__collapse_resort(struct hists *hists, bool threaded)
353 {
354         struct rb_root *root;
355         struct rb_node *next;
356         struct hist_entry *n;
357
358         if (!sort__need_collapse && !threaded)
359                 return;
360
361         root = hists__get_rotate_entries_in(hists);
362         next = rb_first(root);
363         hists->stats.total_period = 0;
364
365         while (next) {
366                 n = rb_entry(next, struct hist_entry, rb_node_in);
367                 next = rb_next(&n->rb_node_in);
368
369                 rb_erase(&n->rb_node_in, root);
370                 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
371                         /*
372                          * If it wasn't combined with one of the entries already
373                          * collapsed, we need to apply the filters that may have
374                          * been set by, say, the hist_browser.
375                          */
376                         hists__apply_filters(hists, n);
377                         hists__inc_nr_entries(hists, n);
378                 }
379         }
380 }
381
382 void hists__collapse_resort(struct hists *hists)
383 {
384         return __hists__collapse_resort(hists, false);
385 }
386
387 void hists__collapse_resort_threaded(struct hists *hists)
388 {
389         return __hists__collapse_resort(hists, true);
390 }
391
392 /*
393  * reverse the map, sort on period.
394  */
395
396 static void __hists__insert_output_entry(struct rb_root *entries,
397                                          struct hist_entry *he,
398                                          u64 min_callchain_hits)
399 {
400         struct rb_node **p = &entries->rb_node;
401         struct rb_node *parent = NULL;
402         struct hist_entry *iter;
403
404         if (symbol_conf.use_callchain)
405                 callchain_param.sort(&he->sorted_chain, he->callchain,
406                                       min_callchain_hits, &callchain_param);
407
408         while (*p != NULL) {
409                 parent = *p;
410                 iter = rb_entry(parent, struct hist_entry, rb_node);
411
412                 if (he->period > iter->period)
413                         p = &(*p)->rb_left;
414                 else
415                         p = &(*p)->rb_right;
416         }
417
418         rb_link_node(&he->rb_node, parent, p);
419         rb_insert_color(&he->rb_node, entries);
420 }
421
422 static void __hists__output_resort(struct hists *hists, bool threaded)
423 {
424         struct rb_root *root;
425         struct rb_node *next;
426         struct hist_entry *n;
427         u64 min_callchain_hits;
428
429         min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
430
431         if (sort__need_collapse || threaded)
432                 root = &hists->entries_collapsed;
433         else
434                 root = hists->entries_in;
435
436         next = rb_first(root);
437         hists->entries = RB_ROOT;
438
439         hists->nr_entries = 0;
440         hists__reset_col_len(hists);
441
442         while (next) {
443                 n = rb_entry(next, struct hist_entry, rb_node_in);
444                 next = rb_next(&n->rb_node_in);
445
446                 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
447                 hists__inc_nr_entries(hists, n);
448         }
449 }
450
451 void hists__output_resort(struct hists *hists)
452 {
453         return __hists__output_resort(hists, false);
454 }
455
456 void hists__output_resort_threaded(struct hists *hists)
457 {
458         return __hists__output_resort(hists, true);
459 }
460
461 static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
462 {
463         int i;
464         int ret = fprintf(fp, "            ");
465
466         for (i = 0; i < left_margin; i++)
467                 ret += fprintf(fp, " ");
468
469         return ret;
470 }
471
472 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
473                                           int left_margin)
474 {
475         int i;
476         size_t ret = callchain__fprintf_left_margin(fp, left_margin);
477
478         for (i = 0; i < depth; i++)
479                 if (depth_mask & (1 << i))
480                         ret += fprintf(fp, "|          ");
481                 else
482                         ret += fprintf(fp, "           ");
483
484         ret += fprintf(fp, "\n");
485
486         return ret;
487 }
488
489 static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
490                                      int depth, int depth_mask, int period,
491                                      u64 total_samples, u64 hits,
492                                      int left_margin)
493 {
494         int i;
495         size_t ret = 0;
496
497         ret += callchain__fprintf_left_margin(fp, left_margin);
498         for (i = 0; i < depth; i++) {
499                 if (depth_mask & (1 << i))
500                         ret += fprintf(fp, "|");
501                 else
502                         ret += fprintf(fp, " ");
503                 if (!period && i == depth - 1) {
504                         double percent;
505
506                         percent = hits * 100.0 / total_samples;
507                         ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
508                 } else
509                         ret += fprintf(fp, "%s", "          ");
510         }
511         if (chain->ms.sym)
512                 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
513         else
514                 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
515
516         return ret;
517 }
518
519 static struct symbol *rem_sq_bracket;
520 static struct callchain_list rem_hits;
521
522 static void init_rem_hits(void)
523 {
524         rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
525         if (!rem_sq_bracket) {
526                 fprintf(stderr, "Not enough memory to display remaining hits\n");
527                 return;
528         }
529
530         strcpy(rem_sq_bracket->name, "[...]");
531         rem_hits.ms.sym = rem_sq_bracket;
532 }
533
534 static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
535                                          u64 total_samples, int depth,
536                                          int depth_mask, int left_margin)
537 {
538         struct rb_node *node, *next;
539         struct callchain_node *child;
540         struct callchain_list *chain;
541         int new_depth_mask = depth_mask;
542         u64 new_total;
543         u64 remaining;
544         size_t ret = 0;
545         int i;
546         uint entries_printed = 0;
547
548         if (callchain_param.mode == CHAIN_GRAPH_REL)
549                 new_total = self->children_hit;
550         else
551                 new_total = total_samples;
552
553         remaining = new_total;
554
555         node = rb_first(&self->rb_root);
556         while (node) {
557                 u64 cumul;
558
559                 child = rb_entry(node, struct callchain_node, rb_node);
560                 cumul = callchain_cumul_hits(child);
561                 remaining -= cumul;
562
563                 /*
564                  * The depth mask manages the output of pipes that show
565                  * the depth. We don't want to keep the pipes of the current
566                  * level for the last child of this depth.
567                  * Except if we have remaining filtered hits. They will
568                  * supersede the last child
569                  */
570                 next = rb_next(node);
571                 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
572                         new_depth_mask &= ~(1 << (depth - 1));
573
574                 /*
575                  * But we keep the older depth mask for the line separator
576                  * to keep the level link until we reach the last child
577                  */
578                 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
579                                                    left_margin);
580                 i = 0;
581                 list_for_each_entry(chain, &child->val, list) {
582                         ret += ipchain__fprintf_graph(fp, chain, depth,
583                                                       new_depth_mask, i++,
584                                                       new_total,
585                                                       cumul,
586                                                       left_margin);
587                 }
588                 ret += __callchain__fprintf_graph(fp, child, new_total,
589                                                   depth + 1,
590                                                   new_depth_mask | (1 << depth),
591                                                   left_margin);
592                 node = next;
593                 if (++entries_printed == callchain_param.print_limit)
594                         break;
595         }
596
597         if (callchain_param.mode == CHAIN_GRAPH_REL &&
598                 remaining && remaining != new_total) {
599
600                 if (!rem_sq_bracket)
601                         return ret;
602
603                 new_depth_mask &= ~(1 << (depth - 1));
604
605                 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
606                                               new_depth_mask, 0, new_total,
607                                               remaining, left_margin);
608         }
609
610         return ret;
611 }
612
613 static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
614                                        u64 total_samples, int left_margin)
615 {
616         struct callchain_list *chain;
617         bool printed = false;
618         int i = 0;
619         int ret = 0;
620         u32 entries_printed = 0;
621
622         list_for_each_entry(chain, &self->val, list) {
623                 if (!i++ && sort__first_dimension == SORT_SYM)
624                         continue;
625
626                 if (!printed) {
627                         ret += callchain__fprintf_left_margin(fp, left_margin);
628                         ret += fprintf(fp, "|\n");
629                         ret += callchain__fprintf_left_margin(fp, left_margin);
630                         ret += fprintf(fp, "---");
631
632                         left_margin += 3;
633                         printed = true;
634                 } else
635                         ret += callchain__fprintf_left_margin(fp, left_margin);
636
637                 if (chain->ms.sym)
638                         ret += fprintf(fp, " %s\n", chain->ms.sym->name);
639                 else
640                         ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
641
642                 if (++entries_printed == callchain_param.print_limit)
643                         break;
644         }
645
646         ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
647
648         return ret;
649 }
650
651 static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
652                                       u64 total_samples)
653 {
654         struct callchain_list *chain;
655         size_t ret = 0;
656
657         if (!self)
658                 return 0;
659
660         ret += callchain__fprintf_flat(fp, self->parent, total_samples);
661
662
663         list_for_each_entry(chain, &self->val, list) {
664                 if (chain->ip >= PERF_CONTEXT_MAX)
665                         continue;
666                 if (chain->ms.sym)
667                         ret += fprintf(fp, "                %s\n", chain->ms.sym->name);
668                 else
669                         ret += fprintf(fp, "                %p\n",
670                                         (void *)(long)chain->ip);
671         }
672
673         return ret;
674 }
675
676 static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
677                                             u64 total_samples, int left_margin)
678 {
679         struct rb_node *rb_node;
680         struct callchain_node *chain;
681         size_t ret = 0;
682         u32 entries_printed = 0;
683
684         rb_node = rb_first(&self->sorted_chain);
685         while (rb_node) {
686                 double percent;
687
688                 chain = rb_entry(rb_node, struct callchain_node, rb_node);
689                 percent = chain->hit * 100.0 / total_samples;
690                 switch (callchain_param.mode) {
691                 case CHAIN_FLAT:
692                         ret += percent_color_fprintf(fp, "           %6.2f%%\n",
693                                                      percent);
694                         ret += callchain__fprintf_flat(fp, chain, total_samples);
695                         break;
696                 case CHAIN_GRAPH_ABS: /* Falldown */
697                 case CHAIN_GRAPH_REL:
698                         ret += callchain__fprintf_graph(fp, chain, total_samples,
699                                                         left_margin);
700                 case CHAIN_NONE:
701                 default:
702                         break;
703                 }
704                 ret += fprintf(fp, "\n");
705                 if (++entries_printed == callchain_param.print_limit)
706                         break;
707                 rb_node = rb_next(rb_node);
708         }
709
710         return ret;
711 }
712
713 void hists__output_recalc_col_len(struct hists *hists, int max_rows)
714 {
715         struct rb_node *next = rb_first(&hists->entries);
716         struct hist_entry *n;
717         int row = 0;
718
719         hists__reset_col_len(hists);
720
721         while (next && row++ < max_rows) {
722                 n = rb_entry(next, struct hist_entry, rb_node);
723                 hists__calc_col_len(hists, n);
724                 next = rb_next(&n->rb_node);
725         }
726 }
727
728 static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
729                                      size_t size, struct hists *pair_hists,
730                                      bool show_displacement, long displacement,
731                                      bool color, u64 session_total)
732 {
733         u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
734         u64 nr_events;
735         const char *sep = symbol_conf.field_sep;
736         int ret;
737
738         if (symbol_conf.exclude_other && !self->parent)
739                 return 0;
740
741         if (pair_hists) {
742                 period = self->pair ? self->pair->period : 0;
743                 nr_events = self->pair ? self->pair->nr_events : 0;
744                 total = pair_hists->stats.total_period;
745                 period_sys = self->pair ? self->pair->period_sys : 0;
746                 period_us = self->pair ? self->pair->period_us : 0;
747                 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
748                 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
749         } else {
750                 period = self->period;
751                 nr_events = self->nr_events;
752                 total = session_total;
753                 period_sys = self->period_sys;
754                 period_us = self->period_us;
755                 period_guest_sys = self->period_guest_sys;
756                 period_guest_us = self->period_guest_us;
757         }
758
759         if (total) {
760                 if (color)
761                         ret = percent_color_snprintf(s, size,
762                                                      sep ? "%.2f" : "   %6.2f%%",
763                                                      (period * 100.0) / total);
764                 else
765                         ret = snprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
766                                        (period * 100.0) / total);
767                 if (symbol_conf.show_cpu_utilization) {
768                         ret += percent_color_snprintf(s + ret, size - ret,
769                                         sep ? "%.2f" : "   %6.2f%%",
770                                         (period_sys * 100.0) / total);
771                         ret += percent_color_snprintf(s + ret, size - ret,
772                                         sep ? "%.2f" : "   %6.2f%%",
773                                         (period_us * 100.0) / total);
774                         if (perf_guest) {
775                                 ret += percent_color_snprintf(s + ret,
776                                                 size - ret,
777                                                 sep ? "%.2f" : "   %6.2f%%",
778                                                 (period_guest_sys * 100.0) /
779                                                                 total);
780                                 ret += percent_color_snprintf(s + ret,
781                                                 size - ret,
782                                                 sep ? "%.2f" : "   %6.2f%%",
783                                                 (period_guest_us * 100.0) /
784                                                                 total);
785                         }
786                 }
787         } else
788                 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
789
790         if (symbol_conf.show_nr_samples) {
791                 if (sep)
792                         ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
793                 else
794                         ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
795         }
796
797         if (symbol_conf.show_total_period) {
798                 if (sep)
799                         ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
800                 else
801                         ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
802         }
803
804         if (pair_hists) {
805                 char bf[32];
806                 double old_percent = 0, new_percent = 0, diff;
807
808                 if (total > 0)
809                         old_percent = (period * 100.0) / total;
810                 if (session_total > 0)
811                         new_percent = (self->period * 100.0) / session_total;
812
813                 diff = new_percent - old_percent;
814
815                 if (fabs(diff) >= 0.01)
816                         snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
817                 else
818                         snprintf(bf, sizeof(bf), " ");
819
820                 if (sep)
821                         ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
822                 else
823                         ret += snprintf(s + ret, size - ret, "%11.11s", bf);
824
825                 if (show_displacement) {
826                         if (displacement)
827                                 snprintf(bf, sizeof(bf), "%+4ld", displacement);
828                         else
829                                 snprintf(bf, sizeof(bf), " ");
830
831                         if (sep)
832                                 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
833                         else
834                                 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
835                 }
836         }
837
838         return ret;
839 }
840
841 int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
842                          struct hists *hists)
843 {
844         const char *sep = symbol_conf.field_sep;
845         struct sort_entry *se;
846         int ret = 0;
847
848         list_for_each_entry(se, &hist_entry__sort_list, list) {
849                 if (se->elide)
850                         continue;
851
852                 ret += snprintf(s + ret, size - ret, "%s", sep ?: "  ");
853                 ret += se->se_snprintf(he, s + ret, size - ret,
854                                        hists__col_len(hists, se->se_width_idx));
855         }
856
857         return ret;
858 }
859
860 int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
861                         struct hists *pair_hists, bool show_displacement,
862                         long displacement, FILE *fp, u64 session_total)
863 {
864         char bf[512];
865         int ret;
866
867         if (size == 0 || size > sizeof(bf))
868                 size = sizeof(bf);
869
870         ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
871                                         show_displacement, displacement,
872                                         true, session_total);
873         hist_entry__snprintf(he, bf + ret, size - ret, hists);
874         return fprintf(fp, "%s\n", bf);
875 }
876
877 static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
878                                             struct hists *hists, FILE *fp,
879                                             u64 session_total)
880 {
881         int left_margin = 0;
882
883         if (sort__first_dimension == SORT_COMM) {
884                 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
885                                                          typeof(*se), list);
886                 left_margin = hists__col_len(hists, se->se_width_idx);
887                 left_margin -= thread__comm_len(self->thread);
888         }
889
890         return hist_entry_callchain__fprintf(fp, self, session_total,
891                                              left_margin);
892 }
893
894 size_t hists__fprintf(struct hists *hists, struct hists *pair,
895                       bool show_displacement, bool show_header, int max_rows,
896                       int max_cols, FILE *fp)
897 {
898         struct sort_entry *se;
899         struct rb_node *nd;
900         size_t ret = 0;
901         unsigned long position = 1;
902         long displacement = 0;
903         unsigned int width;
904         const char *sep = symbol_conf.field_sep;
905         const char *col_width = symbol_conf.col_width_list_str;
906         int nr_rows = 0;
907
908         init_rem_hits();
909
910         if (!show_header)
911                 goto print_entries;
912
913         fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
914
915         if (symbol_conf.show_nr_samples) {
916                 if (sep)
917                         fprintf(fp, "%cSamples", *sep);
918                 else
919                         fputs("  Samples  ", fp);
920         }
921
922         if (symbol_conf.show_total_period) {
923                 if (sep)
924                         ret += fprintf(fp, "%cPeriod", *sep);
925                 else
926                         ret += fprintf(fp, "   Period    ");
927         }
928
929         if (symbol_conf.show_cpu_utilization) {
930                 if (sep) {
931                         ret += fprintf(fp, "%csys", *sep);
932                         ret += fprintf(fp, "%cus", *sep);
933                         if (perf_guest) {
934                                 ret += fprintf(fp, "%cguest sys", *sep);
935                                 ret += fprintf(fp, "%cguest us", *sep);
936                         }
937                 } else {
938                         ret += fprintf(fp, "  sys  ");
939                         ret += fprintf(fp, "  us  ");
940                         if (perf_guest) {
941                                 ret += fprintf(fp, "  guest sys  ");
942                                 ret += fprintf(fp, "  guest us  ");
943                         }
944                 }
945         }
946
947         if (pair) {
948                 if (sep)
949                         ret += fprintf(fp, "%cDelta", *sep);
950                 else
951                         ret += fprintf(fp, "  Delta    ");
952
953                 if (show_displacement) {
954                         if (sep)
955                                 ret += fprintf(fp, "%cDisplacement", *sep);
956                         else
957                                 ret += fprintf(fp, " Displ");
958                 }
959         }
960
961         list_for_each_entry(se, &hist_entry__sort_list, list) {
962                 if (se->elide)
963                         continue;
964                 if (sep) {
965                         fprintf(fp, "%c%s", *sep, se->se_header);
966                         continue;
967                 }
968                 width = strlen(se->se_header);
969                 if (symbol_conf.col_width_list_str) {
970                         if (col_width) {
971                                 hists__set_col_len(hists, se->se_width_idx,
972                                                    atoi(col_width));
973                                 col_width = strchr(col_width, ',');
974                                 if (col_width)
975                                         ++col_width;
976                         }
977                 }
978                 if (!hists__new_col_len(hists, se->se_width_idx, width))
979                         width = hists__col_len(hists, se->se_width_idx);
980                 fprintf(fp, "  %*s", width, se->se_header);
981         }
982
983         fprintf(fp, "\n");
984         if (max_rows && ++nr_rows >= max_rows)
985                 goto out;
986
987         if (sep)
988                 goto print_entries;
989
990         fprintf(fp, "# ........");
991         if (symbol_conf.show_nr_samples)
992                 fprintf(fp, " ..........");
993         if (symbol_conf.show_total_period)
994                 fprintf(fp, " ............");
995         if (pair) {
996                 fprintf(fp, " ..........");
997                 if (show_displacement)
998                         fprintf(fp, " .....");
999         }
1000         list_for_each_entry(se, &hist_entry__sort_list, list) {
1001                 unsigned int i;
1002
1003                 if (se->elide)
1004                         continue;
1005
1006                 fprintf(fp, "  ");
1007                 width = hists__col_len(hists, se->se_width_idx);
1008                 if (width == 0)
1009                         width = strlen(se->se_header);
1010                 for (i = 0; i < width; i++)
1011                         fprintf(fp, ".");
1012         }
1013
1014         fprintf(fp, "\n");
1015         if (max_rows && ++nr_rows >= max_rows)
1016                 goto out;
1017
1018         fprintf(fp, "#\n");
1019         if (max_rows && ++nr_rows >= max_rows)
1020                 goto out;
1021
1022 print_entries:
1023         for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1024                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1025
1026                 if (h->filtered)
1027                         continue;
1028
1029                 if (show_displacement) {
1030                         if (h->pair != NULL)
1031                                 displacement = ((long)h->pair->position -
1032                                                 (long)position);
1033                         else
1034                                 displacement = 0;
1035                         ++position;
1036                 }
1037                 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
1038                                            displacement, fp, hists->stats.total_period);
1039
1040                 if (symbol_conf.use_callchain)
1041                         ret += hist_entry__fprintf_callchain(h, hists, fp,
1042                                                              hists->stats.total_period);
1043                 if (max_rows && ++nr_rows >= max_rows)
1044                         goto out;
1045
1046                 if (h->ms.map == NULL && verbose > 1) {
1047                         __map_groups__fprintf_maps(&h->thread->mg,
1048                                                    MAP__FUNCTION, verbose, fp);
1049                         fprintf(fp, "%.10s end\n", graph_dotted_line);
1050                 }
1051         }
1052 out:
1053         free(rem_sq_bracket);
1054
1055         return ret;
1056 }
1057
1058 /*
1059  * See hists__fprintf to match the column widths
1060  */
1061 unsigned int hists__sort_list_width(struct hists *hists)
1062 {
1063         struct sort_entry *se;
1064         int ret = 9; /* total % */
1065
1066         if (symbol_conf.show_cpu_utilization) {
1067                 ret += 7; /* count_sys % */
1068                 ret += 6; /* count_us % */
1069                 if (perf_guest) {
1070                         ret += 13; /* count_guest_sys % */
1071                         ret += 12; /* count_guest_us % */
1072                 }
1073         }
1074
1075         if (symbol_conf.show_nr_samples)
1076                 ret += 11;
1077
1078         if (symbol_conf.show_total_period)
1079                 ret += 13;
1080
1081         list_for_each_entry(se, &hist_entry__sort_list, list)
1082                 if (!se->elide)
1083                         ret += 2 + hists__col_len(hists, se->se_width_idx);
1084
1085         if (verbose) /* Addr + origin */
1086                 ret += 3 + BITS_PER_LONG / 4;
1087
1088         return ret;
1089 }
1090
1091 static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
1092                                        enum hist_filter filter)
1093 {
1094         h->filtered &= ~(1 << filter);
1095         if (h->filtered)
1096                 return;
1097
1098         ++hists->nr_entries;
1099         if (h->ms.unfolded)
1100                 hists->nr_entries += h->nr_rows;
1101         h->row_offset = 0;
1102         hists->stats.total_period += h->period;
1103         hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
1104
1105         hists__calc_col_len(hists, h);
1106 }
1107
1108
1109 static bool hists__filter_entry_by_dso(struct hists *hists,
1110                                        struct hist_entry *he)
1111 {
1112         if (hists->dso_filter != NULL &&
1113             (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) {
1114                 he->filtered |= (1 << HIST_FILTER__DSO);
1115                 return true;
1116         }
1117
1118         return false;
1119 }
1120
1121 void hists__filter_by_dso(struct hists *hists)
1122 {
1123         struct rb_node *nd;
1124
1125         hists->nr_entries = hists->stats.total_period = 0;
1126         hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1127         hists__reset_col_len(hists);
1128
1129         for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1130                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1131
1132                 if (symbol_conf.exclude_other && !h->parent)
1133                         continue;
1134
1135                 if (hists__filter_entry_by_dso(hists, h))
1136                         continue;
1137
1138                 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
1139         }
1140 }
1141
1142 static bool hists__filter_entry_by_thread(struct hists *hists,
1143                                           struct hist_entry *he)
1144 {
1145         if (hists->thread_filter != NULL &&
1146             he->thread != hists->thread_filter) {
1147                 he->filtered |= (1 << HIST_FILTER__THREAD);
1148                 return true;
1149         }
1150
1151         return false;
1152 }
1153
1154 void hists__filter_by_thread(struct hists *hists)
1155 {
1156         struct rb_node *nd;
1157
1158         hists->nr_entries = hists->stats.total_period = 0;
1159         hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1160         hists__reset_col_len(hists);
1161
1162         for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1163                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1164
1165                 if (hists__filter_entry_by_thread(hists, h))
1166                         continue;
1167
1168                 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
1169         }
1170 }
1171
1172 int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
1173 {
1174         return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1175 }
1176
1177 int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1178 {
1179         return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1180 }
1181
1182 void hists__inc_nr_events(struct hists *hists, u32 type)
1183 {
1184         ++hists->stats.nr_events[0];
1185         ++hists->stats.nr_events[type];
1186 }
1187
1188 size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
1189 {
1190         int i;
1191         size_t ret = 0;
1192
1193         for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1194                 const char *name;
1195
1196                 if (hists->stats.nr_events[i] == 0)
1197                         continue;
1198
1199                 name = perf_event__name(i);
1200                 if (!strcmp(name, "UNKNOWN"))
1201                         continue;
1202
1203                 ret += fprintf(fp, "%16s events: %10d\n", name,
1204                                hists->stats.nr_events[i]);
1205         }
1206
1207         return ret;
1208 }
1209
1210 void hists__init(struct hists *hists)
1211 {
1212         memset(hists, 0, sizeof(*hists));
1213         hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1214         hists->entries_in = &hists->entries_in_array[0];
1215         hists->entries_collapsed = RB_ROOT;
1216         hists->entries = RB_ROOT;
1217         pthread_mutex_init(&hists->lock, NULL);
1218 }