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