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