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