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