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