Merge remote-tracking branch 'asoc/fix/dapm' into asoc-linus
[cascardo/linux.git] / tools / perf / ui / browsers / hists.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <linux/rbtree.h>
5
6 #include "../../util/evsel.h"
7 #include "../../util/evlist.h"
8 #include "../../util/hist.h"
9 #include "../../util/pstack.h"
10 #include "../../util/sort.h"
11 #include "../../util/util.h"
12 #include "../../util/top.h"
13 #include "../../arch/common.h"
14
15 #include "../browsers/hists.h"
16 #include "../helpline.h"
17 #include "../util.h"
18 #include "../ui.h"
19 #include "map.h"
20 #include "annotate.h"
21
22 extern void hist_browser__init_hpp(void);
23
24 static int perf_evsel_browser_title(struct hist_browser *browser,
25                                     char *bf, size_t size);
26 static void hist_browser__update_nr_entries(struct hist_browser *hb);
27
28 static struct rb_node *hists__filter_entries(struct rb_node *nd,
29                                              float min_pcnt);
30
31 static bool hist_browser__has_filter(struct hist_browser *hb)
32 {
33         return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
34 }
35
36 static int hist_browser__get_folding(struct hist_browser *browser)
37 {
38         struct rb_node *nd;
39         struct hists *hists = browser->hists;
40         int unfolded_rows = 0;
41
42         for (nd = rb_first(&hists->entries);
43              (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
44              nd = rb_hierarchy_next(nd)) {
45                 struct hist_entry *he =
46                         rb_entry(nd, struct hist_entry, rb_node);
47
48                 if (he->leaf && he->unfolded)
49                         unfolded_rows += he->nr_rows;
50         }
51         return unfolded_rows;
52 }
53
54 static u32 hist_browser__nr_entries(struct hist_browser *hb)
55 {
56         u32 nr_entries;
57
58         if (symbol_conf.report_hierarchy)
59                 nr_entries = hb->nr_hierarchy_entries;
60         else if (hist_browser__has_filter(hb))
61                 nr_entries = hb->nr_non_filtered_entries;
62         else
63                 nr_entries = hb->hists->nr_entries;
64
65         hb->nr_callchain_rows = hist_browser__get_folding(hb);
66         return nr_entries + hb->nr_callchain_rows;
67 }
68
69 static void hist_browser__update_rows(struct hist_browser *hb)
70 {
71         struct ui_browser *browser = &hb->b;
72         u16 header_offset = hb->show_headers ? 1 : 0, index_row;
73
74         browser->rows = browser->height - header_offset;
75         /*
76          * Verify if we were at the last line and that line isn't
77          * visibe because we now show the header line(s).
78          */
79         index_row = browser->index - browser->top_idx;
80         if (index_row >= browser->rows)
81                 browser->index -= index_row - browser->rows + 1;
82 }
83
84 static void hist_browser__refresh_dimensions(struct ui_browser *browser)
85 {
86         struct hist_browser *hb = container_of(browser, struct hist_browser, b);
87
88         /* 3 == +/- toggle symbol before actual hist_entry rendering */
89         browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
90         /*
91          * FIXME: Just keeping existing behaviour, but this really should be
92          *        before updating browser->width, as it will invalidate the
93          *        calculation above. Fix this and the fallout in another
94          *        changeset.
95          */
96         ui_browser__refresh_dimensions(browser);
97         hist_browser__update_rows(hb);
98 }
99
100 static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
101 {
102         u16 header_offset = browser->show_headers ? 1 : 0;
103
104         ui_browser__gotorc(&browser->b, row + header_offset, column);
105 }
106
107 static void hist_browser__reset(struct hist_browser *browser)
108 {
109         /*
110          * The hists__remove_entry_filter() already folds non-filtered
111          * entries so we can assume it has 0 callchain rows.
112          */
113         browser->nr_callchain_rows = 0;
114
115         hist_browser__update_nr_entries(browser);
116         browser->b.nr_entries = hist_browser__nr_entries(browser);
117         hist_browser__refresh_dimensions(&browser->b);
118         ui_browser__reset_index(&browser->b);
119 }
120
121 static char tree__folded_sign(bool unfolded)
122 {
123         return unfolded ? '-' : '+';
124 }
125
126 static char hist_entry__folded(const struct hist_entry *he)
127 {
128         return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
129 }
130
131 static char callchain_list__folded(const struct callchain_list *cl)
132 {
133         return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
134 }
135
136 static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
137 {
138         cl->unfolded = unfold ? cl->has_children : false;
139 }
140
141 static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
142 {
143         int n = 0;
144         struct rb_node *nd;
145
146         for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
147                 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
148                 struct callchain_list *chain;
149                 char folded_sign = ' '; /* No children */
150
151                 list_for_each_entry(chain, &child->val, list) {
152                         ++n;
153                         /* We need this because we may not have children */
154                         folded_sign = callchain_list__folded(chain);
155                         if (folded_sign == '+')
156                                 break;
157                 }
158
159                 if (folded_sign == '-') /* Have children and they're unfolded */
160                         n += callchain_node__count_rows_rb_tree(child);
161         }
162
163         return n;
164 }
165
166 static int callchain_node__count_flat_rows(struct callchain_node *node)
167 {
168         struct callchain_list *chain;
169         char folded_sign = 0;
170         int n = 0;
171
172         list_for_each_entry(chain, &node->parent_val, list) {
173                 if (!folded_sign) {
174                         /* only check first chain list entry */
175                         folded_sign = callchain_list__folded(chain);
176                         if (folded_sign == '+')
177                                 return 1;
178                 }
179                 n++;
180         }
181
182         list_for_each_entry(chain, &node->val, list) {
183                 if (!folded_sign) {
184                         /* node->parent_val list might be empty */
185                         folded_sign = callchain_list__folded(chain);
186                         if (folded_sign == '+')
187                                 return 1;
188                 }
189                 n++;
190         }
191
192         return n;
193 }
194
195 static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
196 {
197         return 1;
198 }
199
200 static int callchain_node__count_rows(struct callchain_node *node)
201 {
202         struct callchain_list *chain;
203         bool unfolded = false;
204         int n = 0;
205
206         if (callchain_param.mode == CHAIN_FLAT)
207                 return callchain_node__count_flat_rows(node);
208         else if (callchain_param.mode == CHAIN_FOLDED)
209                 return callchain_node__count_folded_rows(node);
210
211         list_for_each_entry(chain, &node->val, list) {
212                 ++n;
213                 unfolded = chain->unfolded;
214         }
215
216         if (unfolded)
217                 n += callchain_node__count_rows_rb_tree(node);
218
219         return n;
220 }
221
222 static int callchain__count_rows(struct rb_root *chain)
223 {
224         struct rb_node *nd;
225         int n = 0;
226
227         for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
228                 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
229                 n += callchain_node__count_rows(node);
230         }
231
232         return n;
233 }
234
235 static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
236                                 bool include_children)
237 {
238         int count = 0;
239         struct rb_node *node;
240         struct hist_entry *child;
241
242         if (he->leaf)
243                 return callchain__count_rows(&he->sorted_chain);
244
245         if (he->has_no_entry)
246                 return 1;
247
248         node = rb_first(&he->hroot_out);
249         while (node) {
250                 float percent;
251
252                 child = rb_entry(node, struct hist_entry, rb_node);
253                 percent = hist_entry__get_percent_limit(child);
254
255                 if (!child->filtered && percent >= hb->min_pcnt) {
256                         count++;
257
258                         if (include_children && child->unfolded)
259                                 count += hierarchy_count_rows(hb, child, true);
260                 }
261
262                 node = rb_next(node);
263         }
264         return count;
265 }
266
267 static bool hist_entry__toggle_fold(struct hist_entry *he)
268 {
269         if (!he)
270                 return false;
271
272         if (!he->has_children)
273                 return false;
274
275         he->unfolded = !he->unfolded;
276         return true;
277 }
278
279 static bool callchain_list__toggle_fold(struct callchain_list *cl)
280 {
281         if (!cl)
282                 return false;
283
284         if (!cl->has_children)
285                 return false;
286
287         cl->unfolded = !cl->unfolded;
288         return true;
289 }
290
291 static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
292 {
293         struct rb_node *nd = rb_first(&node->rb_root);
294
295         for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
296                 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
297                 struct callchain_list *chain;
298                 bool first = true;
299
300                 list_for_each_entry(chain, &child->val, list) {
301                         if (first) {
302                                 first = false;
303                                 chain->has_children = chain->list.next != &child->val ||
304                                                          !RB_EMPTY_ROOT(&child->rb_root);
305                         } else
306                                 chain->has_children = chain->list.next == &child->val &&
307                                                          !RB_EMPTY_ROOT(&child->rb_root);
308                 }
309
310                 callchain_node__init_have_children_rb_tree(child);
311         }
312 }
313
314 static void callchain_node__init_have_children(struct callchain_node *node,
315                                                bool has_sibling)
316 {
317         struct callchain_list *chain;
318
319         chain = list_entry(node->val.next, struct callchain_list, list);
320         chain->has_children = has_sibling;
321
322         if (!list_empty(&node->val)) {
323                 chain = list_entry(node->val.prev, struct callchain_list, list);
324                 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
325         }
326
327         callchain_node__init_have_children_rb_tree(node);
328 }
329
330 static void callchain__init_have_children(struct rb_root *root)
331 {
332         struct rb_node *nd = rb_first(root);
333         bool has_sibling = nd && rb_next(nd);
334
335         for (nd = rb_first(root); nd; nd = rb_next(nd)) {
336                 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
337                 callchain_node__init_have_children(node, has_sibling);
338                 if (callchain_param.mode == CHAIN_FLAT ||
339                     callchain_param.mode == CHAIN_FOLDED)
340                         callchain_node__make_parent_list(node);
341         }
342 }
343
344 static void hist_entry__init_have_children(struct hist_entry *he)
345 {
346         if (he->init_have_children)
347                 return;
348
349         if (he->leaf) {
350                 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
351                 callchain__init_have_children(&he->sorted_chain);
352         } else {
353                 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
354         }
355
356         he->init_have_children = true;
357 }
358
359 static bool hist_browser__toggle_fold(struct hist_browser *browser)
360 {
361         struct hist_entry *he = browser->he_selection;
362         struct map_symbol *ms = browser->selection;
363         struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
364         bool has_children;
365
366         if (!he || !ms)
367                 return false;
368
369         if (ms == &he->ms)
370                 has_children = hist_entry__toggle_fold(he);
371         else
372                 has_children = callchain_list__toggle_fold(cl);
373
374         if (has_children) {
375                 int child_rows = 0;
376
377                 hist_entry__init_have_children(he);
378                 browser->b.nr_entries -= he->nr_rows;
379
380                 if (he->leaf)
381                         browser->nr_callchain_rows -= he->nr_rows;
382                 else
383                         browser->nr_hierarchy_entries -= he->nr_rows;
384
385                 if (symbol_conf.report_hierarchy)
386                         child_rows = hierarchy_count_rows(browser, he, true);
387
388                 if (he->unfolded) {
389                         if (he->leaf)
390                                 he->nr_rows = callchain__count_rows(&he->sorted_chain);
391                         else
392                                 he->nr_rows = hierarchy_count_rows(browser, he, false);
393
394                         /* account grand children */
395                         if (symbol_conf.report_hierarchy)
396                                 browser->b.nr_entries += child_rows - he->nr_rows;
397
398                         if (!he->leaf && he->nr_rows == 0) {
399                                 he->has_no_entry = true;
400                                 he->nr_rows = 1;
401                         }
402                 } else {
403                         if (symbol_conf.report_hierarchy)
404                                 browser->b.nr_entries -= child_rows - he->nr_rows;
405
406                         if (he->has_no_entry)
407                                 he->has_no_entry = false;
408
409                         he->nr_rows = 0;
410                 }
411
412                 browser->b.nr_entries += he->nr_rows;
413
414                 if (he->leaf)
415                         browser->nr_callchain_rows += he->nr_rows;
416                 else
417                         browser->nr_hierarchy_entries += he->nr_rows;
418
419                 return true;
420         }
421
422         /* If it doesn't have children, no toggling performed */
423         return false;
424 }
425
426 static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
427 {
428         int n = 0;
429         struct rb_node *nd;
430
431         for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
432                 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
433                 struct callchain_list *chain;
434                 bool has_children = false;
435
436                 list_for_each_entry(chain, &child->val, list) {
437                         ++n;
438                         callchain_list__set_folding(chain, unfold);
439                         has_children = chain->has_children;
440                 }
441
442                 if (has_children)
443                         n += callchain_node__set_folding_rb_tree(child, unfold);
444         }
445
446         return n;
447 }
448
449 static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
450 {
451         struct callchain_list *chain;
452         bool has_children = false;
453         int n = 0;
454
455         list_for_each_entry(chain, &node->val, list) {
456                 ++n;
457                 callchain_list__set_folding(chain, unfold);
458                 has_children = chain->has_children;
459         }
460
461         if (has_children)
462                 n += callchain_node__set_folding_rb_tree(node, unfold);
463
464         return n;
465 }
466
467 static int callchain__set_folding(struct rb_root *chain, bool unfold)
468 {
469         struct rb_node *nd;
470         int n = 0;
471
472         for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
473                 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
474                 n += callchain_node__set_folding(node, unfold);
475         }
476
477         return n;
478 }
479
480 static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
481                                  bool unfold __maybe_unused)
482 {
483         float percent;
484         struct rb_node *nd;
485         struct hist_entry *child;
486         int n = 0;
487
488         for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
489                 child = rb_entry(nd, struct hist_entry, rb_node);
490                 percent = hist_entry__get_percent_limit(child);
491                 if (!child->filtered && percent >= hb->min_pcnt)
492                         n++;
493         }
494
495         return n;
496 }
497
498 static void hist_entry__set_folding(struct hist_entry *he,
499                                     struct hist_browser *hb, bool unfold)
500 {
501         hist_entry__init_have_children(he);
502         he->unfolded = unfold ? he->has_children : false;
503
504         if (he->has_children) {
505                 int n;
506
507                 if (he->leaf)
508                         n = callchain__set_folding(&he->sorted_chain, unfold);
509                 else
510                         n = hierarchy_set_folding(hb, he, unfold);
511
512                 he->nr_rows = unfold ? n : 0;
513         } else
514                 he->nr_rows = 0;
515 }
516
517 static void
518 __hist_browser__set_folding(struct hist_browser *browser, bool unfold)
519 {
520         struct rb_node *nd;
521         struct hist_entry *he;
522         double percent;
523
524         nd = rb_first(&browser->hists->entries);
525         while (nd) {
526                 he = rb_entry(nd, struct hist_entry, rb_node);
527
528                 /* set folding state even if it's currently folded */
529                 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
530
531                 hist_entry__set_folding(he, browser, unfold);
532
533                 percent = hist_entry__get_percent_limit(he);
534                 if (he->filtered || percent < browser->min_pcnt)
535                         continue;
536
537                 if (!he->depth || unfold)
538                         browser->nr_hierarchy_entries++;
539                 if (he->leaf)
540                         browser->nr_callchain_rows += he->nr_rows;
541                 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
542                         browser->nr_hierarchy_entries++;
543                         he->has_no_entry = true;
544                         he->nr_rows = 1;
545                 } else
546                         he->has_no_entry = false;
547         }
548 }
549
550 static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
551 {
552         browser->nr_hierarchy_entries = 0;
553         browser->nr_callchain_rows = 0;
554         __hist_browser__set_folding(browser, unfold);
555
556         browser->b.nr_entries = hist_browser__nr_entries(browser);
557         /* Go to the start, we may be way after valid entries after a collapse */
558         ui_browser__reset_index(&browser->b);
559 }
560
561 static void ui_browser__warn_lost_events(struct ui_browser *browser)
562 {
563         ui_browser__warning(browser, 4,
564                 "Events are being lost, check IO/CPU overload!\n\n"
565                 "You may want to run 'perf' using a RT scheduler policy:\n\n"
566                 " perf top -r 80\n\n"
567                 "Or reduce the sampling frequency.");
568 }
569
570 static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
571 {
572         return browser->title ? browser->title(browser, bf, size) : 0;
573 }
574
575 int hist_browser__run(struct hist_browser *browser, const char *help)
576 {
577         int key;
578         char title[160];
579         struct hist_browser_timer *hbt = browser->hbt;
580         int delay_secs = hbt ? hbt->refresh : 0;
581
582         browser->b.entries = &browser->hists->entries;
583         browser->b.nr_entries = hist_browser__nr_entries(browser);
584
585         hist_browser__title(browser, title, sizeof(title));
586
587         if (ui_browser__show(&browser->b, title, "%s", help) < 0)
588                 return -1;
589
590         while (1) {
591                 key = ui_browser__run(&browser->b, delay_secs);
592
593                 switch (key) {
594                 case K_TIMER: {
595                         u64 nr_entries;
596                         hbt->timer(hbt->arg);
597
598                         if (hist_browser__has_filter(browser))
599                                 hist_browser__update_nr_entries(browser);
600
601                         nr_entries = hist_browser__nr_entries(browser);
602                         ui_browser__update_nr_entries(&browser->b, nr_entries);
603
604                         if (browser->hists->stats.nr_lost_warned !=
605                             browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
606                                 browser->hists->stats.nr_lost_warned =
607                                         browser->hists->stats.nr_events[PERF_RECORD_LOST];
608                                 ui_browser__warn_lost_events(&browser->b);
609                         }
610
611                         hist_browser__title(browser, title, sizeof(title));
612                         ui_browser__show_title(&browser->b, title);
613                         continue;
614                 }
615                 case 'D': { /* Debug */
616                         static int seq;
617                         struct hist_entry *h = rb_entry(browser->b.top,
618                                                         struct hist_entry, rb_node);
619                         ui_helpline__pop();
620                         ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
621                                            seq++, browser->b.nr_entries,
622                                            browser->hists->nr_entries,
623                                            browser->b.rows,
624                                            browser->b.index,
625                                            browser->b.top_idx,
626                                            h->row_offset, h->nr_rows);
627                 }
628                         break;
629                 case 'C':
630                         /* Collapse the whole world. */
631                         hist_browser__set_folding(browser, false);
632                         break;
633                 case 'E':
634                         /* Expand the whole world. */
635                         hist_browser__set_folding(browser, true);
636                         break;
637                 case 'H':
638                         browser->show_headers = !browser->show_headers;
639                         hist_browser__update_rows(browser);
640                         break;
641                 case K_ENTER:
642                         if (hist_browser__toggle_fold(browser))
643                                 break;
644                         /* fall thru */
645                 default:
646                         goto out;
647                 }
648         }
649 out:
650         ui_browser__hide(&browser->b);
651         return key;
652 }
653
654 struct callchain_print_arg {
655         /* for hists browser */
656         off_t   row_offset;
657         bool    is_current_entry;
658
659         /* for file dump */
660         FILE    *fp;
661         int     printed;
662 };
663
664 typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
665                                          struct callchain_list *chain,
666                                          const char *str, int offset,
667                                          unsigned short row,
668                                          struct callchain_print_arg *arg);
669
670 static void hist_browser__show_callchain_entry(struct hist_browser *browser,
671                                                struct callchain_list *chain,
672                                                const char *str, int offset,
673                                                unsigned short row,
674                                                struct callchain_print_arg *arg)
675 {
676         int color, width;
677         char folded_sign = callchain_list__folded(chain);
678         bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
679
680         color = HE_COLORSET_NORMAL;
681         width = browser->b.width - (offset + 2);
682         if (ui_browser__is_current_entry(&browser->b, row)) {
683                 browser->selection = &chain->ms;
684                 color = HE_COLORSET_SELECTED;
685                 arg->is_current_entry = true;
686         }
687
688         ui_browser__set_color(&browser->b, color);
689         hist_browser__gotorc(browser, row, 0);
690         ui_browser__write_nstring(&browser->b, " ", offset);
691         ui_browser__printf(&browser->b, "%c", folded_sign);
692         ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
693         ui_browser__write_nstring(&browser->b, str, width);
694 }
695
696 static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
697                                                   struct callchain_list *chain,
698                                                   const char *str, int offset,
699                                                   unsigned short row __maybe_unused,
700                                                   struct callchain_print_arg *arg)
701 {
702         char folded_sign = callchain_list__folded(chain);
703
704         arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
705                                 folded_sign, str);
706 }
707
708 typedef bool (*check_output_full_fn)(struct hist_browser *browser,
709                                      unsigned short row);
710
711 static bool hist_browser__check_output_full(struct hist_browser *browser,
712                                             unsigned short row)
713 {
714         return browser->b.rows == row;
715 }
716
717 static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
718                                           unsigned short row __maybe_unused)
719 {
720         return false;
721 }
722
723 #define LEVEL_OFFSET_STEP 3
724
725 static int hist_browser__show_callchain_list(struct hist_browser *browser,
726                                              struct callchain_node *node,
727                                              struct callchain_list *chain,
728                                              unsigned short row, u64 total,
729                                              bool need_percent, int offset,
730                                              print_callchain_entry_fn print,
731                                              struct callchain_print_arg *arg)
732 {
733         char bf[1024], *alloc_str;
734         const char *str;
735
736         if (arg->row_offset != 0) {
737                 arg->row_offset--;
738                 return 0;
739         }
740
741         alloc_str = NULL;
742         str = callchain_list__sym_name(chain, bf, sizeof(bf),
743                                        browser->show_dso);
744
745         if (need_percent) {
746                 char buf[64];
747
748                 callchain_node__scnprintf_value(node, buf, sizeof(buf),
749                                                 total);
750
751                 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
752                         str = "Not enough memory!";
753                 else
754                         str = alloc_str;
755         }
756
757         print(browser, chain, str, offset, row, arg);
758
759         free(alloc_str);
760         return 1;
761 }
762
763 static bool check_percent_display(struct rb_node *node, u64 parent_total)
764 {
765         struct callchain_node *child;
766
767         if (node == NULL)
768                 return false;
769
770         if (rb_next(node))
771                 return true;
772
773         child = rb_entry(node, struct callchain_node, rb_node);
774         return callchain_cumul_hits(child) != parent_total;
775 }
776
777 static int hist_browser__show_callchain_flat(struct hist_browser *browser,
778                                              struct rb_root *root,
779                                              unsigned short row, u64 total,
780                                              u64 parent_total,
781                                              print_callchain_entry_fn print,
782                                              struct callchain_print_arg *arg,
783                                              check_output_full_fn is_output_full)
784 {
785         struct rb_node *node;
786         int first_row = row, offset = LEVEL_OFFSET_STEP;
787         bool need_percent;
788
789         node = rb_first(root);
790         need_percent = check_percent_display(node, parent_total);
791
792         while (node) {
793                 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
794                 struct rb_node *next = rb_next(node);
795                 struct callchain_list *chain;
796                 char folded_sign = ' ';
797                 int first = true;
798                 int extra_offset = 0;
799
800                 list_for_each_entry(chain, &child->parent_val, list) {
801                         bool was_first = first;
802
803                         if (first)
804                                 first = false;
805                         else if (need_percent)
806                                 extra_offset = LEVEL_OFFSET_STEP;
807
808                         folded_sign = callchain_list__folded(chain);
809
810                         row += hist_browser__show_callchain_list(browser, child,
811                                                         chain, row, total,
812                                                         was_first && need_percent,
813                                                         offset + extra_offset,
814                                                         print, arg);
815
816                         if (is_output_full(browser, row))
817                                 goto out;
818
819                         if (folded_sign == '+')
820                                 goto next;
821                 }
822
823                 list_for_each_entry(chain, &child->val, list) {
824                         bool was_first = first;
825
826                         if (first)
827                                 first = false;
828                         else if (need_percent)
829                                 extra_offset = LEVEL_OFFSET_STEP;
830
831                         folded_sign = callchain_list__folded(chain);
832
833                         row += hist_browser__show_callchain_list(browser, child,
834                                                         chain, row, total,
835                                                         was_first && need_percent,
836                                                         offset + extra_offset,
837                                                         print, arg);
838
839                         if (is_output_full(browser, row))
840                                 goto out;
841
842                         if (folded_sign == '+')
843                                 break;
844                 }
845
846 next:
847                 if (is_output_full(browser, row))
848                         break;
849                 node = next;
850         }
851 out:
852         return row - first_row;
853 }
854
855 static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
856                                                 struct callchain_list *chain,
857                                                 char *value_str, char *old_str)
858 {
859         char bf[1024];
860         const char *str;
861         char *new;
862
863         str = callchain_list__sym_name(chain, bf, sizeof(bf),
864                                        browser->show_dso);
865         if (old_str) {
866                 if (asprintf(&new, "%s%s%s", old_str,
867                              symbol_conf.field_sep ?: ";", str) < 0)
868                         new = NULL;
869         } else {
870                 if (value_str) {
871                         if (asprintf(&new, "%s %s", value_str, str) < 0)
872                                 new = NULL;
873                 } else {
874                         if (asprintf(&new, "%s", str) < 0)
875                                 new = NULL;
876                 }
877         }
878         return new;
879 }
880
881 static int hist_browser__show_callchain_folded(struct hist_browser *browser,
882                                                struct rb_root *root,
883                                                unsigned short row, u64 total,
884                                                u64 parent_total,
885                                                print_callchain_entry_fn print,
886                                                struct callchain_print_arg *arg,
887                                                check_output_full_fn is_output_full)
888 {
889         struct rb_node *node;
890         int first_row = row, offset = LEVEL_OFFSET_STEP;
891         bool need_percent;
892
893         node = rb_first(root);
894         need_percent = check_percent_display(node, parent_total);
895
896         while (node) {
897                 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
898                 struct rb_node *next = rb_next(node);
899                 struct callchain_list *chain, *first_chain = NULL;
900                 int first = true;
901                 char *value_str = NULL, *value_str_alloc = NULL;
902                 char *chain_str = NULL, *chain_str_alloc = NULL;
903
904                 if (arg->row_offset != 0) {
905                         arg->row_offset--;
906                         goto next;
907                 }
908
909                 if (need_percent) {
910                         char buf[64];
911
912                         callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
913                         if (asprintf(&value_str, "%s", buf) < 0) {
914                                 value_str = (char *)"<...>";
915                                 goto do_print;
916                         }
917                         value_str_alloc = value_str;
918                 }
919
920                 list_for_each_entry(chain, &child->parent_val, list) {
921                         chain_str = hist_browser__folded_callchain_str(browser,
922                                                 chain, value_str, chain_str);
923                         if (first) {
924                                 first = false;
925                                 first_chain = chain;
926                         }
927
928                         if (chain_str == NULL) {
929                                 chain_str = (char *)"Not enough memory!";
930                                 goto do_print;
931                         }
932
933                         chain_str_alloc = chain_str;
934                 }
935
936                 list_for_each_entry(chain, &child->val, list) {
937                         chain_str = hist_browser__folded_callchain_str(browser,
938                                                 chain, value_str, chain_str);
939                         if (first) {
940                                 first = false;
941                                 first_chain = chain;
942                         }
943
944                         if (chain_str == NULL) {
945                                 chain_str = (char *)"Not enough memory!";
946                                 goto do_print;
947                         }
948
949                         chain_str_alloc = chain_str;
950                 }
951
952 do_print:
953                 print(browser, first_chain, chain_str, offset, row++, arg);
954                 free(value_str_alloc);
955                 free(chain_str_alloc);
956
957 next:
958                 if (is_output_full(browser, row))
959                         break;
960                 node = next;
961         }
962
963         return row - first_row;
964 }
965
966 static int hist_browser__show_callchain_graph(struct hist_browser *browser,
967                                         struct rb_root *root, int level,
968                                         unsigned short row, u64 total,
969                                         u64 parent_total,
970                                         print_callchain_entry_fn print,
971                                         struct callchain_print_arg *arg,
972                                         check_output_full_fn is_output_full)
973 {
974         struct rb_node *node;
975         int first_row = row, offset = level * LEVEL_OFFSET_STEP;
976         bool need_percent;
977         u64 percent_total = total;
978
979         if (callchain_param.mode == CHAIN_GRAPH_REL)
980                 percent_total = parent_total;
981
982         node = rb_first(root);
983         need_percent = check_percent_display(node, parent_total);
984
985         while (node) {
986                 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
987                 struct rb_node *next = rb_next(node);
988                 struct callchain_list *chain;
989                 char folded_sign = ' ';
990                 int first = true;
991                 int extra_offset = 0;
992
993                 list_for_each_entry(chain, &child->val, list) {
994                         bool was_first = first;
995
996                         if (first)
997                                 first = false;
998                         else if (need_percent)
999                                 extra_offset = LEVEL_OFFSET_STEP;
1000
1001                         folded_sign = callchain_list__folded(chain);
1002
1003                         row += hist_browser__show_callchain_list(browser, child,
1004                                                         chain, row, percent_total,
1005                                                         was_first && need_percent,
1006                                                         offset + extra_offset,
1007                                                         print, arg);
1008
1009                         if (is_output_full(browser, row))
1010                                 goto out;
1011
1012                         if (folded_sign == '+')
1013                                 break;
1014                 }
1015
1016                 if (folded_sign == '-') {
1017                         const int new_level = level + (extra_offset ? 2 : 1);
1018
1019                         row += hist_browser__show_callchain_graph(browser, &child->rb_root,
1020                                                             new_level, row, total,
1021                                                             child->children_hit,
1022                                                             print, arg, is_output_full);
1023                 }
1024                 if (is_output_full(browser, row))
1025                         break;
1026                 node = next;
1027         }
1028 out:
1029         return row - first_row;
1030 }
1031
1032 static int hist_browser__show_callchain(struct hist_browser *browser,
1033                                         struct hist_entry *entry, int level,
1034                                         unsigned short row,
1035                                         print_callchain_entry_fn print,
1036                                         struct callchain_print_arg *arg,
1037                                         check_output_full_fn is_output_full)
1038 {
1039         u64 total = hists__total_period(entry->hists);
1040         u64 parent_total;
1041         int printed;
1042
1043         if (symbol_conf.cumulate_callchain)
1044                 parent_total = entry->stat_acc->period;
1045         else
1046                 parent_total = entry->stat.period;
1047
1048         if (callchain_param.mode == CHAIN_FLAT) {
1049                 printed = hist_browser__show_callchain_flat(browser,
1050                                                 &entry->sorted_chain, row,
1051                                                 total, parent_total, print, arg,
1052                                                 is_output_full);
1053         } else if (callchain_param.mode == CHAIN_FOLDED) {
1054                 printed = hist_browser__show_callchain_folded(browser,
1055                                                 &entry->sorted_chain, row,
1056                                                 total, parent_total, print, arg,
1057                                                 is_output_full);
1058         } else {
1059                 printed = hist_browser__show_callchain_graph(browser,
1060                                                 &entry->sorted_chain, level, row,
1061                                                 total, parent_total, print, arg,
1062                                                 is_output_full);
1063         }
1064
1065         if (arg->is_current_entry)
1066                 browser->he_selection = entry;
1067
1068         return printed;
1069 }
1070
1071 struct hpp_arg {
1072         struct ui_browser *b;
1073         char folded_sign;
1074         bool current_entry;
1075 };
1076
1077 static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
1078 {
1079         struct hpp_arg *arg = hpp->ptr;
1080         int ret, len;
1081         va_list args;
1082         double percent;
1083
1084         va_start(args, fmt);
1085         len = va_arg(args, int);
1086         percent = va_arg(args, double);
1087         va_end(args);
1088
1089         ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
1090
1091         ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
1092         ui_browser__printf(arg->b, "%s", hpp->buf);
1093
1094         advance_hpp(hpp, ret);
1095         return ret;
1096 }
1097
1098 #define __HPP_COLOR_PERCENT_FN(_type, _field)                           \
1099 static u64 __hpp_get_##_field(struct hist_entry *he)                    \
1100 {                                                                       \
1101         return he->stat._field;                                         \
1102 }                                                                       \
1103                                                                         \
1104 static int                                                              \
1105 hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,               \
1106                                 struct perf_hpp *hpp,                   \
1107                                 struct hist_entry *he)                  \
1108 {                                                                       \
1109         return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%",   \
1110                         __hpp__slsmg_color_printf, true);               \
1111 }
1112
1113 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                       \
1114 static u64 __hpp_get_acc_##_field(struct hist_entry *he)                \
1115 {                                                                       \
1116         return he->stat_acc->_field;                                    \
1117 }                                                                       \
1118                                                                         \
1119 static int                                                              \
1120 hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,               \
1121                                 struct perf_hpp *hpp,                   \
1122                                 struct hist_entry *he)                  \
1123 {                                                                       \
1124         if (!symbol_conf.cumulate_callchain) {                          \
1125                 struct hpp_arg *arg = hpp->ptr;                         \
1126                 int len = fmt->user_len ?: fmt->len;                    \
1127                 int ret = scnprintf(hpp->buf, hpp->size,                \
1128                                     "%*s", len, "N/A");                 \
1129                 ui_browser__printf(arg->b, "%s", hpp->buf);             \
1130                                                                         \
1131                 return ret;                                             \
1132         }                                                               \
1133         return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field,           \
1134                         " %*.2f%%", __hpp__slsmg_color_printf, true);   \
1135 }
1136
1137 __HPP_COLOR_PERCENT_FN(overhead, period)
1138 __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1139 __HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1140 __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1141 __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
1142 __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
1143
1144 #undef __HPP_COLOR_PERCENT_FN
1145 #undef __HPP_COLOR_ACC_PERCENT_FN
1146
1147 void hist_browser__init_hpp(void)
1148 {
1149         perf_hpp__format[PERF_HPP__OVERHEAD].color =
1150                                 hist_browser__hpp_color_overhead;
1151         perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1152                                 hist_browser__hpp_color_overhead_sys;
1153         perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1154                                 hist_browser__hpp_color_overhead_us;
1155         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1156                                 hist_browser__hpp_color_overhead_guest_sys;
1157         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1158                                 hist_browser__hpp_color_overhead_guest_us;
1159         perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1160                                 hist_browser__hpp_color_overhead_acc;
1161 }
1162
1163 static int hist_browser__show_entry(struct hist_browser *browser,
1164                                     struct hist_entry *entry,
1165                                     unsigned short row)
1166 {
1167         int printed = 0;
1168         int width = browser->b.width;
1169         char folded_sign = ' ';
1170         bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1171         off_t row_offset = entry->row_offset;
1172         bool first = true;
1173         struct perf_hpp_fmt *fmt;
1174
1175         if (current_entry) {
1176                 browser->he_selection = entry;
1177                 browser->selection = &entry->ms;
1178         }
1179
1180         if (symbol_conf.use_callchain) {
1181                 hist_entry__init_have_children(entry);
1182                 folded_sign = hist_entry__folded(entry);
1183         }
1184
1185         if (row_offset == 0) {
1186                 struct hpp_arg arg = {
1187                         .b              = &browser->b,
1188                         .folded_sign    = folded_sign,
1189                         .current_entry  = current_entry,
1190                 };
1191                 int column = 0;
1192
1193                 hist_browser__gotorc(browser, row, 0);
1194
1195                 hists__for_each_format(browser->hists, fmt) {
1196                         char s[2048];
1197                         struct perf_hpp hpp = {
1198                                 .buf    = s,
1199                                 .size   = sizeof(s),
1200                                 .ptr    = &arg,
1201                         };
1202
1203                         if (perf_hpp__should_skip(fmt, entry->hists) ||
1204                             column++ < browser->b.horiz_scroll)
1205                                 continue;
1206
1207                         if (current_entry && browser->b.navkeypressed) {
1208                                 ui_browser__set_color(&browser->b,
1209                                                       HE_COLORSET_SELECTED);
1210                         } else {
1211                                 ui_browser__set_color(&browser->b,
1212                                                       HE_COLORSET_NORMAL);
1213                         }
1214
1215                         if (first) {
1216                                 if (symbol_conf.use_callchain) {
1217                                         ui_browser__printf(&browser->b, "%c ", folded_sign);
1218                                         width -= 2;
1219                                 }
1220                                 first = false;
1221                         } else {
1222                                 ui_browser__printf(&browser->b, "  ");
1223                                 width -= 2;
1224                         }
1225
1226                         if (fmt->color) {
1227                                 int ret = fmt->color(fmt, &hpp, entry);
1228                                 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1229                                 /*
1230                                  * fmt->color() already used ui_browser to
1231                                  * print the non alignment bits, skip it (+ret):
1232                                  */
1233                                 ui_browser__printf(&browser->b, "%s", s + ret);
1234                         } else {
1235                                 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
1236                                 ui_browser__printf(&browser->b, "%s", s);
1237                         }
1238                         width -= hpp.buf - s;
1239                 }
1240
1241                 /* The scroll bar isn't being used */
1242                 if (!browser->b.navkeypressed)
1243                         width += 1;
1244
1245                 ui_browser__write_nstring(&browser->b, "", width);
1246
1247                 ++row;
1248                 ++printed;
1249         } else
1250                 --row_offset;
1251
1252         if (folded_sign == '-' && row != browser->b.rows) {
1253                 struct callchain_print_arg arg = {
1254                         .row_offset = row_offset,
1255                         .is_current_entry = current_entry,
1256                 };
1257
1258                 printed += hist_browser__show_callchain(browser, entry, 1, row,
1259                                         hist_browser__show_callchain_entry, &arg,
1260                                         hist_browser__check_output_full);
1261         }
1262
1263         return printed;
1264 }
1265
1266 static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1267                                               struct hist_entry *entry,
1268                                               unsigned short row,
1269                                               int level)
1270 {
1271         int printed = 0;
1272         int width = browser->b.width;
1273         char folded_sign = ' ';
1274         bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1275         off_t row_offset = entry->row_offset;
1276         bool first = true;
1277         struct perf_hpp_fmt *fmt;
1278         struct perf_hpp_list_node *fmt_node;
1279         struct hpp_arg arg = {
1280                 .b              = &browser->b,
1281                 .current_entry  = current_entry,
1282         };
1283         int column = 0;
1284         int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
1285
1286         if (current_entry) {
1287                 browser->he_selection = entry;
1288                 browser->selection = &entry->ms;
1289         }
1290
1291         hist_entry__init_have_children(entry);
1292         folded_sign = hist_entry__folded(entry);
1293         arg.folded_sign = folded_sign;
1294
1295         if (entry->leaf && row_offset) {
1296                 row_offset--;
1297                 goto show_callchain;
1298         }
1299
1300         hist_browser__gotorc(browser, row, 0);
1301
1302         if (current_entry && browser->b.navkeypressed)
1303                 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1304         else
1305                 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1306
1307         ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1308         width -= level * HIERARCHY_INDENT;
1309
1310         /* the first hpp_list_node is for overhead columns */
1311         fmt_node = list_first_entry(&entry->hists->hpp_formats,
1312                                     struct perf_hpp_list_node, list);
1313         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1314                 char s[2048];
1315                 struct perf_hpp hpp = {
1316                         .buf            = s,
1317                         .size           = sizeof(s),
1318                         .ptr            = &arg,
1319                 };
1320
1321                 if (perf_hpp__should_skip(fmt, entry->hists) ||
1322                     column++ < browser->b.horiz_scroll)
1323                         continue;
1324
1325                 if (current_entry && browser->b.navkeypressed) {
1326                         ui_browser__set_color(&browser->b,
1327                                               HE_COLORSET_SELECTED);
1328                 } else {
1329                         ui_browser__set_color(&browser->b,
1330                                               HE_COLORSET_NORMAL);
1331                 }
1332
1333                 if (first) {
1334                         ui_browser__printf(&browser->b, "%c", folded_sign);
1335                         width--;
1336                         first = false;
1337                 } else {
1338                         ui_browser__printf(&browser->b, "  ");
1339                         width -= 2;
1340                 }
1341
1342                 if (fmt->color) {
1343                         int ret = fmt->color(fmt, &hpp, entry);
1344                         hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1345                         /*
1346                          * fmt->color() already used ui_browser to
1347                          * print the non alignment bits, skip it (+ret):
1348                          */
1349                         ui_browser__printf(&browser->b, "%s", s + ret);
1350                 } else {
1351                         int ret = fmt->entry(fmt, &hpp, entry);
1352                         hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1353                         ui_browser__printf(&browser->b, "%s", s);
1354                 }
1355                 width -= hpp.buf - s;
1356         }
1357
1358         ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1359         width -= hierarchy_indent;
1360
1361         if (column >= browser->b.horiz_scroll) {
1362                 char s[2048];
1363                 struct perf_hpp hpp = {
1364                         .buf            = s,
1365                         .size           = sizeof(s),
1366                         .ptr            = &arg,
1367                 };
1368
1369                 if (current_entry && browser->b.navkeypressed) {
1370                         ui_browser__set_color(&browser->b,
1371                                               HE_COLORSET_SELECTED);
1372                 } else {
1373                         ui_browser__set_color(&browser->b,
1374                                               HE_COLORSET_NORMAL);
1375                 }
1376
1377                 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1378                         ui_browser__write_nstring(&browser->b, "", 2);
1379                         width -= 2;
1380
1381                         /*
1382                          * No need to call hist_entry__snprintf_alignment()
1383                          * since this fmt is always the last column in the
1384                          * hierarchy mode.
1385                          */
1386                         if (fmt->color) {
1387                                 width -= fmt->color(fmt, &hpp, entry);
1388                         } else {
1389                                 int i = 0;
1390
1391                                 width -= fmt->entry(fmt, &hpp, entry);
1392                                 ui_browser__printf(&browser->b, "%s", ltrim(s));
1393
1394                                 while (isspace(s[i++]))
1395                                         width++;
1396                         }
1397                 }
1398         }
1399
1400         /* The scroll bar isn't being used */
1401         if (!browser->b.navkeypressed)
1402                 width += 1;
1403
1404         ui_browser__write_nstring(&browser->b, "", width);
1405
1406         ++row;
1407         ++printed;
1408
1409 show_callchain:
1410         if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1411                 struct callchain_print_arg carg = {
1412                         .row_offset = row_offset,
1413                 };
1414
1415                 printed += hist_browser__show_callchain(browser, entry,
1416                                         level + 1, row,
1417                                         hist_browser__show_callchain_entry, &carg,
1418                                         hist_browser__check_output_full);
1419         }
1420
1421         return printed;
1422 }
1423
1424 static int hist_browser__show_no_entry(struct hist_browser *browser,
1425                                        unsigned short row, int level)
1426 {
1427         int width = browser->b.width;
1428         bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1429         bool first = true;
1430         int column = 0;
1431         int ret;
1432         struct perf_hpp_fmt *fmt;
1433         struct perf_hpp_list_node *fmt_node;
1434         int indent = browser->hists->nr_hpp_node - 2;
1435
1436         if (current_entry) {
1437                 browser->he_selection = NULL;
1438                 browser->selection = NULL;
1439         }
1440
1441         hist_browser__gotorc(browser, row, 0);
1442
1443         if (current_entry && browser->b.navkeypressed)
1444                 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1445         else
1446                 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1447
1448         ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1449         width -= level * HIERARCHY_INDENT;
1450
1451         /* the first hpp_list_node is for overhead columns */
1452         fmt_node = list_first_entry(&browser->hists->hpp_formats,
1453                                     struct perf_hpp_list_node, list);
1454         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1455                 if (perf_hpp__should_skip(fmt, browser->hists) ||
1456                     column++ < browser->b.horiz_scroll)
1457                         continue;
1458
1459                 ret = fmt->width(fmt, NULL, browser->hists);
1460
1461                 if (first) {
1462                         /* for folded sign */
1463                         first = false;
1464                         ret++;
1465                 } else {
1466                         /* space between columns */
1467                         ret += 2;
1468                 }
1469
1470                 ui_browser__write_nstring(&browser->b, "", ret);
1471                 width -= ret;
1472         }
1473
1474         ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1475         width -= indent * HIERARCHY_INDENT;
1476
1477         if (column >= browser->b.horiz_scroll) {
1478                 char buf[32];
1479
1480                 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1481                 ui_browser__printf(&browser->b, "  %s", buf);
1482                 width -= ret + 2;
1483         }
1484
1485         /* The scroll bar isn't being used */
1486         if (!browser->b.navkeypressed)
1487                 width += 1;
1488
1489         ui_browser__write_nstring(&browser->b, "", width);
1490         return 1;
1491 }
1492
1493 static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1494 {
1495         advance_hpp(hpp, inc);
1496         return hpp->size <= 0;
1497 }
1498
1499 static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
1500 {
1501         struct hists *hists = browser->hists;
1502         struct perf_hpp dummy_hpp = {
1503                 .buf    = buf,
1504                 .size   = size,
1505         };
1506         struct perf_hpp_fmt *fmt;
1507         size_t ret = 0;
1508         int column = 0;
1509
1510         if (symbol_conf.use_callchain) {
1511                 ret = scnprintf(buf, size, "  ");
1512                 if (advance_hpp_check(&dummy_hpp, ret))
1513                         return ret;
1514         }
1515
1516         hists__for_each_format(browser->hists, fmt) {
1517                 if (perf_hpp__should_skip(fmt, hists)  || column++ < browser->b.horiz_scroll)
1518                         continue;
1519
1520                 ret = fmt->header(fmt, &dummy_hpp, hists);
1521                 if (advance_hpp_check(&dummy_hpp, ret))
1522                         break;
1523
1524                 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
1525                 if (advance_hpp_check(&dummy_hpp, ret))
1526                         break;
1527         }
1528
1529         return ret;
1530 }
1531
1532 static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1533 {
1534         struct hists *hists = browser->hists;
1535         struct perf_hpp dummy_hpp = {
1536                 .buf    = buf,
1537                 .size   = size,
1538         };
1539         struct perf_hpp_fmt *fmt;
1540         struct perf_hpp_list_node *fmt_node;
1541         size_t ret = 0;
1542         int column = 0;
1543         int indent = hists->nr_hpp_node - 2;
1544         bool first_node, first_col;
1545
1546         ret = scnprintf(buf, size, " ");
1547         if (advance_hpp_check(&dummy_hpp, ret))
1548                 return ret;
1549
1550         /* the first hpp_list_node is for overhead columns */
1551         fmt_node = list_first_entry(&hists->hpp_formats,
1552                                     struct perf_hpp_list_node, list);
1553         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1554                 if (column++ < browser->b.horiz_scroll)
1555                         continue;
1556
1557                 ret = fmt->header(fmt, &dummy_hpp, hists);
1558                 if (advance_hpp_check(&dummy_hpp, ret))
1559                         break;
1560
1561                 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
1562                 if (advance_hpp_check(&dummy_hpp, ret))
1563                         break;
1564         }
1565
1566         ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1567                         indent * HIERARCHY_INDENT, "");
1568         if (advance_hpp_check(&dummy_hpp, ret))
1569                 return ret;
1570
1571         first_node = true;
1572         list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1573                 if (!first_node) {
1574                         ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1575                         if (advance_hpp_check(&dummy_hpp, ret))
1576                                 break;
1577                 }
1578                 first_node = false;
1579
1580                 first_col = true;
1581                 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1582                         char *start;
1583
1584                         if (perf_hpp__should_skip(fmt, hists))
1585                                 continue;
1586
1587                         if (!first_col) {
1588                                 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1589                                 if (advance_hpp_check(&dummy_hpp, ret))
1590                                         break;
1591                         }
1592                         first_col = false;
1593
1594                         ret = fmt->header(fmt, &dummy_hpp, hists);
1595                         dummy_hpp.buf[ret] = '\0';
1596
1597                         start = trim(dummy_hpp.buf);
1598                         ret = strlen(start);
1599
1600                         if (start != dummy_hpp.buf)
1601                                 memmove(dummy_hpp.buf, start, ret + 1);
1602
1603                         if (advance_hpp_check(&dummy_hpp, ret))
1604                                 break;
1605                 }
1606         }
1607
1608         return ret;
1609 }
1610
1611 static void hists_browser__hierarchy_headers(struct hist_browser *browser)
1612 {
1613         char headers[1024];
1614
1615         hists_browser__scnprintf_hierarchy_headers(browser, headers,
1616                                                    sizeof(headers));
1617
1618         ui_browser__gotorc(&browser->b, 0, 0);
1619         ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1620         ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1621 }
1622
1623 static void hists_browser__headers(struct hist_browser *browser)
1624 {
1625         char headers[1024];
1626
1627         hists_browser__scnprintf_headers(browser, headers,
1628                                          sizeof(headers));
1629
1630         ui_browser__gotorc(&browser->b, 0, 0);
1631         ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1632         ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1633 }
1634
1635 static void hist_browser__show_headers(struct hist_browser *browser)
1636 {
1637         if (symbol_conf.report_hierarchy)
1638                 hists_browser__hierarchy_headers(browser);
1639         else
1640                 hists_browser__headers(browser);
1641 }
1642
1643 static void ui_browser__hists_init_top(struct ui_browser *browser)
1644 {
1645         if (browser->top == NULL) {
1646                 struct hist_browser *hb;
1647
1648                 hb = container_of(browser, struct hist_browser, b);
1649                 browser->top = rb_first(&hb->hists->entries);
1650         }
1651 }
1652
1653 static unsigned int hist_browser__refresh(struct ui_browser *browser)
1654 {
1655         unsigned row = 0;
1656         u16 header_offset = 0;
1657         struct rb_node *nd;
1658         struct hist_browser *hb = container_of(browser, struct hist_browser, b);
1659
1660         if (hb->show_headers) {
1661                 hist_browser__show_headers(hb);
1662                 header_offset = 1;
1663         }
1664
1665         ui_browser__hists_init_top(browser);
1666         hb->he_selection = NULL;
1667         hb->selection = NULL;
1668
1669         for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
1670                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1671                 float percent;
1672
1673                 if (h->filtered) {
1674                         /* let it move to sibling */
1675                         h->unfolded = false;
1676                         continue;
1677                 }
1678
1679                 percent = hist_entry__get_percent_limit(h);
1680                 if (percent < hb->min_pcnt)
1681                         continue;
1682
1683                 if (symbol_conf.report_hierarchy) {
1684                         row += hist_browser__show_hierarchy_entry(hb, h, row,
1685                                                                   h->depth);
1686                         if (row == browser->rows)
1687                                 break;
1688
1689                         if (h->has_no_entry) {
1690                                 hist_browser__show_no_entry(hb, row, h->depth + 1);
1691                                 row++;
1692                         }
1693                 } else {
1694                         row += hist_browser__show_entry(hb, h, row);
1695                 }
1696
1697                 if (row == browser->rows)
1698                         break;
1699         }
1700
1701         return row + header_offset;
1702 }
1703
1704 static struct rb_node *hists__filter_entries(struct rb_node *nd,
1705                                              float min_pcnt)
1706 {
1707         while (nd != NULL) {
1708                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1709                 float percent = hist_entry__get_percent_limit(h);
1710
1711                 if (!h->filtered && percent >= min_pcnt)
1712                         return nd;
1713
1714                 /*
1715                  * If it's filtered, its all children also were filtered.
1716                  * So move to sibling node.
1717                  */
1718                 if (rb_next(nd))
1719                         nd = rb_next(nd);
1720                 else
1721                         nd = rb_hierarchy_next(nd);
1722         }
1723
1724         return NULL;
1725 }
1726
1727 static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
1728                                                   float min_pcnt)
1729 {
1730         while (nd != NULL) {
1731                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1732                 float percent = hist_entry__get_percent_limit(h);
1733
1734                 if (!h->filtered && percent >= min_pcnt)
1735                         return nd;
1736
1737                 nd = rb_hierarchy_prev(nd);
1738         }
1739
1740         return NULL;
1741 }
1742
1743 static void ui_browser__hists_seek(struct ui_browser *browser,
1744                                    off_t offset, int whence)
1745 {
1746         struct hist_entry *h;
1747         struct rb_node *nd;
1748         bool first = true;
1749         struct hist_browser *hb;
1750
1751         hb = container_of(browser, struct hist_browser, b);
1752
1753         if (browser->nr_entries == 0)
1754                 return;
1755
1756         ui_browser__hists_init_top(browser);
1757
1758         switch (whence) {
1759         case SEEK_SET:
1760                 nd = hists__filter_entries(rb_first(browser->entries),
1761                                            hb->min_pcnt);
1762                 break;
1763         case SEEK_CUR:
1764                 nd = browser->top;
1765                 goto do_offset;
1766         case SEEK_END:
1767                 nd = rb_hierarchy_last(rb_last(browser->entries));
1768                 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
1769                 first = false;
1770                 break;
1771         default:
1772                 return;
1773         }
1774
1775         /*
1776          * Moves not relative to the first visible entry invalidates its
1777          * row_offset:
1778          */
1779         h = rb_entry(browser->top, struct hist_entry, rb_node);
1780         h->row_offset = 0;
1781
1782         /*
1783          * Here we have to check if nd is expanded (+), if it is we can't go
1784          * the next top level hist_entry, instead we must compute an offset of
1785          * what _not_ to show and not change the first visible entry.
1786          *
1787          * This offset increments when we are going from top to bottom and
1788          * decreases when we're going from bottom to top.
1789          *
1790          * As we don't have backpointers to the top level in the callchains
1791          * structure, we need to always print the whole hist_entry callchain,
1792          * skipping the first ones that are before the first visible entry
1793          * and stop when we printed enough lines to fill the screen.
1794          */
1795 do_offset:
1796         if (!nd)
1797                 return;
1798
1799         if (offset > 0) {
1800                 do {
1801                         h = rb_entry(nd, struct hist_entry, rb_node);
1802                         if (h->unfolded && h->leaf) {
1803                                 u16 remaining = h->nr_rows - h->row_offset;
1804                                 if (offset > remaining) {
1805                                         offset -= remaining;
1806                                         h->row_offset = 0;
1807                                 } else {
1808                                         h->row_offset += offset;
1809                                         offset = 0;
1810                                         browser->top = nd;
1811                                         break;
1812                                 }
1813                         }
1814                         nd = hists__filter_entries(rb_hierarchy_next(nd),
1815                                                    hb->min_pcnt);
1816                         if (nd == NULL)
1817                                 break;
1818                         --offset;
1819                         browser->top = nd;
1820                 } while (offset != 0);
1821         } else if (offset < 0) {
1822                 while (1) {
1823                         h = rb_entry(nd, struct hist_entry, rb_node);
1824                         if (h->unfolded && h->leaf) {
1825                                 if (first) {
1826                                         if (-offset > h->row_offset) {
1827                                                 offset += h->row_offset;
1828                                                 h->row_offset = 0;
1829                                         } else {
1830                                                 h->row_offset += offset;
1831                                                 offset = 0;
1832                                                 browser->top = nd;
1833                                                 break;
1834                                         }
1835                                 } else {
1836                                         if (-offset > h->nr_rows) {
1837                                                 offset += h->nr_rows;
1838                                                 h->row_offset = 0;
1839                                         } else {
1840                                                 h->row_offset = h->nr_rows + offset;
1841                                                 offset = 0;
1842                                                 browser->top = nd;
1843                                                 break;
1844                                         }
1845                                 }
1846                         }
1847
1848                         nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
1849                                                         hb->min_pcnt);
1850                         if (nd == NULL)
1851                                 break;
1852                         ++offset;
1853                         browser->top = nd;
1854                         if (offset == 0) {
1855                                 /*
1856                                  * Last unfiltered hist_entry, check if it is
1857                                  * unfolded, if it is then we should have
1858                                  * row_offset at its last entry.
1859                                  */
1860                                 h = rb_entry(nd, struct hist_entry, rb_node);
1861                                 if (h->unfolded && h->leaf)
1862                                         h->row_offset = h->nr_rows;
1863                                 break;
1864                         }
1865                         first = false;
1866                 }
1867         } else {
1868                 browser->top = nd;
1869                 h = rb_entry(nd, struct hist_entry, rb_node);
1870                 h->row_offset = 0;
1871         }
1872 }
1873
1874 static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1875                                            struct hist_entry *he, FILE *fp,
1876                                            int level)
1877 {
1878         struct callchain_print_arg arg  = {
1879                 .fp = fp,
1880         };
1881
1882         hist_browser__show_callchain(browser, he, level, 0,
1883                                      hist_browser__fprintf_callchain_entry, &arg,
1884                                      hist_browser__check_dump_full);
1885         return arg.printed;
1886 }
1887
1888 static int hist_browser__fprintf_entry(struct hist_browser *browser,
1889                                        struct hist_entry *he, FILE *fp)
1890 {
1891         char s[8192];
1892         int printed = 0;
1893         char folded_sign = ' ';
1894         struct perf_hpp hpp = {
1895                 .buf = s,
1896                 .size = sizeof(s),
1897         };
1898         struct perf_hpp_fmt *fmt;
1899         bool first = true;
1900         int ret;
1901
1902         if (symbol_conf.use_callchain) {
1903                 folded_sign = hist_entry__folded(he);
1904                 printed += fprintf(fp, "%c ", folded_sign);
1905         }
1906
1907         hists__for_each_format(browser->hists, fmt) {
1908                 if (perf_hpp__should_skip(fmt, he->hists))
1909                         continue;
1910
1911                 if (!first) {
1912                         ret = scnprintf(hpp.buf, hpp.size, "  ");
1913                         advance_hpp(&hpp, ret);
1914                 } else
1915                         first = false;
1916
1917                 ret = fmt->entry(fmt, &hpp, he);
1918                 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
1919                 advance_hpp(&hpp, ret);
1920         }
1921         printed += fprintf(fp, "%s\n", s);
1922
1923         if (folded_sign == '-')
1924                 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1925
1926         return printed;
1927 }
1928
1929
1930 static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1931                                                  struct hist_entry *he,
1932                                                  FILE *fp, int level)
1933 {
1934         char s[8192];
1935         int printed = 0;
1936         char folded_sign = ' ';
1937         struct perf_hpp hpp = {
1938                 .buf = s,
1939                 .size = sizeof(s),
1940         };
1941         struct perf_hpp_fmt *fmt;
1942         struct perf_hpp_list_node *fmt_node;
1943         bool first = true;
1944         int ret;
1945         int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
1946
1947         printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1948
1949         folded_sign = hist_entry__folded(he);
1950         printed += fprintf(fp, "%c", folded_sign);
1951
1952         /* the first hpp_list_node is for overhead columns */
1953         fmt_node = list_first_entry(&he->hists->hpp_formats,
1954                                     struct perf_hpp_list_node, list);
1955         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1956                 if (!first) {
1957                         ret = scnprintf(hpp.buf, hpp.size, "  ");
1958                         advance_hpp(&hpp, ret);
1959                 } else
1960                         first = false;
1961
1962                 ret = fmt->entry(fmt, &hpp, he);
1963                 advance_hpp(&hpp, ret);
1964         }
1965
1966         ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1967         advance_hpp(&hpp, ret);
1968
1969         perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1970                 ret = scnprintf(hpp.buf, hpp.size, "  ");
1971                 advance_hpp(&hpp, ret);
1972
1973                 ret = fmt->entry(fmt, &hpp, he);
1974                 advance_hpp(&hpp, ret);
1975         }
1976
1977         printed += fprintf(fp, "%s\n", rtrim(s));
1978
1979         if (he->leaf && folded_sign == '-') {
1980                 printed += hist_browser__fprintf_callchain(browser, he, fp,
1981                                                            he->depth + 1);
1982         }
1983
1984         return printed;
1985 }
1986
1987 static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1988 {
1989         struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1990                                                    browser->min_pcnt);
1991         int printed = 0;
1992
1993         while (nd) {
1994                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1995
1996                 if (symbol_conf.report_hierarchy) {
1997                         printed += hist_browser__fprintf_hierarchy_entry(browser,
1998                                                                          h, fp,
1999                                                                          h->depth);
2000                 } else {
2001                         printed += hist_browser__fprintf_entry(browser, h, fp);
2002                 }
2003
2004                 nd = hists__filter_entries(rb_hierarchy_next(nd),
2005                                            browser->min_pcnt);
2006         }
2007
2008         return printed;
2009 }
2010
2011 static int hist_browser__dump(struct hist_browser *browser)
2012 {
2013         char filename[64];
2014         FILE *fp;
2015
2016         while (1) {
2017                 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2018                 if (access(filename, F_OK))
2019                         break;
2020                 /*
2021                  * XXX: Just an arbitrary lazy upper limit
2022                  */
2023                 if (++browser->print_seq == 8192) {
2024                         ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2025                         return -1;
2026                 }
2027         }
2028
2029         fp = fopen(filename, "w");
2030         if (fp == NULL) {
2031                 char bf[64];
2032                 const char *err = str_error_r(errno, bf, sizeof(bf));
2033                 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
2034                 return -1;
2035         }
2036
2037         ++browser->print_seq;
2038         hist_browser__fprintf(browser, fp);
2039         fclose(fp);
2040         ui_helpline__fpush("%s written!", filename);
2041
2042         return 0;
2043 }
2044
2045 void hist_browser__init(struct hist_browser *browser,
2046                         struct hists *hists)
2047 {
2048         struct perf_hpp_fmt *fmt;
2049
2050         browser->hists                  = hists;
2051         browser->b.refresh              = hist_browser__refresh;
2052         browser->b.refresh_dimensions   = hist_browser__refresh_dimensions;
2053         browser->b.seek                 = ui_browser__hists_seek;
2054         browser->b.use_navkeypressed    = true;
2055         browser->show_headers           = symbol_conf.show_hist_headers;
2056
2057         hists__for_each_format(hists, fmt) {
2058                 perf_hpp__reset_width(fmt, hists);
2059                 ++browser->b.columns;
2060         }
2061 }
2062
2063 struct hist_browser *hist_browser__new(struct hists *hists)
2064 {
2065         struct hist_browser *browser = zalloc(sizeof(*browser));
2066
2067         if (browser)
2068                 hist_browser__init(browser, hists);
2069
2070         return browser;
2071 }
2072
2073 static struct hist_browser *
2074 perf_evsel_browser__new(struct perf_evsel *evsel,
2075                         struct hist_browser_timer *hbt,
2076                         struct perf_env *env)
2077 {
2078         struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2079
2080         if (browser) {
2081                 browser->hbt   = hbt;
2082                 browser->env   = env;
2083                 browser->title = perf_evsel_browser_title;
2084         }
2085         return browser;
2086 }
2087
2088 void hist_browser__delete(struct hist_browser *browser)
2089 {
2090         free(browser);
2091 }
2092
2093 static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
2094 {
2095         return browser->he_selection;
2096 }
2097
2098 static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
2099 {
2100         return browser->he_selection->thread;
2101 }
2102
2103 /* Check whether the browser is for 'top' or 'report' */
2104 static inline bool is_report_browser(void *timer)
2105 {
2106         return timer == NULL;
2107 }
2108
2109 static int perf_evsel_browser_title(struct hist_browser *browser,
2110                                 char *bf, size_t size)
2111 {
2112         struct hist_browser_timer *hbt = browser->hbt;
2113         struct hists *hists = browser->hists;
2114         char unit;
2115         int printed;
2116         const struct dso *dso = hists->dso_filter;
2117         const struct thread *thread = hists->thread_filter;
2118         int socket_id = hists->socket_filter;
2119         unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2120         u64 nr_events = hists->stats.total_period;
2121         struct perf_evsel *evsel = hists_to_evsel(hists);
2122         const char *ev_name = perf_evsel__name(evsel);
2123         char buf[512];
2124         size_t buflen = sizeof(buf);
2125         char ref[30] = " show reference callgraph, ";
2126         bool enable_ref = false;
2127
2128         if (symbol_conf.filter_relative) {
2129                 nr_samples = hists->stats.nr_non_filtered_samples;
2130                 nr_events = hists->stats.total_non_filtered_period;
2131         }
2132
2133         if (perf_evsel__is_group_event(evsel)) {
2134                 struct perf_evsel *pos;
2135
2136                 perf_evsel__group_desc(evsel, buf, buflen);
2137                 ev_name = buf;
2138
2139                 for_each_group_member(pos, evsel) {
2140                         struct hists *pos_hists = evsel__hists(pos);
2141
2142                         if (symbol_conf.filter_relative) {
2143                                 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2144                                 nr_events += pos_hists->stats.total_non_filtered_period;
2145                         } else {
2146                                 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2147                                 nr_events += pos_hists->stats.total_period;
2148                         }
2149                 }
2150         }
2151
2152         if (symbol_conf.show_ref_callgraph &&
2153             strstr(ev_name, "call-graph=no"))
2154                 enable_ref = true;
2155         nr_samples = convert_unit(nr_samples, &unit);
2156         printed = scnprintf(bf, size,
2157                            "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2158                            nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
2159
2160
2161         if (hists->uid_filter_str)
2162                 printed += snprintf(bf + printed, size - printed,
2163                                     ", UID: %s", hists->uid_filter_str);
2164         if (thread) {
2165                 if (hists__has(hists, thread)) {
2166                         printed += scnprintf(bf + printed, size - printed,
2167                                     ", Thread: %s(%d)",
2168                                      (thread->comm_set ? thread__comm_str(thread) : ""),
2169                                     thread->tid);
2170                 } else {
2171                         printed += scnprintf(bf + printed, size - printed,
2172                                     ", Thread: %s",
2173                                      (thread->comm_set ? thread__comm_str(thread) : ""));
2174                 }
2175         }
2176         if (dso)
2177                 printed += scnprintf(bf + printed, size - printed,
2178                                     ", DSO: %s", dso->short_name);
2179         if (socket_id > -1)
2180                 printed += scnprintf(bf + printed, size - printed,
2181                                     ", Processor Socket: %d", socket_id);
2182         if (!is_report_browser(hbt)) {
2183                 struct perf_top *top = hbt->arg;
2184
2185                 if (top->zero)
2186                         printed += scnprintf(bf + printed, size - printed, " [z]");
2187         }
2188
2189         return printed;
2190 }
2191
2192 static inline void free_popup_options(char **options, int n)
2193 {
2194         int i;
2195
2196         for (i = 0; i < n; ++i)
2197                 zfree(&options[i]);
2198 }
2199
2200 /*
2201  * Only runtime switching of perf data file will make "input_name" point
2202  * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2203  * whether we need to call free() for current "input_name" during the switch.
2204  */
2205 static bool is_input_name_malloced = false;
2206
2207 static int switch_data_file(void)
2208 {
2209         char *pwd, *options[32], *abs_path[32], *tmp;
2210         DIR *pwd_dir;
2211         int nr_options = 0, choice = -1, ret = -1;
2212         struct dirent *dent;
2213
2214         pwd = getenv("PWD");
2215         if (!pwd)
2216                 return ret;
2217
2218         pwd_dir = opendir(pwd);
2219         if (!pwd_dir)
2220                 return ret;
2221
2222         memset(options, 0, sizeof(options));
2223         memset(options, 0, sizeof(abs_path));
2224
2225         while ((dent = readdir(pwd_dir))) {
2226                 char path[PATH_MAX];
2227                 u64 magic;
2228                 char *name = dent->d_name;
2229                 FILE *file;
2230
2231                 if (!(dent->d_type == DT_REG))
2232                         continue;
2233
2234                 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2235
2236                 file = fopen(path, "r");
2237                 if (!file)
2238                         continue;
2239
2240                 if (fread(&magic, 1, 8, file) < 8)
2241                         goto close_file_and_continue;
2242
2243                 if (is_perf_magic(magic)) {
2244                         options[nr_options] = strdup(name);
2245                         if (!options[nr_options])
2246                                 goto close_file_and_continue;
2247
2248                         abs_path[nr_options] = strdup(path);
2249                         if (!abs_path[nr_options]) {
2250                                 zfree(&options[nr_options]);
2251                                 ui__warning("Can't search all data files due to memory shortage.\n");
2252                                 fclose(file);
2253                                 break;
2254                         }
2255
2256                         nr_options++;
2257                 }
2258
2259 close_file_and_continue:
2260                 fclose(file);
2261                 if (nr_options >= 32) {
2262                         ui__warning("Too many perf data files in PWD!\n"
2263                                     "Only the first 32 files will be listed.\n");
2264                         break;
2265                 }
2266         }
2267         closedir(pwd_dir);
2268
2269         if (nr_options) {
2270                 choice = ui__popup_menu(nr_options, options);
2271                 if (choice < nr_options && choice >= 0) {
2272                         tmp = strdup(abs_path[choice]);
2273                         if (tmp) {
2274                                 if (is_input_name_malloced)
2275                                         free((void *)input_name);
2276                                 input_name = tmp;
2277                                 is_input_name_malloced = true;
2278                                 ret = 0;
2279                         } else
2280                                 ui__warning("Data switch failed due to memory shortage!\n");
2281                 }
2282         }
2283
2284         free_popup_options(options, nr_options);
2285         free_popup_options(abs_path, nr_options);
2286         return ret;
2287 }
2288
2289 struct popup_action {
2290         struct thread           *thread;
2291         struct map_symbol       ms;
2292         int                     socket;
2293
2294         int (*fn)(struct hist_browser *browser, struct popup_action *act);
2295 };
2296
2297 static int
2298 do_annotate(struct hist_browser *browser, struct popup_action *act)
2299 {
2300         struct perf_evsel *evsel;
2301         struct annotation *notes;
2302         struct hist_entry *he;
2303         int err;
2304
2305         if (!objdump_path && perf_env__lookup_objdump(browser->env))
2306                 return 0;
2307
2308         notes = symbol__annotation(act->ms.sym);
2309         if (!notes->src)
2310                 return 0;
2311
2312         evsel = hists_to_evsel(browser->hists);
2313         err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
2314         he = hist_browser__selected_entry(browser);
2315         /*
2316          * offer option to annotate the other branch source or target
2317          * (if they exists) when returning from annotate
2318          */
2319         if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2320                 return 1;
2321
2322         ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2323         if (err)
2324                 ui_browser__handle_resize(&browser->b);
2325         return 0;
2326 }
2327
2328 static int
2329 add_annotate_opt(struct hist_browser *browser __maybe_unused,
2330                  struct popup_action *act, char **optstr,
2331                  struct map *map, struct symbol *sym)
2332 {
2333         if (sym == NULL || map->dso->annotate_warned)
2334                 return 0;
2335
2336         if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2337                 return 0;
2338
2339         act->ms.map = map;
2340         act->ms.sym = sym;
2341         act->fn = do_annotate;
2342         return 1;
2343 }
2344
2345 static int
2346 do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2347 {
2348         struct thread *thread = act->thread;
2349
2350         if ((!hists__has(browser->hists, thread) &&
2351              !hists__has(browser->hists, comm)) || thread == NULL)
2352                 return 0;
2353
2354         if (browser->hists->thread_filter) {
2355                 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2356                 perf_hpp__set_elide(HISTC_THREAD, false);
2357                 thread__zput(browser->hists->thread_filter);
2358                 ui_helpline__pop();
2359         } else {
2360                 if (hists__has(browser->hists, thread)) {
2361                         ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2362                                            thread->comm_set ? thread__comm_str(thread) : "",
2363                                            thread->tid);
2364                 } else {
2365                         ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2366                                            thread->comm_set ? thread__comm_str(thread) : "");
2367                 }
2368
2369                 browser->hists->thread_filter = thread__get(thread);
2370                 perf_hpp__set_elide(HISTC_THREAD, false);
2371                 pstack__push(browser->pstack, &browser->hists->thread_filter);
2372         }
2373
2374         hists__filter_by_thread(browser->hists);
2375         hist_browser__reset(browser);
2376         return 0;
2377 }
2378
2379 static int
2380 add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2381                char **optstr, struct thread *thread)
2382 {
2383         int ret;
2384
2385         if ((!hists__has(browser->hists, thread) &&
2386              !hists__has(browser->hists, comm)) || thread == NULL)
2387                 return 0;
2388
2389         if (hists__has(browser->hists, thread)) {
2390                 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2391                                browser->hists->thread_filter ? "out of" : "into",
2392                                thread->comm_set ? thread__comm_str(thread) : "",
2393                                thread->tid);
2394         } else {
2395                 ret = asprintf(optstr, "Zoom %s %s thread",
2396                                browser->hists->thread_filter ? "out of" : "into",
2397                                thread->comm_set ? thread__comm_str(thread) : "");
2398         }
2399         if (ret < 0)
2400                 return 0;
2401
2402         act->thread = thread;
2403         act->fn = do_zoom_thread;
2404         return 1;
2405 }
2406
2407 static int
2408 do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2409 {
2410         struct map *map = act->ms.map;
2411
2412         if (!hists__has(browser->hists, dso) || map == NULL)
2413                 return 0;
2414
2415         if (browser->hists->dso_filter) {
2416                 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2417                 perf_hpp__set_elide(HISTC_DSO, false);
2418                 browser->hists->dso_filter = NULL;
2419                 ui_helpline__pop();
2420         } else {
2421                 if (map == NULL)
2422                         return 0;
2423                 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
2424                                    __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2425                 browser->hists->dso_filter = map->dso;
2426                 perf_hpp__set_elide(HISTC_DSO, true);
2427                 pstack__push(browser->pstack, &browser->hists->dso_filter);
2428         }
2429
2430         hists__filter_by_dso(browser->hists);
2431         hist_browser__reset(browser);
2432         return 0;
2433 }
2434
2435 static int
2436 add_dso_opt(struct hist_browser *browser, struct popup_action *act,
2437             char **optstr, struct map *map)
2438 {
2439         if (!hists__has(browser->hists, dso) || map == NULL)
2440                 return 0;
2441
2442         if (asprintf(optstr, "Zoom %s %s DSO",
2443                      browser->hists->dso_filter ? "out of" : "into",
2444                      __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
2445                 return 0;
2446
2447         act->ms.map = map;
2448         act->fn = do_zoom_dso;
2449         return 1;
2450 }
2451
2452 static int
2453 do_browse_map(struct hist_browser *browser __maybe_unused,
2454               struct popup_action *act)
2455 {
2456         map__browse(act->ms.map);
2457         return 0;
2458 }
2459
2460 static int
2461 add_map_opt(struct hist_browser *browser,
2462             struct popup_action *act, char **optstr, struct map *map)
2463 {
2464         if (!hists__has(browser->hists, dso) || map == NULL)
2465                 return 0;
2466
2467         if (asprintf(optstr, "Browse map details") < 0)
2468                 return 0;
2469
2470         act->ms.map = map;
2471         act->fn = do_browse_map;
2472         return 1;
2473 }
2474
2475 static int
2476 do_run_script(struct hist_browser *browser __maybe_unused,
2477               struct popup_action *act)
2478 {
2479         char script_opt[64];
2480         memset(script_opt, 0, sizeof(script_opt));
2481
2482         if (act->thread) {
2483                 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
2484                           thread__comm_str(act->thread));
2485         } else if (act->ms.sym) {
2486                 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
2487                           act->ms.sym->name);
2488         }
2489
2490         script_browse(script_opt);
2491         return 0;
2492 }
2493
2494 static int
2495 add_script_opt(struct hist_browser *browser __maybe_unused,
2496                struct popup_action *act, char **optstr,
2497                struct thread *thread, struct symbol *sym)
2498 {
2499         if (thread) {
2500                 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2501                              thread__comm_str(thread)) < 0)
2502                         return 0;
2503         } else if (sym) {
2504                 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2505                              sym->name) < 0)
2506                         return 0;
2507         } else {
2508                 if (asprintf(optstr, "Run scripts for all samples") < 0)
2509                         return 0;
2510         }
2511
2512         act->thread = thread;
2513         act->ms.sym = sym;
2514         act->fn = do_run_script;
2515         return 1;
2516 }
2517
2518 static int
2519 do_switch_data(struct hist_browser *browser __maybe_unused,
2520                struct popup_action *act __maybe_unused)
2521 {
2522         if (switch_data_file()) {
2523                 ui__warning("Won't switch the data files due to\n"
2524                             "no valid data file get selected!\n");
2525                 return 0;
2526         }
2527
2528         return K_SWITCH_INPUT_DATA;
2529 }
2530
2531 static int
2532 add_switch_opt(struct hist_browser *browser,
2533                struct popup_action *act, char **optstr)
2534 {
2535         if (!is_report_browser(browser->hbt))
2536                 return 0;
2537
2538         if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2539                 return 0;
2540
2541         act->fn = do_switch_data;
2542         return 1;
2543 }
2544
2545 static int
2546 do_exit_browser(struct hist_browser *browser __maybe_unused,
2547                 struct popup_action *act __maybe_unused)
2548 {
2549         return 0;
2550 }
2551
2552 static int
2553 add_exit_opt(struct hist_browser *browser __maybe_unused,
2554              struct popup_action *act, char **optstr)
2555 {
2556         if (asprintf(optstr, "Exit") < 0)
2557                 return 0;
2558
2559         act->fn = do_exit_browser;
2560         return 1;
2561 }
2562
2563 static int
2564 do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2565 {
2566         if (!hists__has(browser->hists, socket) || act->socket < 0)
2567                 return 0;
2568
2569         if (browser->hists->socket_filter > -1) {
2570                 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2571                 browser->hists->socket_filter = -1;
2572                 perf_hpp__set_elide(HISTC_SOCKET, false);
2573         } else {
2574                 browser->hists->socket_filter = act->socket;
2575                 perf_hpp__set_elide(HISTC_SOCKET, true);
2576                 pstack__push(browser->pstack, &browser->hists->socket_filter);
2577         }
2578
2579         hists__filter_by_socket(browser->hists);
2580         hist_browser__reset(browser);
2581         return 0;
2582 }
2583
2584 static int
2585 add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2586                char **optstr, int socket_id)
2587 {
2588         if (!hists__has(browser->hists, socket) || socket_id < 0)
2589                 return 0;
2590
2591         if (asprintf(optstr, "Zoom %s Processor Socket %d",
2592                      (browser->hists->socket_filter > -1) ? "out of" : "into",
2593                      socket_id) < 0)
2594                 return 0;
2595
2596         act->socket = socket_id;
2597         act->fn = do_zoom_socket;
2598         return 1;
2599 }
2600
2601 static void hist_browser__update_nr_entries(struct hist_browser *hb)
2602 {
2603         u64 nr_entries = 0;
2604         struct rb_node *nd = rb_first(&hb->hists->entries);
2605
2606         if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
2607                 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2608                 return;
2609         }
2610
2611         while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2612                 nr_entries++;
2613                 nd = rb_hierarchy_next(nd);
2614         }
2615
2616         hb->nr_non_filtered_entries = nr_entries;
2617         hb->nr_hierarchy_entries = nr_entries;
2618 }
2619
2620 static void hist_browser__update_percent_limit(struct hist_browser *hb,
2621                                                double percent)
2622 {
2623         struct hist_entry *he;
2624         struct rb_node *nd = rb_first(&hb->hists->entries);
2625         u64 total = hists__total_period(hb->hists);
2626         u64 min_callchain_hits = total * (percent / 100);
2627
2628         hb->min_pcnt = callchain_param.min_percent = percent;
2629
2630         while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2631                 he = rb_entry(nd, struct hist_entry, rb_node);
2632
2633                 if (he->has_no_entry) {
2634                         he->has_no_entry = false;
2635                         he->nr_rows = 0;
2636                 }
2637
2638                 if (!he->leaf || !symbol_conf.use_callchain)
2639                         goto next;
2640
2641                 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2642                         total = he->stat.period;
2643
2644                         if (symbol_conf.cumulate_callchain)
2645                                 total = he->stat_acc->period;
2646
2647                         min_callchain_hits = total * (percent / 100);
2648                 }
2649
2650                 callchain_param.sort(&he->sorted_chain, he->callchain,
2651                                      min_callchain_hits, &callchain_param);
2652
2653 next:
2654                 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
2655
2656                 /* force to re-evaluate folding state of callchains */
2657                 he->init_have_children = false;
2658                 hist_entry__set_folding(he, hb, false);
2659         }
2660 }
2661
2662 static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2663                                     const char *helpline,
2664                                     bool left_exits,
2665                                     struct hist_browser_timer *hbt,
2666                                     float min_pcnt,
2667                                     struct perf_env *env)
2668 {
2669         struct hists *hists = evsel__hists(evsel);
2670         struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
2671         struct branch_info *bi;
2672 #define MAX_OPTIONS  16
2673         char *options[MAX_OPTIONS];
2674         struct popup_action actions[MAX_OPTIONS];
2675         int nr_options = 0;
2676         int key = -1;
2677         char buf[64];
2678         int delay_secs = hbt ? hbt->refresh : 0;
2679
2680 #define HIST_BROWSER_HELP_COMMON                                        \
2681         "h/?/F1        Show this window\n"                              \
2682         "UP/DOWN/PGUP\n"                                                \
2683         "PGDN/SPACE    Navigate\n"                                      \
2684         "q/ESC/CTRL+C  Exit browser\n\n"                                \
2685         "For multiple event sessions:\n\n"                              \
2686         "TAB/UNTAB     Switch events\n\n"                               \
2687         "For symbolic views (--sort has sym):\n\n"                      \
2688         "ENTER         Zoom into DSO/Threads & Annotate current symbol\n" \
2689         "ESC           Zoom out\n"                                      \
2690         "a             Annotate current symbol\n"                       \
2691         "C             Collapse all callchains\n"                       \
2692         "d             Zoom into current DSO\n"                         \
2693         "E             Expand all callchains\n"                         \
2694         "F             Toggle percentage of filtered entries\n"         \
2695         "H             Display column headers\n"                        \
2696         "L             Change percent limit\n"                          \
2697         "m             Display context menu\n"                          \
2698         "S             Zoom into current Processor Socket\n"            \
2699
2700         /* help messages are sorted by lexical order of the hotkey */
2701         const char report_help[] = HIST_BROWSER_HELP_COMMON
2702         "i             Show header information\n"
2703         "P             Print histograms to perf.hist.N\n"
2704         "r             Run available scripts\n"
2705         "s             Switch to another data file in PWD\n"
2706         "t             Zoom into current Thread\n"
2707         "V             Verbose (DSO names in callchains, etc)\n"
2708         "/             Filter symbol by name";
2709         const char top_help[] = HIST_BROWSER_HELP_COMMON
2710         "P             Print histograms to perf.hist.N\n"
2711         "t             Zoom into current Thread\n"
2712         "V             Verbose (DSO names in callchains, etc)\n"
2713         "z             Toggle zeroing of samples\n"
2714         "f             Enable/Disable events\n"
2715         "/             Filter symbol by name";
2716
2717         if (browser == NULL)
2718                 return -1;
2719
2720         /* reset abort key so that it can get Ctrl-C as a key */
2721         SLang_reset_tty();
2722         SLang_init_tty(0, 0, 0);
2723
2724         if (min_pcnt)
2725                 browser->min_pcnt = min_pcnt;
2726         hist_browser__update_nr_entries(browser);
2727
2728         browser->pstack = pstack__new(3);
2729         if (browser->pstack == NULL)
2730                 goto out;
2731
2732         ui_helpline__push(helpline);
2733
2734         memset(options, 0, sizeof(options));
2735         memset(actions, 0, sizeof(actions));
2736
2737         if (symbol_conf.col_width_list_str)
2738                 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2739
2740         while (1) {
2741                 struct thread *thread = NULL;
2742                 struct map *map = NULL;
2743                 int choice = 0;
2744                 int socked_id = -1;
2745
2746                 nr_options = 0;
2747
2748                 key = hist_browser__run(browser, helpline);
2749
2750                 if (browser->he_selection != NULL) {
2751                         thread = hist_browser__selected_thread(browser);
2752                         map = browser->selection->map;
2753                         socked_id = browser->he_selection->socket;
2754                 }
2755                 switch (key) {
2756                 case K_TAB:
2757                 case K_UNTAB:
2758                         if (nr_events == 1)
2759                                 continue;
2760                         /*
2761                          * Exit the browser, let hists__browser_tree
2762                          * go to the next or previous
2763                          */
2764                         goto out_free_stack;
2765                 case 'a':
2766                         if (!hists__has(hists, sym)) {
2767                                 ui_browser__warning(&browser->b, delay_secs * 2,
2768                         "Annotation is only available for symbolic views, "
2769                         "include \"sym*\" in --sort to use it.");
2770                                 continue;
2771                         }
2772
2773                         if (browser->selection == NULL ||
2774                             browser->selection->sym == NULL ||
2775                             browser->selection->map->dso->annotate_warned)
2776                                 continue;
2777
2778                         actions->ms.map = browser->selection->map;
2779                         actions->ms.sym = browser->selection->sym;
2780                         do_annotate(browser, actions);
2781                         continue;
2782                 case 'P':
2783                         hist_browser__dump(browser);
2784                         continue;
2785                 case 'd':
2786                         actions->ms.map = map;
2787                         do_zoom_dso(browser, actions);
2788                         continue;
2789                 case 'V':
2790                         browser->show_dso = !browser->show_dso;
2791                         continue;
2792                 case 't':
2793                         actions->thread = thread;
2794                         do_zoom_thread(browser, actions);
2795                         continue;
2796                 case 'S':
2797                         actions->socket = socked_id;
2798                         do_zoom_socket(browser, actions);
2799                         continue;
2800                 case '/':
2801                         if (ui_browser__input_window("Symbol to show",
2802                                         "Please enter the name of symbol you want to see.\n"
2803                                         "To remove the filter later, press / + ENTER.",
2804                                         buf, "ENTER: OK, ESC: Cancel",
2805                                         delay_secs * 2) == K_ENTER) {
2806                                 hists->symbol_filter_str = *buf ? buf : NULL;
2807                                 hists__filter_by_symbol(hists);
2808                                 hist_browser__reset(browser);
2809                         }
2810                         continue;
2811                 case 'r':
2812                         if (is_report_browser(hbt)) {
2813                                 actions->thread = NULL;
2814                                 actions->ms.sym = NULL;
2815                                 do_run_script(browser, actions);
2816                         }
2817                         continue;
2818                 case 's':
2819                         if (is_report_browser(hbt)) {
2820                                 key = do_switch_data(browser, actions);
2821                                 if (key == K_SWITCH_INPUT_DATA)
2822                                         goto out_free_stack;
2823                         }
2824                         continue;
2825                 case 'i':
2826                         /* env->arch is NULL for live-mode (i.e. perf top) */
2827                         if (env->arch)
2828                                 tui__header_window(env);
2829                         continue;
2830                 case 'F':
2831                         symbol_conf.filter_relative ^= 1;
2832                         continue;
2833                 case 'z':
2834                         if (!is_report_browser(hbt)) {
2835                                 struct perf_top *top = hbt->arg;
2836
2837                                 top->zero = !top->zero;
2838                         }
2839                         continue;
2840                 case 'L':
2841                         if (ui_browser__input_window("Percent Limit",
2842                                         "Please enter the value you want to hide entries under that percent.",
2843                                         buf, "ENTER: OK, ESC: Cancel",
2844                                         delay_secs * 2) == K_ENTER) {
2845                                 char *end;
2846                                 double new_percent = strtod(buf, &end);
2847
2848                                 if (new_percent < 0 || new_percent > 100) {
2849                                         ui_browser__warning(&browser->b, delay_secs * 2,
2850                                                 "Invalid percent: %.2f", new_percent);
2851                                         continue;
2852                                 }
2853
2854                                 hist_browser__update_percent_limit(browser, new_percent);
2855                                 hist_browser__reset(browser);
2856                         }
2857                         continue;
2858                 case K_F1:
2859                 case 'h':
2860                 case '?':
2861                         ui_browser__help_window(&browser->b,
2862                                 is_report_browser(hbt) ? report_help : top_help);
2863                         continue;
2864                 case K_ENTER:
2865                 case K_RIGHT:
2866                 case 'm':
2867                         /* menu */
2868                         break;
2869                 case K_ESC:
2870                 case K_LEFT: {
2871                         const void *top;
2872
2873                         if (pstack__empty(browser->pstack)) {
2874                                 /*
2875                                  * Go back to the perf_evsel_menu__run or other user
2876                                  */
2877                                 if (left_exits)
2878                                         goto out_free_stack;
2879
2880                                 if (key == K_ESC &&
2881                                     ui_browser__dialog_yesno(&browser->b,
2882                                                              "Do you really want to exit?"))
2883                                         goto out_free_stack;
2884
2885                                 continue;
2886                         }
2887                         top = pstack__peek(browser->pstack);
2888                         if (top == &browser->hists->dso_filter) {
2889                                 /*
2890                                  * No need to set actions->dso here since
2891                                  * it's just to remove the current filter.
2892                                  * Ditto for thread below.
2893                                  */
2894                                 do_zoom_dso(browser, actions);
2895                         } else if (top == &browser->hists->thread_filter) {
2896                                 do_zoom_thread(browser, actions);
2897                         } else if (top == &browser->hists->socket_filter) {
2898                                 do_zoom_socket(browser, actions);
2899                         }
2900                         continue;
2901                 }
2902                 case 'q':
2903                 case CTRL('c'):
2904                         goto out_free_stack;
2905                 case 'f':
2906                         if (!is_report_browser(hbt)) {
2907                                 struct perf_top *top = hbt->arg;
2908
2909                                 perf_evlist__toggle_enable(top->evlist);
2910                                 /*
2911                                  * No need to refresh, resort/decay histogram
2912                                  * entries if we are not collecting samples:
2913                                  */
2914                                 if (top->evlist->enabled) {
2915                                         helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2916                                         hbt->refresh = delay_secs;
2917                                 } else {
2918                                         helpline = "Press 'f' again to re-enable the events";
2919                                         hbt->refresh = 0;
2920                                 }
2921                                 continue;
2922                         }
2923                         /* Fall thru */
2924                 default:
2925                         helpline = "Press '?' for help on key bindings";
2926                         continue;
2927                 }
2928
2929                 if (!hists__has(hists, sym) || browser->selection == NULL)
2930                         goto skip_annotation;
2931
2932                 if (sort__mode == SORT_MODE__BRANCH) {
2933                         bi = browser->he_selection->branch_info;
2934
2935                         if (bi == NULL)
2936                                 goto skip_annotation;
2937
2938                         nr_options += add_annotate_opt(browser,
2939                                                        &actions[nr_options],
2940                                                        &options[nr_options],
2941                                                        bi->from.map,
2942                                                        bi->from.sym);
2943                         if (bi->to.sym != bi->from.sym)
2944                                 nr_options += add_annotate_opt(browser,
2945                                                         &actions[nr_options],
2946                                                         &options[nr_options],
2947                                                         bi->to.map,
2948                                                         bi->to.sym);
2949                 } else {
2950                         nr_options += add_annotate_opt(browser,
2951                                                        &actions[nr_options],
2952                                                        &options[nr_options],
2953                                                        browser->selection->map,
2954                                                        browser->selection->sym);
2955                 }
2956 skip_annotation:
2957                 nr_options += add_thread_opt(browser, &actions[nr_options],
2958                                              &options[nr_options], thread);
2959                 nr_options += add_dso_opt(browser, &actions[nr_options],
2960                                           &options[nr_options], map);
2961                 nr_options += add_map_opt(browser, &actions[nr_options],
2962                                           &options[nr_options],
2963                                           browser->selection ?
2964                                                 browser->selection->map : NULL);
2965                 nr_options += add_socket_opt(browser, &actions[nr_options],
2966                                              &options[nr_options],
2967                                              socked_id);
2968                 /* perf script support */
2969                 if (!is_report_browser(hbt))
2970                         goto skip_scripting;
2971
2972                 if (browser->he_selection) {
2973                         if (hists__has(hists, thread) && thread) {
2974                                 nr_options += add_script_opt(browser,
2975                                                              &actions[nr_options],
2976                                                              &options[nr_options],
2977                                                              thread, NULL);
2978                         }
2979                         /*
2980                          * Note that browser->selection != NULL
2981                          * when browser->he_selection is not NULL,
2982                          * so we don't need to check browser->selection
2983                          * before fetching browser->selection->sym like what
2984                          * we do before fetching browser->selection->map.
2985                          *
2986                          * See hist_browser__show_entry.
2987                          */
2988                         if (hists__has(hists, sym) && browser->selection->sym) {
2989                                 nr_options += add_script_opt(browser,
2990                                                              &actions[nr_options],
2991                                                              &options[nr_options],
2992                                                              NULL, browser->selection->sym);
2993                         }
2994                 }
2995                 nr_options += add_script_opt(browser, &actions[nr_options],
2996                                              &options[nr_options], NULL, NULL);
2997                 nr_options += add_switch_opt(browser, &actions[nr_options],
2998                                              &options[nr_options]);
2999 skip_scripting:
3000                 nr_options += add_exit_opt(browser, &actions[nr_options],
3001                                            &options[nr_options]);
3002
3003                 do {
3004                         struct popup_action *act;
3005
3006                         choice = ui__popup_menu(nr_options, options);
3007                         if (choice == -1 || choice >= nr_options)
3008                                 break;
3009
3010                         act = &actions[choice];
3011                         key = act->fn(browser, act);
3012                 } while (key == 1);
3013
3014                 if (key == K_SWITCH_INPUT_DATA)
3015                         break;
3016         }
3017 out_free_stack:
3018         pstack__delete(browser->pstack);
3019 out:
3020         hist_browser__delete(browser);
3021         free_popup_options(options, MAX_OPTIONS);
3022         return key;
3023 }
3024
3025 struct perf_evsel_menu {
3026         struct ui_browser b;
3027         struct perf_evsel *selection;
3028         bool lost_events, lost_events_warned;
3029         float min_pcnt;
3030         struct perf_env *env;
3031 };
3032
3033 static void perf_evsel_menu__write(struct ui_browser *browser,
3034                                    void *entry, int row)
3035 {
3036         struct perf_evsel_menu *menu = container_of(browser,
3037                                                     struct perf_evsel_menu, b);
3038         struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3039         struct hists *hists = evsel__hists(evsel);
3040         bool current_entry = ui_browser__is_current_entry(browser, row);
3041         unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
3042         const char *ev_name = perf_evsel__name(evsel);
3043         char bf[256], unit;
3044         const char *warn = " ";
3045         size_t printed;
3046
3047         ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3048                                                        HE_COLORSET_NORMAL);
3049
3050         if (perf_evsel__is_group_event(evsel)) {
3051                 struct perf_evsel *pos;
3052
3053                 ev_name = perf_evsel__group_name(evsel);
3054
3055                 for_each_group_member(pos, evsel) {
3056                         struct hists *pos_hists = evsel__hists(pos);
3057                         nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
3058                 }
3059         }
3060
3061         nr_events = convert_unit(nr_events, &unit);
3062         printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
3063                            unit, unit == ' ' ? "" : " ", ev_name);
3064         ui_browser__printf(browser, "%s", bf);
3065
3066         nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
3067         if (nr_events != 0) {
3068                 menu->lost_events = true;
3069                 if (!current_entry)
3070                         ui_browser__set_color(browser, HE_COLORSET_TOP);
3071                 nr_events = convert_unit(nr_events, &unit);
3072                 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3073                                      nr_events, unit, unit == ' ' ? "" : " ");
3074                 warn = bf;
3075         }
3076
3077         ui_browser__write_nstring(browser, warn, browser->width - printed);
3078
3079         if (current_entry)
3080                 menu->selection = evsel;
3081 }
3082
3083 static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3084                                 int nr_events, const char *help,
3085                                 struct hist_browser_timer *hbt)
3086 {
3087         struct perf_evlist *evlist = menu->b.priv;
3088         struct perf_evsel *pos;
3089         const char *title = "Available samples";
3090         int delay_secs = hbt ? hbt->refresh : 0;
3091         int key;
3092
3093         if (ui_browser__show(&menu->b, title,
3094                              "ESC: exit, ENTER|->: Browse histograms") < 0)
3095                 return -1;
3096
3097         while (1) {
3098                 key = ui_browser__run(&menu->b, delay_secs);
3099
3100                 switch (key) {
3101                 case K_TIMER:
3102                         hbt->timer(hbt->arg);
3103
3104                         if (!menu->lost_events_warned && menu->lost_events) {
3105                                 ui_browser__warn_lost_events(&menu->b);
3106                                 menu->lost_events_warned = true;
3107                         }
3108                         continue;
3109                 case K_RIGHT:
3110                 case K_ENTER:
3111                         if (!menu->selection)
3112                                 continue;
3113                         pos = menu->selection;
3114 browse_hists:
3115                         perf_evlist__set_selected(evlist, pos);
3116                         /*
3117                          * Give the calling tool a chance to populate the non
3118                          * default evsel resorted hists tree.
3119                          */
3120                         if (hbt)
3121                                 hbt->timer(hbt->arg);
3122                         key = perf_evsel__hists_browse(pos, nr_events, help,
3123                                                        true, hbt,
3124                                                        menu->min_pcnt,
3125                                                        menu->env);
3126                         ui_browser__show_title(&menu->b, title);
3127                         switch (key) {
3128                         case K_TAB:
3129                                 if (pos->node.next == &evlist->entries)
3130                                         pos = perf_evlist__first(evlist);
3131                                 else
3132                                         pos = perf_evsel__next(pos);
3133                                 goto browse_hists;
3134                         case K_UNTAB:
3135                                 if (pos->node.prev == &evlist->entries)
3136                                         pos = perf_evlist__last(evlist);
3137                                 else
3138                                         pos = perf_evsel__prev(pos);
3139                                 goto browse_hists;
3140                         case K_SWITCH_INPUT_DATA:
3141                         case 'q':
3142                         case CTRL('c'):
3143                                 goto out;
3144                         case K_ESC:
3145                         default:
3146                                 continue;
3147                         }
3148                 case K_LEFT:
3149                         continue;
3150                 case K_ESC:
3151                         if (!ui_browser__dialog_yesno(&menu->b,
3152                                                "Do you really want to exit?"))
3153                                 continue;
3154                         /* Fall thru */
3155                 case 'q':
3156                 case CTRL('c'):
3157                         goto out;
3158                 default:
3159                         continue;
3160                 }
3161         }
3162
3163 out:
3164         ui_browser__hide(&menu->b);
3165         return key;
3166 }
3167
3168 static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
3169                                  void *entry)
3170 {
3171         struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3172
3173         if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3174                 return true;
3175
3176         return false;
3177 }
3178
3179 static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
3180                                            int nr_entries, const char *help,
3181                                            struct hist_browser_timer *hbt,
3182                                            float min_pcnt,
3183                                            struct perf_env *env)
3184 {
3185         struct perf_evsel *pos;
3186         struct perf_evsel_menu menu = {
3187                 .b = {
3188                         .entries    = &evlist->entries,
3189                         .refresh    = ui_browser__list_head_refresh,
3190                         .seek       = ui_browser__list_head_seek,
3191                         .write      = perf_evsel_menu__write,
3192                         .filter     = filter_group_entries,
3193                         .nr_entries = nr_entries,
3194                         .priv       = evlist,
3195                 },
3196                 .min_pcnt = min_pcnt,
3197                 .env = env,
3198         };
3199
3200         ui_helpline__push("Press ESC to exit");
3201
3202         evlist__for_each_entry(evlist, pos) {
3203                 const char *ev_name = perf_evsel__name(pos);
3204                 size_t line_len = strlen(ev_name) + 7;
3205
3206                 if (menu.b.width < line_len)
3207                         menu.b.width = line_len;
3208         }
3209
3210         return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
3211 }
3212
3213 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
3214                                   struct hist_browser_timer *hbt,
3215                                   float min_pcnt,
3216                                   struct perf_env *env)
3217 {
3218         int nr_entries = evlist->nr_entries;
3219
3220 single_entry:
3221         if (nr_entries == 1) {
3222                 struct perf_evsel *first = perf_evlist__first(evlist);
3223
3224                 return perf_evsel__hists_browse(first, nr_entries, help,
3225                                                 false, hbt, min_pcnt,
3226                                                 env);
3227         }
3228
3229         if (symbol_conf.event_group) {
3230                 struct perf_evsel *pos;
3231
3232                 nr_entries = 0;
3233                 evlist__for_each_entry(evlist, pos) {
3234                         if (perf_evsel__is_group_leader(pos))
3235                                 nr_entries++;
3236                 }
3237
3238                 if (nr_entries == 1)
3239                         goto single_entry;
3240         }
3241
3242         return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
3243                                                hbt, min_pcnt, env);
3244 }