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