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