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