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