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