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