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