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