xref: /linux/tools/perf/ui/browsers/hists.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
276b31a29SArnaldo Carvalho de Melo #include <dirent.h>
3a43783aeSArnaldo Carvalho de Melo #include <errno.h>
4fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
5aca7a94dSNamhyung Kim #include <stdio.h>
6aca7a94dSNamhyung Kim #include <stdlib.h>
7aca7a94dSNamhyung Kim #include <string.h>
8aca7a94dSNamhyung Kim #include <linux/rbtree.h>
93ca43b60SArnaldo Carvalho de Melo #include <linux/string.h>
10b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h>
111d6c49dfSAndi Kleen #include <linux/time64.h>
127f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
13aca7a94dSNamhyung Kim 
14b4209025SArnaldo Carvalho de Melo #include "../../util/debug.h"
154a3cec84SArnaldo Carvalho de Melo #include "../../util/dso.h"
16b10ba7f1SArnaldo Carvalho de Melo #include "../../util/callchain.h"
17aca7a94dSNamhyung Kim #include "../../util/evsel.h"
18aca7a94dSNamhyung Kim #include "../../util/evlist.h"
19f2a39fe8SArnaldo Carvalho de Melo #include "../../util/header.h"
20aca7a94dSNamhyung Kim #include "../../util/hist.h"
21209f4e70SArnaldo Carvalho de Melo #include "../../util/machine.h"
221101f69aSArnaldo Carvalho de Melo #include "../../util/map.h"
23209f4e70SArnaldo Carvalho de Melo #include "../../util/maps.h"
24daecf9e0SArnaldo Carvalho de Melo #include "../../util/symbol.h"
25d3300a3cSArnaldo Carvalho de Melo #include "../../util/map_symbol.h"
26d3300a3cSArnaldo Carvalho de Melo #include "../../util/branch.h"
27aca7a94dSNamhyung Kim #include "../../util/pstack.h"
28aca7a94dSNamhyung Kim #include "../../util/sort.h"
2942337a22SNamhyung Kim #include "../../util/top.h"
30e7ff8920SArnaldo Carvalho de Melo #include "../../util/thread.h"
317fa46cbfSJin Yao #include "../../util/block-info.h"
32f12ad272SIan Rogers #include "../../util/util.h"
3368d80758SNamhyung Kim #include "../../arch/common.h"
34aca7a94dSNamhyung Kim 
35f758990fSJiri Olsa #include "../browsers/hists.h"
36aca7a94dSNamhyung Kim #include "../helpline.h"
37aca7a94dSNamhyung Kim #include "../util.h"
38aca7a94dSNamhyung Kim #include "../ui.h"
39aca7a94dSNamhyung Kim #include "map.h"
40d755330cSJiri Olsa #include "annotate.h"
410bfbe661SNamhyung Kim #include "annotate-data.h"
42632a5cabSArnaldo Carvalho de Melo #include "srcline.h"
43a067558eSArnaldo Carvalho de Melo #include "string2.h"
4458db1d6eSArnaldo Carvalho de Melo #include "units.h"
451d6c49dfSAndi Kleen #include "time-utils.h"
46aca7a94dSNamhyung Kim 
473052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h>
483d689ed6SArnaldo Carvalho de Melo 
49f5951d56SNamhyung Kim extern void hist_browser__init_hpp(void);
50f5951d56SNamhyung Kim 
51f016d24aSArnaldo Carvalho de Melo static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size);
52112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb);
53aca7a94dSNamhyung Kim 
54c3b78952SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd,
55c3b78952SNamhyung Kim 					     float min_pcnt);
56c3b78952SNamhyung Kim 
hist_browser__has_filter(struct hist_browser * hb)57268397cbSNamhyung Kim static bool hist_browser__has_filter(struct hist_browser *hb)
58268397cbSNamhyung Kim {
595a1a99cdSJiri Olsa 	return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
60268397cbSNamhyung Kim }
61268397cbSNamhyung Kim 
hist_browser__get_folding(struct hist_browser * browser)624fabf3d1SHe Kuang static int hist_browser__get_folding(struct hist_browser *browser)
634fabf3d1SHe Kuang {
644fabf3d1SHe Kuang 	struct rb_node *nd;
654fabf3d1SHe Kuang 	struct hists *hists = browser->hists;
664fabf3d1SHe Kuang 	int unfolded_rows = 0;
674fabf3d1SHe Kuang 
682eb3d689SDavidlohr Bueso 	for (nd = rb_first_cached(&hists->entries);
694fabf3d1SHe Kuang 	     (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
70f5b763feSNamhyung Kim 	     nd = rb_hierarchy_next(nd)) {
714fabf3d1SHe Kuang 		struct hist_entry *he =
724fabf3d1SHe Kuang 			rb_entry(nd, struct hist_entry, rb_node);
734fabf3d1SHe Kuang 
74f5b763feSNamhyung Kim 		if (he->leaf && he->unfolded)
754fabf3d1SHe Kuang 			unfolded_rows += he->nr_rows;
764fabf3d1SHe Kuang 	}
774fabf3d1SHe Kuang 	return unfolded_rows;
784fabf3d1SHe Kuang }
794fabf3d1SHe Kuang 
hist_browser__set_title_space(struct hist_browser * hb)80ef9ff601SArnaldo Carvalho de Melo static void hist_browser__set_title_space(struct hist_browser *hb)
81ef9ff601SArnaldo Carvalho de Melo {
82ef9ff601SArnaldo Carvalho de Melo 	struct ui_browser *browser = &hb->b;
83ef9ff601SArnaldo Carvalho de Melo 	struct hists *hists = hb->hists;
84ef9ff601SArnaldo Carvalho de Melo 	struct perf_hpp_list *hpp_list = hists->hpp_list;
85ef9ff601SArnaldo Carvalho de Melo 
86ef9ff601SArnaldo Carvalho de Melo 	browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0;
87ef9ff601SArnaldo Carvalho de Melo }
88ef9ff601SArnaldo Carvalho de Melo 
hist_browser__nr_entries(struct hist_browser * hb)89c3b78952SNamhyung Kim static u32 hist_browser__nr_entries(struct hist_browser *hb)
90c3b78952SNamhyung Kim {
91c3b78952SNamhyung Kim 	u32 nr_entries;
92c3b78952SNamhyung Kim 
93f5b763feSNamhyung Kim 	if (symbol_conf.report_hierarchy)
94f5b763feSNamhyung Kim 		nr_entries = hb->nr_hierarchy_entries;
95f5b763feSNamhyung Kim 	else if (hist_browser__has_filter(hb))
96c3b78952SNamhyung Kim 		nr_entries = hb->nr_non_filtered_entries;
97c3b78952SNamhyung Kim 	else
98c3b78952SNamhyung Kim 		nr_entries = hb->hists->nr_entries;
99c3b78952SNamhyung Kim 
1004fabf3d1SHe Kuang 	hb->nr_callchain_rows = hist_browser__get_folding(hb);
101c3b78952SNamhyung Kim 	return nr_entries + hb->nr_callchain_rows;
102c3b78952SNamhyung Kim }
103c3b78952SNamhyung Kim 
hist_browser__update_rows(struct hist_browser * hb)104025bf7eaSArnaldo Carvalho de Melo static void hist_browser__update_rows(struct hist_browser *hb)
105025bf7eaSArnaldo Carvalho de Melo {
106025bf7eaSArnaldo Carvalho de Melo 	struct ui_browser *browser = &hb->b;
107f8e6710dSJiri Olsa 	struct hists *hists = hb->hists;
108f8e6710dSJiri Olsa 	struct perf_hpp_list *hpp_list = hists->hpp_list;
109ef9ff601SArnaldo Carvalho de Melo 	u16 index_row;
110025bf7eaSArnaldo Carvalho de Melo 
111ef9ff601SArnaldo Carvalho de Melo 	if (!hb->show_headers) {
112ef9ff601SArnaldo Carvalho de Melo 		browser->rows += browser->extra_title_lines;
113ef9ff601SArnaldo Carvalho de Melo 		browser->extra_title_lines = 0;
114ef9ff601SArnaldo Carvalho de Melo 		return;
115ef9ff601SArnaldo Carvalho de Melo 	}
116ef9ff601SArnaldo Carvalho de Melo 
117ef9ff601SArnaldo Carvalho de Melo 	browser->extra_title_lines = hpp_list->nr_header_lines;
118ef9ff601SArnaldo Carvalho de Melo 	browser->rows -= browser->extra_title_lines;
119025bf7eaSArnaldo Carvalho de Melo 	/*
120025bf7eaSArnaldo Carvalho de Melo 	 * Verify if we were at the last line and that line isn't
1214d39c89fSIngo Molnar 	 * visible because we now show the header line(s).
122025bf7eaSArnaldo Carvalho de Melo 	 */
123025bf7eaSArnaldo Carvalho de Melo 	index_row = browser->index - browser->top_idx;
124025bf7eaSArnaldo Carvalho de Melo 	if (index_row >= browser->rows)
125025bf7eaSArnaldo Carvalho de Melo 		browser->index -= index_row - browser->rows + 1;
126025bf7eaSArnaldo Carvalho de Melo }
127025bf7eaSArnaldo Carvalho de Melo 
hist_browser__refresh_dimensions(struct ui_browser * browser)128357cfff1SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct ui_browser *browser)
129aca7a94dSNamhyung Kim {
130357cfff1SArnaldo Carvalho de Melo 	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
131357cfff1SArnaldo Carvalho de Melo 
132aca7a94dSNamhyung Kim 	/* 3 == +/- toggle symbol before actual hist_entry rendering */
133357cfff1SArnaldo Carvalho de Melo 	browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
134357cfff1SArnaldo Carvalho de Melo 	/*
135357cfff1SArnaldo Carvalho de Melo  	 * FIXME: Just keeping existing behaviour, but this really should be
136357cfff1SArnaldo Carvalho de Melo  	 *	  before updating browser->width, as it will invalidate the
137357cfff1SArnaldo Carvalho de Melo  	 *	  calculation above. Fix this and the fallout in another
138357cfff1SArnaldo Carvalho de Melo  	 *	  changeset.
139357cfff1SArnaldo Carvalho de Melo  	 */
140357cfff1SArnaldo Carvalho de Melo 	ui_browser__refresh_dimensions(browser);
141ca3ff33bSArnaldo Carvalho de Melo }
142ca3ff33bSArnaldo Carvalho de Melo 
hist_browser__reset(struct hist_browser * browser)14305e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser)
144aca7a94dSNamhyung Kim {
145c3b78952SNamhyung Kim 	/*
146c3b78952SNamhyung Kim 	 * The hists__remove_entry_filter() already folds non-filtered
147c3b78952SNamhyung Kim 	 * entries so we can assume it has 0 callchain rows.
148c3b78952SNamhyung Kim 	 */
149c3b78952SNamhyung Kim 	browser->nr_callchain_rows = 0;
150c3b78952SNamhyung Kim 
151268397cbSNamhyung Kim 	hist_browser__update_nr_entries(browser);
152c3b78952SNamhyung Kim 	browser->b.nr_entries = hist_browser__nr_entries(browser);
153357cfff1SArnaldo Carvalho de Melo 	hist_browser__refresh_dimensions(&browser->b);
15405e8b080SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
155aca7a94dSNamhyung Kim }
156aca7a94dSNamhyung Kim 
tree__folded_sign(bool unfolded)157aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded)
158aca7a94dSNamhyung Kim {
159aca7a94dSNamhyung Kim 	return unfolded ? '-' : '+';
160aca7a94dSNamhyung Kim }
161aca7a94dSNamhyung Kim 
hist_entry__folded(const struct hist_entry * he)16205e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he)
163aca7a94dSNamhyung Kim {
1643698dab1SNamhyung Kim 	return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
165aca7a94dSNamhyung Kim }
166aca7a94dSNamhyung Kim 
callchain_list__folded(const struct callchain_list * cl)16705e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl)
168aca7a94dSNamhyung Kim {
1693698dab1SNamhyung Kim 	return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
170aca7a94dSNamhyung Kim }
171aca7a94dSNamhyung Kim 
callchain_list__set_folding(struct callchain_list * cl,bool unfold)1723698dab1SNamhyung Kim static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
173aca7a94dSNamhyung Kim {
1743698dab1SNamhyung Kim 	cl->unfolded = unfold ? cl->has_children : false;
175aca7a94dSNamhyung Kim }
176aca7a94dSNamhyung Kim 
callchain_node__count_rows_rb_tree(struct callchain_node * node)17705e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
178aca7a94dSNamhyung Kim {
1792a704fc8SMilian Wolff 	int n = 0;
180aca7a94dSNamhyung Kim 	struct rb_node *nd;
181aca7a94dSNamhyung Kim 
18205e8b080SArnaldo Carvalho de Melo 	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
183aca7a94dSNamhyung Kim 		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
184aca7a94dSNamhyung Kim 		struct callchain_list *chain;
185aca7a94dSNamhyung Kim 		char folded_sign = ' '; /* No children */
186aca7a94dSNamhyung Kim 
187aca7a94dSNamhyung Kim 		list_for_each_entry(chain, &child->val, list) {
188aca7a94dSNamhyung Kim 			++n;
1890d3eb0b7SJin Yao 
190aca7a94dSNamhyung Kim 			/* We need this because we may not have children */
191aca7a94dSNamhyung Kim 			folded_sign = callchain_list__folded(chain);
192aca7a94dSNamhyung Kim 			if (folded_sign == '+')
193aca7a94dSNamhyung Kim 				break;
194aca7a94dSNamhyung Kim 		}
195aca7a94dSNamhyung Kim 
196aca7a94dSNamhyung Kim 		if (folded_sign == '-') /* Have children and they're unfolded */
197aca7a94dSNamhyung Kim 			n += callchain_node__count_rows_rb_tree(child);
198aca7a94dSNamhyung Kim 	}
199aca7a94dSNamhyung Kim 
200aca7a94dSNamhyung Kim 	return n;
201aca7a94dSNamhyung Kim }
202aca7a94dSNamhyung Kim 
callchain_node__count_flat_rows(struct callchain_node * node)2034b3a3212SNamhyung Kim static int callchain_node__count_flat_rows(struct callchain_node *node)
2044b3a3212SNamhyung Kim {
2054b3a3212SNamhyung Kim 	struct callchain_list *chain;
2064b3a3212SNamhyung Kim 	char folded_sign = 0;
2074b3a3212SNamhyung Kim 	int n = 0;
2084b3a3212SNamhyung Kim 
2094b3a3212SNamhyung Kim 	list_for_each_entry(chain, &node->parent_val, list) {
2104b3a3212SNamhyung Kim 		if (!folded_sign) {
2114b3a3212SNamhyung Kim 			/* only check first chain list entry */
2124b3a3212SNamhyung Kim 			folded_sign = callchain_list__folded(chain);
2134b3a3212SNamhyung Kim 			if (folded_sign == '+')
2144b3a3212SNamhyung Kim 				return 1;
2154b3a3212SNamhyung Kim 		}
2164b3a3212SNamhyung Kim 		n++;
2174b3a3212SNamhyung Kim 	}
2184b3a3212SNamhyung Kim 
2194b3a3212SNamhyung Kim 	list_for_each_entry(chain, &node->val, list) {
2204b3a3212SNamhyung Kim 		if (!folded_sign) {
2214b3a3212SNamhyung Kim 			/* node->parent_val list might be empty */
2224b3a3212SNamhyung Kim 			folded_sign = callchain_list__folded(chain);
2234b3a3212SNamhyung Kim 			if (folded_sign == '+')
2244b3a3212SNamhyung Kim 				return 1;
2254b3a3212SNamhyung Kim 		}
2264b3a3212SNamhyung Kim 		n++;
2274b3a3212SNamhyung Kim 	}
2284b3a3212SNamhyung Kim 
2294b3a3212SNamhyung Kim 	return n;
2304b3a3212SNamhyung Kim }
2314b3a3212SNamhyung Kim 
callchain_node__count_folded_rows(struct callchain_node * node __maybe_unused)2328c430a34SNamhyung Kim static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
2338c430a34SNamhyung Kim {
2348c430a34SNamhyung Kim 	return 1;
2358c430a34SNamhyung Kim }
2368c430a34SNamhyung Kim 
callchain_node__count_rows(struct callchain_node * node)237aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node)
238aca7a94dSNamhyung Kim {
239aca7a94dSNamhyung Kim 	struct callchain_list *chain;
240aca7a94dSNamhyung Kim 	bool unfolded = false;
2412a704fc8SMilian Wolff 	int n = 0;
242aca7a94dSNamhyung Kim 
2434b3a3212SNamhyung Kim 	if (callchain_param.mode == CHAIN_FLAT)
2444b3a3212SNamhyung Kim 		return callchain_node__count_flat_rows(node);
2458c430a34SNamhyung Kim 	else if (callchain_param.mode == CHAIN_FOLDED)
2468c430a34SNamhyung Kim 		return callchain_node__count_folded_rows(node);
2474b3a3212SNamhyung Kim 
248aca7a94dSNamhyung Kim 	list_for_each_entry(chain, &node->val, list) {
249aca7a94dSNamhyung Kim 		++n;
2500d3eb0b7SJin Yao 
2513698dab1SNamhyung Kim 		unfolded = chain->unfolded;
252aca7a94dSNamhyung Kim 	}
253aca7a94dSNamhyung Kim 
254aca7a94dSNamhyung Kim 	if (unfolded)
255aca7a94dSNamhyung Kim 		n += callchain_node__count_rows_rb_tree(node);
256aca7a94dSNamhyung Kim 
257aca7a94dSNamhyung Kim 	return n;
258aca7a94dSNamhyung Kim }
259aca7a94dSNamhyung Kim 
callchain__count_rows(struct rb_root * chain)260aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain)
261aca7a94dSNamhyung Kim {
262aca7a94dSNamhyung Kim 	struct rb_node *nd;
263aca7a94dSNamhyung Kim 	int n = 0;
264aca7a94dSNamhyung Kim 
265aca7a94dSNamhyung Kim 	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
266aca7a94dSNamhyung Kim 		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
267aca7a94dSNamhyung Kim 		n += callchain_node__count_rows(node);
268aca7a94dSNamhyung Kim 	}
269aca7a94dSNamhyung Kim 
270aca7a94dSNamhyung Kim 	return n;
271aca7a94dSNamhyung Kim }
272aca7a94dSNamhyung Kim 
hierarchy_count_rows(struct hist_browser * hb,struct hist_entry * he,bool include_children)273f5b763feSNamhyung Kim static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
274f5b763feSNamhyung Kim 				bool include_children)
275f5b763feSNamhyung Kim {
276f5b763feSNamhyung Kim 	int count = 0;
277f5b763feSNamhyung Kim 	struct rb_node *node;
278f5b763feSNamhyung Kim 	struct hist_entry *child;
279f5b763feSNamhyung Kim 
280f5b763feSNamhyung Kim 	if (he->leaf)
281f5b763feSNamhyung Kim 		return callchain__count_rows(&he->sorted_chain);
282f5b763feSNamhyung Kim 
28379dded87SNamhyung Kim 	if (he->has_no_entry)
28479dded87SNamhyung Kim 		return 1;
28579dded87SNamhyung Kim 
2862eb3d689SDavidlohr Bueso 	node = rb_first_cached(&he->hroot_out);
287f5b763feSNamhyung Kim 	while (node) {
288f5b763feSNamhyung Kim 		float percent;
289f5b763feSNamhyung Kim 
290f5b763feSNamhyung Kim 		child = rb_entry(node, struct hist_entry, rb_node);
291f5b763feSNamhyung Kim 		percent = hist_entry__get_percent_limit(child);
292f5b763feSNamhyung Kim 
293f5b763feSNamhyung Kim 		if (!child->filtered && percent >= hb->min_pcnt) {
294f5b763feSNamhyung Kim 			count++;
295f5b763feSNamhyung Kim 
296f5b763feSNamhyung Kim 			if (include_children && child->unfolded)
297f5b763feSNamhyung Kim 				count += hierarchy_count_rows(hb, child, true);
298f5b763feSNamhyung Kim 		}
299f5b763feSNamhyung Kim 
300f5b763feSNamhyung Kim 		node = rb_next(node);
301f5b763feSNamhyung Kim 	}
302f5b763feSNamhyung Kim 	return count;
303f5b763feSNamhyung Kim }
304f5b763feSNamhyung Kim 
hist_entry__toggle_fold(struct hist_entry * he)3053698dab1SNamhyung Kim static bool hist_entry__toggle_fold(struct hist_entry *he)
306aca7a94dSNamhyung Kim {
3073698dab1SNamhyung Kim 	if (!he)
308aca7a94dSNamhyung Kim 		return false;
309aca7a94dSNamhyung Kim 
3103698dab1SNamhyung Kim 	if (!he->has_children)
311aca7a94dSNamhyung Kim 		return false;
312aca7a94dSNamhyung Kim 
3133698dab1SNamhyung Kim 	he->unfolded = !he->unfolded;
3143698dab1SNamhyung Kim 	return true;
3153698dab1SNamhyung Kim }
3163698dab1SNamhyung Kim 
callchain_list__toggle_fold(struct callchain_list * cl)3173698dab1SNamhyung Kim static bool callchain_list__toggle_fold(struct callchain_list *cl)
3183698dab1SNamhyung Kim {
3193698dab1SNamhyung Kim 	if (!cl)
3203698dab1SNamhyung Kim 		return false;
3213698dab1SNamhyung Kim 
3223698dab1SNamhyung Kim 	if (!cl->has_children)
3233698dab1SNamhyung Kim 		return false;
3243698dab1SNamhyung Kim 
3253698dab1SNamhyung Kim 	cl->unfolded = !cl->unfolded;
326aca7a94dSNamhyung Kim 	return true;
327aca7a94dSNamhyung Kim }
328aca7a94dSNamhyung Kim 
callchain_node__init_have_children_rb_tree(struct callchain_node * node)32905e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
330aca7a94dSNamhyung Kim {
33105e8b080SArnaldo Carvalho de Melo 	struct rb_node *nd = rb_first(&node->rb_root);
332aca7a94dSNamhyung Kim 
33305e8b080SArnaldo Carvalho de Melo 	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
334aca7a94dSNamhyung Kim 		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
335aca7a94dSNamhyung Kim 		struct callchain_list *chain;
336aca7a94dSNamhyung Kim 		bool first = true;
337aca7a94dSNamhyung Kim 
338aca7a94dSNamhyung Kim 		list_for_each_entry(chain, &child->val, list) {
339aca7a94dSNamhyung Kim 			if (first) {
340aca7a94dSNamhyung Kim 				first = false;
3413698dab1SNamhyung Kim 				chain->has_children = chain->list.next != &child->val ||
342aca7a94dSNamhyung Kim 							 !RB_EMPTY_ROOT(&child->rb_root);
343aca7a94dSNamhyung Kim 			} else
3443698dab1SNamhyung Kim 				chain->has_children = chain->list.next == &child->val &&
345aca7a94dSNamhyung Kim 							 !RB_EMPTY_ROOT(&child->rb_root);
346aca7a94dSNamhyung Kim 		}
347aca7a94dSNamhyung Kim 
348aca7a94dSNamhyung Kim 		callchain_node__init_have_children_rb_tree(child);
349aca7a94dSNamhyung Kim 	}
350aca7a94dSNamhyung Kim }
351aca7a94dSNamhyung Kim 
callchain_node__init_have_children(struct callchain_node * node,bool has_sibling)352a7444af6SNamhyung Kim static void callchain_node__init_have_children(struct callchain_node *node,
353a7444af6SNamhyung Kim 					       bool has_sibling)
354aca7a94dSNamhyung Kim {
355aca7a94dSNamhyung Kim 	struct callchain_list *chain;
356aca7a94dSNamhyung Kim 
357a7444af6SNamhyung Kim 	chain = list_entry(node->val.next, struct callchain_list, list);
3583698dab1SNamhyung Kim 	chain->has_children = has_sibling;
359a7444af6SNamhyung Kim 
36090989035SAndres Freund 	if (!list_empty(&node->val)) {
36182162b5aSNamhyung Kim 		chain = list_entry(node->val.prev, struct callchain_list, list);
3623698dab1SNamhyung Kim 		chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
36382162b5aSNamhyung Kim 	}
364aca7a94dSNamhyung Kim 
36505e8b080SArnaldo Carvalho de Melo 	callchain_node__init_have_children_rb_tree(node);
366aca7a94dSNamhyung Kim }
367aca7a94dSNamhyung Kim 
callchain__init_have_children(struct rb_root * root)36805e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root)
369aca7a94dSNamhyung Kim {
370a7444af6SNamhyung Kim 	struct rb_node *nd = rb_first(root);
371a7444af6SNamhyung Kim 	bool has_sibling = nd && rb_next(nd);
372aca7a94dSNamhyung Kim 
37305e8b080SArnaldo Carvalho de Melo 	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
374aca7a94dSNamhyung Kim 		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
375a7444af6SNamhyung Kim 		callchain_node__init_have_children(node, has_sibling);
3768c430a34SNamhyung Kim 		if (callchain_param.mode == CHAIN_FLAT ||
3778c430a34SNamhyung Kim 		    callchain_param.mode == CHAIN_FOLDED)
3784b3a3212SNamhyung Kim 			callchain_node__make_parent_list(node);
379aca7a94dSNamhyung Kim 	}
380aca7a94dSNamhyung Kim }
381aca7a94dSNamhyung Kim 
hist_entry__init_have_children(struct hist_entry * he)38205e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he)
383aca7a94dSNamhyung Kim {
384f5b763feSNamhyung Kim 	if (he->init_have_children)
385f5b763feSNamhyung Kim 		return;
386f5b763feSNamhyung Kim 
387f5b763feSNamhyung Kim 	if (he->leaf) {
3883698dab1SNamhyung Kim 		he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
38905e8b080SArnaldo Carvalho de Melo 		callchain__init_have_children(&he->sorted_chain);
390f5b763feSNamhyung Kim 	} else {
3912eb3d689SDavidlohr Bueso 		he->has_children = !RB_EMPTY_ROOT(&he->hroot_out.rb_root);
392aca7a94dSNamhyung Kim 	}
393f5b763feSNamhyung Kim 
394f5b763feSNamhyung Kim 	he->init_have_children = true;
395aca7a94dSNamhyung Kim }
396aca7a94dSNamhyung Kim 
hist_browser__selection_has_children(struct hist_browser * browser)397bdc633feSArnaldo Carvalho de Melo static bool hist_browser__selection_has_children(struct hist_browser *browser)
398bdc633feSArnaldo Carvalho de Melo {
399bdc633feSArnaldo Carvalho de Melo 	struct hist_entry *he = browser->he_selection;
400bdc633feSArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->selection;
401bdc633feSArnaldo Carvalho de Melo 
402bdc633feSArnaldo Carvalho de Melo 	if (!he || !ms)
403bdc633feSArnaldo Carvalho de Melo 		return false;
404bdc633feSArnaldo Carvalho de Melo 
405bdc633feSArnaldo Carvalho de Melo 	if (ms == &he->ms)
406bdc633feSArnaldo Carvalho de Melo 	       return he->has_children;
407bdc633feSArnaldo Carvalho de Melo 
408bdc633feSArnaldo Carvalho de Melo 	return container_of(ms, struct callchain_list, ms)->has_children;
409bdc633feSArnaldo Carvalho de Melo }
410bdc633feSArnaldo Carvalho de Melo 
hist_browser__selection_unfolded(struct hist_browser * browser)411bdc633feSArnaldo Carvalho de Melo static bool hist_browser__selection_unfolded(struct hist_browser *browser)
412bdc633feSArnaldo Carvalho de Melo {
413bdc633feSArnaldo Carvalho de Melo 	struct hist_entry *he = browser->he_selection;
414bdc633feSArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->selection;
415bdc633feSArnaldo Carvalho de Melo 
416bdc633feSArnaldo Carvalho de Melo 	if (!he || !ms)
417bdc633feSArnaldo Carvalho de Melo 		return false;
418bdc633feSArnaldo Carvalho de Melo 
419bdc633feSArnaldo Carvalho de Melo 	if (ms == &he->ms)
420bdc633feSArnaldo Carvalho de Melo 	       return he->unfolded;
421bdc633feSArnaldo Carvalho de Melo 
422bdc633feSArnaldo Carvalho de Melo 	return container_of(ms, struct callchain_list, ms)->unfolded;
423bdc633feSArnaldo Carvalho de Melo }
424bdc633feSArnaldo Carvalho de Melo 
hist_browser__selection_sym_name(struct hist_browser * browser,char * bf,size_t size)425bdc633feSArnaldo Carvalho de Melo static char *hist_browser__selection_sym_name(struct hist_browser *browser, char *bf, size_t size)
426bdc633feSArnaldo Carvalho de Melo {
427bdc633feSArnaldo Carvalho de Melo 	struct hist_entry *he = browser->he_selection;
428bdc633feSArnaldo Carvalho de Melo 	struct map_symbol *ms = browser->selection;
429bdc633feSArnaldo Carvalho de Melo 	struct callchain_list *callchain_entry;
430bdc633feSArnaldo Carvalho de Melo 
431bdc633feSArnaldo Carvalho de Melo 	if (!he || !ms)
432bdc633feSArnaldo Carvalho de Melo 		return NULL;
433bdc633feSArnaldo Carvalho de Melo 
434bdc633feSArnaldo Carvalho de Melo 	if (ms == &he->ms) {
435bdc633feSArnaldo Carvalho de Melo 	       hist_entry__sym_snprintf(he, bf, size, 0);
436bdc633feSArnaldo Carvalho de Melo 	       return bf + 4; // skip the level, e.g. '[k] '
437bdc633feSArnaldo Carvalho de Melo 	}
438bdc633feSArnaldo Carvalho de Melo 
439bdc633feSArnaldo Carvalho de Melo 	callchain_entry = container_of(ms, struct callchain_list, ms);
440bdc633feSArnaldo Carvalho de Melo 	return callchain_list__sym_name(callchain_entry, bf, size, browser->show_dso);
441bdc633feSArnaldo Carvalho de Melo }
442bdc633feSArnaldo Carvalho de Melo 
hist_browser__toggle_fold(struct hist_browser * browser)44305e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser)
444aca7a94dSNamhyung Kim {
44505e8b080SArnaldo Carvalho de Melo 	struct hist_entry *he = browser->he_selection;
4463698dab1SNamhyung Kim 	struct map_symbol *ms = browser->selection;
4473698dab1SNamhyung Kim 	struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
4483698dab1SNamhyung Kim 	bool has_children;
449aca7a94dSNamhyung Kim 
4504938cf0cSWang Nan 	if (!he || !ms)
4514938cf0cSWang Nan 		return false;
4524938cf0cSWang Nan 
4533698dab1SNamhyung Kim 	if (ms == &he->ms)
4543698dab1SNamhyung Kim 		has_children = hist_entry__toggle_fold(he);
4553698dab1SNamhyung Kim 	else
4563698dab1SNamhyung Kim 		has_children = callchain_list__toggle_fold(cl);
4573698dab1SNamhyung Kim 
4583698dab1SNamhyung Kim 	if (has_children) {
459f5b763feSNamhyung Kim 		int child_rows = 0;
460f5b763feSNamhyung Kim 
461aca7a94dSNamhyung Kim 		hist_entry__init_have_children(he);
462c3b78952SNamhyung Kim 		browser->b.nr_entries -= he->nr_rows;
463aca7a94dSNamhyung Kim 
464f5b763feSNamhyung Kim 		if (he->leaf)
465f5b763feSNamhyung Kim 			browser->nr_callchain_rows -= he->nr_rows;
466f5b763feSNamhyung Kim 		else
467f5b763feSNamhyung Kim 			browser->nr_hierarchy_entries -= he->nr_rows;
468f5b763feSNamhyung Kim 
469f5b763feSNamhyung Kim 		if (symbol_conf.report_hierarchy)
470f5b763feSNamhyung Kim 			child_rows = hierarchy_count_rows(browser, he, true);
471f5b763feSNamhyung Kim 
472f5b763feSNamhyung Kim 		if (he->unfolded) {
473f5b763feSNamhyung Kim 			if (he->leaf)
4740d3eb0b7SJin Yao 				he->nr_rows = callchain__count_rows(
4750d3eb0b7SJin Yao 						&he->sorted_chain);
476aca7a94dSNamhyung Kim 			else
477f5b763feSNamhyung Kim 				he->nr_rows = hierarchy_count_rows(browser, he, false);
478f5b763feSNamhyung Kim 
479f5b763feSNamhyung Kim 			/* account grand children */
480f5b763feSNamhyung Kim 			if (symbol_conf.report_hierarchy)
481f5b763feSNamhyung Kim 				browser->b.nr_entries += child_rows - he->nr_rows;
48279dded87SNamhyung Kim 
48379dded87SNamhyung Kim 			if (!he->leaf && he->nr_rows == 0) {
48479dded87SNamhyung Kim 				he->has_no_entry = true;
48579dded87SNamhyung Kim 				he->nr_rows = 1;
48679dded87SNamhyung Kim 			}
487f5b763feSNamhyung Kim 		} else {
488f5b763feSNamhyung Kim 			if (symbol_conf.report_hierarchy)
489f5b763feSNamhyung Kim 				browser->b.nr_entries -= child_rows - he->nr_rows;
490f5b763feSNamhyung Kim 
49179dded87SNamhyung Kim 			if (he->has_no_entry)
49279dded87SNamhyung Kim 				he->has_no_entry = false;
49379dded87SNamhyung Kim 
494aca7a94dSNamhyung Kim 			he->nr_rows = 0;
495f5b763feSNamhyung Kim 		}
496c3b78952SNamhyung Kim 
497c3b78952SNamhyung Kim 		browser->b.nr_entries += he->nr_rows;
498f5b763feSNamhyung Kim 
499f5b763feSNamhyung Kim 		if (he->leaf)
500c3b78952SNamhyung Kim 			browser->nr_callchain_rows += he->nr_rows;
501f5b763feSNamhyung Kim 		else
502f5b763feSNamhyung Kim 			browser->nr_hierarchy_entries += he->nr_rows;
503aca7a94dSNamhyung Kim 
504aca7a94dSNamhyung Kim 		return true;
505aca7a94dSNamhyung Kim 	}
506aca7a94dSNamhyung Kim 
507aca7a94dSNamhyung Kim 	/* If it doesn't have children, no toggling performed */
508aca7a94dSNamhyung Kim 	return false;
509aca7a94dSNamhyung Kim }
510aca7a94dSNamhyung Kim 
callchain_node__set_folding_rb_tree(struct callchain_node * node,bool unfold)51105e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
512aca7a94dSNamhyung Kim {
513aca7a94dSNamhyung Kim 	int n = 0;
514aca7a94dSNamhyung Kim 	struct rb_node *nd;
515aca7a94dSNamhyung Kim 
51605e8b080SArnaldo Carvalho de Melo 	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
517aca7a94dSNamhyung Kim 		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
518aca7a94dSNamhyung Kim 		struct callchain_list *chain;
519aca7a94dSNamhyung Kim 		bool has_children = false;
520aca7a94dSNamhyung Kim 
521aca7a94dSNamhyung Kim 		list_for_each_entry(chain, &child->val, list) {
522aca7a94dSNamhyung Kim 			++n;
5233698dab1SNamhyung Kim 			callchain_list__set_folding(chain, unfold);
5243698dab1SNamhyung Kim 			has_children = chain->has_children;
525aca7a94dSNamhyung Kim 		}
526aca7a94dSNamhyung Kim 
527aca7a94dSNamhyung Kim 		if (has_children)
528aca7a94dSNamhyung Kim 			n += callchain_node__set_folding_rb_tree(child, unfold);
529aca7a94dSNamhyung Kim 	}
530aca7a94dSNamhyung Kim 
531aca7a94dSNamhyung Kim 	return n;
532aca7a94dSNamhyung Kim }
533aca7a94dSNamhyung Kim 
callchain_node__set_folding(struct callchain_node * node,bool unfold)534aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
535aca7a94dSNamhyung Kim {
536aca7a94dSNamhyung Kim 	struct callchain_list *chain;
537aca7a94dSNamhyung Kim 	bool has_children = false;
538aca7a94dSNamhyung Kim 	int n = 0;
539aca7a94dSNamhyung Kim 
540aca7a94dSNamhyung Kim 	list_for_each_entry(chain, &node->val, list) {
541aca7a94dSNamhyung Kim 		++n;
5423698dab1SNamhyung Kim 		callchain_list__set_folding(chain, unfold);
5433698dab1SNamhyung Kim 		has_children = chain->has_children;
544aca7a94dSNamhyung Kim 	}
545aca7a94dSNamhyung Kim 
546aca7a94dSNamhyung Kim 	if (has_children)
547aca7a94dSNamhyung Kim 		n += callchain_node__set_folding_rb_tree(node, unfold);
548aca7a94dSNamhyung Kim 
549aca7a94dSNamhyung Kim 	return n;
550aca7a94dSNamhyung Kim }
551aca7a94dSNamhyung Kim 
callchain__set_folding(struct rb_root * chain,bool unfold)552aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold)
553aca7a94dSNamhyung Kim {
554aca7a94dSNamhyung Kim 	struct rb_node *nd;
555aca7a94dSNamhyung Kim 	int n = 0;
556aca7a94dSNamhyung Kim 
557aca7a94dSNamhyung Kim 	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
558aca7a94dSNamhyung Kim 		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
559aca7a94dSNamhyung Kim 		n += callchain_node__set_folding(node, unfold);
560aca7a94dSNamhyung Kim 	}
561aca7a94dSNamhyung Kim 
562aca7a94dSNamhyung Kim 	return n;
563aca7a94dSNamhyung Kim }
564aca7a94dSNamhyung Kim 
hierarchy_set_folding(struct hist_browser * hb,struct hist_entry * he,bool unfold __maybe_unused)565492b1010SNamhyung Kim static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
566492b1010SNamhyung Kim 				 bool unfold __maybe_unused)
567492b1010SNamhyung Kim {
568492b1010SNamhyung Kim 	float percent;
569492b1010SNamhyung Kim 	struct rb_node *nd;
570492b1010SNamhyung Kim 	struct hist_entry *child;
571492b1010SNamhyung Kim 	int n = 0;
572492b1010SNamhyung Kim 
5732eb3d689SDavidlohr Bueso 	for (nd = rb_first_cached(&he->hroot_out); nd; nd = rb_next(nd)) {
574492b1010SNamhyung Kim 		child = rb_entry(nd, struct hist_entry, rb_node);
575492b1010SNamhyung Kim 		percent = hist_entry__get_percent_limit(child);
576492b1010SNamhyung Kim 		if (!child->filtered && percent >= hb->min_pcnt)
577492b1010SNamhyung Kim 			n++;
578492b1010SNamhyung Kim 	}
579492b1010SNamhyung Kim 
580492b1010SNamhyung Kim 	return n;
581492b1010SNamhyung Kim }
582492b1010SNamhyung Kim 
hist_entry__set_folding(struct hist_entry * he,struct hist_browser * hb,bool unfold)583f6b8436bSNamhyung Kim static void hist_entry__set_folding(struct hist_entry *he,
584492b1010SNamhyung Kim 				    struct hist_browser *hb, bool unfold)
585aca7a94dSNamhyung Kim {
58605e8b080SArnaldo Carvalho de Melo 	hist_entry__init_have_children(he);
5873698dab1SNamhyung Kim 	he->unfolded = unfold ? he->has_children : false;
588aca7a94dSNamhyung Kim 
5893698dab1SNamhyung Kim 	if (he->has_children) {
590492b1010SNamhyung Kim 		int n;
591492b1010SNamhyung Kim 
592492b1010SNamhyung Kim 		if (he->leaf)
593492b1010SNamhyung Kim 			n = callchain__set_folding(&he->sorted_chain, unfold);
594492b1010SNamhyung Kim 		else
595492b1010SNamhyung Kim 			n = hierarchy_set_folding(hb, he, unfold);
596492b1010SNamhyung Kim 
59705e8b080SArnaldo Carvalho de Melo 		he->nr_rows = unfold ? n : 0;
598aca7a94dSNamhyung Kim 	} else
59905e8b080SArnaldo Carvalho de Melo 		he->nr_rows = 0;
600aca7a94dSNamhyung Kim }
601aca7a94dSNamhyung Kim 
602f6b8436bSNamhyung Kim static void
__hist_browser__set_folding(struct hist_browser * browser,bool unfold)603f6b8436bSNamhyung Kim __hist_browser__set_folding(struct hist_browser *browser, bool unfold)
604aca7a94dSNamhyung Kim {
605f6b8436bSNamhyung Kim 	struct rb_node *nd;
606f6b8436bSNamhyung Kim 	struct hist_entry *he;
607492b1010SNamhyung Kim 	double percent;
608aca7a94dSNamhyung Kim 
609f6b8436bSNamhyung Kim 	nd = rb_first_cached(&browser->hists->entries);
610f6b8436bSNamhyung Kim 	while (nd) {
611f6b8436bSNamhyung Kim 		he = rb_entry(nd, struct hist_entry, rb_node);
612f6b8436bSNamhyung Kim 
613f6b8436bSNamhyung Kim 		/* set folding state even if it's currently folded */
614f6b8436bSNamhyung Kim 		nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
615f6b8436bSNamhyung Kim 
616f6b8436bSNamhyung Kim 		hist_entry__set_folding(he, browser, unfold);
617f6b8436bSNamhyung Kim 
618492b1010SNamhyung Kim 		percent = hist_entry__get_percent_limit(he);
619492b1010SNamhyung Kim 		if (he->filtered || percent < browser->min_pcnt)
620f6b8436bSNamhyung Kim 			continue;
621492b1010SNamhyung Kim 
622492b1010SNamhyung Kim 		if (!he->depth || unfold)
623492b1010SNamhyung Kim 			browser->nr_hierarchy_entries++;
624492b1010SNamhyung Kim 		if (he->leaf)
625c3b78952SNamhyung Kim 			browser->nr_callchain_rows += he->nr_rows;
62679dded87SNamhyung Kim 		else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
62779dded87SNamhyung Kim 			browser->nr_hierarchy_entries++;
62879dded87SNamhyung Kim 			he->has_no_entry = true;
62979dded87SNamhyung Kim 			he->nr_rows = 1;
63079dded87SNamhyung Kim 		} else
63179dded87SNamhyung Kim 			he->has_no_entry = false;
632aca7a94dSNamhyung Kim 	}
633aca7a94dSNamhyung Kim }
634aca7a94dSNamhyung Kim 
hist_browser__set_folding(struct hist_browser * browser,bool unfold)63505e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
636aca7a94dSNamhyung Kim {
637492b1010SNamhyung Kim 	browser->nr_hierarchy_entries = 0;
638c3b78952SNamhyung Kim 	browser->nr_callchain_rows = 0;
639c3b78952SNamhyung Kim 	__hist_browser__set_folding(browser, unfold);
640c3b78952SNamhyung Kim 
641c3b78952SNamhyung Kim 	browser->b.nr_entries = hist_browser__nr_entries(browser);
642aca7a94dSNamhyung Kim 	/* Go to the start, we may be way after valid entries after a collapse */
64305e8b080SArnaldo Carvalho de Melo 	ui_browser__reset_index(&browser->b);
644aca7a94dSNamhyung Kim }
645aca7a94dSNamhyung Kim 
hist_browser__set_folding_selected(struct hist_browser * browser,bool unfold)6460e3fa7a7SJiri Olsa static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
6470e3fa7a7SJiri Olsa {
6480e3fa7a7SJiri Olsa 	if (!browser->he_selection)
6490e3fa7a7SJiri Olsa 		return;
6500e3fa7a7SJiri Olsa 
651f6b8436bSNamhyung Kim 	if (unfold == browser->he_selection->unfolded)
652f6b8436bSNamhyung Kim 		return;
653f6b8436bSNamhyung Kim 
654f6b8436bSNamhyung Kim 	hist_browser__toggle_fold(browser);
6550e3fa7a7SJiri Olsa }
6560e3fa7a7SJiri Olsa 
ui_browser__warn_lost_events(struct ui_browser * browser)657aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser)
658aca7a94dSNamhyung Kim {
659aca7a94dSNamhyung Kim 	ui_browser__warning(browser, 4,
660aca7a94dSNamhyung Kim 		"Events are being lost, check IO/CPU overload!\n\n"
661aca7a94dSNamhyung Kim 		"You may want to run 'perf' using a RT scheduler policy:\n\n"
662aca7a94dSNamhyung Kim 		" perf top -r 80\n\n"
663aca7a94dSNamhyung Kim 		"Or reduce the sampling frequency.");
664aca7a94dSNamhyung Kim }
665aca7a94dSNamhyung Kim 
hist_browser__title(struct hist_browser * browser,char * bf,size_t size)6665b91a86fSJiri Olsa static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
6675b91a86fSJiri Olsa {
6685b91a86fSJiri Olsa 	return browser->title ? browser->title(browser, bf, size) : 0;
6695b91a86fSJiri Olsa }
6705b91a86fSJiri Olsa 
hist_browser__handle_hotkey(struct hist_browser * browser,bool warn_lost_event,char * title,size_t size,int key)671376c3c22SArnaldo Carvalho de Melo static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_lost_event, char *title, size_t size, int key)
672aca7a94dSNamhyung Kim {
673aca7a94dSNamhyung Kim 	switch (key) {
674fa5df943SNamhyung Kim 	case K_TIMER: {
675d10ec006SArnaldo Carvalho de Melo 		struct hist_browser_timer *hbt = browser->hbt;
6760f0abbacSNamhyung Kim 		struct evsel *evsel = hists_to_evsel(browser->hists);
677fa5df943SNamhyung Kim 		u64 nr_entries;
678ceb75476SLeo Yan 
679ceb75476SLeo Yan 		WARN_ON_ONCE(!hbt);
680ceb75476SLeo Yan 
681ceb75476SLeo Yan 		if (hbt)
6829783adf7SNamhyung Kim 			hbt->timer(hbt->arg);
683fa5df943SNamhyung Kim 
684d10ec006SArnaldo Carvalho de Melo 		if (hist_browser__has_filter(browser) || symbol_conf.report_hierarchy)
685112f761fSNamhyung Kim 			hist_browser__update_nr_entries(browser);
686fa5df943SNamhyung Kim 
687c3b78952SNamhyung Kim 		nr_entries = hist_browser__nr_entries(browser);
688fa5df943SNamhyung Kim 		ui_browser__update_nr_entries(&browser->b, nr_entries);
689aca7a94dSNamhyung Kim 
69006cc1a47SKan Liang 		if (warn_lost_event &&
6910f0abbacSNamhyung Kim 		    (evsel->evlist->stats.nr_lost_warned !=
6920f0abbacSNamhyung Kim 		     evsel->evlist->stats.nr_events[PERF_RECORD_LOST])) {
6930f0abbacSNamhyung Kim 			evsel->evlist->stats.nr_lost_warned =
6940f0abbacSNamhyung Kim 				evsel->evlist->stats.nr_events[PERF_RECORD_LOST];
69505e8b080SArnaldo Carvalho de Melo 			ui_browser__warn_lost_events(&browser->b);
696aca7a94dSNamhyung Kim 		}
697aca7a94dSNamhyung Kim 
698376c3c22SArnaldo Carvalho de Melo 		hist_browser__title(browser, title, size);
69905e8b080SArnaldo Carvalho de Melo 		ui_browser__show_title(&browser->b, title);
700d10ec006SArnaldo Carvalho de Melo 		break;
701fa5df943SNamhyung Kim 	}
702aca7a94dSNamhyung Kim 	case 'D': { /* Debug */
703d10ec006SArnaldo Carvalho de Melo 		struct hist_entry *h = rb_entry(browser->b.top, struct hist_entry, rb_node);
704aca7a94dSNamhyung Kim 		static int seq;
705d10ec006SArnaldo Carvalho de Melo 
706aca7a94dSNamhyung Kim 		ui_helpline__pop();
707fdae6400SArnaldo Carvalho de Melo 		ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
708d10ec006SArnaldo Carvalho de Melo 				   seq++, browser->b.nr_entries, browser->hists->nr_entries,
709d10ec006SArnaldo Carvalho de Melo 				   browser->b.extra_title_lines, browser->b.rows,
710d10ec006SArnaldo Carvalho de Melo 				   browser->b.index, browser->b.top_idx, h->row_offset, h->nr_rows);
711aca7a94dSNamhyung Kim 	}
712aca7a94dSNamhyung Kim 		break;
713aca7a94dSNamhyung Kim 	case 'C':
714aca7a94dSNamhyung Kim 		/* Collapse the whole world. */
71505e8b080SArnaldo Carvalho de Melo 		hist_browser__set_folding(browser, false);
716aca7a94dSNamhyung Kim 		break;
7170e3fa7a7SJiri Olsa 	case 'c':
7180e3fa7a7SJiri Olsa 		/* Collapse the selected entry. */
7190e3fa7a7SJiri Olsa 		hist_browser__set_folding_selected(browser, false);
7200e3fa7a7SJiri Olsa 		break;
721aca7a94dSNamhyung Kim 	case 'E':
722aca7a94dSNamhyung Kim 		/* Expand the whole world. */
72305e8b080SArnaldo Carvalho de Melo 		hist_browser__set_folding(browser, true);
724aca7a94dSNamhyung Kim 		break;
7250e3fa7a7SJiri Olsa 	case 'e':
726f6b8436bSNamhyung Kim 		/* Toggle expand/collapse the selected entry. */
727f6b8436bSNamhyung Kim 		hist_browser__toggle_fold(browser);
7280e3fa7a7SJiri Olsa 		break;
729025bf7eaSArnaldo Carvalho de Melo 	case 'H':
730025bf7eaSArnaldo Carvalho de Melo 		browser->show_headers = !browser->show_headers;
731025bf7eaSArnaldo Carvalho de Melo 		hist_browser__update_rows(browser);
732025bf7eaSArnaldo Carvalho de Melo 		break;
7339218a913SArnaldo Carvalho de Melo 	case '+':
73405e8b080SArnaldo Carvalho de Melo 		if (hist_browser__toggle_fold(browser))
735aca7a94dSNamhyung Kim 			break;
736aca7a94dSNamhyung Kim 		/* fall thru */
737aca7a94dSNamhyung Kim 	default:
738d10ec006SArnaldo Carvalho de Melo 		return -1;
739aca7a94dSNamhyung Kim 	}
740d10ec006SArnaldo Carvalho de Melo 
741d10ec006SArnaldo Carvalho de Melo 	return 0;
742d10ec006SArnaldo Carvalho de Melo }
743d10ec006SArnaldo Carvalho de Melo 
hist_browser__run(struct hist_browser * browser,const char * help,bool warn_lost_event,int key)744d10ec006SArnaldo Carvalho de Melo int hist_browser__run(struct hist_browser *browser, const char *help,
745d10ec006SArnaldo Carvalho de Melo 		      bool warn_lost_event, int key)
746d10ec006SArnaldo Carvalho de Melo {
747d10ec006SArnaldo Carvalho de Melo 	char title[160];
748d10ec006SArnaldo Carvalho de Melo 	struct hist_browser_timer *hbt = browser->hbt;
749d10ec006SArnaldo Carvalho de Melo 	int delay_secs = hbt ? hbt->refresh : 0;
750d10ec006SArnaldo Carvalho de Melo 
751d10ec006SArnaldo Carvalho de Melo 	browser->b.entries = &browser->hists->entries;
752d10ec006SArnaldo Carvalho de Melo 	browser->b.nr_entries = hist_browser__nr_entries(browser);
753d10ec006SArnaldo Carvalho de Melo 
754d10ec006SArnaldo Carvalho de Melo 	hist_browser__title(browser, title, sizeof(title));
755d10ec006SArnaldo Carvalho de Melo 
756d10ec006SArnaldo Carvalho de Melo 	if (ui_browser__show(&browser->b, title, "%s", help) < 0)
757d10ec006SArnaldo Carvalho de Melo 		return -1;
758d10ec006SArnaldo Carvalho de Melo 
759376c3c22SArnaldo Carvalho de Melo 	if (key && hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key))
760d10ec006SArnaldo Carvalho de Melo 		goto out;
761d10ec006SArnaldo Carvalho de Melo 
762d10ec006SArnaldo Carvalho de Melo 	while (1) {
763d10ec006SArnaldo Carvalho de Melo 		key = ui_browser__run(&browser->b, delay_secs);
764d10ec006SArnaldo Carvalho de Melo 
765376c3c22SArnaldo Carvalho de Melo 		if (hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key))
766d10ec006SArnaldo Carvalho de Melo 			break;
767aca7a94dSNamhyung Kim 	}
768aca7a94dSNamhyung Kim out:
76905e8b080SArnaldo Carvalho de Melo 	ui_browser__hide(&browser->b);
770aca7a94dSNamhyung Kim 	return key;
771aca7a94dSNamhyung Kim }
772aca7a94dSNamhyung Kim 
77339ee533fSNamhyung Kim struct callchain_print_arg {
77439ee533fSNamhyung Kim 	/* for hists browser */
77539ee533fSNamhyung Kim 	off_t	row_offset;
77639ee533fSNamhyung Kim 	bool	is_current_entry;
77739ee533fSNamhyung Kim 
77839ee533fSNamhyung Kim 	/* for file dump */
77939ee533fSNamhyung Kim 	FILE	*fp;
78039ee533fSNamhyung Kim 	int	printed;
78139ee533fSNamhyung Kim };
78239ee533fSNamhyung Kim 
78339ee533fSNamhyung Kim typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
78439ee533fSNamhyung Kim 					 struct callchain_list *chain,
78539ee533fSNamhyung Kim 					 const char *str, int offset,
78639ee533fSNamhyung Kim 					 unsigned short row,
78739ee533fSNamhyung Kim 					 struct callchain_print_arg *arg);
78839ee533fSNamhyung Kim 
hist_browser__show_callchain_entry(struct hist_browser * browser,struct callchain_list * chain,const char * str,int offset,unsigned short row,struct callchain_print_arg * arg)789f4536dddSNamhyung Kim static void hist_browser__show_callchain_entry(struct hist_browser *browser,
790f4536dddSNamhyung Kim 					       struct callchain_list *chain,
79139ee533fSNamhyung Kim 					       const char *str, int offset,
79239ee533fSNamhyung Kim 					       unsigned short row,
79339ee533fSNamhyung Kim 					       struct callchain_print_arg *arg)
794f4536dddSNamhyung Kim {
795f4536dddSNamhyung Kim 	int color, width;
79639ee533fSNamhyung Kim 	char folded_sign = callchain_list__folded(chain);
79770e97278SArnaldo Carvalho de Melo 	bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
798f4536dddSNamhyung Kim 
799f4536dddSNamhyung Kim 	color = HE_COLORSET_NORMAL;
800f4536dddSNamhyung Kim 	width = browser->b.width - (offset + 2);
801f4536dddSNamhyung Kim 	if (ui_browser__is_current_entry(&browser->b, row)) {
802f4536dddSNamhyung Kim 		browser->selection = &chain->ms;
803f4536dddSNamhyung Kim 		color = HE_COLORSET_SELECTED;
80439ee533fSNamhyung Kim 		arg->is_current_entry = true;
805f4536dddSNamhyung Kim 	}
806f4536dddSNamhyung Kim 
807f4536dddSNamhyung Kim 	ui_browser__set_color(&browser->b, color);
808ef9ff601SArnaldo Carvalho de Melo 	ui_browser__gotorc(&browser->b, row, 0);
80926270a00SArnaldo Carvalho de Melo 	ui_browser__write_nstring(&browser->b, " ", offset);
810517dfdb3SArnaldo Carvalho de Melo 	ui_browser__printf(&browser->b, "%c", folded_sign);
81170e97278SArnaldo Carvalho de Melo 	ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
81226270a00SArnaldo Carvalho de Melo 	ui_browser__write_nstring(&browser->b, str, width);
813f4536dddSNamhyung Kim }
814f4536dddSNamhyung Kim 
hist_browser__fprintf_callchain_entry(struct hist_browser * b __maybe_unused,struct callchain_list * chain,const char * str,int offset,unsigned short row __maybe_unused,struct callchain_print_arg * arg)81539ee533fSNamhyung Kim static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
81639ee533fSNamhyung Kim 						  struct callchain_list *chain,
81739ee533fSNamhyung Kim 						  const char *str, int offset,
81839ee533fSNamhyung Kim 						  unsigned short row __maybe_unused,
81939ee533fSNamhyung Kim 						  struct callchain_print_arg *arg)
82039ee533fSNamhyung Kim {
82139ee533fSNamhyung Kim 	char folded_sign = callchain_list__folded(chain);
82239ee533fSNamhyung Kim 
82339ee533fSNamhyung Kim 	arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
82439ee533fSNamhyung Kim 				folded_sign, str);
82539ee533fSNamhyung Kim }
82639ee533fSNamhyung Kim 
82739ee533fSNamhyung Kim typedef bool (*check_output_full_fn)(struct hist_browser *browser,
82839ee533fSNamhyung Kim 				     unsigned short row);
82939ee533fSNamhyung Kim 
hist_browser__check_output_full(struct hist_browser * browser,unsigned short row)83039ee533fSNamhyung Kim static bool hist_browser__check_output_full(struct hist_browser *browser,
83139ee533fSNamhyung Kim 					    unsigned short row)
83239ee533fSNamhyung Kim {
83339ee533fSNamhyung Kim 	return browser->b.rows == row;
83439ee533fSNamhyung Kim }
83539ee533fSNamhyung Kim 
hist_browser__check_dump_full(struct hist_browser * browser __maybe_unused,unsigned short row __maybe_unused)83639ee533fSNamhyung Kim static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
83739ee533fSNamhyung Kim 					  unsigned short row __maybe_unused)
83839ee533fSNamhyung Kim {
83939ee533fSNamhyung Kim 	return false;
84039ee533fSNamhyung Kim }
84139ee533fSNamhyung Kim 
842aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3
843aca7a94dSNamhyung Kim 
hist_browser__show_callchain_list(struct hist_browser * browser,struct callchain_node * node,struct callchain_list * chain,unsigned short row,u64 total,bool need_percent,int offset,print_callchain_entry_fn print,struct callchain_print_arg * arg)84418bb8381SNamhyung Kim static int hist_browser__show_callchain_list(struct hist_browser *browser,
84518bb8381SNamhyung Kim 					     struct callchain_node *node,
84618bb8381SNamhyung Kim 					     struct callchain_list *chain,
84718bb8381SNamhyung Kim 					     unsigned short row, u64 total,
84818bb8381SNamhyung Kim 					     bool need_percent, int offset,
84918bb8381SNamhyung Kim 					     print_callchain_entry_fn print,
85018bb8381SNamhyung Kim 					     struct callchain_print_arg *arg)
85118bb8381SNamhyung Kim {
85218bb8381SNamhyung Kim 	char bf[1024], *alloc_str;
853fef51ecdSJin Yao 	char buf[64], *alloc_str2;
85418bb8381SNamhyung Kim 	const char *str;
8552a704fc8SMilian Wolff 	int ret = 1;
85618bb8381SNamhyung Kim 
85718bb8381SNamhyung Kim 	if (arg->row_offset != 0) {
85818bb8381SNamhyung Kim 		arg->row_offset--;
85918bb8381SNamhyung Kim 		return 0;
86018bb8381SNamhyung Kim 	}
86118bb8381SNamhyung Kim 
86218bb8381SNamhyung Kim 	alloc_str = NULL;
863fef51ecdSJin Yao 	alloc_str2 = NULL;
864fef51ecdSJin Yao 
86518bb8381SNamhyung Kim 	str = callchain_list__sym_name(chain, bf, sizeof(bf),
86618bb8381SNamhyung Kim 				       browser->show_dso);
86718bb8381SNamhyung Kim 
868fef51ecdSJin Yao 	if (symbol_conf.show_branchflag_count) {
869c4ee0625SJin Yao 		callchain_list_counts__printf_value(chain, NULL,
870fef51ecdSJin Yao 						    buf, sizeof(buf));
87118bb8381SNamhyung Kim 
872fef51ecdSJin Yao 		if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
873fef51ecdSJin Yao 			str = "Not enough memory!";
874fef51ecdSJin Yao 		else
875fef51ecdSJin Yao 			str = alloc_str2;
876fef51ecdSJin Yao 	}
877fef51ecdSJin Yao 
878fef51ecdSJin Yao 	if (need_percent) {
87918bb8381SNamhyung Kim 		callchain_node__scnprintf_value(node, buf, sizeof(buf),
88018bb8381SNamhyung Kim 						total);
88118bb8381SNamhyung Kim 
88218bb8381SNamhyung Kim 		if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
88318bb8381SNamhyung Kim 			str = "Not enough memory!";
88418bb8381SNamhyung Kim 		else
88518bb8381SNamhyung Kim 			str = alloc_str;
88618bb8381SNamhyung Kim 	}
88718bb8381SNamhyung Kim 
88818bb8381SNamhyung Kim 	print(browser, chain, str, offset, row, arg);
88918bb8381SNamhyung Kim 	free(alloc_str);
890fef51ecdSJin Yao 	free(alloc_str2);
8910d3eb0b7SJin Yao 
8922a704fc8SMilian Wolff 	return ret;
89318bb8381SNamhyung Kim }
89418bb8381SNamhyung Kim 
check_percent_display(struct rb_node * node,u64 parent_total)89559c624e2SNamhyung Kim static bool check_percent_display(struct rb_node *node, u64 parent_total)
89659c624e2SNamhyung Kim {
89759c624e2SNamhyung Kim 	struct callchain_node *child;
89859c624e2SNamhyung Kim 
89959c624e2SNamhyung Kim 	if (node == NULL)
90059c624e2SNamhyung Kim 		return false;
90159c624e2SNamhyung Kim 
90259c624e2SNamhyung Kim 	if (rb_next(node))
90359c624e2SNamhyung Kim 		return true;
90459c624e2SNamhyung Kim 
90559c624e2SNamhyung Kim 	child = rb_entry(node, struct callchain_node, rb_node);
90659c624e2SNamhyung Kim 	return callchain_cumul_hits(child) != parent_total;
90759c624e2SNamhyung Kim }
90859c624e2SNamhyung Kim 
hist_browser__show_callchain_flat(struct hist_browser * browser,struct rb_root * root,unsigned short row,u64 total,u64 parent_total,print_callchain_entry_fn print,struct callchain_print_arg * arg,check_output_full_fn is_output_full)9094b3a3212SNamhyung Kim static int hist_browser__show_callchain_flat(struct hist_browser *browser,
9104b3a3212SNamhyung Kim 					     struct rb_root *root,
9114b3a3212SNamhyung Kim 					     unsigned short row, u64 total,
91259c624e2SNamhyung Kim 					     u64 parent_total,
9134b3a3212SNamhyung Kim 					     print_callchain_entry_fn print,
9144b3a3212SNamhyung Kim 					     struct callchain_print_arg *arg,
9154b3a3212SNamhyung Kim 					     check_output_full_fn is_output_full)
9164b3a3212SNamhyung Kim {
9174b3a3212SNamhyung Kim 	struct rb_node *node;
9184b3a3212SNamhyung Kim 	int first_row = row, offset = LEVEL_OFFSET_STEP;
9194b3a3212SNamhyung Kim 	bool need_percent;
9204b3a3212SNamhyung Kim 
9214b3a3212SNamhyung Kim 	node = rb_first(root);
92259c624e2SNamhyung Kim 	need_percent = check_percent_display(node, parent_total);
9234b3a3212SNamhyung Kim 
9244b3a3212SNamhyung Kim 	while (node) {
9254b3a3212SNamhyung Kim 		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
9264b3a3212SNamhyung Kim 		struct rb_node *next = rb_next(node);
9274b3a3212SNamhyung Kim 		struct callchain_list *chain;
9284b3a3212SNamhyung Kim 		char folded_sign = ' ';
9294b3a3212SNamhyung Kim 		int first = true;
9304b3a3212SNamhyung Kim 		int extra_offset = 0;
9314b3a3212SNamhyung Kim 
9324b3a3212SNamhyung Kim 		list_for_each_entry(chain, &child->parent_val, list) {
9334b3a3212SNamhyung Kim 			bool was_first = first;
9344b3a3212SNamhyung Kim 
9354b3a3212SNamhyung Kim 			if (first)
9364b3a3212SNamhyung Kim 				first = false;
9374b3a3212SNamhyung Kim 			else if (need_percent)
9384b3a3212SNamhyung Kim 				extra_offset = LEVEL_OFFSET_STEP;
9394b3a3212SNamhyung Kim 
9404b3a3212SNamhyung Kim 			folded_sign = callchain_list__folded(chain);
9414b3a3212SNamhyung Kim 
9424b3a3212SNamhyung Kim 			row += hist_browser__show_callchain_list(browser, child,
9434b3a3212SNamhyung Kim 							chain, row, total,
9444b3a3212SNamhyung Kim 							was_first && need_percent,
9454b3a3212SNamhyung Kim 							offset + extra_offset,
9464b3a3212SNamhyung Kim 							print, arg);
9474b3a3212SNamhyung Kim 
9484b3a3212SNamhyung Kim 			if (is_output_full(browser, row))
9494b3a3212SNamhyung Kim 				goto out;
9504b3a3212SNamhyung Kim 
9514b3a3212SNamhyung Kim 			if (folded_sign == '+')
9524b3a3212SNamhyung Kim 				goto next;
9534b3a3212SNamhyung Kim 		}
9544b3a3212SNamhyung Kim 
9554b3a3212SNamhyung Kim 		list_for_each_entry(chain, &child->val, list) {
9564b3a3212SNamhyung Kim 			bool was_first = first;
9574b3a3212SNamhyung Kim 
9584b3a3212SNamhyung Kim 			if (first)
9594b3a3212SNamhyung Kim 				first = false;
9604b3a3212SNamhyung Kim 			else if (need_percent)
9614b3a3212SNamhyung Kim 				extra_offset = LEVEL_OFFSET_STEP;
9624b3a3212SNamhyung Kim 
9634b3a3212SNamhyung Kim 			folded_sign = callchain_list__folded(chain);
9644b3a3212SNamhyung Kim 
9654b3a3212SNamhyung Kim 			row += hist_browser__show_callchain_list(browser, child,
9664b3a3212SNamhyung Kim 							chain, row, total,
9674b3a3212SNamhyung Kim 							was_first && need_percent,
9684b3a3212SNamhyung Kim 							offset + extra_offset,
9694b3a3212SNamhyung Kim 							print, arg);
9704b3a3212SNamhyung Kim 
9714b3a3212SNamhyung Kim 			if (is_output_full(browser, row))
9724b3a3212SNamhyung Kim 				goto out;
9734b3a3212SNamhyung Kim 
9744b3a3212SNamhyung Kim 			if (folded_sign == '+')
9754b3a3212SNamhyung Kim 				break;
9764b3a3212SNamhyung Kim 		}
9774b3a3212SNamhyung Kim 
9784b3a3212SNamhyung Kim next:
9794b3a3212SNamhyung Kim 		if (is_output_full(browser, row))
9804b3a3212SNamhyung Kim 			break;
9814b3a3212SNamhyung Kim 		node = next;
9824b3a3212SNamhyung Kim 	}
9834b3a3212SNamhyung Kim out:
9844b3a3212SNamhyung Kim 	return row - first_row;
9854b3a3212SNamhyung Kim }
9864b3a3212SNamhyung Kim 
hist_browser__folded_callchain_str(struct hist_browser * browser,struct callchain_list * chain,char * value_str,char * old_str)9878c430a34SNamhyung Kim static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
9888c430a34SNamhyung Kim 						struct callchain_list *chain,
9898c430a34SNamhyung Kim 						char *value_str, char *old_str)
9908c430a34SNamhyung Kim {
9918c430a34SNamhyung Kim 	char bf[1024];
9928c430a34SNamhyung Kim 	const char *str;
9938c430a34SNamhyung Kim 	char *new;
9948c430a34SNamhyung Kim 
9958c430a34SNamhyung Kim 	str = callchain_list__sym_name(chain, bf, sizeof(bf),
9968c430a34SNamhyung Kim 				       browser->show_dso);
9978c430a34SNamhyung Kim 	if (old_str) {
9988c430a34SNamhyung Kim 		if (asprintf(&new, "%s%s%s", old_str,
9998c430a34SNamhyung Kim 			     symbol_conf.field_sep ?: ";", str) < 0)
10008c430a34SNamhyung Kim 			new = NULL;
10018c430a34SNamhyung Kim 	} else {
10028c430a34SNamhyung Kim 		if (value_str) {
10038c430a34SNamhyung Kim 			if (asprintf(&new, "%s %s", value_str, str) < 0)
10048c430a34SNamhyung Kim 				new = NULL;
10058c430a34SNamhyung Kim 		} else {
10068c430a34SNamhyung Kim 			if (asprintf(&new, "%s", str) < 0)
10078c430a34SNamhyung Kim 				new = NULL;
10088c430a34SNamhyung Kim 		}
10098c430a34SNamhyung Kim 	}
10108c430a34SNamhyung Kim 	return new;
10118c430a34SNamhyung Kim }
10128c430a34SNamhyung Kim 
hist_browser__show_callchain_folded(struct hist_browser * browser,struct rb_root * root,unsigned short row,u64 total,u64 parent_total,print_callchain_entry_fn print,struct callchain_print_arg * arg,check_output_full_fn is_output_full)10138c430a34SNamhyung Kim static int hist_browser__show_callchain_folded(struct hist_browser *browser,
10148c430a34SNamhyung Kim 					       struct rb_root *root,
10158c430a34SNamhyung Kim 					       unsigned short row, u64 total,
101659c624e2SNamhyung Kim 					       u64 parent_total,
10178c430a34SNamhyung Kim 					       print_callchain_entry_fn print,
10188c430a34SNamhyung Kim 					       struct callchain_print_arg *arg,
10198c430a34SNamhyung Kim 					       check_output_full_fn is_output_full)
10208c430a34SNamhyung Kim {
10218c430a34SNamhyung Kim 	struct rb_node *node;
10228c430a34SNamhyung Kim 	int first_row = row, offset = LEVEL_OFFSET_STEP;
10238c430a34SNamhyung Kim 	bool need_percent;
10248c430a34SNamhyung Kim 
10258c430a34SNamhyung Kim 	node = rb_first(root);
102659c624e2SNamhyung Kim 	need_percent = check_percent_display(node, parent_total);
10278c430a34SNamhyung Kim 
10288c430a34SNamhyung Kim 	while (node) {
10298c430a34SNamhyung Kim 		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
10308c430a34SNamhyung Kim 		struct rb_node *next = rb_next(node);
10318c430a34SNamhyung Kim 		struct callchain_list *chain, *first_chain = NULL;
10328c430a34SNamhyung Kim 		int first = true;
10338c430a34SNamhyung Kim 		char *value_str = NULL, *value_str_alloc = NULL;
10348c430a34SNamhyung Kim 		char *chain_str = NULL, *chain_str_alloc = NULL;
10358c430a34SNamhyung Kim 
10368c430a34SNamhyung Kim 		if (arg->row_offset != 0) {
10378c430a34SNamhyung Kim 			arg->row_offset--;
10388c430a34SNamhyung Kim 			goto next;
10398c430a34SNamhyung Kim 		}
10408c430a34SNamhyung Kim 
10418c430a34SNamhyung Kim 		if (need_percent) {
10428c430a34SNamhyung Kim 			char buf[64];
10438c430a34SNamhyung Kim 
10448c430a34SNamhyung Kim 			callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
10458c430a34SNamhyung Kim 			if (asprintf(&value_str, "%s", buf) < 0) {
10468c430a34SNamhyung Kim 				value_str = (char *)"<...>";
10478c430a34SNamhyung Kim 				goto do_print;
10488c430a34SNamhyung Kim 			}
10498c430a34SNamhyung Kim 			value_str_alloc = value_str;
10508c430a34SNamhyung Kim 		}
10518c430a34SNamhyung Kim 
10528c430a34SNamhyung Kim 		list_for_each_entry(chain, &child->parent_val, list) {
10538c430a34SNamhyung Kim 			chain_str = hist_browser__folded_callchain_str(browser,
10548c430a34SNamhyung Kim 						chain, value_str, chain_str);
10558c430a34SNamhyung Kim 			if (first) {
10568c430a34SNamhyung Kim 				first = false;
10578c430a34SNamhyung Kim 				first_chain = chain;
10588c430a34SNamhyung Kim 			}
10598c430a34SNamhyung Kim 
10608c430a34SNamhyung Kim 			if (chain_str == NULL) {
10618c430a34SNamhyung Kim 				chain_str = (char *)"Not enough memory!";
10628c430a34SNamhyung Kim 				goto do_print;
10638c430a34SNamhyung Kim 			}
10648c430a34SNamhyung Kim 
10658c430a34SNamhyung Kim 			chain_str_alloc = chain_str;
10668c430a34SNamhyung Kim 		}
10678c430a34SNamhyung Kim 
10688c430a34SNamhyung Kim 		list_for_each_entry(chain, &child->val, list) {
10698c430a34SNamhyung Kim 			chain_str = hist_browser__folded_callchain_str(browser,
10708c430a34SNamhyung Kim 						chain, value_str, chain_str);
10718c430a34SNamhyung Kim 			if (first) {
10728c430a34SNamhyung Kim 				first = false;
10738c430a34SNamhyung Kim 				first_chain = chain;
10748c430a34SNamhyung Kim 			}
10758c430a34SNamhyung Kim 
10768c430a34SNamhyung Kim 			if (chain_str == NULL) {
10778c430a34SNamhyung Kim 				chain_str = (char *)"Not enough memory!";
10788c430a34SNamhyung Kim 				goto do_print;
10798c430a34SNamhyung Kim 			}
10808c430a34SNamhyung Kim 
10818c430a34SNamhyung Kim 			chain_str_alloc = chain_str;
10828c430a34SNamhyung Kim 		}
10838c430a34SNamhyung Kim 
10848c430a34SNamhyung Kim do_print:
10858c430a34SNamhyung Kim 		print(browser, first_chain, chain_str, offset, row++, arg);
10868c430a34SNamhyung Kim 		free(value_str_alloc);
10878c430a34SNamhyung Kim 		free(chain_str_alloc);
10888c430a34SNamhyung Kim 
10898c430a34SNamhyung Kim next:
10908c430a34SNamhyung Kim 		if (is_output_full(browser, row))
10918c430a34SNamhyung Kim 			break;
10928c430a34SNamhyung Kim 		node = next;
10938c430a34SNamhyung Kim 	}
10948c430a34SNamhyung Kim 
10958c430a34SNamhyung Kim 	return row - first_row;
10968c430a34SNamhyung Kim }
10978c430a34SNamhyung Kim 
hist_browser__show_callchain_graph(struct hist_browser * browser,struct rb_root * root,int level,unsigned short row,u64 total,u64 parent_total,print_callchain_entry_fn print,struct callchain_print_arg * arg,check_output_full_fn is_output_full)10980c841c6cSNamhyung Kim static int hist_browser__show_callchain_graph(struct hist_browser *browser,
1099c09a7e75SNamhyung Kim 					struct rb_root *root, int level,
110039ee533fSNamhyung Kim 					unsigned short row, u64 total,
11015eca104eSNamhyung Kim 					u64 parent_total,
110239ee533fSNamhyung Kim 					print_callchain_entry_fn print,
110339ee533fSNamhyung Kim 					struct callchain_print_arg *arg,
110439ee533fSNamhyung Kim 					check_output_full_fn is_output_full)
1105aca7a94dSNamhyung Kim {
1106aca7a94dSNamhyung Kim 	struct rb_node *node;
1107f4536dddSNamhyung Kim 	int first_row = row, offset = level * LEVEL_OFFSET_STEP;
11084087d11cSNamhyung Kim 	bool need_percent;
11095eca104eSNamhyung Kim 	u64 percent_total = total;
11105eca104eSNamhyung Kim 
11115eca104eSNamhyung Kim 	if (callchain_param.mode == CHAIN_GRAPH_REL)
11125eca104eSNamhyung Kim 		percent_total = parent_total;
1113aca7a94dSNamhyung Kim 
1114c09a7e75SNamhyung Kim 	node = rb_first(root);
111559c624e2SNamhyung Kim 	need_percent = check_percent_display(node, parent_total);
11164087d11cSNamhyung Kim 
1117aca7a94dSNamhyung Kim 	while (node) {
1118aca7a94dSNamhyung Kim 		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1119aca7a94dSNamhyung Kim 		struct rb_node *next = rb_next(node);
1120aca7a94dSNamhyung Kim 		struct callchain_list *chain;
1121aca7a94dSNamhyung Kim 		char folded_sign = ' ';
1122aca7a94dSNamhyung Kim 		int first = true;
1123aca7a94dSNamhyung Kim 		int extra_offset = 0;
1124aca7a94dSNamhyung Kim 
1125aca7a94dSNamhyung Kim 		list_for_each_entry(chain, &child->val, list) {
1126aca7a94dSNamhyung Kim 			bool was_first = first;
1127aca7a94dSNamhyung Kim 
1128aca7a94dSNamhyung Kim 			if (first)
1129aca7a94dSNamhyung Kim 				first = false;
11304087d11cSNamhyung Kim 			else if (need_percent)
1131aca7a94dSNamhyung Kim 				extra_offset = LEVEL_OFFSET_STEP;
1132aca7a94dSNamhyung Kim 
1133aca7a94dSNamhyung Kim 			folded_sign = callchain_list__folded(chain);
1134aca7a94dSNamhyung Kim 
113518bb8381SNamhyung Kim 			row += hist_browser__show_callchain_list(browser, child,
11365eca104eSNamhyung Kim 							chain, row, percent_total,
113718bb8381SNamhyung Kim 							was_first && need_percent,
113818bb8381SNamhyung Kim 							offset + extra_offset,
113918bb8381SNamhyung Kim 							print, arg);
1140c09a7e75SNamhyung Kim 
114118bb8381SNamhyung Kim 			if (is_output_full(browser, row))
1142aca7a94dSNamhyung Kim 				goto out;
114318bb8381SNamhyung Kim 
1144aca7a94dSNamhyung Kim 			if (folded_sign == '+')
1145aca7a94dSNamhyung Kim 				break;
1146aca7a94dSNamhyung Kim 		}
1147aca7a94dSNamhyung Kim 
1148aca7a94dSNamhyung Kim 		if (folded_sign == '-') {
1149aca7a94dSNamhyung Kim 			const int new_level = level + (extra_offset ? 2 : 1);
1150c09a7e75SNamhyung Kim 
11510c841c6cSNamhyung Kim 			row += hist_browser__show_callchain_graph(browser, &child->rb_root,
11525eca104eSNamhyung Kim 							    new_level, row, total,
11535eca104eSNamhyung Kim 							    child->children_hit,
115439ee533fSNamhyung Kim 							    print, arg, is_output_full);
1155aca7a94dSNamhyung Kim 		}
115639ee533fSNamhyung Kim 		if (is_output_full(browser, row))
1157c09a7e75SNamhyung Kim 			break;
1158aca7a94dSNamhyung Kim 		node = next;
1159aca7a94dSNamhyung Kim 	}
1160aca7a94dSNamhyung Kim out:
1161aca7a94dSNamhyung Kim 	return row - first_row;
1162aca7a94dSNamhyung Kim }
1163aca7a94dSNamhyung Kim 
hist_browser__show_callchain(struct hist_browser * browser,struct hist_entry * entry,int level,unsigned short row,print_callchain_entry_fn print,struct callchain_print_arg * arg,check_output_full_fn is_output_full)11640c841c6cSNamhyung Kim static int hist_browser__show_callchain(struct hist_browser *browser,
11650c841c6cSNamhyung Kim 					struct hist_entry *entry, int level,
11660c841c6cSNamhyung Kim 					unsigned short row,
11670c841c6cSNamhyung Kim 					print_callchain_entry_fn print,
11680c841c6cSNamhyung Kim 					struct callchain_print_arg *arg,
11690c841c6cSNamhyung Kim 					check_output_full_fn is_output_full)
11700c841c6cSNamhyung Kim {
11710c841c6cSNamhyung Kim 	u64 total = hists__total_period(entry->hists);
11725eca104eSNamhyung Kim 	u64 parent_total;
11730c841c6cSNamhyung Kim 	int printed;
11740c841c6cSNamhyung Kim 
11750c841c6cSNamhyung Kim 	if (symbol_conf.cumulate_callchain)
11765eca104eSNamhyung Kim 		parent_total = entry->stat_acc->period;
11770c841c6cSNamhyung Kim 	else
11785eca104eSNamhyung Kim 		parent_total = entry->stat.period;
11790c841c6cSNamhyung Kim 
11800c841c6cSNamhyung Kim 	if (callchain_param.mode == CHAIN_FLAT) {
11810c841c6cSNamhyung Kim 		printed = hist_browser__show_callchain_flat(browser,
11825eca104eSNamhyung Kim 						&entry->sorted_chain, row,
11835eca104eSNamhyung Kim 						total, parent_total, print, arg,
11845eca104eSNamhyung Kim 						is_output_full);
11850c841c6cSNamhyung Kim 	} else if (callchain_param.mode == CHAIN_FOLDED) {
11860c841c6cSNamhyung Kim 		printed = hist_browser__show_callchain_folded(browser,
11875eca104eSNamhyung Kim 						&entry->sorted_chain, row,
11885eca104eSNamhyung Kim 						total, parent_total, print, arg,
11895eca104eSNamhyung Kim 						is_output_full);
11900c841c6cSNamhyung Kim 	} else {
11910c841c6cSNamhyung Kim 		printed = hist_browser__show_callchain_graph(browser,
11925eca104eSNamhyung Kim 						&entry->sorted_chain, level, row,
11935eca104eSNamhyung Kim 						total, parent_total, print, arg,
11945eca104eSNamhyung Kim 						is_output_full);
11950c841c6cSNamhyung Kim 	}
11960c841c6cSNamhyung Kim 
11970c841c6cSNamhyung Kim 	if (arg->is_current_entry)
11980c841c6cSNamhyung Kim 		browser->he_selection = entry;
11990c841c6cSNamhyung Kim 
12000c841c6cSNamhyung Kim 	return printed;
12010c841c6cSNamhyung Kim }
12020c841c6cSNamhyung Kim 
120389701460SNamhyung Kim struct hpp_arg {
120489701460SNamhyung Kim 	struct ui_browser *b;
120589701460SNamhyung Kim 	char folded_sign;
120689701460SNamhyung Kim 	bool current_entry;
120789701460SNamhyung Kim };
120889701460SNamhyung Kim 
__hpp__slsmg_color_printf(struct perf_hpp * hpp,const char * fmt,...)120998ba1609SJiri Olsa int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
12102f6d9009SNamhyung Kim {
12112f6d9009SNamhyung Kim 	struct hpp_arg *arg = hpp->ptr;
1212d675107cSNamhyung Kim 	int ret, len;
12132f6d9009SNamhyung Kim 	va_list args;
12142f6d9009SNamhyung Kim 	double percent;
12152f6d9009SNamhyung Kim 
12162f6d9009SNamhyung Kim 	va_start(args, fmt);
1217d675107cSNamhyung Kim 	len = va_arg(args, int);
12182f6d9009SNamhyung Kim 	percent = va_arg(args, double);
12192f6d9009SNamhyung Kim 	va_end(args);
12205aed9d24SNamhyung Kim 
122189701460SNamhyung Kim 	ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
12225aed9d24SNamhyung Kim 
1223d675107cSNamhyung Kim 	ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
1224517dfdb3SArnaldo Carvalho de Melo 	ui_browser__printf(arg->b, "%s", hpp->buf);
122589701460SNamhyung Kim 
12265aed9d24SNamhyung Kim 	return ret;
1227f5951d56SNamhyung Kim }
1228f5951d56SNamhyung Kim 
1229fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field)				\
12305aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he)			\
12315aed9d24SNamhyung Kim {									\
12325aed9d24SNamhyung Kim 	return he->stat._field;						\
12335aed9d24SNamhyung Kim }									\
12345aed9d24SNamhyung Kim 									\
12352c5d4b4aSJiri Olsa static int								\
12365b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
12372c5d4b4aSJiri Olsa 				struct perf_hpp *hpp,			\
12385aed9d24SNamhyung Kim 				struct hist_entry *he)			\
12395aed9d24SNamhyung Kim {									\
12405b591669SNamhyung Kim 	return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%",	\
12412f6d9009SNamhyung Kim 			__hpp__slsmg_color_printf, true);		\
12425aed9d24SNamhyung Kim }
1243f5951d56SNamhyung Kim 
12440434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)			\
12450434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he)		\
12460434ddd2SNamhyung Kim {									\
12470434ddd2SNamhyung Kim 	return he->stat_acc->_field;					\
12480434ddd2SNamhyung Kim }									\
12490434ddd2SNamhyung Kim 									\
12500434ddd2SNamhyung Kim static int								\
12515b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,		\
12520434ddd2SNamhyung Kim 				struct perf_hpp *hpp,			\
12530434ddd2SNamhyung Kim 				struct hist_entry *he)			\
12540434ddd2SNamhyung Kim {									\
12550434ddd2SNamhyung Kim 	if (!symbol_conf.cumulate_callchain) {				\
1256517dfdb3SArnaldo Carvalho de Melo 		struct hpp_arg *arg = hpp->ptr;				\
12575b591669SNamhyung Kim 		int len = fmt->user_len ?: fmt->len;			\
1258d675107cSNamhyung Kim 		int ret = scnprintf(hpp->buf, hpp->size,		\
12595b591669SNamhyung Kim 				    "%*s", len, "N/A");			\
1260517dfdb3SArnaldo Carvalho de Melo 		ui_browser__printf(arg->b, "%s", hpp->buf);		\
12610434ddd2SNamhyung Kim 									\
12620434ddd2SNamhyung Kim 		return ret;						\
12630434ddd2SNamhyung Kim 	}								\
12645b591669SNamhyung Kim 	return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field,		\
12655b591669SNamhyung Kim 			" %*.2f%%", __hpp__slsmg_color_printf, true);	\
12660434ddd2SNamhyung Kim }
12670434ddd2SNamhyung Kim 
__HPP_COLOR_PERCENT_FN(overhead,period)1268fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period)
1269fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1270fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1271fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1272fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
12730434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
12745aed9d24SNamhyung Kim 
12755aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN
12760434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN
1277f5951d56SNamhyung Kim 
1278f5951d56SNamhyung Kim void hist_browser__init_hpp(void)
1279f5951d56SNamhyung Kim {
1280f5951d56SNamhyung Kim 	perf_hpp__format[PERF_HPP__OVERHEAD].color =
1281f5951d56SNamhyung Kim 				hist_browser__hpp_color_overhead;
1282f5951d56SNamhyung Kim 	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1283f5951d56SNamhyung Kim 				hist_browser__hpp_color_overhead_sys;
1284f5951d56SNamhyung Kim 	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1285f5951d56SNamhyung Kim 				hist_browser__hpp_color_overhead_us;
1286f5951d56SNamhyung Kim 	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1287f5951d56SNamhyung Kim 				hist_browser__hpp_color_overhead_guest_sys;
1288f5951d56SNamhyung Kim 	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1289f5951d56SNamhyung Kim 				hist_browser__hpp_color_overhead_guest_us;
12900434ddd2SNamhyung Kim 	perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
12910434ddd2SNamhyung Kim 				hist_browser__hpp_color_overhead_acc;
12924968ac8fSAndi Kleen 
12934968ac8fSAndi Kleen 	res_sample_init();
1294f5951d56SNamhyung Kim }
1295f5951d56SNamhyung Kim 
hist_browser__show_entry(struct hist_browser * browser,struct hist_entry * entry,unsigned short row)129605e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser,
1297aca7a94dSNamhyung Kim 				    struct hist_entry *entry,
1298aca7a94dSNamhyung Kim 				    unsigned short row)
1299aca7a94dSNamhyung Kim {
13001240005eSJiri Olsa 	int printed = 0;
130167d25916SNamhyung Kim 	int width = browser->b.width;
1302aca7a94dSNamhyung Kim 	char folded_sign = ' ';
130305e8b080SArnaldo Carvalho de Melo 	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1304fabd37b8SArnaldo Carvalho de Melo 	bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain;
1305aca7a94dSNamhyung Kim 	off_t row_offset = entry->row_offset;
130663a1a3d8SNamhyung Kim 	bool first = true;
13071240005eSJiri Olsa 	struct perf_hpp_fmt *fmt;
1308aca7a94dSNamhyung Kim 
1309aca7a94dSNamhyung Kim 	if (current_entry) {
131005e8b080SArnaldo Carvalho de Melo 		browser->he_selection = entry;
131105e8b080SArnaldo Carvalho de Melo 		browser->selection = &entry->ms;
1312aca7a94dSNamhyung Kim 	}
1313aca7a94dSNamhyung Kim 
1314fabd37b8SArnaldo Carvalho de Melo 	if (use_callchain) {
1315aca7a94dSNamhyung Kim 		hist_entry__init_have_children(entry);
1316aca7a94dSNamhyung Kim 		folded_sign = hist_entry__folded(entry);
1317aca7a94dSNamhyung Kim 	}
1318aca7a94dSNamhyung Kim 
1319aca7a94dSNamhyung Kim 	if (row_offset == 0) {
132089701460SNamhyung Kim 		struct hpp_arg arg = {
132189701460SNamhyung Kim 			.b		= &browser->b,
132289701460SNamhyung Kim 			.folded_sign	= folded_sign,
132389701460SNamhyung Kim 			.current_entry	= current_entry,
132489701460SNamhyung Kim 		};
1325c6c3c02dSArnaldo Carvalho de Melo 		int column = 0;
1326f5951d56SNamhyung Kim 
1327ef9ff601SArnaldo Carvalho de Melo 		ui_browser__gotorc(&browser->b, row, 0);
1328f5951d56SNamhyung Kim 
1329f0786af5SJiri Olsa 		hists__for_each_format(browser->hists, fmt) {
133089fee709SArnaldo Carvalho de Melo 			char s[2048];
133189fee709SArnaldo Carvalho de Melo 			struct perf_hpp hpp = {
133289fee709SArnaldo Carvalho de Melo 				.buf	= s,
133389fee709SArnaldo Carvalho de Melo 				.size	= sizeof(s),
133489fee709SArnaldo Carvalho de Melo 				.ptr	= &arg,
133589fee709SArnaldo Carvalho de Melo 			};
133689fee709SArnaldo Carvalho de Melo 
1337361459f1SNamhyung Kim 			if (perf_hpp__should_skip(fmt, entry->hists) ||
1338361459f1SNamhyung Kim 			    column++ < browser->b.horiz_scroll)
1339e67d49a7SNamhyung Kim 				continue;
1340e67d49a7SNamhyung Kim 
1341fb821c9eSNamhyung Kim 			if (current_entry && browser->b.navkeypressed) {
1342fb821c9eSNamhyung Kim 				ui_browser__set_color(&browser->b,
1343fb821c9eSNamhyung Kim 						      HE_COLORSET_SELECTED);
1344fb821c9eSNamhyung Kim 			} else {
1345fb821c9eSNamhyung Kim 				ui_browser__set_color(&browser->b,
1346fb821c9eSNamhyung Kim 						      HE_COLORSET_NORMAL);
1347fb821c9eSNamhyung Kim 			}
1348fb821c9eSNamhyung Kim 
1349fb821c9eSNamhyung Kim 			if (first) {
1350fabd37b8SArnaldo Carvalho de Melo 				if (use_callchain) {
1351517dfdb3SArnaldo Carvalho de Melo 					ui_browser__printf(&browser->b, "%c ", folded_sign);
1352f5951d56SNamhyung Kim 					width -= 2;
1353f5951d56SNamhyung Kim 				}
135463a1a3d8SNamhyung Kim 				first = false;
1355fb821c9eSNamhyung Kim 			} else {
1356517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(&browser->b, "  ");
1357fb821c9eSNamhyung Kim 				width -= 2;
1358fb821c9eSNamhyung Kim 			}
1359f5951d56SNamhyung Kim 
13601240005eSJiri Olsa 			if (fmt->color) {
136189fee709SArnaldo Carvalho de Melo 				int ret = fmt->color(fmt, &hpp, entry);
136289fee709SArnaldo Carvalho de Melo 				hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
136389fee709SArnaldo Carvalho de Melo 				/*
136489fee709SArnaldo Carvalho de Melo 				 * fmt->color() already used ui_browser to
136589fee709SArnaldo Carvalho de Melo 				 * print the non alignment bits, skip it (+ret):
136689fee709SArnaldo Carvalho de Melo 				 */
136789fee709SArnaldo Carvalho de Melo 				ui_browser__printf(&browser->b, "%s", s + ret);
1368f5951d56SNamhyung Kim 			} else {
136989fee709SArnaldo Carvalho de Melo 				hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
1370517dfdb3SArnaldo Carvalho de Melo 				ui_browser__printf(&browser->b, "%s", s);
1371f5951d56SNamhyung Kim 			}
137289fee709SArnaldo Carvalho de Melo 			width -= hpp.buf - s;
1373f5951d56SNamhyung Kim 		}
1374aca7a94dSNamhyung Kim 
1375aca7a94dSNamhyung Kim 		/* The scroll bar isn't being used */
137605e8b080SArnaldo Carvalho de Melo 		if (!browser->b.navkeypressed)
1377aca7a94dSNamhyung Kim 			width += 1;
1378aca7a94dSNamhyung Kim 
137926270a00SArnaldo Carvalho de Melo 		ui_browser__write_nstring(&browser->b, "", width);
138026d8b338SNamhyung Kim 
1381aca7a94dSNamhyung Kim 		++row;
1382aca7a94dSNamhyung Kim 		++printed;
1383aca7a94dSNamhyung Kim 	} else
1384aca7a94dSNamhyung Kim 		--row_offset;
1385aca7a94dSNamhyung Kim 
138662c95ae3SArnaldo Carvalho de Melo 	if (folded_sign == '-' && row != browser->b.rows) {
138739ee533fSNamhyung Kim 		struct callchain_print_arg arg = {
138839ee533fSNamhyung Kim 			.row_offset = row_offset,
138939ee533fSNamhyung Kim 			.is_current_entry = current_entry,
139039ee533fSNamhyung Kim 		};
1391c09a7e75SNamhyung Kim 
13920d3eb0b7SJin Yao 		printed += hist_browser__show_callchain(browser,
13930d3eb0b7SJin Yao 				entry, 1, row,
13940d3eb0b7SJin Yao 				hist_browser__show_callchain_entry,
13950d3eb0b7SJin Yao 				&arg,
13964b3a3212SNamhyung Kim 				hist_browser__check_output_full);
1397aca7a94dSNamhyung Kim 	}
1398aca7a94dSNamhyung Kim 
1399aca7a94dSNamhyung Kim 	return printed;
1400aca7a94dSNamhyung Kim }
1401aca7a94dSNamhyung Kim 
hist_browser__show_hierarchy_entry(struct hist_browser * browser,struct hist_entry * entry,unsigned short row,int level)1402d0506edbSNamhyung Kim static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1403d0506edbSNamhyung Kim 					      struct hist_entry *entry,
1404d0506edbSNamhyung Kim 					      unsigned short row,
14052dbbe9f2SNamhyung Kim 					      int level)
1406d0506edbSNamhyung Kim {
1407d0506edbSNamhyung Kim 	int printed = 0;
1408d0506edbSNamhyung Kim 	int width = browser->b.width;
1409d0506edbSNamhyung Kim 	char folded_sign = ' ';
1410d0506edbSNamhyung Kim 	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1411d0506edbSNamhyung Kim 	off_t row_offset = entry->row_offset;
1412d0506edbSNamhyung Kim 	bool first = true;
1413d0506edbSNamhyung Kim 	struct perf_hpp_fmt *fmt;
1414a61a22f6SNamhyung Kim 	struct perf_hpp_list_node *fmt_node;
1415d0506edbSNamhyung Kim 	struct hpp_arg arg = {
1416d0506edbSNamhyung Kim 		.b		= &browser->b,
1417d0506edbSNamhyung Kim 		.current_entry	= current_entry,
1418d0506edbSNamhyung Kim 	};
1419d0506edbSNamhyung Kim 	int column = 0;
14202dbbe9f2SNamhyung Kim 	int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
1421d0506edbSNamhyung Kim 
1422d0506edbSNamhyung Kim 	if (current_entry) {
1423d0506edbSNamhyung Kim 		browser->he_selection = entry;
1424d0506edbSNamhyung Kim 		browser->selection = &entry->ms;
1425d0506edbSNamhyung Kim 	}
1426d0506edbSNamhyung Kim 
1427d0506edbSNamhyung Kim 	hist_entry__init_have_children(entry);
1428d0506edbSNamhyung Kim 	folded_sign = hist_entry__folded(entry);
1429d0506edbSNamhyung Kim 	arg.folded_sign = folded_sign;
1430d0506edbSNamhyung Kim 
1431d0506edbSNamhyung Kim 	if (entry->leaf && row_offset) {
1432d0506edbSNamhyung Kim 		row_offset--;
1433d0506edbSNamhyung Kim 		goto show_callchain;
1434d0506edbSNamhyung Kim 	}
1435d0506edbSNamhyung Kim 
1436ef9ff601SArnaldo Carvalho de Melo 	ui_browser__gotorc(&browser->b, row, 0);
1437d0506edbSNamhyung Kim 
1438d0506edbSNamhyung Kim 	if (current_entry && browser->b.navkeypressed)
1439d0506edbSNamhyung Kim 		ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1440d0506edbSNamhyung Kim 	else
1441d0506edbSNamhyung Kim 		ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1442d0506edbSNamhyung Kim 
1443d0506edbSNamhyung Kim 	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1444d0506edbSNamhyung Kim 	width -= level * HIERARCHY_INDENT;
1445d0506edbSNamhyung Kim 
1446a61a22f6SNamhyung Kim 	/* the first hpp_list_node is for overhead columns */
1447a61a22f6SNamhyung Kim 	fmt_node = list_first_entry(&entry->hists->hpp_formats,
1448a61a22f6SNamhyung Kim 				    struct perf_hpp_list_node, list);
1449a61a22f6SNamhyung Kim 	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1450d0506edbSNamhyung Kim 		char s[2048];
1451d0506edbSNamhyung Kim 		struct perf_hpp hpp = {
1452d0506edbSNamhyung Kim 			.buf		= s,
1453d0506edbSNamhyung Kim 			.size		= sizeof(s),
1454d0506edbSNamhyung Kim 			.ptr		= &arg,
1455d0506edbSNamhyung Kim 		};
1456d0506edbSNamhyung Kim 
1457d0506edbSNamhyung Kim 		if (perf_hpp__should_skip(fmt, entry->hists) ||
1458d0506edbSNamhyung Kim 		    column++ < browser->b.horiz_scroll)
1459d0506edbSNamhyung Kim 			continue;
1460d0506edbSNamhyung Kim 
1461d0506edbSNamhyung Kim 		if (current_entry && browser->b.navkeypressed) {
1462d0506edbSNamhyung Kim 			ui_browser__set_color(&browser->b,
1463d0506edbSNamhyung Kim 					      HE_COLORSET_SELECTED);
1464d0506edbSNamhyung Kim 		} else {
1465d0506edbSNamhyung Kim 			ui_browser__set_color(&browser->b,
1466d0506edbSNamhyung Kim 					      HE_COLORSET_NORMAL);
1467d0506edbSNamhyung Kim 		}
1468d0506edbSNamhyung Kim 
1469d0506edbSNamhyung Kim 		if (first) {
1470d0506edbSNamhyung Kim 			ui_browser__printf(&browser->b, "%c ", folded_sign);
14713d9f4683SNamhyung Kim 			width -= 2;
1472d0506edbSNamhyung Kim 			first = false;
1473d0506edbSNamhyung Kim 		} else {
1474d0506edbSNamhyung Kim 			ui_browser__printf(&browser->b, "  ");
1475d0506edbSNamhyung Kim 			width -= 2;
1476d0506edbSNamhyung Kim 		}
1477d0506edbSNamhyung Kim 
1478d0506edbSNamhyung Kim 		if (fmt->color) {
1479d0506edbSNamhyung Kim 			int ret = fmt->color(fmt, &hpp, entry);
1480d0506edbSNamhyung Kim 			hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1481d0506edbSNamhyung Kim 			/*
1482d0506edbSNamhyung Kim 			 * fmt->color() already used ui_browser to
1483d0506edbSNamhyung Kim 			 * print the non alignment bits, skip it (+ret):
1484d0506edbSNamhyung Kim 			 */
1485d0506edbSNamhyung Kim 			ui_browser__printf(&browser->b, "%s", s + ret);
1486d0506edbSNamhyung Kim 		} else {
1487d0506edbSNamhyung Kim 			int ret = fmt->entry(fmt, &hpp, entry);
1488d0506edbSNamhyung Kim 			hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1489d0506edbSNamhyung Kim 			ui_browser__printf(&browser->b, "%s", s);
1490d0506edbSNamhyung Kim 		}
1491d0506edbSNamhyung Kim 		width -= hpp.buf - s;
1492d0506edbSNamhyung Kim 	}
1493d0506edbSNamhyung Kim 
1494b9bf911eSNamhyung Kim 	if (!first) {
1495d0506edbSNamhyung Kim 		ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1496d0506edbSNamhyung Kim 		width -= hierarchy_indent;
1497b9bf911eSNamhyung Kim 	}
1498d0506edbSNamhyung Kim 
1499d0506edbSNamhyung Kim 	if (column >= browser->b.horiz_scroll) {
1500d0506edbSNamhyung Kim 		char s[2048];
1501d0506edbSNamhyung Kim 		struct perf_hpp hpp = {
1502d0506edbSNamhyung Kim 			.buf		= s,
1503d0506edbSNamhyung Kim 			.size		= sizeof(s),
1504d0506edbSNamhyung Kim 			.ptr		= &arg,
1505d0506edbSNamhyung Kim 		};
1506d0506edbSNamhyung Kim 
1507d0506edbSNamhyung Kim 		if (current_entry && browser->b.navkeypressed) {
1508d0506edbSNamhyung Kim 			ui_browser__set_color(&browser->b,
1509d0506edbSNamhyung Kim 					      HE_COLORSET_SELECTED);
1510d0506edbSNamhyung Kim 		} else {
1511d0506edbSNamhyung Kim 			ui_browser__set_color(&browser->b,
1512d0506edbSNamhyung Kim 					      HE_COLORSET_NORMAL);
1513d0506edbSNamhyung Kim 		}
1514d0506edbSNamhyung Kim 
15151b2dbbf4SNamhyung Kim 		perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1516131d51ebSNamhyung Kim 			if (first) {
1517131d51ebSNamhyung Kim 				ui_browser__printf(&browser->b, "%c ", folded_sign);
1518131d51ebSNamhyung Kim 				first = false;
1519131d51ebSNamhyung Kim 			} else {
1520d0506edbSNamhyung Kim 				ui_browser__write_nstring(&browser->b, "", 2);
1521131d51ebSNamhyung Kim 			}
1522131d51ebSNamhyung Kim 
1523d0506edbSNamhyung Kim 			width -= 2;
1524d0506edbSNamhyung Kim 
1525d0506edbSNamhyung Kim 			/*
1526d0506edbSNamhyung Kim 			 * No need to call hist_entry__snprintf_alignment()
1527d0506edbSNamhyung Kim 			 * since this fmt is always the last column in the
1528d0506edbSNamhyung Kim 			 * hierarchy mode.
1529d0506edbSNamhyung Kim 			 */
1530d0506edbSNamhyung Kim 			if (fmt->color) {
1531d0506edbSNamhyung Kim 				width -= fmt->color(fmt, &hpp, entry);
1532d0506edbSNamhyung Kim 			} else {
1533cb1fab91SNamhyung Kim 				int i = 0;
1534cb1fab91SNamhyung Kim 
1535d0506edbSNamhyung Kim 				width -= fmt->entry(fmt, &hpp, entry);
153632858480SArnaldo Carvalho de Melo 				ui_browser__printf(&browser->b, "%s", skip_spaces(s));
1537cb1fab91SNamhyung Kim 
1538cb1fab91SNamhyung Kim 				while (isspace(s[i++]))
1539cb1fab91SNamhyung Kim 					width++;
1540d0506edbSNamhyung Kim 			}
1541d0506edbSNamhyung Kim 		}
15421b2dbbf4SNamhyung Kim 	}
1543d0506edbSNamhyung Kim 
1544d0506edbSNamhyung Kim 	/* The scroll bar isn't being used */
1545d0506edbSNamhyung Kim 	if (!browser->b.navkeypressed)
1546d0506edbSNamhyung Kim 		width += 1;
1547d0506edbSNamhyung Kim 
1548d0506edbSNamhyung Kim 	ui_browser__write_nstring(&browser->b, "", width);
1549d0506edbSNamhyung Kim 
1550d0506edbSNamhyung Kim 	++row;
1551d0506edbSNamhyung Kim 	++printed;
1552d0506edbSNamhyung Kim 
1553d0506edbSNamhyung Kim show_callchain:
1554d0506edbSNamhyung Kim 	if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1555d0506edbSNamhyung Kim 		struct callchain_print_arg carg = {
1556d0506edbSNamhyung Kim 			.row_offset = row_offset,
1557d0506edbSNamhyung Kim 		};
1558d0506edbSNamhyung Kim 
1559d0506edbSNamhyung Kim 		printed += hist_browser__show_callchain(browser, entry,
1560d0506edbSNamhyung Kim 					level + 1, row,
1561d0506edbSNamhyung Kim 					hist_browser__show_callchain_entry, &carg,
1562d0506edbSNamhyung Kim 					hist_browser__check_output_full);
1563d0506edbSNamhyung Kim 	}
1564d0506edbSNamhyung Kim 
1565d0506edbSNamhyung Kim 	return printed;
1566d0506edbSNamhyung Kim }
1567d0506edbSNamhyung Kim 
hist_browser__show_no_entry(struct hist_browser * browser,unsigned short row,int level)156879dded87SNamhyung Kim static int hist_browser__show_no_entry(struct hist_browser *browser,
15692dbbe9f2SNamhyung Kim 				       unsigned short row, int level)
157079dded87SNamhyung Kim {
157179dded87SNamhyung Kim 	int width = browser->b.width;
157279dded87SNamhyung Kim 	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
157379dded87SNamhyung Kim 	bool first = true;
157479dded87SNamhyung Kim 	int column = 0;
157579dded87SNamhyung Kim 	int ret;
157679dded87SNamhyung Kim 	struct perf_hpp_fmt *fmt;
1577a61a22f6SNamhyung Kim 	struct perf_hpp_list_node *fmt_node;
15782dbbe9f2SNamhyung Kim 	int indent = browser->hists->nr_hpp_node - 2;
157979dded87SNamhyung Kim 
158079dded87SNamhyung Kim 	if (current_entry) {
158179dded87SNamhyung Kim 		browser->he_selection = NULL;
158279dded87SNamhyung Kim 		browser->selection = NULL;
158379dded87SNamhyung Kim 	}
158479dded87SNamhyung Kim 
1585ef9ff601SArnaldo Carvalho de Melo 	ui_browser__gotorc(&browser->b, row, 0);
158679dded87SNamhyung Kim 
158779dded87SNamhyung Kim 	if (current_entry && browser->b.navkeypressed)
158879dded87SNamhyung Kim 		ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
158979dded87SNamhyung Kim 	else
159079dded87SNamhyung Kim 		ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
159179dded87SNamhyung Kim 
159279dded87SNamhyung Kim 	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
159379dded87SNamhyung Kim 	width -= level * HIERARCHY_INDENT;
159479dded87SNamhyung Kim 
1595a61a22f6SNamhyung Kim 	/* the first hpp_list_node is for overhead columns */
1596a61a22f6SNamhyung Kim 	fmt_node = list_first_entry(&browser->hists->hpp_formats,
1597a61a22f6SNamhyung Kim 				    struct perf_hpp_list_node, list);
1598a61a22f6SNamhyung Kim 	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
159979dded87SNamhyung Kim 		if (perf_hpp__should_skip(fmt, browser->hists) ||
160079dded87SNamhyung Kim 		    column++ < browser->b.horiz_scroll)
160179dded87SNamhyung Kim 			continue;
160279dded87SNamhyung Kim 
1603da1b0407SJiri Olsa 		ret = fmt->width(fmt, NULL, browser->hists);
160479dded87SNamhyung Kim 
160579dded87SNamhyung Kim 		if (first) {
160679dded87SNamhyung Kim 			/* for folded sign */
160779dded87SNamhyung Kim 			first = false;
160879dded87SNamhyung Kim 			ret++;
160979dded87SNamhyung Kim 		} else {
161079dded87SNamhyung Kim 			/* space between columns */
161179dded87SNamhyung Kim 			ret += 2;
161279dded87SNamhyung Kim 		}
161379dded87SNamhyung Kim 
161479dded87SNamhyung Kim 		ui_browser__write_nstring(&browser->b, "", ret);
161579dded87SNamhyung Kim 		width -= ret;
161679dded87SNamhyung Kim 	}
161779dded87SNamhyung Kim 
16182dbbe9f2SNamhyung Kim 	ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
16192dbbe9f2SNamhyung Kim 	width -= indent * HIERARCHY_INDENT;
162079dded87SNamhyung Kim 
162179dded87SNamhyung Kim 	if (column >= browser->b.horiz_scroll) {
162279dded87SNamhyung Kim 		char buf[32];
162379dded87SNamhyung Kim 
162479dded87SNamhyung Kim 		ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
162579dded87SNamhyung Kim 		ui_browser__printf(&browser->b, "  %s", buf);
162679dded87SNamhyung Kim 		width -= ret + 2;
162779dded87SNamhyung Kim 	}
162879dded87SNamhyung Kim 
162979dded87SNamhyung Kim 	/* The scroll bar isn't being used */
163079dded87SNamhyung Kim 	if (!browser->b.navkeypressed)
163179dded87SNamhyung Kim 		width += 1;
163279dded87SNamhyung Kim 
163379dded87SNamhyung Kim 	ui_browser__write_nstring(&browser->b, "", width);
163479dded87SNamhyung Kim 	return 1;
163579dded87SNamhyung Kim }
163679dded87SNamhyung Kim 
advance_hpp_check(struct perf_hpp * hpp,int inc)163781a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc)
163881a888feSJiri Olsa {
163981a888feSJiri Olsa 	advance_hpp(hpp, inc);
164081a888feSJiri Olsa 	return hpp->size <= 0;
164181a888feSJiri Olsa }
164281a888feSJiri Olsa 
164369705b35SJiri Olsa static int
hists_browser__scnprintf_headers(struct hist_browser * browser,char * buf,size_t size,int line)164469705b35SJiri Olsa hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
164569705b35SJiri Olsa 				 size_t size, int line)
164681a888feSJiri Olsa {
1647c6c3c02dSArnaldo Carvalho de Melo 	struct hists *hists = browser->hists;
164881a888feSJiri Olsa 	struct perf_hpp dummy_hpp = {
164981a888feSJiri Olsa 		.buf    = buf,
165081a888feSJiri Olsa 		.size   = size,
165181a888feSJiri Olsa 	};
165281a888feSJiri Olsa 	struct perf_hpp_fmt *fmt;
165381a888feSJiri Olsa 	size_t ret = 0;
1654c6c3c02dSArnaldo Carvalho de Melo 	int column = 0;
165529659ab4SJiri Olsa 	int span = 0;
165681a888feSJiri Olsa 
1657fabd37b8SArnaldo Carvalho de Melo 	if (hists__has_callchains(hists) && symbol_conf.use_callchain) {
165881a888feSJiri Olsa 		ret = scnprintf(buf, size, "  ");
165981a888feSJiri Olsa 		if (advance_hpp_check(&dummy_hpp, ret))
166081a888feSJiri Olsa 			return ret;
166181a888feSJiri Olsa 	}
166281a888feSJiri Olsa 
1663f0786af5SJiri Olsa 	hists__for_each_format(browser->hists, fmt) {
1664361459f1SNamhyung Kim 		if (perf_hpp__should_skip(fmt, hists)  || column++ < browser->b.horiz_scroll)
166581a888feSJiri Olsa 			continue;
166681a888feSJiri Olsa 
166729659ab4SJiri Olsa 		ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
166881a888feSJiri Olsa 		if (advance_hpp_check(&dummy_hpp, ret))
166981a888feSJiri Olsa 			break;
167081a888feSJiri Olsa 
167129659ab4SJiri Olsa 		if (span)
167229659ab4SJiri Olsa 			continue;
167329659ab4SJiri Olsa 
167481a888feSJiri Olsa 		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
167581a888feSJiri Olsa 		if (advance_hpp_check(&dummy_hpp, ret))
167681a888feSJiri Olsa 			break;
167781a888feSJiri Olsa 	}
167881a888feSJiri Olsa 
167981a888feSJiri Olsa 	return ret;
168081a888feSJiri Olsa }
168181a888feSJiri Olsa 
hists_browser__scnprintf_hierarchy_headers(struct hist_browser * browser,char * buf,size_t size)1682d8b92400SNamhyung Kim static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1683d8b92400SNamhyung Kim {
1684d8b92400SNamhyung Kim 	struct hists *hists = browser->hists;
1685d8b92400SNamhyung Kim 	struct perf_hpp dummy_hpp = {
1686d8b92400SNamhyung Kim 		.buf    = buf,
1687d8b92400SNamhyung Kim 		.size   = size,
1688d8b92400SNamhyung Kim 	};
1689d8b92400SNamhyung Kim 	struct perf_hpp_fmt *fmt;
1690a61a22f6SNamhyung Kim 	struct perf_hpp_list_node *fmt_node;
1691d8b92400SNamhyung Kim 	size_t ret = 0;
1692d8b92400SNamhyung Kim 	int column = 0;
16932dbbe9f2SNamhyung Kim 	int indent = hists->nr_hpp_node - 2;
1694a61a22f6SNamhyung Kim 	bool first_node, first_col;
1695d8b92400SNamhyung Kim 
1696d8b92400SNamhyung Kim 	ret = scnprintf(buf, size, "  ");
1697d8b92400SNamhyung Kim 	if (advance_hpp_check(&dummy_hpp, ret))
1698d8b92400SNamhyung Kim 		return ret;
1699d8b92400SNamhyung Kim 
1700b9bf911eSNamhyung Kim 	first_node = true;
1701a61a22f6SNamhyung Kim 	/* the first hpp_list_node is for overhead columns */
1702a61a22f6SNamhyung Kim 	fmt_node = list_first_entry(&hists->hpp_formats,
1703a61a22f6SNamhyung Kim 				    struct perf_hpp_list_node, list);
1704a61a22f6SNamhyung Kim 	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1705d8b92400SNamhyung Kim 		if (column++ < browser->b.horiz_scroll)
1706d8b92400SNamhyung Kim 			continue;
1707d8b92400SNamhyung Kim 
170829659ab4SJiri Olsa 		ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
1709d8b92400SNamhyung Kim 		if (advance_hpp_check(&dummy_hpp, ret))
1710d8b92400SNamhyung Kim 			break;
1711d8b92400SNamhyung Kim 
1712d8b92400SNamhyung Kim 		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
1713d8b92400SNamhyung Kim 		if (advance_hpp_check(&dummy_hpp, ret))
1714d8b92400SNamhyung Kim 			break;
1715b9bf911eSNamhyung Kim 
1716b9bf911eSNamhyung Kim 		first_node = false;
1717d8b92400SNamhyung Kim 	}
1718d8b92400SNamhyung Kim 
1719b9bf911eSNamhyung Kim 	if (!first_node) {
1720d8b92400SNamhyung Kim 		ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
17212dbbe9f2SNamhyung Kim 				indent * HIERARCHY_INDENT, "");
1722d8b92400SNamhyung Kim 		if (advance_hpp_check(&dummy_hpp, ret))
1723d8b92400SNamhyung Kim 			return ret;
1724b9bf911eSNamhyung Kim 	}
1725d8b92400SNamhyung Kim 
1726a61a22f6SNamhyung Kim 	first_node = true;
1727a61a22f6SNamhyung Kim 	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1728a61a22f6SNamhyung Kim 		if (!first_node) {
1729d8b92400SNamhyung Kim 			ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1730d8b92400SNamhyung Kim 			if (advance_hpp_check(&dummy_hpp, ret))
1731d8b92400SNamhyung Kim 				break;
1732d8b92400SNamhyung Kim 		}
1733a61a22f6SNamhyung Kim 		first_node = false;
1734a61a22f6SNamhyung Kim 
1735a61a22f6SNamhyung Kim 		first_col = true;
1736a61a22f6SNamhyung Kim 		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1737a61a22f6SNamhyung Kim 			char *start;
1738a61a22f6SNamhyung Kim 
1739a61a22f6SNamhyung Kim 			if (perf_hpp__should_skip(fmt, hists))
1740a61a22f6SNamhyung Kim 				continue;
1741a61a22f6SNamhyung Kim 
1742a61a22f6SNamhyung Kim 			if (!first_col) {
1743a61a22f6SNamhyung Kim 				ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1744a61a22f6SNamhyung Kim 				if (advance_hpp_check(&dummy_hpp, ret))
1745a61a22f6SNamhyung Kim 					break;
1746a61a22f6SNamhyung Kim 			}
1747a61a22f6SNamhyung Kim 			first_col = false;
1748d8b92400SNamhyung Kim 
174929659ab4SJiri Olsa 			ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
1750d8b92400SNamhyung Kim 			dummy_hpp.buf[ret] = '\0';
1751d8b92400SNamhyung Kim 
17523ca43b60SArnaldo Carvalho de Melo 			start = strim(dummy_hpp.buf);
1753cb1fab91SNamhyung Kim 			ret = strlen(start);
1754cb1fab91SNamhyung Kim 
1755cb1fab91SNamhyung Kim 			if (start != dummy_hpp.buf)
1756cb1fab91SNamhyung Kim 				memmove(dummy_hpp.buf, start, ret + 1);
1757cb1fab91SNamhyung Kim 
1758d8b92400SNamhyung Kim 			if (advance_hpp_check(&dummy_hpp, ret))
1759d8b92400SNamhyung Kim 				break;
1760d8b92400SNamhyung Kim 		}
1761a61a22f6SNamhyung Kim 	}
1762d8b92400SNamhyung Kim 
1763d8b92400SNamhyung Kim 	return ret;
1764d8b92400SNamhyung Kim }
1765d8b92400SNamhyung Kim 
hists_browser__hierarchy_headers(struct hist_browser * browser)176601b4770dSJiri Olsa static void hists_browser__hierarchy_headers(struct hist_browser *browser)
1767025bf7eaSArnaldo Carvalho de Melo {
176881a888feSJiri Olsa 	char headers[1024];
176981a888feSJiri Olsa 
1770d8b92400SNamhyung Kim 	hists_browser__scnprintf_hierarchy_headers(browser, headers,
1771d8b92400SNamhyung Kim 						   sizeof(headers));
177201b4770dSJiri Olsa 
1773e2cabf2aSNamhyung Kim 	ui_browser__gotorc_title(&browser->b, 0, 0);
1774025bf7eaSArnaldo Carvalho de Melo 	ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
177526270a00SArnaldo Carvalho de Melo 	ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1776025bf7eaSArnaldo Carvalho de Melo }
1777025bf7eaSArnaldo Carvalho de Melo 
hists_browser__headers(struct hist_browser * browser)177801b4770dSJiri Olsa static void hists_browser__headers(struct hist_browser *browser)
177901b4770dSJiri Olsa {
178069705b35SJiri Olsa 	struct hists *hists = browser->hists;
178169705b35SJiri Olsa 	struct perf_hpp_list *hpp_list = hists->hpp_list;
178269705b35SJiri Olsa 
178369705b35SJiri Olsa 	int line;
178469705b35SJiri Olsa 
178569705b35SJiri Olsa 	for (line = 0; line < hpp_list->nr_header_lines; line++) {
178601b4770dSJiri Olsa 		char headers[1024];
178701b4770dSJiri Olsa 
178801b4770dSJiri Olsa 		hists_browser__scnprintf_headers(browser, headers,
178969705b35SJiri Olsa 						 sizeof(headers), line);
179001b4770dSJiri Olsa 
1791ef9ff601SArnaldo Carvalho de Melo 		ui_browser__gotorc_title(&browser->b, line, 0);
179201b4770dSJiri Olsa 		ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
179301b4770dSJiri Olsa 		ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
179401b4770dSJiri Olsa 	}
179569705b35SJiri Olsa }
179601b4770dSJiri Olsa 
hist_browser__show_headers(struct hist_browser * browser)179701b4770dSJiri Olsa static void hist_browser__show_headers(struct hist_browser *browser)
179801b4770dSJiri Olsa {
179901b4770dSJiri Olsa 	if (symbol_conf.report_hierarchy)
180001b4770dSJiri Olsa 		hists_browser__hierarchy_headers(browser);
180101b4770dSJiri Olsa 	else
180201b4770dSJiri Olsa 		hists_browser__headers(browser);
180301b4770dSJiri Olsa }
180401b4770dSJiri Olsa 
ui_browser__hists_init_top(struct ui_browser * browser)1805aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser)
1806aca7a94dSNamhyung Kim {
1807aca7a94dSNamhyung Kim 	if (browser->top == NULL) {
1808aca7a94dSNamhyung Kim 		struct hist_browser *hb;
1809aca7a94dSNamhyung Kim 
1810aca7a94dSNamhyung Kim 		hb = container_of(browser, struct hist_browser, b);
18112eb3d689SDavidlohr Bueso 		browser->top = rb_first_cached(&hb->hists->entries);
1812aca7a94dSNamhyung Kim 	}
1813aca7a94dSNamhyung Kim }
1814aca7a94dSNamhyung Kim 
hist_browser__refresh(struct ui_browser * browser)181505e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser)
1816aca7a94dSNamhyung Kim {
1817aca7a94dSNamhyung Kim 	unsigned row = 0;
1818aca7a94dSNamhyung Kim 	struct rb_node *nd;
181905e8b080SArnaldo Carvalho de Melo 	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
1820aca7a94dSNamhyung Kim 
182194e87a8bSArnaldo Carvalho de Melo 	if (hb->show_headers)
1822025bf7eaSArnaldo Carvalho de Melo 		hist_browser__show_headers(hb);
1823025bf7eaSArnaldo Carvalho de Melo 
182405e8b080SArnaldo Carvalho de Melo 	ui_browser__hists_init_top(browser);
1825979d2cacSWang Nan 	hb->he_selection = NULL;
1826979d2cacSWang Nan 	hb->selection = NULL;
1827aca7a94dSNamhyung Kim 
1828d0506edbSNamhyung Kim 	for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
1829aca7a94dSNamhyung Kim 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
183014135663SNamhyung Kim 		float percent;
1831aca7a94dSNamhyung Kim 
1832d0506edbSNamhyung Kim 		if (h->filtered) {
1833d0506edbSNamhyung Kim 			/* let it move to sibling */
1834d0506edbSNamhyung Kim 			h->unfolded = false;
1835aca7a94dSNamhyung Kim 			continue;
1836d0506edbSNamhyung Kim 		}
1837aca7a94dSNamhyung Kim 
18387fa46cbfSJin Yao 		if (symbol_conf.report_individual_block)
18397fa46cbfSJin Yao 			percent = block_info__total_cycles_percent(h);
18407fa46cbfSJin Yao 		else
184114135663SNamhyung Kim 			percent = hist_entry__get_percent_limit(h);
18427fa46cbfSJin Yao 
1843064f1981SNamhyung Kim 		if (percent < hb->min_pcnt)
1844064f1981SNamhyung Kim 			continue;
1845064f1981SNamhyung Kim 
1846d0506edbSNamhyung Kim 		if (symbol_conf.report_hierarchy) {
1847d0506edbSNamhyung Kim 			row += hist_browser__show_hierarchy_entry(hb, h, row,
18482dbbe9f2SNamhyung Kim 								  h->depth);
184979dded87SNamhyung Kim 			if (row == browser->rows)
185079dded87SNamhyung Kim 				break;
185179dded87SNamhyung Kim 
185279dded87SNamhyung Kim 			if (h->has_no_entry) {
1853a61a22f6SNamhyung Kim 				hist_browser__show_no_entry(hb, row, h->depth + 1);
185479dded87SNamhyung Kim 				row++;
185579dded87SNamhyung Kim 			}
1856d0506edbSNamhyung Kim 		} else {
1857aca7a94dSNamhyung Kim 			row += hist_browser__show_entry(hb, h, row);
1858d0506edbSNamhyung Kim 		}
1859d0506edbSNamhyung Kim 
186062c95ae3SArnaldo Carvalho de Melo 		if (row == browser->rows)
1861aca7a94dSNamhyung Kim 			break;
1862aca7a94dSNamhyung Kim 	}
1863aca7a94dSNamhyung Kim 
186494e87a8bSArnaldo Carvalho de Melo 	return row;
1865aca7a94dSNamhyung Kim }
1866aca7a94dSNamhyung Kim 
hists__filter_entries(struct rb_node * nd,float min_pcnt)1867064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd,
1868064f1981SNamhyung Kim 					     float min_pcnt)
1869aca7a94dSNamhyung Kim {
1870aca7a94dSNamhyung Kim 	while (nd != NULL) {
1871aca7a94dSNamhyung Kim 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
187214135663SNamhyung Kim 		float percent = hist_entry__get_percent_limit(h);
1873064f1981SNamhyung Kim 
1874c0f1527bSNamhyung Kim 		if (!h->filtered && percent >= min_pcnt)
1875aca7a94dSNamhyung Kim 			return nd;
1876aca7a94dSNamhyung Kim 
1877d0506edbSNamhyung Kim 		/*
1878d0506edbSNamhyung Kim 		 * If it's filtered, its all children also were filtered.
1879d0506edbSNamhyung Kim 		 * So move to sibling node.
1880d0506edbSNamhyung Kim 		 */
1881d0506edbSNamhyung Kim 		if (rb_next(nd))
1882aca7a94dSNamhyung Kim 			nd = rb_next(nd);
1883d0506edbSNamhyung Kim 		else
1884d0506edbSNamhyung Kim 			nd = rb_hierarchy_next(nd);
1885aca7a94dSNamhyung Kim 	}
1886aca7a94dSNamhyung Kim 
1887aca7a94dSNamhyung Kim 	return NULL;
1888aca7a94dSNamhyung Kim }
1889aca7a94dSNamhyung Kim 
hists__filter_prev_entries(struct rb_node * nd,float min_pcnt)1890064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
1891064f1981SNamhyung Kim 						  float min_pcnt)
1892aca7a94dSNamhyung Kim {
1893aca7a94dSNamhyung Kim 	while (nd != NULL) {
1894aca7a94dSNamhyung Kim 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
189514135663SNamhyung Kim 		float percent = hist_entry__get_percent_limit(h);
1896064f1981SNamhyung Kim 
1897064f1981SNamhyung Kim 		if (!h->filtered && percent >= min_pcnt)
1898aca7a94dSNamhyung Kim 			return nd;
1899aca7a94dSNamhyung Kim 
1900d0506edbSNamhyung Kim 		nd = rb_hierarchy_prev(nd);
1901aca7a94dSNamhyung Kim 	}
1902aca7a94dSNamhyung Kim 
1903aca7a94dSNamhyung Kim 	return NULL;
1904aca7a94dSNamhyung Kim }
1905aca7a94dSNamhyung Kim 
ui_browser__hists_seek(struct ui_browser * browser,off_t offset,int whence)190605e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser,
1907aca7a94dSNamhyung Kim 				   off_t offset, int whence)
1908aca7a94dSNamhyung Kim {
1909aca7a94dSNamhyung Kim 	struct hist_entry *h;
1910aca7a94dSNamhyung Kim 	struct rb_node *nd;
1911aca7a94dSNamhyung Kim 	bool first = true;
1912064f1981SNamhyung Kim 	struct hist_browser *hb;
1913064f1981SNamhyung Kim 
1914064f1981SNamhyung Kim 	hb = container_of(browser, struct hist_browser, b);
1915aca7a94dSNamhyung Kim 
191605e8b080SArnaldo Carvalho de Melo 	if (browser->nr_entries == 0)
1917aca7a94dSNamhyung Kim 		return;
1918aca7a94dSNamhyung Kim 
191905e8b080SArnaldo Carvalho de Melo 	ui_browser__hists_init_top(browser);
1920aca7a94dSNamhyung Kim 
1921aca7a94dSNamhyung Kim 	switch (whence) {
1922aca7a94dSNamhyung Kim 	case SEEK_SET:
1923064f1981SNamhyung Kim 		nd = hists__filter_entries(rb_first(browser->entries),
192414135663SNamhyung Kim 					   hb->min_pcnt);
1925aca7a94dSNamhyung Kim 		break;
1926aca7a94dSNamhyung Kim 	case SEEK_CUR:
192705e8b080SArnaldo Carvalho de Melo 		nd = browser->top;
1928aca7a94dSNamhyung Kim 		goto do_offset;
1929aca7a94dSNamhyung Kim 	case SEEK_END:
1930d0506edbSNamhyung Kim 		nd = rb_hierarchy_last(rb_last(browser->entries));
1931d0506edbSNamhyung Kim 		nd = hists__filter_prev_entries(nd, hb->min_pcnt);
1932aca7a94dSNamhyung Kim 		first = false;
1933aca7a94dSNamhyung Kim 		break;
1934aca7a94dSNamhyung Kim 	default:
1935aca7a94dSNamhyung Kim 		return;
1936aca7a94dSNamhyung Kim 	}
1937aca7a94dSNamhyung Kim 
1938aca7a94dSNamhyung Kim 	/*
1939aca7a94dSNamhyung Kim 	 * Moves not relative to the first visible entry invalidates its
1940aca7a94dSNamhyung Kim 	 * row_offset:
1941aca7a94dSNamhyung Kim 	 */
194205e8b080SArnaldo Carvalho de Melo 	h = rb_entry(browser->top, struct hist_entry, rb_node);
1943aca7a94dSNamhyung Kim 	h->row_offset = 0;
1944aca7a94dSNamhyung Kim 
1945aca7a94dSNamhyung Kim 	/*
1946aca7a94dSNamhyung Kim 	 * Here we have to check if nd is expanded (+), if it is we can't go
1947aca7a94dSNamhyung Kim 	 * the next top level hist_entry, instead we must compute an offset of
1948aca7a94dSNamhyung Kim 	 * what _not_ to show and not change the first visible entry.
1949aca7a94dSNamhyung Kim 	 *
1950aca7a94dSNamhyung Kim 	 * This offset increments when we are going from top to bottom and
1951aca7a94dSNamhyung Kim 	 * decreases when we're going from bottom to top.
1952aca7a94dSNamhyung Kim 	 *
1953aca7a94dSNamhyung Kim 	 * As we don't have backpointers to the top level in the callchains
1954aca7a94dSNamhyung Kim 	 * structure, we need to always print the whole hist_entry callchain,
1955aca7a94dSNamhyung Kim 	 * skipping the first ones that are before the first visible entry
1956aca7a94dSNamhyung Kim 	 * and stop when we printed enough lines to fill the screen.
1957aca7a94dSNamhyung Kim 	 */
1958aca7a94dSNamhyung Kim do_offset:
1959837eeb75SWang Nan 	if (!nd)
1960837eeb75SWang Nan 		return;
1961837eeb75SWang Nan 
1962aca7a94dSNamhyung Kim 	if (offset > 0) {
1963aca7a94dSNamhyung Kim 		do {
1964aca7a94dSNamhyung Kim 			h = rb_entry(nd, struct hist_entry, rb_node);
1965d0506edbSNamhyung Kim 			if (h->unfolded && h->leaf) {
1966aca7a94dSNamhyung Kim 				u16 remaining = h->nr_rows - h->row_offset;
1967aca7a94dSNamhyung Kim 				if (offset > remaining) {
1968aca7a94dSNamhyung Kim 					offset -= remaining;
1969aca7a94dSNamhyung Kim 					h->row_offset = 0;
1970aca7a94dSNamhyung Kim 				} else {
1971aca7a94dSNamhyung Kim 					h->row_offset += offset;
1972aca7a94dSNamhyung Kim 					offset = 0;
197305e8b080SArnaldo Carvalho de Melo 					browser->top = nd;
1974aca7a94dSNamhyung Kim 					break;
1975aca7a94dSNamhyung Kim 				}
1976aca7a94dSNamhyung Kim 			}
1977d0506edbSNamhyung Kim 			nd = hists__filter_entries(rb_hierarchy_next(nd),
1978d0506edbSNamhyung Kim 						   hb->min_pcnt);
1979aca7a94dSNamhyung Kim 			if (nd == NULL)
1980aca7a94dSNamhyung Kim 				break;
1981aca7a94dSNamhyung Kim 			--offset;
198205e8b080SArnaldo Carvalho de Melo 			browser->top = nd;
1983aca7a94dSNamhyung Kim 		} while (offset != 0);
1984aca7a94dSNamhyung Kim 	} else if (offset < 0) {
1985aca7a94dSNamhyung Kim 		while (1) {
1986aca7a94dSNamhyung Kim 			h = rb_entry(nd, struct hist_entry, rb_node);
1987d0506edbSNamhyung Kim 			if (h->unfolded && h->leaf) {
1988aca7a94dSNamhyung Kim 				if (first) {
1989aca7a94dSNamhyung Kim 					if (-offset > h->row_offset) {
1990aca7a94dSNamhyung Kim 						offset += h->row_offset;
1991aca7a94dSNamhyung Kim 						h->row_offset = 0;
1992aca7a94dSNamhyung Kim 					} else {
1993aca7a94dSNamhyung Kim 						h->row_offset += offset;
1994aca7a94dSNamhyung Kim 						offset = 0;
199505e8b080SArnaldo Carvalho de Melo 						browser->top = nd;
1996aca7a94dSNamhyung Kim 						break;
1997aca7a94dSNamhyung Kim 					}
1998aca7a94dSNamhyung Kim 				} else {
1999aca7a94dSNamhyung Kim 					if (-offset > h->nr_rows) {
2000aca7a94dSNamhyung Kim 						offset += h->nr_rows;
2001aca7a94dSNamhyung Kim 						h->row_offset = 0;
2002aca7a94dSNamhyung Kim 					} else {
2003aca7a94dSNamhyung Kim 						h->row_offset = h->nr_rows + offset;
2004aca7a94dSNamhyung Kim 						offset = 0;
200505e8b080SArnaldo Carvalho de Melo 						browser->top = nd;
2006aca7a94dSNamhyung Kim 						break;
2007aca7a94dSNamhyung Kim 					}
2008aca7a94dSNamhyung Kim 				}
2009aca7a94dSNamhyung Kim 			}
2010aca7a94dSNamhyung Kim 
2011d0506edbSNamhyung Kim 			nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
2012064f1981SNamhyung Kim 							hb->min_pcnt);
2013aca7a94dSNamhyung Kim 			if (nd == NULL)
2014aca7a94dSNamhyung Kim 				break;
2015aca7a94dSNamhyung Kim 			++offset;
201605e8b080SArnaldo Carvalho de Melo 			browser->top = nd;
2017aca7a94dSNamhyung Kim 			if (offset == 0) {
2018aca7a94dSNamhyung Kim 				/*
2019aca7a94dSNamhyung Kim 				 * Last unfiltered hist_entry, check if it is
2020aca7a94dSNamhyung Kim 				 * unfolded, if it is then we should have
2021aca7a94dSNamhyung Kim 				 * row_offset at its last entry.
2022aca7a94dSNamhyung Kim 				 */
2023aca7a94dSNamhyung Kim 				h = rb_entry(nd, struct hist_entry, rb_node);
2024d0506edbSNamhyung Kim 				if (h->unfolded && h->leaf)
2025aca7a94dSNamhyung Kim 					h->row_offset = h->nr_rows;
2026aca7a94dSNamhyung Kim 				break;
2027aca7a94dSNamhyung Kim 			}
2028aca7a94dSNamhyung Kim 			first = false;
2029aca7a94dSNamhyung Kim 		}
2030aca7a94dSNamhyung Kim 	} else {
203105e8b080SArnaldo Carvalho de Melo 		browser->top = nd;
2032aca7a94dSNamhyung Kim 		h = rb_entry(nd, struct hist_entry, rb_node);
2033aca7a94dSNamhyung Kim 		h->row_offset = 0;
2034aca7a94dSNamhyung Kim 	}
2035aca7a94dSNamhyung Kim }
2036aca7a94dSNamhyung Kim 
hist_browser__fprintf_callchain(struct hist_browser * browser,struct hist_entry * he,FILE * fp,int level)2037aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser,
2038d0506edbSNamhyung Kim 					   struct hist_entry *he, FILE *fp,
2039d0506edbSNamhyung Kim 					   int level)
2040aff3f3f6SArnaldo Carvalho de Melo {
204139ee533fSNamhyung Kim 	struct callchain_print_arg arg  = {
204239ee533fSNamhyung Kim 		.fp = fp,
204339ee533fSNamhyung Kim 	};
2044aff3f3f6SArnaldo Carvalho de Melo 
2045d0506edbSNamhyung Kim 	hist_browser__show_callchain(browser, he, level, 0,
204639ee533fSNamhyung Kim 				     hist_browser__fprintf_callchain_entry, &arg,
204739ee533fSNamhyung Kim 				     hist_browser__check_dump_full);
204839ee533fSNamhyung Kim 	return arg.printed;
2049aff3f3f6SArnaldo Carvalho de Melo }
2050aff3f3f6SArnaldo Carvalho de Melo 
hist_browser__fprintf_entry(struct hist_browser * browser,struct hist_entry * he,FILE * fp)2051aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser,
2052aff3f3f6SArnaldo Carvalho de Melo 				       struct hist_entry *he, FILE *fp)
2053aff3f3f6SArnaldo Carvalho de Melo {
2054aff3f3f6SArnaldo Carvalho de Melo 	char s[8192];
2055aff3f3f6SArnaldo Carvalho de Melo 	int printed = 0;
2056aff3f3f6SArnaldo Carvalho de Melo 	char folded_sign = ' ';
205726d8b338SNamhyung Kim 	struct perf_hpp hpp = {
205826d8b338SNamhyung Kim 		.buf = s,
205926d8b338SNamhyung Kim 		.size = sizeof(s),
206026d8b338SNamhyung Kim 	};
206126d8b338SNamhyung Kim 	struct perf_hpp_fmt *fmt;
206226d8b338SNamhyung Kim 	bool first = true;
206326d8b338SNamhyung Kim 	int ret;
2064aff3f3f6SArnaldo Carvalho de Melo 
2065fabd37b8SArnaldo Carvalho de Melo 	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
2066aff3f3f6SArnaldo Carvalho de Melo 		folded_sign = hist_entry__folded(he);
2067aff3f3f6SArnaldo Carvalho de Melo 		printed += fprintf(fp, "%c ", folded_sign);
20681b6b678eSArnaldo Carvalho de Melo 	}
2069aff3f3f6SArnaldo Carvalho de Melo 
2070f0786af5SJiri Olsa 	hists__for_each_format(browser->hists, fmt) {
2071361459f1SNamhyung Kim 		if (perf_hpp__should_skip(fmt, he->hists))
2072e67d49a7SNamhyung Kim 			continue;
2073e67d49a7SNamhyung Kim 
207426d8b338SNamhyung Kim 		if (!first) {
207526d8b338SNamhyung Kim 			ret = scnprintf(hpp.buf, hpp.size, "  ");
207626d8b338SNamhyung Kim 			advance_hpp(&hpp, ret);
207726d8b338SNamhyung Kim 		} else
207826d8b338SNamhyung Kim 			first = false;
2079aff3f3f6SArnaldo Carvalho de Melo 
208026d8b338SNamhyung Kim 		ret = fmt->entry(fmt, &hpp, he);
208189fee709SArnaldo Carvalho de Melo 		ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
208226d8b338SNamhyung Kim 		advance_hpp(&hpp, ret);
208326d8b338SNamhyung Kim 	}
208489fee709SArnaldo Carvalho de Melo 	printed += fprintf(fp, "%s\n", s);
2085aff3f3f6SArnaldo Carvalho de Melo 
2086aff3f3f6SArnaldo Carvalho de Melo 	if (folded_sign == '-')
2087d0506edbSNamhyung Kim 		printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2088d0506edbSNamhyung Kim 
2089d0506edbSNamhyung Kim 	return printed;
2090d0506edbSNamhyung Kim }
2091d0506edbSNamhyung Kim 
2092d0506edbSNamhyung Kim 
hist_browser__fprintf_hierarchy_entry(struct hist_browser * browser,struct hist_entry * he,FILE * fp,int level)2093d0506edbSNamhyung Kim static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2094d0506edbSNamhyung Kim 						 struct hist_entry *he,
2095325a6283SNamhyung Kim 						 FILE *fp, int level)
2096d0506edbSNamhyung Kim {
2097d0506edbSNamhyung Kim 	char s[8192];
2098d0506edbSNamhyung Kim 	int printed = 0;
2099d0506edbSNamhyung Kim 	char folded_sign = ' ';
2100d0506edbSNamhyung Kim 	struct perf_hpp hpp = {
2101d0506edbSNamhyung Kim 		.buf = s,
2102d0506edbSNamhyung Kim 		.size = sizeof(s),
2103d0506edbSNamhyung Kim 	};
2104d0506edbSNamhyung Kim 	struct perf_hpp_fmt *fmt;
2105325a6283SNamhyung Kim 	struct perf_hpp_list_node *fmt_node;
2106d0506edbSNamhyung Kim 	bool first = true;
2107d0506edbSNamhyung Kim 	int ret;
2108325a6283SNamhyung Kim 	int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
2109d0506edbSNamhyung Kim 
2110d0506edbSNamhyung Kim 	printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2111d0506edbSNamhyung Kim 
2112d0506edbSNamhyung Kim 	folded_sign = hist_entry__folded(he);
2113d0506edbSNamhyung Kim 	printed += fprintf(fp, "%c", folded_sign);
2114d0506edbSNamhyung Kim 
2115325a6283SNamhyung Kim 	/* the first hpp_list_node is for overhead columns */
2116325a6283SNamhyung Kim 	fmt_node = list_first_entry(&he->hists->hpp_formats,
2117325a6283SNamhyung Kim 				    struct perf_hpp_list_node, list);
2118325a6283SNamhyung Kim 	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
2119d0506edbSNamhyung Kim 		if (!first) {
2120d0506edbSNamhyung Kim 			ret = scnprintf(hpp.buf, hpp.size, "  ");
2121d0506edbSNamhyung Kim 			advance_hpp(&hpp, ret);
2122d0506edbSNamhyung Kim 		} else
2123d0506edbSNamhyung Kim 			first = false;
2124d0506edbSNamhyung Kim 
2125d0506edbSNamhyung Kim 		ret = fmt->entry(fmt, &hpp, he);
2126d0506edbSNamhyung Kim 		advance_hpp(&hpp, ret);
2127d0506edbSNamhyung Kim 	}
2128d0506edbSNamhyung Kim 
2129d0506edbSNamhyung Kim 	ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2130d0506edbSNamhyung Kim 	advance_hpp(&hpp, ret);
2131d0506edbSNamhyung Kim 
21321b2dbbf4SNamhyung Kim 	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
21331b2dbbf4SNamhyung Kim 		ret = scnprintf(hpp.buf, hpp.size, "  ");
21341b2dbbf4SNamhyung Kim 		advance_hpp(&hpp, ret);
21351b2dbbf4SNamhyung Kim 
2136d0506edbSNamhyung Kim 		ret = fmt->entry(fmt, &hpp, he);
2137d0506edbSNamhyung Kim 		advance_hpp(&hpp, ret);
21381b2dbbf4SNamhyung Kim 	}
2139d0506edbSNamhyung Kim 
214013c230abSArnaldo Carvalho de Melo 	strim(s);
214113c230abSArnaldo Carvalho de Melo 	printed += fprintf(fp, "%s\n", s);
2142d0506edbSNamhyung Kim 
2143d0506edbSNamhyung Kim 	if (he->leaf && folded_sign == '-') {
2144d0506edbSNamhyung Kim 		printed += hist_browser__fprintf_callchain(browser, he, fp,
2145d0506edbSNamhyung Kim 							   he->depth + 1);
2146d0506edbSNamhyung Kim 	}
2147aff3f3f6SArnaldo Carvalho de Melo 
2148aff3f3f6SArnaldo Carvalho de Melo 	return printed;
2149aff3f3f6SArnaldo Carvalho de Melo }
2150aff3f3f6SArnaldo Carvalho de Melo 
hist_browser__fprintf(struct hist_browser * browser,FILE * fp)2151aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2152aff3f3f6SArnaldo Carvalho de Melo {
2153064f1981SNamhyung Kim 	struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
2154064f1981SNamhyung Kim 						   browser->min_pcnt);
2155aff3f3f6SArnaldo Carvalho de Melo 	int printed = 0;
2156aff3f3f6SArnaldo Carvalho de Melo 
2157aff3f3f6SArnaldo Carvalho de Melo 	while (nd) {
2158aff3f3f6SArnaldo Carvalho de Melo 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2159aff3f3f6SArnaldo Carvalho de Melo 
2160d0506edbSNamhyung Kim 		if (symbol_conf.report_hierarchy) {
2161d0506edbSNamhyung Kim 			printed += hist_browser__fprintf_hierarchy_entry(browser,
2162d0506edbSNamhyung Kim 									 h, fp,
2163325a6283SNamhyung Kim 									 h->depth);
2164d0506edbSNamhyung Kim 		} else {
2165aff3f3f6SArnaldo Carvalho de Melo 			printed += hist_browser__fprintf_entry(browser, h, fp);
2166d0506edbSNamhyung Kim 		}
2167d0506edbSNamhyung Kim 
2168d0506edbSNamhyung Kim 		nd = hists__filter_entries(rb_hierarchy_next(nd),
2169d0506edbSNamhyung Kim 					   browser->min_pcnt);
2170aff3f3f6SArnaldo Carvalho de Melo 	}
2171aff3f3f6SArnaldo Carvalho de Melo 
2172aff3f3f6SArnaldo Carvalho de Melo 	return printed;
2173aff3f3f6SArnaldo Carvalho de Melo }
2174aff3f3f6SArnaldo Carvalho de Melo 
hist_browser__dump(struct hist_browser * browser)2175aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser)
2176aff3f3f6SArnaldo Carvalho de Melo {
2177aff3f3f6SArnaldo Carvalho de Melo 	char filename[64];
2178aff3f3f6SArnaldo Carvalho de Melo 	FILE *fp;
2179aff3f3f6SArnaldo Carvalho de Melo 
2180aff3f3f6SArnaldo Carvalho de Melo 	while (1) {
2181aff3f3f6SArnaldo Carvalho de Melo 		scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2182aff3f3f6SArnaldo Carvalho de Melo 		if (access(filename, F_OK))
2183aff3f3f6SArnaldo Carvalho de Melo 			break;
2184aff3f3f6SArnaldo Carvalho de Melo 		/*
2185aff3f3f6SArnaldo Carvalho de Melo  		 * XXX: Just an arbitrary lazy upper limit
2186aff3f3f6SArnaldo Carvalho de Melo  		 */
2187aff3f3f6SArnaldo Carvalho de Melo 		if (++browser->print_seq == 8192) {
2188aff3f3f6SArnaldo Carvalho de Melo 			ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2189aff3f3f6SArnaldo Carvalho de Melo 			return -1;
2190aff3f3f6SArnaldo Carvalho de Melo 		}
2191aff3f3f6SArnaldo Carvalho de Melo 	}
2192aff3f3f6SArnaldo Carvalho de Melo 
2193aff3f3f6SArnaldo Carvalho de Melo 	fp = fopen(filename, "w");
2194aff3f3f6SArnaldo Carvalho de Melo 	if (fp == NULL) {
2195aff3f3f6SArnaldo Carvalho de Melo 		char bf[64];
2196c8b5f2c9SArnaldo Carvalho de Melo 		const char *err = str_error_r(errno, bf, sizeof(bf));
21974cc49d4dSKirill A. Shutemov 		ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
2198aff3f3f6SArnaldo Carvalho de Melo 		return -1;
2199aff3f3f6SArnaldo Carvalho de Melo 	}
2200aff3f3f6SArnaldo Carvalho de Melo 
2201aff3f3f6SArnaldo Carvalho de Melo 	++browser->print_seq;
2202aff3f3f6SArnaldo Carvalho de Melo 	hist_browser__fprintf(browser, fp);
2203aff3f3f6SArnaldo Carvalho de Melo 	fclose(fp);
2204aff3f3f6SArnaldo Carvalho de Melo 	ui_helpline__fpush("%s written!", filename);
2205aff3f3f6SArnaldo Carvalho de Melo 
2206aff3f3f6SArnaldo Carvalho de Melo 	return 0;
2207aff3f3f6SArnaldo Carvalho de Melo }
2208aff3f3f6SArnaldo Carvalho de Melo 
hist_browser__init(struct hist_browser * browser,struct hists * hists)2209fcd86426SJiri Olsa void hist_browser__init(struct hist_browser *browser,
2210fcd86426SJiri Olsa 			struct hists *hists)
2211aca7a94dSNamhyung Kim {
2212b1c7a8f7SJiri Olsa 	struct perf_hpp_fmt *fmt;
2213b1c7a8f7SJiri Olsa 
221405e8b080SArnaldo Carvalho de Melo 	browser->hists			= hists;
221505e8b080SArnaldo Carvalho de Melo 	browser->b.refresh		= hist_browser__refresh;
2216357cfff1SArnaldo Carvalho de Melo 	browser->b.refresh_dimensions	= hist_browser__refresh_dimensions;
221705e8b080SArnaldo Carvalho de Melo 	browser->b.seek			= ui_browser__hists_seek;
221805e8b080SArnaldo Carvalho de Melo 	browser->b.use_navkeypressed	= true;
2219c8302367SJiri Olsa 	browser->show_headers		= symbol_conf.show_hist_headers;
2220ef9ff601SArnaldo Carvalho de Melo 	hist_browser__set_title_space(browser);
2221b1c7a8f7SJiri Olsa 
22228a06b0beSNamhyung Kim 	if (symbol_conf.report_hierarchy) {
22238a06b0beSNamhyung Kim 		struct perf_hpp_list_node *fmt_node;
22248a06b0beSNamhyung Kim 
22258a06b0beSNamhyung Kim 		/* count overhead columns (in the first node) */
22268a06b0beSNamhyung Kim 		fmt_node = list_first_entry(&hists->hpp_formats,
22278a06b0beSNamhyung Kim 					    struct perf_hpp_list_node, list);
22288a06b0beSNamhyung Kim 		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
22298a06b0beSNamhyung Kim 			++browser->b.columns;
22308a06b0beSNamhyung Kim 
22318a06b0beSNamhyung Kim 		/* add a single column for whole hierarchy sort keys*/
22328a06b0beSNamhyung Kim 		++browser->b.columns;
22338a06b0beSNamhyung Kim 	} else {
2234e3b60bc9SNamhyung Kim 		hists__for_each_format(hists, fmt)
2235b1c7a8f7SJiri Olsa 			++browser->b.columns;
22368a06b0beSNamhyung Kim 	}
2237e3b60bc9SNamhyung Kim 
2238e3b60bc9SNamhyung Kim 	hists__reset_column_width(hists);
2239aca7a94dSNamhyung Kim }
2240aca7a94dSNamhyung Kim 
hist_browser__new(struct hists * hists)2241fcd86426SJiri Olsa struct hist_browser *hist_browser__new(struct hists *hists)
2242fcd86426SJiri Olsa {
2243fcd86426SJiri Olsa 	struct hist_browser *browser = zalloc(sizeof(*browser));
2244fcd86426SJiri Olsa 
2245fcd86426SJiri Olsa 	if (browser)
2246fcd86426SJiri Olsa 		hist_browser__init(browser, hists);
2247fcd86426SJiri Olsa 
224805e8b080SArnaldo Carvalho de Melo 	return browser;
2249aca7a94dSNamhyung Kim }
2250aca7a94dSNamhyung Kim 
2251a6ec894dSJiri Olsa static struct hist_browser *
perf_evsel_browser__new(struct evsel * evsel,struct hist_browser_timer * hbt,struct perf_env * env)225232dcd021SJiri Olsa perf_evsel_browser__new(struct evsel *evsel,
2253a6ec894dSJiri Olsa 			struct hist_browser_timer *hbt,
225422197fb2SNamhyung Kim 			struct perf_env *env)
2255a6ec894dSJiri Olsa {
2256a6ec894dSJiri Olsa 	struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2257a6ec894dSJiri Olsa 
2258a6ec894dSJiri Olsa 	if (browser) {
2259a6ec894dSJiri Olsa 		browser->hbt   = hbt;
2260a6ec894dSJiri Olsa 		browser->env   = env;
2261f016d24aSArnaldo Carvalho de Melo 		browser->title = hists_browser__scnprintf_title;
2262a6ec894dSJiri Olsa 	}
2263a6ec894dSJiri Olsa 	return browser;
2264a6ec894dSJiri Olsa }
2265a6ec894dSJiri Olsa 
hist_browser__delete(struct hist_browser * browser)2266dabd2012SJiri Olsa void hist_browser__delete(struct hist_browser *browser)
2267aca7a94dSNamhyung Kim {
226805e8b080SArnaldo Carvalho de Melo 	free(browser);
2269aca7a94dSNamhyung Kim }
2270aca7a94dSNamhyung Kim 
hist_browser__selected_entry(struct hist_browser * browser)227105e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
2272aca7a94dSNamhyung Kim {
227305e8b080SArnaldo Carvalho de Melo 	return browser->he_selection;
2274aca7a94dSNamhyung Kim }
2275aca7a94dSNamhyung Kim 
hist_browser__selected_thread(struct hist_browser * browser)227605e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
2277aca7a94dSNamhyung Kim {
227805e8b080SArnaldo Carvalho de Melo 	return browser->he_selection->thread;
2279aca7a94dSNamhyung Kim }
2280aca7a94dSNamhyung Kim 
hist_browser__selected_res_sample(struct hist_browser * browser)2281d61cbb85SWei Li static struct res_sample *hist_browser__selected_res_sample(struct hist_browser *browser)
2282d61cbb85SWei Li {
2283d61cbb85SWei Li 	return browser->he_selection ? browser->he_selection->res_samples : NULL;
2284d61cbb85SWei Li }
2285d61cbb85SWei Li 
22861e378ebdSTaeung Song /* Check whether the browser is for 'top' or 'report' */
is_report_browser(void * timer)22871e378ebdSTaeung Song static inline bool is_report_browser(void *timer)
22881e378ebdSTaeung Song {
22891e378ebdSTaeung Song 	return timer == NULL;
22901e378ebdSTaeung Song }
22911e378ebdSTaeung Song 
hists_browser__scnprintf_title(struct hist_browser * browser,char * bf,size_t size)2292967a464aSArnaldo Carvalho de Melo static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size)
2293967a464aSArnaldo Carvalho de Melo {
2294967a464aSArnaldo Carvalho de Melo 	struct hist_browser_timer *hbt = browser->hbt;
2295967a464aSArnaldo Carvalho de Melo 	int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt));
2296967a464aSArnaldo Carvalho de Melo 
22971e378ebdSTaeung Song 	if (!is_report_browser(hbt)) {
22981e378ebdSTaeung Song 		struct perf_top *top = hbt->arg;
22991e378ebdSTaeung Song 
2300d24e3c98SJiri Olsa 		printed += scnprintf(bf + printed, size - printed,
2301d24e3c98SJiri Olsa 				     " lost: %" PRIu64 "/%" PRIu64,
2302d24e3c98SJiri Olsa 				     top->lost, top->lost_total);
2303d24e3c98SJiri Olsa 
230497f7e0b3SJiri Olsa 		printed += scnprintf(bf + printed, size - printed,
230597f7e0b3SJiri Olsa 				     " drop: %" PRIu64 "/%" PRIu64,
230697f7e0b3SJiri Olsa 				     top->drop, top->drop_total);
230797f7e0b3SJiri Olsa 
23081e378ebdSTaeung Song 		if (top->zero)
23091e378ebdSTaeung Song 			printed += scnprintf(bf + printed, size - printed, " [z]");
23108aa5c8edSJiri Olsa 
23118aa5c8edSJiri Olsa 		perf_top__reset_sample_counters(top);
23121e378ebdSTaeung Song 	}
23131e378ebdSTaeung Song 
23148aa5c8edSJiri Olsa 
2315aca7a94dSNamhyung Kim 	return printed;
2316aca7a94dSNamhyung Kim }
2317aca7a94dSNamhyung Kim 
free_popup_options(char ** options,int n)2318aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n)
2319aca7a94dSNamhyung Kim {
2320aca7a94dSNamhyung Kim 	int i;
2321aca7a94dSNamhyung Kim 
232204662523SArnaldo Carvalho de Melo 	for (i = 0; i < n; ++i)
232304662523SArnaldo Carvalho de Melo 		zfree(&options[i]);
2324aca7a94dSNamhyung Kim }
2325aca7a94dSNamhyung Kim 
2326341487abSFeng Tang /*
2327341487abSFeng Tang  * Only runtime switching of perf data file will make "input_name" point
2328341487abSFeng Tang  * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2329341487abSFeng Tang  * whether we need to call free() for current "input_name" during the switch.
2330341487abSFeng Tang  */
2331341487abSFeng Tang static bool is_input_name_malloced = false;
2332341487abSFeng Tang 
switch_data_file(void)2333341487abSFeng Tang static int switch_data_file(void)
2334341487abSFeng Tang {
2335341487abSFeng Tang 	char *pwd, *options[32], *abs_path[32], *tmp;
2336341487abSFeng Tang 	DIR *pwd_dir;
2337341487abSFeng Tang 	int nr_options = 0, choice = -1, ret = -1;
2338341487abSFeng Tang 	struct dirent *dent;
2339341487abSFeng Tang 
2340341487abSFeng Tang 	pwd = getenv("PWD");
2341341487abSFeng Tang 	if (!pwd)
2342341487abSFeng Tang 		return ret;
2343341487abSFeng Tang 
2344341487abSFeng Tang 	pwd_dir = opendir(pwd);
2345341487abSFeng Tang 	if (!pwd_dir)
2346341487abSFeng Tang 		return ret;
2347341487abSFeng Tang 
2348341487abSFeng Tang 	memset(options, 0, sizeof(options));
23493ef5b402SChangbin Du 	memset(abs_path, 0, sizeof(abs_path));
2350341487abSFeng Tang 
2351341487abSFeng Tang 	while ((dent = readdir(pwd_dir))) {
2352341487abSFeng Tang 		char path[PATH_MAX];
2353341487abSFeng Tang 		u64 magic;
2354341487abSFeng Tang 		char *name = dent->d_name;
2355341487abSFeng Tang 		FILE *file;
2356341487abSFeng Tang 
2357341487abSFeng Tang 		if (!(dent->d_type == DT_REG))
2358341487abSFeng Tang 			continue;
2359341487abSFeng Tang 
2360341487abSFeng Tang 		snprintf(path, sizeof(path), "%s/%s", pwd, name);
2361341487abSFeng Tang 
2362341487abSFeng Tang 		file = fopen(path, "r");
2363341487abSFeng Tang 		if (!file)
2364341487abSFeng Tang 			continue;
2365341487abSFeng Tang 
2366341487abSFeng Tang 		if (fread(&magic, 1, 8, file) < 8)
2367341487abSFeng Tang 			goto close_file_and_continue;
2368341487abSFeng Tang 
2369341487abSFeng Tang 		if (is_perf_magic(magic)) {
2370341487abSFeng Tang 			options[nr_options] = strdup(name);
2371341487abSFeng Tang 			if (!options[nr_options])
2372341487abSFeng Tang 				goto close_file_and_continue;
2373341487abSFeng Tang 
2374341487abSFeng Tang 			abs_path[nr_options] = strdup(path);
2375341487abSFeng Tang 			if (!abs_path[nr_options]) {
237674cf249dSArnaldo Carvalho de Melo 				zfree(&options[nr_options]);
2377341487abSFeng Tang 				ui__warning("Can't search all data files due to memory shortage.\n");
2378341487abSFeng Tang 				fclose(file);
2379341487abSFeng Tang 				break;
2380341487abSFeng Tang 			}
2381341487abSFeng Tang 
2382341487abSFeng Tang 			nr_options++;
2383341487abSFeng Tang 		}
2384341487abSFeng Tang 
2385341487abSFeng Tang close_file_and_continue:
2386341487abSFeng Tang 		fclose(file);
2387341487abSFeng Tang 		if (nr_options >= 32) {
2388341487abSFeng Tang 			ui__warning("Too many perf data files in PWD!\n"
2389341487abSFeng Tang 				    "Only the first 32 files will be listed.\n");
2390341487abSFeng Tang 			break;
2391341487abSFeng Tang 		}
2392341487abSFeng Tang 	}
2393341487abSFeng Tang 	closedir(pwd_dir);
2394341487abSFeng Tang 
2395341487abSFeng Tang 	if (nr_options) {
2396d0712656SArnaldo Carvalho de Melo 		choice = ui__popup_menu(nr_options, options, NULL);
2397341487abSFeng Tang 		if (choice < nr_options && choice >= 0) {
2398341487abSFeng Tang 			tmp = strdup(abs_path[choice]);
2399341487abSFeng Tang 			if (tmp) {
2400341487abSFeng Tang 				if (is_input_name_malloced)
2401341487abSFeng Tang 					free((void *)input_name);
2402341487abSFeng Tang 				input_name = tmp;
2403341487abSFeng Tang 				is_input_name_malloced = true;
2404341487abSFeng Tang 				ret = 0;
2405341487abSFeng Tang 			} else
2406341487abSFeng Tang 				ui__warning("Data switch failed due to memory shortage!\n");
2407341487abSFeng Tang 		}
2408341487abSFeng Tang 	}
2409341487abSFeng Tang 
2410341487abSFeng Tang 	free_popup_options(options, nr_options);
2411341487abSFeng Tang 	free_popup_options(abs_path, nr_options);
2412341487abSFeng Tang 	return ret;
2413341487abSFeng Tang }
2414341487abSFeng Tang 
2415ea7cd592SNamhyung Kim struct popup_action {
24161d6c49dfSAndi Kleen 	unsigned long		time;
2417ea7cd592SNamhyung Kim 	struct thread 		*thread;
241851e9ea99SIan Rogers 	struct evsel	*evsel;
241951e9ea99SIan Rogers 	int (*fn)(struct hist_browser *browser, struct popup_action *act);
2420ea7cd592SNamhyung Kim 	struct map_symbol 	ms;
242184734b06SKan Liang 	int			socket;
24224968ac8fSAndi Kleen 	enum rstype		rstype;
2423ea7cd592SNamhyung Kim 
2424ea7cd592SNamhyung Kim };
2425ea7cd592SNamhyung Kim 
2426bc7cad42SNamhyung Kim static int
do_annotate(struct hist_browser * browser,struct popup_action * act)2427ea7cd592SNamhyung Kim do_annotate(struct hist_browser *browser, struct popup_action *act)
2428bc7cad42SNamhyung Kim {
242932dcd021SJiri Olsa 	struct evsel *evsel;
2430bc7cad42SNamhyung Kim 	struct annotation *notes;
2431bc7cad42SNamhyung Kim 	struct hist_entry *he;
2432bc7cad42SNamhyung Kim 	int err;
2433bc7cad42SNamhyung Kim 
243422197fb2SNamhyung Kim 	if (!annotate_opts.objdump_path &&
243522197fb2SNamhyung Kim 	    perf_env__lookup_objdump(browser->env, &annotate_opts.objdump_path))
2436bc7cad42SNamhyung Kim 		return 0;
2437bc7cad42SNamhyung Kim 
2438ea7cd592SNamhyung Kim 	notes = symbol__annotation(act->ms.sym);
2439bc7cad42SNamhyung Kim 	if (!notes->src)
2440bc7cad42SNamhyung Kim 		return 0;
2441bc7cad42SNamhyung Kim 
2442848a5e50SJin Yao 	if (browser->block_evsel)
2443848a5e50SJin Yao 		evsel = browser->block_evsel;
2444848a5e50SJin Yao 	else
2445bc7cad42SNamhyung Kim 		evsel = hists_to_evsel(browser->hists);
2446848a5e50SJin Yao 
244722197fb2SNamhyung Kim 	err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
2448bc7cad42SNamhyung Kim 	he = hist_browser__selected_entry(browser);
2449bc7cad42SNamhyung Kim 	/*
2450bc7cad42SNamhyung Kim 	 * offer option to annotate the other branch source or target
2451bc7cad42SNamhyung Kim 	 * (if they exists) when returning from annotate
2452bc7cad42SNamhyung Kim 	 */
2453bc7cad42SNamhyung Kim 	if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2454bc7cad42SNamhyung Kim 		return 1;
2455bc7cad42SNamhyung Kim 
2456bc7cad42SNamhyung Kim 	ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2457bc7cad42SNamhyung Kim 	if (err)
2458bc7cad42SNamhyung Kim 		ui_browser__handle_resize(&browser->b);
2459bc7cad42SNamhyung Kim 	return 0;
2460bc7cad42SNamhyung Kim }
2461bc7cad42SNamhyung Kim 
symbol__new_unresolved(u64 addr,struct map * map)24627b0a0dcbSJin Yao static struct symbol *symbol__new_unresolved(u64 addr, struct map *map)
24637b0a0dcbSJin Yao {
24647b0a0dcbSJin Yao 	struct annotated_source *src;
24657b0a0dcbSJin Yao 	struct symbol *sym;
24667b0a0dcbSJin Yao 	char name[64];
24677b0a0dcbSJin Yao 
24687b0a0dcbSJin Yao 	snprintf(name, sizeof(name), "%.*" PRIx64, BITS_PER_LONG / 4, addr);
24697b0a0dcbSJin Yao 
24707b0a0dcbSJin Yao 	sym = symbol__new(addr, ANNOTATION_DUMMY_LEN, 0, 0, name);
24717b0a0dcbSJin Yao 	if (sym) {
24727b0a0dcbSJin Yao 		src = symbol__hists(sym, 1);
24737b0a0dcbSJin Yao 		if (!src) {
24747b0a0dcbSJin Yao 			symbol__delete(sym);
24757b0a0dcbSJin Yao 			return NULL;
24767b0a0dcbSJin Yao 		}
24777b0a0dcbSJin Yao 
247863df0e4bSIan Rogers 		dso__insert_symbol(map__dso(map), sym);
24797b0a0dcbSJin Yao 	}
24807b0a0dcbSJin Yao 
24817b0a0dcbSJin Yao 	return sym;
24827b0a0dcbSJin Yao }
24837b0a0dcbSJin Yao 
2484bc7cad42SNamhyung Kim static int
add_annotate_opt(struct hist_browser * browser __maybe_unused,struct popup_action * act,char ** optstr,struct map_symbol * ms,u64 addr)2485ea7cd592SNamhyung Kim add_annotate_opt(struct hist_browser *browser __maybe_unused,
2486ea7cd592SNamhyung Kim 		 struct popup_action *act, char **optstr,
24877b0a0dcbSJin Yao 		 struct map_symbol *ms,
24887b0a0dcbSJin Yao 		 u64 addr)
2489bc7cad42SNamhyung Kim {
24903ad1be6fSArnaldo Carvalho de Melo 	struct dso *dso;
249163df0e4bSIan Rogers 
2492ee756ef7SIan Rogers 	if (!ms->map || (dso = map__dso(ms->map)) == NULL || dso__annotate_warned(dso))
24937b0a0dcbSJin Yao 		return 0;
24947b0a0dcbSJin Yao 
24957b0a0dcbSJin Yao 	if (!ms->sym)
24967b0a0dcbSJin Yao 		ms->sym = symbol__new_unresolved(addr, ms->map);
24977b0a0dcbSJin Yao 
24987b0a0dcbSJin Yao 	if (ms->sym == NULL || symbol__annotation(ms->sym)->src == NULL)
2499ea7cd592SNamhyung Kim 		return 0;
2500ea7cd592SNamhyung Kim 
2501d46a4cdfSArnaldo Carvalho de Melo 	if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0)
2502ea7cd592SNamhyung Kim 		return 0;
2503ea7cd592SNamhyung Kim 
2504d46a4cdfSArnaldo Carvalho de Melo 	act->ms = *ms;
2505ea7cd592SNamhyung Kim 	act->fn = do_annotate;
2506ea7cd592SNamhyung Kim 	return 1;
2507ea7cd592SNamhyung Kim }
2508ea7cd592SNamhyung Kim 
2509ea7cd592SNamhyung Kim static int
do_annotate_type(struct hist_browser * browser,struct popup_action * act)25100bfbe661SNamhyung Kim do_annotate_type(struct hist_browser *browser, struct popup_action *act)
25110bfbe661SNamhyung Kim {
25120bfbe661SNamhyung Kim 	struct hist_entry *he = browser->he_selection;
25130bfbe661SNamhyung Kim 
25140bfbe661SNamhyung Kim 	hist_entry__annotate_data_tui(he, act->evsel, browser->hbt);
25150bfbe661SNamhyung Kim 	ui_browser__handle_resize(&browser->b);
25160bfbe661SNamhyung Kim 	return 0;
25170bfbe661SNamhyung Kim }
25180bfbe661SNamhyung Kim 
25190bfbe661SNamhyung Kim static int
add_annotate_type_opt(struct hist_browser * browser,struct popup_action * act,char ** optstr,struct hist_entry * he)25200bfbe661SNamhyung Kim add_annotate_type_opt(struct hist_browser *browser,
25210bfbe661SNamhyung Kim 		      struct popup_action *act, char **optstr,
25220bfbe661SNamhyung Kim 		      struct hist_entry *he)
25230bfbe661SNamhyung Kim {
25240bfbe661SNamhyung Kim 	if (he == NULL || he->mem_type == NULL || he->mem_type->histograms == NULL)
25250bfbe661SNamhyung Kim 		return 0;
25260bfbe661SNamhyung Kim 
25270bfbe661SNamhyung Kim 	if (asprintf(optstr, "Annotate type %s", he->mem_type->self.type_name) < 0)
25280bfbe661SNamhyung Kim 		return 0;
25290bfbe661SNamhyung Kim 
25300bfbe661SNamhyung Kim 	act->evsel = hists_to_evsel(browser->hists);
25310bfbe661SNamhyung Kim 	act->fn = do_annotate_type;
25320bfbe661SNamhyung Kim 	return 1;
25330bfbe661SNamhyung Kim }
25340bfbe661SNamhyung Kim 
25350bfbe661SNamhyung Kim static int
do_zoom_thread(struct hist_browser * browser,struct popup_action * act)2536ea7cd592SNamhyung Kim do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2537ea7cd592SNamhyung Kim {
2538ea7cd592SNamhyung Kim 	struct thread *thread = act->thread;
2539ea7cd592SNamhyung Kim 
25407cecb7feSJiri Olsa 	if ((!hists__has(browser->hists, thread) &&
25417cecb7feSJiri Olsa 	     !hists__has(browser->hists, comm)) || thread == NULL)
2542599a2f38SNamhyung Kim 		return 0;
2543599a2f38SNamhyung Kim 
2544bc7cad42SNamhyung Kim 	if (browser->hists->thread_filter) {
2545bc7cad42SNamhyung Kim 		pstack__remove(browser->pstack, &browser->hists->thread_filter);
2546bc7cad42SNamhyung Kim 		perf_hpp__set_elide(HISTC_THREAD, false);
2547bc7cad42SNamhyung Kim 		thread__zput(browser->hists->thread_filter);
2548bc7cad42SNamhyung Kim 		ui_helpline__pop();
2549bc7cad42SNamhyung Kim 	} else {
2550ee84a303SIan Rogers 		const char *comm_set_str =
2551ee84a303SIan Rogers 			thread__comm_set(thread) ? thread__comm_str(thread) : "";
2552ee84a303SIan Rogers 
2553fa82911aSJiri Olsa 		if (hists__has(browser->hists, thread)) {
25547727a925SArnaldo Carvalho de Melo 			ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2555ee84a303SIan Rogers 					   comm_set_str, thread__tid(thread));
25566962ccb3SNamhyung Kim 		} else {
25576962ccb3SNamhyung Kim 			ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2558ee84a303SIan Rogers 					   comm_set_str);
25596962ccb3SNamhyung Kim 		}
25606962ccb3SNamhyung Kim 
2561bc7cad42SNamhyung Kim 		browser->hists->thread_filter = thread__get(thread);
2562bc7cad42SNamhyung Kim 		perf_hpp__set_elide(HISTC_THREAD, false);
2563bc7cad42SNamhyung Kim 		pstack__push(browser->pstack, &browser->hists->thread_filter);
2564bc7cad42SNamhyung Kim 	}
2565bc7cad42SNamhyung Kim 
2566bc7cad42SNamhyung Kim 	hists__filter_by_thread(browser->hists);
2567bc7cad42SNamhyung Kim 	hist_browser__reset(browser);
2568bc7cad42SNamhyung Kim 	return 0;
2569bc7cad42SNamhyung Kim }
2570bc7cad42SNamhyung Kim 
2571bc7cad42SNamhyung Kim static int
add_thread_opt(struct hist_browser * browser,struct popup_action * act,char ** optstr,struct thread * thread)2572ea7cd592SNamhyung Kim add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2573ea7cd592SNamhyung Kim 	       char **optstr, struct thread *thread)
2574bc7cad42SNamhyung Kim {
25756962ccb3SNamhyung Kim 	int ret;
2576ee84a303SIan Rogers 	const char *comm_set_str, *in_out;
25776962ccb3SNamhyung Kim 
25787cecb7feSJiri Olsa 	if ((!hists__has(browser->hists, thread) &&
25797cecb7feSJiri Olsa 	     !hists__has(browser->hists, comm)) || thread == NULL)
2580ea7cd592SNamhyung Kim 		return 0;
2581ea7cd592SNamhyung Kim 
2582ee84a303SIan Rogers 	in_out = browser->hists->thread_filter ? "out of" : "into";
2583ee84a303SIan Rogers 	comm_set_str = thread__comm_set(thread) ? thread__comm_str(thread) : "";
2584fa82911aSJiri Olsa 	if (hists__has(browser->hists, thread)) {
25856962ccb3SNamhyung Kim 		ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2586ee84a303SIan Rogers 			       in_out, comm_set_str, thread__tid(thread));
25876962ccb3SNamhyung Kim 	} else {
2588ee84a303SIan Rogers 		ret = asprintf(optstr, "Zoom %s %s thread", in_out, comm_set_str);
25896962ccb3SNamhyung Kim 	}
25906962ccb3SNamhyung Kim 	if (ret < 0)
2591ea7cd592SNamhyung Kim 		return 0;
2592ea7cd592SNamhyung Kim 
2593ea7cd592SNamhyung Kim 	act->thread = thread;
2594ea7cd592SNamhyung Kim 	act->fn = do_zoom_thread;
2595ea7cd592SNamhyung Kim 	return 1;
2596ea7cd592SNamhyung Kim }
2597ea7cd592SNamhyung Kim 
hists_browser__zoom_map(struct hist_browser * browser,struct map * map)2598632003f4SArnaldo Carvalho de Melo static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map)
2599ea7cd592SNamhyung Kim {
260069849fc5SJiri Olsa 	if (!hists__has(browser->hists, dso) || map == NULL)
2601599a2f38SNamhyung Kim 		return 0;
2602599a2f38SNamhyung Kim 
2603bc7cad42SNamhyung Kim 	if (browser->hists->dso_filter) {
2604bc7cad42SNamhyung Kim 		pstack__remove(browser->pstack, &browser->hists->dso_filter);
2605bc7cad42SNamhyung Kim 		perf_hpp__set_elide(HISTC_DSO, false);
2606bc7cad42SNamhyung Kim 		browser->hists->dso_filter = NULL;
2607bc7cad42SNamhyung Kim 		ui_helpline__pop();
2608bc7cad42SNamhyung Kim 	} else {
260963df0e4bSIan Rogers 		struct dso *dso = map__dso(map);
26107727a925SArnaldo Carvalho de Melo 		ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
2611ee756ef7SIan Rogers 				   __map__is_kernel(map) ? "the Kernel" : dso__short_name(dso));
261263df0e4bSIan Rogers 		browser->hists->dso_filter = dso;
2613bc7cad42SNamhyung Kim 		perf_hpp__set_elide(HISTC_DSO, true);
2614bc7cad42SNamhyung Kim 		pstack__push(browser->pstack, &browser->hists->dso_filter);
2615bc7cad42SNamhyung Kim 	}
2616bc7cad42SNamhyung Kim 
2617bc7cad42SNamhyung Kim 	hists__filter_by_dso(browser->hists);
2618bc7cad42SNamhyung Kim 	hist_browser__reset(browser);
2619bc7cad42SNamhyung Kim 	return 0;
2620bc7cad42SNamhyung Kim }
2621bc7cad42SNamhyung Kim 
2622bc7cad42SNamhyung Kim static int
do_zoom_dso(struct hist_browser * browser,struct popup_action * act)2623632003f4SArnaldo Carvalho de Melo do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2624632003f4SArnaldo Carvalho de Melo {
2625632003f4SArnaldo Carvalho de Melo 	return hists_browser__zoom_map(browser, act->ms.map);
2626632003f4SArnaldo Carvalho de Melo }
2627632003f4SArnaldo Carvalho de Melo 
2628632003f4SArnaldo Carvalho de Melo static int
add_dso_opt(struct hist_browser * browser,struct popup_action * act,char ** optstr,struct map * map)2629ea7cd592SNamhyung Kim add_dso_opt(struct hist_browser *browser, struct popup_action *act,
2630045b80ddSArnaldo Carvalho de Melo 	    char **optstr, struct map *map)
2631bc7cad42SNamhyung Kim {
263269849fc5SJiri Olsa 	if (!hists__has(browser->hists, dso) || map == NULL)
2633ea7cd592SNamhyung Kim 		return 0;
2634ea7cd592SNamhyung Kim 
2635209f4e70SArnaldo Carvalho de Melo 	if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)",
2636ea7cd592SNamhyung Kim 		     browser->hists->dso_filter ? "out of" : "into",
2637ee756ef7SIan Rogers 		     __map__is_kernel(map) ? "the Kernel" : dso__short_name(map__dso(map))) < 0)
2638ea7cd592SNamhyung Kim 		return 0;
2639ea7cd592SNamhyung Kim 
2640045b80ddSArnaldo Carvalho de Melo 	act->ms.map = map;
2641ea7cd592SNamhyung Kim 	act->fn = do_zoom_dso;
2642ea7cd592SNamhyung Kim 	return 1;
2643ea7cd592SNamhyung Kim }
2644ea7cd592SNamhyung Kim 
do_toggle_callchain(struct hist_browser * browser,struct popup_action * act __maybe_unused)2645d5a599d9SArnaldo Carvalho de Melo static int do_toggle_callchain(struct hist_browser *browser, struct popup_action *act __maybe_unused)
2646d5a599d9SArnaldo Carvalho de Melo {
2647d5a599d9SArnaldo Carvalho de Melo 	hist_browser__toggle_fold(browser);
2648d5a599d9SArnaldo Carvalho de Melo 	return 0;
2649d5a599d9SArnaldo Carvalho de Melo }
2650d5a599d9SArnaldo Carvalho de Melo 
add_callchain_toggle_opt(struct hist_browser * browser,struct popup_action * act,char ** optstr)2651d5a599d9SArnaldo Carvalho de Melo static int add_callchain_toggle_opt(struct hist_browser *browser, struct popup_action *act, char **optstr)
2652d5a599d9SArnaldo Carvalho de Melo {
2653bdc633feSArnaldo Carvalho de Melo 	char sym_name[512];
2654d5a599d9SArnaldo Carvalho de Melo 
2655bdc633feSArnaldo Carvalho de Melo         if (!hist_browser__selection_has_children(browser))
2656d5a599d9SArnaldo Carvalho de Melo                 return 0;
2657d5a599d9SArnaldo Carvalho de Melo 
2658bdc633feSArnaldo Carvalho de Melo 	if (asprintf(optstr, "%s [%s] callchain (one level, same as '+' hotkey, use 'e'/'c' for the whole main level entry)",
2659bdc633feSArnaldo Carvalho de Melo 		     hist_browser__selection_unfolded(browser) ? "Collapse" : "Expand",
2660bdc633feSArnaldo Carvalho de Melo 		     hist_browser__selection_sym_name(browser, sym_name, sizeof(sym_name))) < 0)
2661d5a599d9SArnaldo Carvalho de Melo 		return 0;
2662d5a599d9SArnaldo Carvalho de Melo 
2663d5a599d9SArnaldo Carvalho de Melo 	act->fn = do_toggle_callchain;
2664d5a599d9SArnaldo Carvalho de Melo 	return 1;
2665d5a599d9SArnaldo Carvalho de Melo }
2666d5a599d9SArnaldo Carvalho de Melo 
2667ea7cd592SNamhyung Kim static int
do_browse_map(struct hist_browser * browser __maybe_unused,struct popup_action * act)2668ea7cd592SNamhyung Kim do_browse_map(struct hist_browser *browser __maybe_unused,
2669ea7cd592SNamhyung Kim 	      struct popup_action *act)
2670ea7cd592SNamhyung Kim {
2671ea7cd592SNamhyung Kim 	map__browse(act->ms.map);
2672bc7cad42SNamhyung Kim 	return 0;
2673bc7cad42SNamhyung Kim }
2674bc7cad42SNamhyung Kim 
2675bc7cad42SNamhyung Kim static int
add_map_opt(struct hist_browser * browser,struct popup_action * act,char ** optstr,struct map * map)267669849fc5SJiri Olsa add_map_opt(struct hist_browser *browser,
2677ea7cd592SNamhyung Kim 	    struct popup_action *act, char **optstr, struct map *map)
2678ea7cd592SNamhyung Kim {
267969849fc5SJiri Olsa 	if (!hists__has(browser->hists, dso) || map == NULL)
2680ea7cd592SNamhyung Kim 		return 0;
2681ea7cd592SNamhyung Kim 
2682ea7cd592SNamhyung Kim 	if (asprintf(optstr, "Browse map details") < 0)
2683ea7cd592SNamhyung Kim 		return 0;
2684ea7cd592SNamhyung Kim 
2685ea7cd592SNamhyung Kim 	act->ms.map = map;
2686ea7cd592SNamhyung Kim 	act->fn = do_browse_map;
2687ea7cd592SNamhyung Kim 	return 1;
2688ea7cd592SNamhyung Kim }
2689ea7cd592SNamhyung Kim 
2690ea7cd592SNamhyung Kim static int
do_run_script(struct hist_browser * browser __maybe_unused,struct popup_action * act)2691bc7cad42SNamhyung Kim do_run_script(struct hist_browser *browser __maybe_unused,
2692ea7cd592SNamhyung Kim 	      struct popup_action *act)
2693bc7cad42SNamhyung Kim {
26941d6c49dfSAndi Kleen 	char *script_opt;
26951d6c49dfSAndi Kleen 	int len;
26961d6c49dfSAndi Kleen 	int n = 0;
2697bc7cad42SNamhyung Kim 
26981d6c49dfSAndi Kleen 	len = 100;
26991d6c49dfSAndi Kleen 	if (act->thread)
27001d6c49dfSAndi Kleen 		len += strlen(thread__comm_str(act->thread));
27011d6c49dfSAndi Kleen 	else if (act->ms.sym)
27021d6c49dfSAndi Kleen 		len += strlen(act->ms.sym->name);
27031d6c49dfSAndi Kleen 	script_opt = malloc(len);
27041d6c49dfSAndi Kleen 	if (!script_opt)
27051d6c49dfSAndi Kleen 		return -1;
27061d6c49dfSAndi Kleen 
27071d6c49dfSAndi Kleen 	script_opt[0] = 0;
2708ea7cd592SNamhyung Kim 	if (act->thread) {
27091d6c49dfSAndi Kleen 		n = scnprintf(script_opt, len, " -c %s ",
2710ea7cd592SNamhyung Kim 			  thread__comm_str(act->thread));
2711ea7cd592SNamhyung Kim 	} else if (act->ms.sym) {
27121d6c49dfSAndi Kleen 		n = scnprintf(script_opt, len, " -S %s ",
2713ea7cd592SNamhyung Kim 			  act->ms.sym->name);
2714bc7cad42SNamhyung Kim 	}
2715bc7cad42SNamhyung Kim 
27161d6c49dfSAndi Kleen 	if (act->time) {
27171d6c49dfSAndi Kleen 		char start[32], end[32];
27181d6c49dfSAndi Kleen 		unsigned long starttime = act->time;
27191d6c49dfSAndi Kleen 		unsigned long endtime = act->time + symbol_conf.time_quantum;
27201d6c49dfSAndi Kleen 
27211d6c49dfSAndi Kleen 		if (starttime == endtime) { /* Display 1ms as fallback */
27221d6c49dfSAndi Kleen 			starttime -= 1*NSEC_PER_MSEC;
27231d6c49dfSAndi Kleen 			endtime += 1*NSEC_PER_MSEC;
27241d6c49dfSAndi Kleen 		}
27251d6c49dfSAndi Kleen 		timestamp__scnprintf_usec(starttime, start, sizeof start);
27261d6c49dfSAndi Kleen 		timestamp__scnprintf_usec(endtime, end, sizeof end);
27271d6c49dfSAndi Kleen 		n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end);
27281d6c49dfSAndi Kleen 	}
27291d6c49dfSAndi Kleen 
27306f3da20eSAndi Kleen 	script_browse(script_opt, act->evsel);
27311d6c49dfSAndi Kleen 	free(script_opt);
2732bc7cad42SNamhyung Kim 	return 0;
2733bc7cad42SNamhyung Kim }
2734bc7cad42SNamhyung Kim 
2735bc7cad42SNamhyung Kim static int
do_res_sample_script(struct hist_browser * browser __maybe_unused,struct popup_action * act)27364968ac8fSAndi Kleen do_res_sample_script(struct hist_browser *browser __maybe_unused,
27374968ac8fSAndi Kleen 		     struct popup_action *act)
27384968ac8fSAndi Kleen {
27394968ac8fSAndi Kleen 	struct hist_entry *he;
27404968ac8fSAndi Kleen 
27414968ac8fSAndi Kleen 	he = hist_browser__selected_entry(browser);
27424968ac8fSAndi Kleen 	res_sample_browse(he->res_samples, he->num_res, act->evsel, act->rstype);
27434968ac8fSAndi Kleen 	return 0;
27444968ac8fSAndi Kleen }
27454968ac8fSAndi Kleen 
27464968ac8fSAndi Kleen static int
add_script_opt_2(struct hist_browser * browser __maybe_unused,struct popup_action * act,char ** optstr,struct thread * thread,struct symbol * sym,struct evsel * evsel,const char * tstr)27471d6c49dfSAndi Kleen add_script_opt_2(struct hist_browser *browser __maybe_unused,
2748ea7cd592SNamhyung Kim 	       struct popup_action *act, char **optstr,
27491d6c49dfSAndi Kleen 	       struct thread *thread, struct symbol *sym,
275032dcd021SJiri Olsa 	       struct evsel *evsel, const char *tstr)
2751ea7cd592SNamhyung Kim {
27521d6c49dfSAndi Kleen 
2753ea7cd592SNamhyung Kim 	if (thread) {
27541d6c49dfSAndi Kleen 		if (asprintf(optstr, "Run scripts for samples of thread [%s]%s",
27551d6c49dfSAndi Kleen 			     thread__comm_str(thread), tstr) < 0)
2756ea7cd592SNamhyung Kim 			return 0;
2757ea7cd592SNamhyung Kim 	} else if (sym) {
27581d6c49dfSAndi Kleen 		if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s",
27591d6c49dfSAndi Kleen 			     sym->name, tstr) < 0)
2760ea7cd592SNamhyung Kim 			return 0;
2761ea7cd592SNamhyung Kim 	} else {
27621d6c49dfSAndi Kleen 		if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0)
2763ea7cd592SNamhyung Kim 			return 0;
2764ea7cd592SNamhyung Kim 	}
2765ea7cd592SNamhyung Kim 
2766ea7cd592SNamhyung Kim 	act->thread = thread;
2767ea7cd592SNamhyung Kim 	act->ms.sym = sym;
27686f3da20eSAndi Kleen 	act->evsel = evsel;
2769ea7cd592SNamhyung Kim 	act->fn = do_run_script;
2770ea7cd592SNamhyung Kim 	return 1;
2771ea7cd592SNamhyung Kim }
2772ea7cd592SNamhyung Kim 
2773ea7cd592SNamhyung Kim static int
add_script_opt(struct hist_browser * browser,struct popup_action * act,char ** optstr,struct thread * thread,struct symbol * sym,struct evsel * evsel)27741d6c49dfSAndi Kleen add_script_opt(struct hist_browser *browser,
27751d6c49dfSAndi Kleen 	       struct popup_action *act, char **optstr,
27766f3da20eSAndi Kleen 	       struct thread *thread, struct symbol *sym,
277732dcd021SJiri Olsa 	       struct evsel *evsel)
27781d6c49dfSAndi Kleen {
27791d6c49dfSAndi Kleen 	int n, j;
27801d6c49dfSAndi Kleen 	struct hist_entry *he;
27811d6c49dfSAndi Kleen 
27826f3da20eSAndi Kleen 	n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, "");
27831d6c49dfSAndi Kleen 
27841d6c49dfSAndi Kleen 	he = hist_browser__selected_entry(browser);
27851d6c49dfSAndi Kleen 	if (sort_order && strstr(sort_order, "time")) {
27861d6c49dfSAndi Kleen 		char tstr[128];
27871d6c49dfSAndi Kleen 
27881d6c49dfSAndi Kleen 		optstr++;
27891d6c49dfSAndi Kleen 		act++;
27901d6c49dfSAndi Kleen 		j = sprintf(tstr, " in ");
27911d6c49dfSAndi Kleen 		j += timestamp__scnprintf_usec(he->time, tstr + j,
27921d6c49dfSAndi Kleen 					       sizeof tstr - j);
27931d6c49dfSAndi Kleen 		j += sprintf(tstr + j, "-");
27941d6c49dfSAndi Kleen 		timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum,
27956f3da20eSAndi Kleen 				          tstr + j, sizeof tstr - j);
27961d6c49dfSAndi Kleen 		n += add_script_opt_2(browser, act, optstr, thread, sym,
27976f3da20eSAndi Kleen 					  evsel, tstr);
27981d6c49dfSAndi Kleen 		act->time = he->time;
27991d6c49dfSAndi Kleen 	}
28001d6c49dfSAndi Kleen 	return n;
28011d6c49dfSAndi Kleen }
28021d6c49dfSAndi Kleen 
28031d6c49dfSAndi Kleen static int
add_res_sample_opt(struct hist_browser * browser __maybe_unused,struct popup_action * act,char ** optstr,struct res_sample * res_sample,struct evsel * evsel,enum rstype type)28044968ac8fSAndi Kleen add_res_sample_opt(struct hist_browser *browser __maybe_unused,
28054968ac8fSAndi Kleen 		   struct popup_action *act, char **optstr,
28064968ac8fSAndi Kleen 		   struct res_sample *res_sample,
280732dcd021SJiri Olsa 		   struct evsel *evsel,
28084968ac8fSAndi Kleen 		   enum rstype type)
28094968ac8fSAndi Kleen {
28104968ac8fSAndi Kleen 	if (!res_sample)
28114968ac8fSAndi Kleen 		return 0;
28124968ac8fSAndi Kleen 
28134968ac8fSAndi Kleen 	if (asprintf(optstr, "Show context for individual samples %s",
28144968ac8fSAndi Kleen 		type == A_ASM ? "with assembler" :
28154968ac8fSAndi Kleen 		type == A_SOURCE ? "with source" : "") < 0)
28164968ac8fSAndi Kleen 		return 0;
28174968ac8fSAndi Kleen 
28184968ac8fSAndi Kleen 	act->fn = do_res_sample_script;
28194968ac8fSAndi Kleen 	act->evsel = evsel;
28204968ac8fSAndi Kleen 	act->rstype = type;
28214968ac8fSAndi Kleen 	return 1;
28224968ac8fSAndi Kleen }
28234968ac8fSAndi Kleen 
28244968ac8fSAndi Kleen static int
do_switch_data(struct hist_browser * browser __maybe_unused,struct popup_action * act __maybe_unused)2825ea7cd592SNamhyung Kim do_switch_data(struct hist_browser *browser __maybe_unused,
2826ea7cd592SNamhyung Kim 	       struct popup_action *act __maybe_unused)
2827bc7cad42SNamhyung Kim {
2828bc7cad42SNamhyung Kim 	if (switch_data_file()) {
2829bc7cad42SNamhyung Kim 		ui__warning("Won't switch the data files due to\n"
2830bc7cad42SNamhyung Kim 			    "no valid data file get selected!\n");
2831ea7cd592SNamhyung Kim 		return 0;
2832bc7cad42SNamhyung Kim 	}
2833bc7cad42SNamhyung Kim 
2834bc7cad42SNamhyung Kim 	return K_SWITCH_INPUT_DATA;
2835bc7cad42SNamhyung Kim }
2836bc7cad42SNamhyung Kim 
2837ea7cd592SNamhyung Kim static int
add_switch_opt(struct hist_browser * browser,struct popup_action * act,char ** optstr)2838ea7cd592SNamhyung Kim add_switch_opt(struct hist_browser *browser,
2839ea7cd592SNamhyung Kim 	       struct popup_action *act, char **optstr)
2840ea7cd592SNamhyung Kim {
2841ea7cd592SNamhyung Kim 	if (!is_report_browser(browser->hbt))
2842ea7cd592SNamhyung Kim 		return 0;
2843ea7cd592SNamhyung Kim 
2844ea7cd592SNamhyung Kim 	if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2845ea7cd592SNamhyung Kim 		return 0;
2846ea7cd592SNamhyung Kim 
2847ea7cd592SNamhyung Kim 	act->fn = do_switch_data;
2848ea7cd592SNamhyung Kim 	return 1;
2849ea7cd592SNamhyung Kim }
2850ea7cd592SNamhyung Kim 
2851ea7cd592SNamhyung Kim static int
do_exit_browser(struct hist_browser * browser __maybe_unused,struct popup_action * act __maybe_unused)2852ea7cd592SNamhyung Kim do_exit_browser(struct hist_browser *browser __maybe_unused,
2853ea7cd592SNamhyung Kim 		struct popup_action *act __maybe_unused)
2854ea7cd592SNamhyung Kim {
2855ea7cd592SNamhyung Kim 	return 0;
2856ea7cd592SNamhyung Kim }
2857ea7cd592SNamhyung Kim 
2858ea7cd592SNamhyung Kim static int
add_exit_opt(struct hist_browser * browser __maybe_unused,struct popup_action * act,char ** optstr)2859ea7cd592SNamhyung Kim add_exit_opt(struct hist_browser *browser __maybe_unused,
2860ea7cd592SNamhyung Kim 	     struct popup_action *act, char **optstr)
2861ea7cd592SNamhyung Kim {
2862ea7cd592SNamhyung Kim 	if (asprintf(optstr, "Exit") < 0)
2863ea7cd592SNamhyung Kim 		return 0;
2864ea7cd592SNamhyung Kim 
2865ea7cd592SNamhyung Kim 	act->fn = do_exit_browser;
2866ea7cd592SNamhyung Kim 	return 1;
2867ea7cd592SNamhyung Kim }
2868ea7cd592SNamhyung Kim 
286984734b06SKan Liang static int
do_zoom_socket(struct hist_browser * browser,struct popup_action * act)287084734b06SKan Liang do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
287184734b06SKan Liang {
287235a634f7SJiri Olsa 	if (!hists__has(browser->hists, socket) || act->socket < 0)
2873599a2f38SNamhyung Kim 		return 0;
2874599a2f38SNamhyung Kim 
287584734b06SKan Liang 	if (browser->hists->socket_filter > -1) {
287684734b06SKan Liang 		pstack__remove(browser->pstack, &browser->hists->socket_filter);
287784734b06SKan Liang 		browser->hists->socket_filter = -1;
287884734b06SKan Liang 		perf_hpp__set_elide(HISTC_SOCKET, false);
287984734b06SKan Liang 	} else {
288084734b06SKan Liang 		browser->hists->socket_filter = act->socket;
288184734b06SKan Liang 		perf_hpp__set_elide(HISTC_SOCKET, true);
288284734b06SKan Liang 		pstack__push(browser->pstack, &browser->hists->socket_filter);
288384734b06SKan Liang 	}
288484734b06SKan Liang 
288584734b06SKan Liang 	hists__filter_by_socket(browser->hists);
288684734b06SKan Liang 	hist_browser__reset(browser);
288784734b06SKan Liang 	return 0;
288884734b06SKan Liang }
288984734b06SKan Liang 
289084734b06SKan Liang static int
add_socket_opt(struct hist_browser * browser,struct popup_action * act,char ** optstr,int socket_id)289184734b06SKan Liang add_socket_opt(struct hist_browser *browser, struct popup_action *act,
289284734b06SKan Liang 	       char **optstr, int socket_id)
289384734b06SKan Liang {
289435a634f7SJiri Olsa 	if (!hists__has(browser->hists, socket) || socket_id < 0)
289584734b06SKan Liang 		return 0;
289684734b06SKan Liang 
289784734b06SKan Liang 	if (asprintf(optstr, "Zoom %s Processor Socket %d",
289884734b06SKan Liang 		     (browser->hists->socket_filter > -1) ? "out of" : "into",
289984734b06SKan Liang 		     socket_id) < 0)
290084734b06SKan Liang 		return 0;
290184734b06SKan Liang 
290284734b06SKan Liang 	act->socket = socket_id;
290384734b06SKan Liang 	act->fn = do_zoom_socket;
290484734b06SKan Liang 	return 1;
290584734b06SKan Liang }
290684734b06SKan Liang 
hist_browser__update_nr_entries(struct hist_browser * hb)2907112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb)
2908064f1981SNamhyung Kim {
2909064f1981SNamhyung Kim 	u64 nr_entries = 0;
29102eb3d689SDavidlohr Bueso 	struct rb_node *nd = rb_first_cached(&hb->hists->entries);
2911064f1981SNamhyung Kim 
2912f5b763feSNamhyung Kim 	if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
2913268397cbSNamhyung Kim 		hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2914268397cbSNamhyung Kim 		return;
2915268397cbSNamhyung Kim 	}
2916268397cbSNamhyung Kim 
291714135663SNamhyung Kim 	while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2918064f1981SNamhyung Kim 		nr_entries++;
2919f5b763feSNamhyung Kim 		nd = rb_hierarchy_next(nd);
2920064f1981SNamhyung Kim 	}
2921064f1981SNamhyung Kim 
2922112f761fSNamhyung Kim 	hb->nr_non_filtered_entries = nr_entries;
2923f5b763feSNamhyung Kim 	hb->nr_hierarchy_entries = nr_entries;
2924064f1981SNamhyung Kim }
2925341487abSFeng Tang 
hist_browser__update_percent_limit(struct hist_browser * hb,double percent)2926b62e8dfcSNamhyung Kim static void hist_browser__update_percent_limit(struct hist_browser *hb,
2927b62e8dfcSNamhyung Kim 					       double percent)
2928b62e8dfcSNamhyung Kim {
2929b62e8dfcSNamhyung Kim 	struct hist_entry *he;
29302eb3d689SDavidlohr Bueso 	struct rb_node *nd = rb_first_cached(&hb->hists->entries);
2931b62e8dfcSNamhyung Kim 	u64 total = hists__total_period(hb->hists);
2932b62e8dfcSNamhyung Kim 	u64 min_callchain_hits = total * (percent / 100);
2933b62e8dfcSNamhyung Kim 
2934b62e8dfcSNamhyung Kim 	hb->min_pcnt = callchain_param.min_percent = percent;
2935b62e8dfcSNamhyung Kim 
2936b62e8dfcSNamhyung Kim 	while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2937b62e8dfcSNamhyung Kim 		he = rb_entry(nd, struct hist_entry, rb_node);
2938b62e8dfcSNamhyung Kim 
293979dded87SNamhyung Kim 		if (he->has_no_entry) {
294079dded87SNamhyung Kim 			he->has_no_entry = false;
294179dded87SNamhyung Kim 			he->nr_rows = 0;
294279dded87SNamhyung Kim 		}
294379dded87SNamhyung Kim 
2944fabd37b8SArnaldo Carvalho de Melo 		if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
2945d0506edbSNamhyung Kim 			goto next;
2946d0506edbSNamhyung Kim 
2947b62e8dfcSNamhyung Kim 		if (callchain_param.mode == CHAIN_GRAPH_REL) {
2948b62e8dfcSNamhyung Kim 			total = he->stat.period;
2949b62e8dfcSNamhyung Kim 
2950b62e8dfcSNamhyung Kim 			if (symbol_conf.cumulate_callchain)
2951b62e8dfcSNamhyung Kim 				total = he->stat_acc->period;
2952b62e8dfcSNamhyung Kim 
2953b62e8dfcSNamhyung Kim 			min_callchain_hits = total * (percent / 100);
2954b62e8dfcSNamhyung Kim 		}
2955b62e8dfcSNamhyung Kim 
2956b62e8dfcSNamhyung Kim 		callchain_param.sort(&he->sorted_chain, he->callchain,
2957b62e8dfcSNamhyung Kim 				     min_callchain_hits, &callchain_param);
2958b62e8dfcSNamhyung Kim 
2959d0506edbSNamhyung Kim next:
2960201fde73SNamhyung Kim 		nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
2961d0506edbSNamhyung Kim 
2962b62e8dfcSNamhyung Kim 		/* force to re-evaluate folding state of callchains */
2963b62e8dfcSNamhyung Kim 		he->init_have_children = false;
2964492b1010SNamhyung Kim 		hist_entry__set_folding(he, hb, false);
2965b62e8dfcSNamhyung Kim 	}
2966b62e8dfcSNamhyung Kim }
2967b62e8dfcSNamhyung Kim 
evsel__hists_browse(struct evsel * evsel,int nr_events,const char * helpline,bool left_exits,struct hist_browser_timer * hbt,float min_pcnt,struct perf_env * env,bool warn_lost_event)296856933029SArnaldo Carvalho de Melo static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *helpline,
296956933029SArnaldo Carvalho de Melo 			       bool left_exits, struct hist_browser_timer *hbt, float min_pcnt,
297022197fb2SNamhyung Kim 			       struct perf_env *env, bool warn_lost_event)
2971aca7a94dSNamhyung Kim {
29724ea062edSArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
297322197fb2SNamhyung Kim 	struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
2974ceb75476SLeo Yan 	struct branch_info *bi = NULL;
2975f2b487dbSNamhyung Kim #define MAX_OPTIONS  16
2976f2b487dbSNamhyung Kim 	char *options[MAX_OPTIONS];
2977ea7cd592SNamhyung Kim 	struct popup_action actions[MAX_OPTIONS];
2978aca7a94dSNamhyung Kim 	int nr_options = 0;
2979aca7a94dSNamhyung Kim 	int key = -1;
298086449b12SSong Liu 	char buf[128];
29819783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
2982aca7a94dSNamhyung Kim 
2983e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON					\
2984e8e684a5SNamhyung Kim 	"h/?/F1        Show this window\n"				\
2985e8e684a5SNamhyung Kim 	"UP/DOWN/PGUP\n"						\
2986e8e684a5SNamhyung Kim 	"PGDN/SPACE    Navigate\n"					\
29876a02f06eSAndi Kleen 	"q/ESC/CTRL+C  Exit browser or go back to previous screen\n\n"	\
2988e8e684a5SNamhyung Kim 	"For multiple event sessions:\n\n"				\
2989e8e684a5SNamhyung Kim 	"TAB/UNTAB     Switch events\n\n"				\
2990e8e684a5SNamhyung Kim 	"For symbolic views (--sort has sym):\n\n"			\
29917727a925SArnaldo Carvalho de Melo 	"ENTER         Zoom into DSO/Threads & Annotate current symbol\n" \
29927727a925SArnaldo Carvalho de Melo 	"ESC           Zoom out\n"					\
29939218a913SArnaldo Carvalho de Melo 	"+             Expand/Collapse one callchain level\n"		\
2994e8e684a5SNamhyung Kim 	"a             Annotate current symbol\n"			\
2995e8e684a5SNamhyung Kim 	"C             Collapse all callchains\n"			\
2996e8e684a5SNamhyung Kim 	"d             Zoom into current DSO\n"				\
2997e6d6abfcSArnaldo Carvalho de Melo 	"e             Expand/Collapse main entry callchains\n"	\
2998e8e684a5SNamhyung Kim 	"E             Expand all callchains\n"				\
2999105eb30fSNamhyung Kim 	"F             Toggle percentage of filtered entries\n"		\
3000025bf7eaSArnaldo Carvalho de Melo 	"H             Display column headers\n"			\
3001209f4e70SArnaldo Carvalho de Melo 	"k             Zoom into the kernel map\n"			\
3002b62e8dfcSNamhyung Kim 	"L             Change percent limit\n"				\
300331eb4360SNamhyung Kim 	"m             Display context menu\n"				\
300484734b06SKan Liang 	"S             Zoom into current Processor Socket\n"		\
3005e8e684a5SNamhyung Kim 
3006e8e684a5SNamhyung Kim 	/* help messages are sorted by lexical order of the hotkey */
300749b8e2beSRasmus Villemoes 	static const char report_help[] = HIST_BROWSER_HELP_COMMON
30086dd60135SNamhyung Kim 	"i             Show header information\n"
3009e8e684a5SNamhyung Kim 	"P             Print histograms to perf.hist.N\n"
3010e8e684a5SNamhyung Kim 	"r             Run available scripts\n"
3011e8e684a5SNamhyung Kim 	"s             Switch to another data file in PWD\n"
3012e8e684a5SNamhyung Kim 	"t             Zoom into current Thread\n"
3013e8e684a5SNamhyung Kim 	"V             Verbose (DSO names in callchains, etc)\n"
3014dbddf174SJin Yao 	"/             Filter symbol by name\n"
3015dbddf174SJin Yao 	"0-9           Sort by event n in group";
301649b8e2beSRasmus Villemoes 	static const char top_help[] = HIST_BROWSER_HELP_COMMON
3017e8e684a5SNamhyung Kim 	"P             Print histograms to perf.hist.N\n"
3018e8e684a5SNamhyung Kim 	"t             Zoom into current Thread\n"
3019e8e684a5SNamhyung Kim 	"V             Verbose (DSO names in callchains, etc)\n"
302042337a22SNamhyung Kim 	"z             Toggle zeroing of samples\n"
3021fbb7997eSArnaldo Carvalho de Melo 	"f             Enable/Disable events\n"
3022e8e684a5SNamhyung Kim 	"/             Filter symbol by name";
3023e8e684a5SNamhyung Kim 
3024aca7a94dSNamhyung Kim 	if (browser == NULL)
3025aca7a94dSNamhyung Kim 		return -1;
3026aca7a94dSNamhyung Kim 
3027ed426915SNamhyung Kim 	/* reset abort key so that it can get Ctrl-C as a key */
3028ed426915SNamhyung Kim 	SLang_reset_tty();
3029ed426915SNamhyung Kim 	SLang_init_tty(0, 0, 0);
30306af6d224SAhelenia Ziemiańska 	SLtty_set_suspend_state(true);
3031ed426915SNamhyung Kim 
303203905048SNamhyung Kim 	if (min_pcnt)
3033064f1981SNamhyung Kim 		browser->min_pcnt = min_pcnt;
3034112f761fSNamhyung Kim 	hist_browser__update_nr_entries(browser);
3035064f1981SNamhyung Kim 
303684734b06SKan Liang 	browser->pstack = pstack__new(3);
303701f00a1cSNamhyung Kim 	if (browser->pstack == NULL)
3038aca7a94dSNamhyung Kim 		goto out;
3039aca7a94dSNamhyung Kim 
3040aca7a94dSNamhyung Kim 	ui_helpline__push(helpline);
3041aca7a94dSNamhyung Kim 
3042aca7a94dSNamhyung Kim 	memset(options, 0, sizeof(options));
3043ea7cd592SNamhyung Kim 	memset(actions, 0, sizeof(actions));
3044aca7a94dSNamhyung Kim 
30455b591669SNamhyung Kim 	if (symbol_conf.col_width_list_str)
30465b591669SNamhyung Kim 		perf_hpp__set_user_width(symbol_conf.col_width_list_str);
30475b591669SNamhyung Kim 
30485c959b6dSArnaldo Carvalho de Melo 	if (!is_report_browser(hbt))
30495c959b6dSArnaldo Carvalho de Melo 		browser->b.no_samples_msg = "Collecting samples...";
30505c959b6dSArnaldo Carvalho de Melo 
3051aca7a94dSNamhyung Kim 	while (1) {
3052f3b623b8SArnaldo Carvalho de Melo 		struct thread *thread = NULL;
3053045b80ddSArnaldo Carvalho de Melo 		struct map *map = NULL;
30544c8b9c0fSArnaldo Carvalho de Melo 		int choice;
305584734b06SKan Liang 		int socked_id = -1;
3056aca7a94dSNamhyung Kim 
30574c8b9c0fSArnaldo Carvalho de Melo 		key = 0; // reset key
30584c8b9c0fSArnaldo Carvalho de Melo do_hotkey:		 // key came straight from options ui__popup_menu()
30594c8b9c0fSArnaldo Carvalho de Melo 		choice = nr_options = 0;
30604c8b9c0fSArnaldo Carvalho de Melo 		key = hist_browser__run(browser, helpline, warn_lost_event, key);
3061aca7a94dSNamhyung Kim 
3062aca7a94dSNamhyung Kim 		if (browser->he_selection != NULL) {
3063aca7a94dSNamhyung Kim 			thread = hist_browser__selected_thread(browser);
3064045b80ddSArnaldo Carvalho de Melo 			map = browser->selection->map;
306584734b06SKan Liang 			socked_id = browser->he_selection->socket;
3066aca7a94dSNamhyung Kim 		}
3067aca7a94dSNamhyung Kim 		switch (key) {
3068aca7a94dSNamhyung Kim 		case K_TAB:
3069aca7a94dSNamhyung Kim 		case K_UNTAB:
3070aca7a94dSNamhyung Kim 			if (nr_events == 1)
3071aca7a94dSNamhyung Kim 				continue;
3072aca7a94dSNamhyung Kim 			/*
3073aca7a94dSNamhyung Kim 			 * Exit the browser, let hists__browser_tree
3074aca7a94dSNamhyung Kim 			 * go to the next or previous
3075aca7a94dSNamhyung Kim 			 */
3076aca7a94dSNamhyung Kim 			goto out_free_stack;
3077dbddf174SJin Yao 		case '0' ... '9':
3078dbddf174SJin Yao 			if (!symbol_conf.event_group ||
3079dbddf174SJin Yao 			    evsel->core.nr_members < 2) {
3080dbddf174SJin Yao 				snprintf(buf, sizeof(buf),
3081dbddf174SJin Yao 					 "Sort by index only available with group events!");
3082dbddf174SJin Yao 				helpline = buf;
3083dbddf174SJin Yao 				continue;
3084dbddf174SJin Yao 			}
3085dbddf174SJin Yao 
3086dbddf174SJin Yao 			if (key - '0' == symbol_conf.group_sort_idx)
3087dbddf174SJin Yao 				continue;
3088dbddf174SJin Yao 
3089dbddf174SJin Yao 			symbol_conf.group_sort_idx = key - '0';
3090dbddf174SJin Yao 
3091dbddf174SJin Yao 			if (symbol_conf.group_sort_idx >= evsel->core.nr_members) {
3092dbddf174SJin Yao 				snprintf(buf, sizeof(buf),
3093dbddf174SJin Yao 					 "Max event group index to sort is %d (index from 0 to %d)",
3094dbddf174SJin Yao 					 evsel->core.nr_members - 1,
3095dbddf174SJin Yao 					 evsel->core.nr_members - 1);
3096dbddf174SJin Yao 				helpline = buf;
3097dbddf174SJin Yao 				continue;
3098dbddf174SJin Yao 			}
3099dbddf174SJin Yao 
3100dbddf174SJin Yao 			key = K_RELOAD;
3101dbddf174SJin Yao 			goto out_free_stack;
3102aca7a94dSNamhyung Kim 		case 'a':
31032e0453afSJiri Olsa 			if (!hists__has(hists, sym)) {
3104aca7a94dSNamhyung Kim 				ui_browser__warning(&browser->b, delay_secs * 2,
3105aca7a94dSNamhyung Kim 			"Annotation is only available for symbolic views, "
3106aca7a94dSNamhyung Kim 			"include \"sym*\" in --sort to use it.");
3107aca7a94dSNamhyung Kim 				continue;
3108aca7a94dSNamhyung Kim 			}
3109aca7a94dSNamhyung Kim 
3110ec0479a6SJin Yao 			if (!browser->selection ||
3111ec0479a6SJin Yao 			    !browser->selection->map ||
311263df0e4bSIan Rogers 			    !map__dso(browser->selection->map) ||
3113ee756ef7SIan Rogers 			    dso__annotate_warned(map__dso(browser->selection->map))) {
3114ec0479a6SJin Yao 				continue;
3115ec0479a6SJin Yao 			}
3116ec0479a6SJin Yao 
3117ec0479a6SJin Yao 			if (!browser->selection->sym) {
3118ec0479a6SJin Yao 				if (!browser->he_selection)
3119aca7a94dSNamhyung Kim 					continue;
3120bc7cad42SNamhyung Kim 
3121ec0479a6SJin Yao 				if (sort__mode == SORT_MODE__BRANCH) {
3122ec0479a6SJin Yao 					bi = browser->he_selection->branch_info;
3123ec0479a6SJin Yao 					if (!bi || !bi->to.ms.map)
3124ec0479a6SJin Yao 						continue;
3125ec0479a6SJin Yao 
3126ec0479a6SJin Yao 					actions->ms.sym = symbol__new_unresolved(bi->to.al_addr, bi->to.ms.map);
3127ec0479a6SJin Yao 					actions->ms.map = bi->to.ms.map;
3128ec0479a6SJin Yao 				} else {
3129ec0479a6SJin Yao 					actions->ms.sym = symbol__new_unresolved(browser->he_selection->ip,
3130ec0479a6SJin Yao 										 browser->selection->map);
3131ec0479a6SJin Yao 					actions->ms.map = browser->selection->map;
3132ec0479a6SJin Yao 				}
3133ec0479a6SJin Yao 
3134ec0479a6SJin Yao 				if (!actions->ms.sym)
3135ec0479a6SJin Yao 					continue;
3136ec0479a6SJin Yao 			} else {
3137ea537f22SArnaldo Carvalho de Melo 				if (symbol__annotation(browser->selection->sym)->src == NULL) {
3138ea537f22SArnaldo Carvalho de Melo 					ui_browser__warning(&browser->b, delay_secs * 2,
3139ea537f22SArnaldo Carvalho de Melo 						"No samples for the \"%s\" symbol.\n\n"
3140ea537f22SArnaldo Carvalho de Melo 						"Probably appeared just in a callchain",
3141ea537f22SArnaldo Carvalho de Melo 						browser->selection->sym->name);
3142ea537f22SArnaldo Carvalho de Melo 					continue;
3143ea537f22SArnaldo Carvalho de Melo 				}
3144ea537f22SArnaldo Carvalho de Melo 
3145ea7cd592SNamhyung Kim 				actions->ms.map = browser->selection->map;
3146ea7cd592SNamhyung Kim 				actions->ms.sym = browser->selection->sym;
3147ec0479a6SJin Yao 			}
3148ec0479a6SJin Yao 
3149ea7cd592SNamhyung Kim 			do_annotate(browser, actions);
3150bc7cad42SNamhyung Kim 			continue;
3151aff3f3f6SArnaldo Carvalho de Melo 		case 'P':
3152aff3f3f6SArnaldo Carvalho de Melo 			hist_browser__dump(browser);
3153aff3f3f6SArnaldo Carvalho de Melo 			continue;
3154aca7a94dSNamhyung Kim 		case 'd':
3155fae00650SArnaldo Carvalho de Melo 			actions->ms.map = map;
3156ea7cd592SNamhyung Kim 			do_zoom_dso(browser, actions);
3157bc7cad42SNamhyung Kim 			continue;
3158209f4e70SArnaldo Carvalho de Melo 		case 'k':
3159209f4e70SArnaldo Carvalho de Melo 			if (browser->selection != NULL)
31605ab6d715SIan Rogers 				hists_browser__zoom_map(browser,
31615ab6d715SIan Rogers 					      maps__machine(browser->selection->maps)->vmlinux_map);
3162209f4e70SArnaldo Carvalho de Melo 			continue;
3163a7cb8863SArnaldo Carvalho de Melo 		case 'V':
316421e8c810SAlexis Berlemont 			verbose = (verbose + 1) % 4;
316521e8c810SAlexis Berlemont 			browser->show_dso = verbose > 0;
316621e8c810SAlexis Berlemont 			ui_helpline__fpush("Verbosity level set to %d\n",
316721e8c810SAlexis Berlemont 					   verbose);
3168a7cb8863SArnaldo Carvalho de Melo 			continue;
3169aca7a94dSNamhyung Kim 		case 't':
3170ea7cd592SNamhyung Kim 			actions->thread = thread;
3171ea7cd592SNamhyung Kim 			do_zoom_thread(browser, actions);
3172bc7cad42SNamhyung Kim 			continue;
317384734b06SKan Liang 		case 'S':
317484734b06SKan Liang 			actions->socket = socked_id;
317584734b06SKan Liang 			do_zoom_socket(browser, actions);
317684734b06SKan Liang 			continue;
31775a5626b1SArnaldo Carvalho de Melo 		case '/':
3178aca7a94dSNamhyung Kim 			if (ui_browser__input_window("Symbol to show",
31794aa8e454SArnaldo Carvalho de Melo 					"Please enter the name of symbol you want to see.\n"
31804aa8e454SArnaldo Carvalho de Melo 					"To remove the filter later, press / + ENTER.",
3181aca7a94dSNamhyung Kim 					buf, "ENTER: OK, ESC: Cancel",
3182aca7a94dSNamhyung Kim 					delay_secs * 2) == K_ENTER) {
318305e8b080SArnaldo Carvalho de Melo 				hists->symbol_filter_str = *buf ? buf : NULL;
318405e8b080SArnaldo Carvalho de Melo 				hists__filter_by_symbol(hists);
3185aca7a94dSNamhyung Kim 				hist_browser__reset(browser);
3186aca7a94dSNamhyung Kim 			}
3187aca7a94dSNamhyung Kim 			continue;
3188cdbab7c2SFeng Tang 		case 'r':
3189ea7cd592SNamhyung Kim 			if (is_report_browser(hbt)) {
3190ea7cd592SNamhyung Kim 				actions->thread = NULL;
3191ea7cd592SNamhyung Kim 				actions->ms.sym = NULL;
3192ea7cd592SNamhyung Kim 				do_run_script(browser, actions);
3193ea7cd592SNamhyung Kim 			}
3194c77d8d70SFeng Tang 			continue;
3195341487abSFeng Tang 		case 's':
3196bc7cad42SNamhyung Kim 			if (is_report_browser(hbt)) {
3197ea7cd592SNamhyung Kim 				key = do_switch_data(browser, actions);
3198bc7cad42SNamhyung Kim 				if (key == K_SWITCH_INPUT_DATA)
3199bc7cad42SNamhyung Kim 					goto out_free_stack;
3200bc7cad42SNamhyung Kim 			}
3201341487abSFeng Tang 			continue;
32026dd60135SNamhyung Kim 		case 'i':
32036dd60135SNamhyung Kim 			/* env->arch is NULL for live-mode (i.e. perf top) */
32046dd60135SNamhyung Kim 			if (env->arch)
32056dd60135SNamhyung Kim 				tui__header_window(env);
32066dd60135SNamhyung Kim 			continue;
3207105eb30fSNamhyung Kim 		case 'F':
3208105eb30fSNamhyung Kim 			symbol_conf.filter_relative ^= 1;
3209105eb30fSNamhyung Kim 			continue;
321042337a22SNamhyung Kim 		case 'z':
321142337a22SNamhyung Kim 			if (!is_report_browser(hbt)) {
321242337a22SNamhyung Kim 				struct perf_top *top = hbt->arg;
321342337a22SNamhyung Kim 
321442337a22SNamhyung Kim 				top->zero = !top->zero;
321542337a22SNamhyung Kim 			}
321642337a22SNamhyung Kim 			continue;
3217b62e8dfcSNamhyung Kim 		case 'L':
3218b62e8dfcSNamhyung Kim 			if (ui_browser__input_window("Percent Limit",
3219b62e8dfcSNamhyung Kim 					"Please enter the value you want to hide entries under that percent.",
3220b62e8dfcSNamhyung Kim 					buf, "ENTER: OK, ESC: Cancel",
3221b62e8dfcSNamhyung Kim 					delay_secs * 2) == K_ENTER) {
3222b62e8dfcSNamhyung Kim 				char *end;
3223b62e8dfcSNamhyung Kim 				double new_percent = strtod(buf, &end);
3224b62e8dfcSNamhyung Kim 
3225b62e8dfcSNamhyung Kim 				if (new_percent < 0 || new_percent > 100) {
3226b62e8dfcSNamhyung Kim 					ui_browser__warning(&browser->b, delay_secs * 2,
3227b62e8dfcSNamhyung Kim 						"Invalid percent: %.2f", new_percent);
3228b62e8dfcSNamhyung Kim 					continue;
3229b62e8dfcSNamhyung Kim 				}
3230b62e8dfcSNamhyung Kim 
3231b62e8dfcSNamhyung Kim 				hist_browser__update_percent_limit(browser, new_percent);
3232b62e8dfcSNamhyung Kim 				hist_browser__reset(browser);
3233b62e8dfcSNamhyung Kim 			}
3234b62e8dfcSNamhyung Kim 			continue;
3235aca7a94dSNamhyung Kim 		case K_F1:
3236aca7a94dSNamhyung Kim 		case 'h':
3237aca7a94dSNamhyung Kim 		case '?':
3238aca7a94dSNamhyung Kim 			ui_browser__help_window(&browser->b,
3239e8e684a5SNamhyung Kim 				is_report_browser(hbt) ? report_help : top_help);
3240aca7a94dSNamhyung Kim 			continue;
3241aca7a94dSNamhyung Kim 		case K_ENTER:
3242aca7a94dSNamhyung Kim 		case K_RIGHT:
324331eb4360SNamhyung Kim 		case 'm':
3244aca7a94dSNamhyung Kim 			/* menu */
3245aca7a94dSNamhyung Kim 			break;
324663ab1749SArnaldo Carvalho de Melo 		case K_ESC:
3247aca7a94dSNamhyung Kim 		case K_LEFT: {
3248aca7a94dSNamhyung Kim 			const void *top;
3249aca7a94dSNamhyung Kim 
325001f00a1cSNamhyung Kim 			if (pstack__empty(browser->pstack)) {
3251aca7a94dSNamhyung Kim 				/*
3252aca7a94dSNamhyung Kim 				 * Go back to the perf_evsel_menu__run or other user
3253aca7a94dSNamhyung Kim 				 */
3254aca7a94dSNamhyung Kim 				if (left_exits)
3255aca7a94dSNamhyung Kim 					goto out_free_stack;
325663ab1749SArnaldo Carvalho de Melo 
325763ab1749SArnaldo Carvalho de Melo 				if (key == K_ESC &&
325863ab1749SArnaldo Carvalho de Melo 				    ui_browser__dialog_yesno(&browser->b,
325963ab1749SArnaldo Carvalho de Melo 							     "Do you really want to exit?"))
326063ab1749SArnaldo Carvalho de Melo 					goto out_free_stack;
326163ab1749SArnaldo Carvalho de Melo 
3262aca7a94dSNamhyung Kim 				continue;
3263aca7a94dSNamhyung Kim 			}
32643f777403SArnaldo Carvalho de Melo 			actions->ms.map = map;
32656422184bSNamhyung Kim 			top = pstack__peek(browser->pstack);
3266bc7cad42SNamhyung Kim 			if (top == &browser->hists->dso_filter) {
32676422184bSNamhyung Kim 				/*
32686422184bSNamhyung Kim 				 * No need to set actions->dso here since
32696422184bSNamhyung Kim 				 * it's just to remove the current filter.
32706422184bSNamhyung Kim 				 * Ditto for thread below.
32716422184bSNamhyung Kim 				 */
32726422184bSNamhyung Kim 				do_zoom_dso(browser, actions);
327384734b06SKan Liang 			} else if (top == &browser->hists->thread_filter) {
32746422184bSNamhyung Kim 				do_zoom_thread(browser, actions);
327584734b06SKan Liang 			} else if (top == &browser->hists->socket_filter) {
327684734b06SKan Liang 				do_zoom_socket(browser, actions);
327784734b06SKan Liang 			}
3278aca7a94dSNamhyung Kim 			continue;
3279aca7a94dSNamhyung Kim 		}
3280aca7a94dSNamhyung Kim 		case 'q':
3281aca7a94dSNamhyung Kim 		case CTRL('c'):
3282516e5368SArnaldo Carvalho de Melo 			goto out_free_stack;
3283fbb7997eSArnaldo Carvalho de Melo 		case 'f':
328413d1e536SNamhyung Kim 			if (!is_report_browser(hbt)) {
328513d1e536SNamhyung Kim 				struct perf_top *top = hbt->arg;
328613d1e536SNamhyung Kim 
3287ade9d208SArnaldo Carvalho de Melo 				evlist__toggle_enable(top->evlist);
328813d1e536SNamhyung Kim 				/*
328913d1e536SNamhyung Kim 				 * No need to refresh, resort/decay histogram
329013d1e536SNamhyung Kim 				 * entries if we are not collecting samples:
329113d1e536SNamhyung Kim 				 */
329213d1e536SNamhyung Kim 				if (top->evlist->enabled) {
329313d1e536SNamhyung Kim 					helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
329413d1e536SNamhyung Kim 					hbt->refresh = delay_secs;
329513d1e536SNamhyung Kim 				} else {
329613d1e536SNamhyung Kim 					helpline = "Press 'f' again to re-enable the events";
329713d1e536SNamhyung Kim 					hbt->refresh = 0;
329813d1e536SNamhyung Kim 				}
329913d1e536SNamhyung Kim 				continue;
330013d1e536SNamhyung Kim 			}
33013e323dc0SArnaldo Carvalho de Melo 			/* Fall thru */
3302aca7a94dSNamhyung Kim 		default:
33033e323dc0SArnaldo Carvalho de Melo 			helpline = "Press '?' for help on key bindings";
3304aca7a94dSNamhyung Kim 			continue;
3305aca7a94dSNamhyung Kim 		}
3306aca7a94dSNamhyung Kim 
33072e0453afSJiri Olsa 		if (!hists__has(hists, sym) || browser->selection == NULL)
33080ba332f7SArnaldo Carvalho de Melo 			goto skip_annotation;
33090ba332f7SArnaldo Carvalho de Melo 
331055369fc1SNamhyung Kim 		if (sort__mode == SORT_MODE__BRANCH) {
3311ceb75476SLeo Yan 
3312ceb75476SLeo Yan 			if (browser->he_selection)
3313aca7a94dSNamhyung Kim 				bi = browser->he_selection->branch_info;
33140ba332f7SArnaldo Carvalho de Melo 
33150ba332f7SArnaldo Carvalho de Melo 			if (bi == NULL)
33160ba332f7SArnaldo Carvalho de Melo 				goto skip_annotation;
33170ba332f7SArnaldo Carvalho de Melo 
3318ea7cd592SNamhyung Kim 			nr_options += add_annotate_opt(browser,
3319ea7cd592SNamhyung Kim 						       &actions[nr_options],
3320ea7cd592SNamhyung Kim 						       &options[nr_options],
33217b0a0dcbSJin Yao 						       &bi->from.ms,
33227b0a0dcbSJin Yao 						       bi->from.al_addr);
3323d46a4cdfSArnaldo Carvalho de Melo 			if (bi->to.ms.sym != bi->from.ms.sym)
3324ea7cd592SNamhyung Kim 				nr_options += add_annotate_opt(browser,
3325ea7cd592SNamhyung Kim 							&actions[nr_options],
3326ea7cd592SNamhyung Kim 							&options[nr_options],
33277b0a0dcbSJin Yao 							&bi->to.ms,
33287b0a0dcbSJin Yao 							bi->to.al_addr);
3329ef1aec60SIan Rogers 		} else if (browser->he_selection) {
3330ea7cd592SNamhyung Kim 			nr_options += add_annotate_opt(browser,
3331ea7cd592SNamhyung Kim 						       &actions[nr_options],
3332ea7cd592SNamhyung Kim 						       &options[nr_options],
33337b0a0dcbSJin Yao 						       browser->selection,
33347b0a0dcbSJin Yao 						       browser->he_selection->ip);
3335446fb96cSArnaldo Carvalho de Melo 		}
33360ba332f7SArnaldo Carvalho de Melo skip_annotation:
33370bfbe661SNamhyung Kim 		nr_options += add_annotate_type_opt(browser,
33380bfbe661SNamhyung Kim 						    &actions[nr_options],
33390bfbe661SNamhyung Kim 						    &options[nr_options],
33400bfbe661SNamhyung Kim 						    browser->he_selection);
3341ea7cd592SNamhyung Kim 		nr_options += add_thread_opt(browser, &actions[nr_options],
3342ea7cd592SNamhyung Kim 					     &options[nr_options], thread);
3343ea7cd592SNamhyung Kim 		nr_options += add_dso_opt(browser, &actions[nr_options],
3344045b80ddSArnaldo Carvalho de Melo 					  &options[nr_options], map);
3345d5a599d9SArnaldo Carvalho de Melo 		nr_options += add_callchain_toggle_opt(browser, &actions[nr_options], &options[nr_options]);
3346ea7cd592SNamhyung Kim 		nr_options += add_map_opt(browser, &actions[nr_options],
3347ea7cd592SNamhyung Kim 					  &options[nr_options],
3348bd315aabSWang Nan 					  browser->selection ?
3349bd315aabSWang Nan 						browser->selection->map : NULL);
335084734b06SKan Liang 		nr_options += add_socket_opt(browser, &actions[nr_options],
335184734b06SKan Liang 					     &options[nr_options],
335284734b06SKan Liang 					     socked_id);
3353cdbab7c2SFeng Tang 		/* perf script support */
3354b1baae89SNamhyung Kim 		if (!is_report_browser(hbt))
3355b1baae89SNamhyung Kim 			goto skip_scripting;
3356b1baae89SNamhyung Kim 
3357cdbab7c2SFeng Tang 		if (browser->he_selection) {
3358fa82911aSJiri Olsa 			if (hists__has(hists, thread) && thread) {
3359ea7cd592SNamhyung Kim 				nr_options += add_script_opt(browser,
3360ea7cd592SNamhyung Kim 							     &actions[nr_options],
3361ea7cd592SNamhyung Kim 							     &options[nr_options],
33626f3da20eSAndi Kleen 							     thread, NULL, evsel);
33632eafd410SNamhyung Kim 			}
3364bd315aabSWang Nan 			/*
3365bd315aabSWang Nan 			 * Note that browser->selection != NULL
3366bd315aabSWang Nan 			 * when browser->he_selection is not NULL,
3367bd315aabSWang Nan 			 * so we don't need to check browser->selection
3368bd315aabSWang Nan 			 * before fetching browser->selection->sym like what
3369bd315aabSWang Nan 			 * we do before fetching browser->selection->map.
3370bd315aabSWang Nan 			 *
3371bd315aabSWang Nan 			 * See hist_browser__show_entry.
3372bd315aabSWang Nan 			 */
33732e0453afSJiri Olsa 			if (hists__has(hists, sym) && browser->selection->sym) {
3374ea7cd592SNamhyung Kim 				nr_options += add_script_opt(browser,
3375ea7cd592SNamhyung Kim 							     &actions[nr_options],
3376ea7cd592SNamhyung Kim 							     &options[nr_options],
33776f3da20eSAndi Kleen 							     NULL, browser->selection->sym,
33786f3da20eSAndi Kleen 							     evsel);
3379cdbab7c2SFeng Tang 			}
3380c221acb0SNamhyung Kim 		}
3381ea7cd592SNamhyung Kim 		nr_options += add_script_opt(browser, &actions[nr_options],
33826f3da20eSAndi Kleen 					     &options[nr_options], NULL, NULL, evsel);
33834968ac8fSAndi Kleen 		nr_options += add_res_sample_opt(browser, &actions[nr_options],
33844968ac8fSAndi Kleen 						 &options[nr_options],
3385d61cbb85SWei Li 						 hist_browser__selected_res_sample(browser),
33864968ac8fSAndi Kleen 						 evsel, A_NORMAL);
33874968ac8fSAndi Kleen 		nr_options += add_res_sample_opt(browser, &actions[nr_options],
33884968ac8fSAndi Kleen 						 &options[nr_options],
3389d61cbb85SWei Li 						 hist_browser__selected_res_sample(browser),
33904968ac8fSAndi Kleen 						 evsel, A_ASM);
33914968ac8fSAndi Kleen 		nr_options += add_res_sample_opt(browser, &actions[nr_options],
33924968ac8fSAndi Kleen 						 &options[nr_options],
3393d61cbb85SWei Li 						 hist_browser__selected_res_sample(browser),
33944968ac8fSAndi Kleen 						 evsel, A_SOURCE);
3395ea7cd592SNamhyung Kim 		nr_options += add_switch_opt(browser, &actions[nr_options],
3396ea7cd592SNamhyung Kim 					     &options[nr_options]);
3397b1baae89SNamhyung Kim skip_scripting:
3398ea7cd592SNamhyung Kim 		nr_options += add_exit_opt(browser, &actions[nr_options],
3399ea7cd592SNamhyung Kim 					   &options[nr_options]);
3400aca7a94dSNamhyung Kim 
3401ea7cd592SNamhyung Kim 		do {
3402ea7cd592SNamhyung Kim 			struct popup_action *act;
3403ea7cd592SNamhyung Kim 
34044c8b9c0fSArnaldo Carvalho de Melo 			choice = ui__popup_menu(nr_options, options, &key);
34054c8b9c0fSArnaldo Carvalho de Melo 			if (choice == -1)
3406aca7a94dSNamhyung Kim 				break;
3407aca7a94dSNamhyung Kim 
34084c8b9c0fSArnaldo Carvalho de Melo 			if (choice == nr_options)
34094c8b9c0fSArnaldo Carvalho de Melo 				goto do_hotkey;
34104c8b9c0fSArnaldo Carvalho de Melo 
3411ea7cd592SNamhyung Kim 			act = &actions[choice];
3412ea7cd592SNamhyung Kim 			key = act->fn(browser, act);
3413ea7cd592SNamhyung Kim 		} while (key == 1);
3414aca7a94dSNamhyung Kim 
3415bc7cad42SNamhyung Kim 		if (key == K_SWITCH_INPUT_DATA)
3416341487abSFeng Tang 			break;
3417341487abSFeng Tang 	}
3418aca7a94dSNamhyung Kim out_free_stack:
341901f00a1cSNamhyung Kim 	pstack__delete(browser->pstack);
3420aca7a94dSNamhyung Kim out:
3421aca7a94dSNamhyung Kim 	hist_browser__delete(browser);
3422f2b487dbSNamhyung Kim 	free_popup_options(options, MAX_OPTIONS);
3423aca7a94dSNamhyung Kim 	return key;
3424aca7a94dSNamhyung Kim }
3425aca7a94dSNamhyung Kim 
342632dcd021SJiri Olsa struct evsel_menu {
3427aca7a94dSNamhyung Kim 	struct ui_browser b;
342832dcd021SJiri Olsa 	struct evsel *selection;
3429aca7a94dSNamhyung Kim 	bool lost_events, lost_events_warned;
3430064f1981SNamhyung Kim 	float min_pcnt;
3431ce80d3beSKan Liang 	struct perf_env *env;
3432aca7a94dSNamhyung Kim };
3433aca7a94dSNamhyung Kim 
perf_evsel_menu__write(struct ui_browser * browser,void * entry,int row)3434aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser,
3435aca7a94dSNamhyung Kim 				   void *entry, int row)
3436aca7a94dSNamhyung Kim {
343732dcd021SJiri Olsa 	struct evsel_menu *menu = container_of(browser,
343832dcd021SJiri Olsa 						    struct evsel_menu, b);
3439b27c4eceSJiri Olsa 	struct evsel *evsel = list_entry(entry, struct evsel, core.node);
34404ea062edSArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
3441aca7a94dSNamhyung Kim 	bool current_entry = ui_browser__is_current_entry(browser, row);
34420f0abbacSNamhyung Kim 	unsigned long nr_events = hists->stats.nr_samples;
34438ab2e96dSArnaldo Carvalho de Melo 	const char *ev_name = evsel__name(evsel);
3444aca7a94dSNamhyung Kim 	char bf[256], unit;
3445aca7a94dSNamhyung Kim 	const char *warn = " ";
3446aca7a94dSNamhyung Kim 	size_t printed;
3447aca7a94dSNamhyung Kim 
3448aca7a94dSNamhyung Kim 	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3449aca7a94dSNamhyung Kim 						       HE_COLORSET_NORMAL);
3450aca7a94dSNamhyung Kim 
3451c754c382SArnaldo Carvalho de Melo 	if (evsel__is_group_event(evsel)) {
345232dcd021SJiri Olsa 		struct evsel *pos;
3453717e263fSNamhyung Kim 
34548ab2e96dSArnaldo Carvalho de Melo 		ev_name = evsel__group_name(evsel);
3455717e263fSNamhyung Kim 
3456717e263fSNamhyung Kim 		for_each_group_member(pos, evsel) {
34574ea062edSArnaldo Carvalho de Melo 			struct hists *pos_hists = evsel__hists(pos);
34580f0abbacSNamhyung Kim 			nr_events += pos_hists->stats.nr_samples;
3459717e263fSNamhyung Kim 		}
3460717e263fSNamhyung Kim 	}
3461717e263fSNamhyung Kim 
3462aca7a94dSNamhyung Kim 	nr_events = convert_unit(nr_events, &unit);
3463aca7a94dSNamhyung Kim 	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
3464aca7a94dSNamhyung Kim 			   unit, unit == ' ' ? "" : " ", ev_name);
3465517dfdb3SArnaldo Carvalho de Melo 	ui_browser__printf(browser, "%s", bf);
3466aca7a94dSNamhyung Kim 
34670f0abbacSNamhyung Kim 	nr_events = evsel->evlist->stats.nr_events[PERF_RECORD_LOST];
3468aca7a94dSNamhyung Kim 	if (nr_events != 0) {
3469aca7a94dSNamhyung Kim 		menu->lost_events = true;
3470aca7a94dSNamhyung Kim 		if (!current_entry)
3471aca7a94dSNamhyung Kim 			ui_browser__set_color(browser, HE_COLORSET_TOP);
3472aca7a94dSNamhyung Kim 		nr_events = convert_unit(nr_events, &unit);
3473aca7a94dSNamhyung Kim 		printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3474aca7a94dSNamhyung Kim 				     nr_events, unit, unit == ' ' ? "" : " ");
3475aca7a94dSNamhyung Kim 		warn = bf;
3476aca7a94dSNamhyung Kim 	}
3477aca7a94dSNamhyung Kim 
347826270a00SArnaldo Carvalho de Melo 	ui_browser__write_nstring(browser, warn, browser->width - printed);
3479aca7a94dSNamhyung Kim 
3480aca7a94dSNamhyung Kim 	if (current_entry)
3481aca7a94dSNamhyung Kim 		menu->selection = evsel;
3482aca7a94dSNamhyung Kim }
3483aca7a94dSNamhyung Kim 
perf_evsel_menu__run(struct evsel_menu * menu,int nr_events,const char * help,struct hist_browser_timer * hbt,bool warn_lost_event)348432dcd021SJiri Olsa static int perf_evsel_menu__run(struct evsel_menu *menu,
3485aca7a94dSNamhyung Kim 				int nr_events, const char *help,
348606cc1a47SKan Liang 				struct hist_browser_timer *hbt,
348706cc1a47SKan Liang 				bool warn_lost_event)
3488aca7a94dSNamhyung Kim {
348963503dbaSJiri Olsa 	struct evlist *evlist = menu->b.priv;
349032dcd021SJiri Olsa 	struct evsel *pos;
3491dd00d486SJiri Olsa 	const char *title = "Available samples";
34929783adf7SNamhyung Kim 	int delay_secs = hbt ? hbt->refresh : 0;
3493aca7a94dSNamhyung Kim 	int key;
3494aca7a94dSNamhyung Kim 
3495aca7a94dSNamhyung Kim 	if (ui_browser__show(&menu->b, title,
3496aca7a94dSNamhyung Kim 			     "ESC: exit, ENTER|->: Browse histograms") < 0)
3497aca7a94dSNamhyung Kim 		return -1;
3498aca7a94dSNamhyung Kim 
3499aca7a94dSNamhyung Kim 	while (1) {
3500aca7a94dSNamhyung Kim 		key = ui_browser__run(&menu->b, delay_secs);
3501aca7a94dSNamhyung Kim 
3502aca7a94dSNamhyung Kim 		switch (key) {
3503aca7a94dSNamhyung Kim 		case K_TIMER:
3504ceb75476SLeo Yan 			if (hbt)
35059783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
3506aca7a94dSNamhyung Kim 
350706cc1a47SKan Liang 			if (!menu->lost_events_warned &&
350806cc1a47SKan Liang 			    menu->lost_events &&
350906cc1a47SKan Liang 			    warn_lost_event) {
3510aca7a94dSNamhyung Kim 				ui_browser__warn_lost_events(&menu->b);
3511aca7a94dSNamhyung Kim 				menu->lost_events_warned = true;
3512aca7a94dSNamhyung Kim 			}
3513aca7a94dSNamhyung Kim 			continue;
3514aca7a94dSNamhyung Kim 		case K_RIGHT:
3515aca7a94dSNamhyung Kim 		case K_ENTER:
3516aca7a94dSNamhyung Kim 			if (!menu->selection)
3517aca7a94dSNamhyung Kim 				continue;
3518aca7a94dSNamhyung Kim 			pos = menu->selection;
3519aca7a94dSNamhyung Kim browse_hists:
3520900c8eadSArnaldo Carvalho de Melo 			evlist__set_selected(evlist, pos);
3521aca7a94dSNamhyung Kim 			/*
3522aca7a94dSNamhyung Kim 			 * Give the calling tool a chance to populate the non
3523aca7a94dSNamhyung Kim 			 * default evsel resorted hists tree.
3524aca7a94dSNamhyung Kim 			 */
35259783adf7SNamhyung Kim 			if (hbt)
35269783adf7SNamhyung Kim 				hbt->timer(hbt->arg);
352756933029SArnaldo Carvalho de Melo 			key = evsel__hists_browse(pos, nr_events, help, true, hbt,
352856933029SArnaldo Carvalho de Melo 						  menu->min_pcnt, menu->env,
352922197fb2SNamhyung Kim 						  warn_lost_event);
3530aca7a94dSNamhyung Kim 			ui_browser__show_title(&menu->b, title);
3531aca7a94dSNamhyung Kim 			switch (key) {
3532aca7a94dSNamhyung Kim 			case K_TAB:
3533ce9036a6SJiri Olsa 				if (pos->core.node.next == &evlist->core.entries)
3534515dbe48SJiri Olsa 					pos = evlist__first(evlist);
3535aca7a94dSNamhyung Kim 				else
3536e470daeaSArnaldo Carvalho de Melo 					pos = evsel__next(pos);
3537aca7a94dSNamhyung Kim 				goto browse_hists;
3538aca7a94dSNamhyung Kim 			case K_UNTAB:
3539ce9036a6SJiri Olsa 				if (pos->core.node.prev == &evlist->core.entries)
3540515dbe48SJiri Olsa 					pos = evlist__last(evlist);
3541aca7a94dSNamhyung Kim 				else
3542e470daeaSArnaldo Carvalho de Melo 					pos = evsel__prev(pos);
3543aca7a94dSNamhyung Kim 				goto browse_hists;
3544341487abSFeng Tang 			case K_SWITCH_INPUT_DATA:
35455e3b810aSJin Yao 			case K_RELOAD:
3546aca7a94dSNamhyung Kim 			case 'q':
3547aca7a94dSNamhyung Kim 			case CTRL('c'):
3548aca7a94dSNamhyung Kim 				goto out;
354963ab1749SArnaldo Carvalho de Melo 			case K_ESC:
3550aca7a94dSNamhyung Kim 			default:
3551aca7a94dSNamhyung Kim 				continue;
3552aca7a94dSNamhyung Kim 			}
3553aca7a94dSNamhyung Kim 		case K_LEFT:
3554aca7a94dSNamhyung Kim 			continue;
3555aca7a94dSNamhyung Kim 		case K_ESC:
3556aca7a94dSNamhyung Kim 			if (!ui_browser__dialog_yesno(&menu->b,
3557aca7a94dSNamhyung Kim 					       "Do you really want to exit?"))
3558aca7a94dSNamhyung Kim 				continue;
3559aca7a94dSNamhyung Kim 			/* Fall thru */
3560aca7a94dSNamhyung Kim 		case 'q':
3561aca7a94dSNamhyung Kim 		case CTRL('c'):
3562aca7a94dSNamhyung Kim 			goto out;
3563aca7a94dSNamhyung Kim 		default:
3564aca7a94dSNamhyung Kim 			continue;
3565aca7a94dSNamhyung Kim 		}
3566aca7a94dSNamhyung Kim 	}
3567aca7a94dSNamhyung Kim 
3568aca7a94dSNamhyung Kim out:
3569aca7a94dSNamhyung Kim 	ui_browser__hide(&menu->b);
3570aca7a94dSNamhyung Kim 	return key;
3571aca7a94dSNamhyung Kim }
3572aca7a94dSNamhyung Kim 
filter_group_entries(struct ui_browser * browser __maybe_unused,void * entry)3573316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
3574fc24d7c2SNamhyung Kim 				 void *entry)
3575fc24d7c2SNamhyung Kim {
3576b27c4eceSJiri Olsa 	struct evsel *evsel = list_entry(entry, struct evsel, core.node);
3577fc24d7c2SNamhyung Kim 
3578c754c382SArnaldo Carvalho de Melo 	if (symbol_conf.event_group && !evsel__is_group_leader(evsel))
3579fc24d7c2SNamhyung Kim 		return true;
3580fc24d7c2SNamhyung Kim 
3581fc24d7c2SNamhyung Kim 	return false;
3582fc24d7c2SNamhyung Kim }
3583fc24d7c2SNamhyung Kim 
__evlist__tui_browse_hists(struct evlist * evlist,int nr_entries,const char * help,struct hist_browser_timer * hbt,float min_pcnt,struct perf_env * env,bool warn_lost_event)3584f4bd0b4aSArnaldo Carvalho de Melo static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, const char *help,
3585f4bd0b4aSArnaldo Carvalho de Melo 				      struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env,
358622197fb2SNamhyung Kim 				      bool warn_lost_event)
3587aca7a94dSNamhyung Kim {
358832dcd021SJiri Olsa 	struct evsel *pos;
358932dcd021SJiri Olsa 	struct evsel_menu menu = {
3590aca7a94dSNamhyung Kim 		.b = {
3591ce9036a6SJiri Olsa 			.entries    = &evlist->core.entries,
3592aca7a94dSNamhyung Kim 			.refresh    = ui_browser__list_head_refresh,
3593aca7a94dSNamhyung Kim 			.seek	    = ui_browser__list_head_seek,
3594aca7a94dSNamhyung Kim 			.write	    = perf_evsel_menu__write,
3595fc24d7c2SNamhyung Kim 			.filter	    = filter_group_entries,
3596fc24d7c2SNamhyung Kim 			.nr_entries = nr_entries,
3597aca7a94dSNamhyung Kim 			.priv	    = evlist,
3598aca7a94dSNamhyung Kim 		},
3599064f1981SNamhyung Kim 		.min_pcnt = min_pcnt,
360068d80758SNamhyung Kim 		.env = env,
3601aca7a94dSNamhyung Kim 	};
3602aca7a94dSNamhyung Kim 
3603aca7a94dSNamhyung Kim 	ui_helpline__push("Press ESC to exit");
3604aca7a94dSNamhyung Kim 
3605e5cadb93SArnaldo Carvalho de Melo 	evlist__for_each_entry(evlist, pos) {
36068ab2e96dSArnaldo Carvalho de Melo 		const char *ev_name = evsel__name(pos);
3607aca7a94dSNamhyung Kim 		size_t line_len = strlen(ev_name) + 7;
3608aca7a94dSNamhyung Kim 
3609aca7a94dSNamhyung Kim 		if (menu.b.width < line_len)
3610aca7a94dSNamhyung Kim 			menu.b.width = line_len;
3611aca7a94dSNamhyung Kim 	}
3612aca7a94dSNamhyung Kim 
361306cc1a47SKan Liang 	return perf_evsel_menu__run(&menu, nr_entries, help,
361406cc1a47SKan Liang 				    hbt, warn_lost_event);
3615aca7a94dSNamhyung Kim }
3616aca7a94dSNamhyung Kim 
evlist__single_entry(struct evlist * evlist)3617e414fd1aSArnaldo Carvalho de Melo static bool evlist__single_entry(struct evlist *evlist)
3618bee9ca1cSArnaldo Carvalho de Melo {
3619bee9ca1cSArnaldo Carvalho de Melo 	int nr_entries = evlist->core.nr_entries;
3620bee9ca1cSArnaldo Carvalho de Melo 
3621bee9ca1cSArnaldo Carvalho de Melo 	if (nr_entries == 1)
3622bee9ca1cSArnaldo Carvalho de Melo 	       return true;
3623bee9ca1cSArnaldo Carvalho de Melo 
3624bee9ca1cSArnaldo Carvalho de Melo 	if (nr_entries == 2) {
3625bee9ca1cSArnaldo Carvalho de Melo 		struct evsel *last = evlist__last(evlist);
3626bee9ca1cSArnaldo Carvalho de Melo 
3627bee9ca1cSArnaldo Carvalho de Melo 		if (evsel__is_dummy_event(last))
3628bee9ca1cSArnaldo Carvalho de Melo 			return true;
3629bee9ca1cSArnaldo Carvalho de Melo 	}
3630bee9ca1cSArnaldo Carvalho de Melo 
3631bee9ca1cSArnaldo Carvalho de Melo 	return false;
3632bee9ca1cSArnaldo Carvalho de Melo }
3633bee9ca1cSArnaldo Carvalho de Melo 
evlist__tui_browse_hists(struct evlist * evlist,const char * help,struct hist_browser_timer * hbt,float min_pcnt,struct perf_env * env,bool warn_lost_event)3634f4bd0b4aSArnaldo Carvalho de Melo int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt,
363522197fb2SNamhyung Kim 			     float min_pcnt, struct perf_env *env, bool warn_lost_event)
3636aca7a94dSNamhyung Kim {
36376484d2f9SJiri Olsa 	int nr_entries = evlist->core.nr_entries;
3638fc24d7c2SNamhyung Kim 
3639e414fd1aSArnaldo Carvalho de Melo 	if (evlist__single_entry(evlist)) {
3640d4ccbacbSArnaldo Carvalho de Melo single_entry: {
3641515dbe48SJiri Olsa 		struct evsel *first = evlist__first(evlist);
3642fc24d7c2SNamhyung Kim 
364356933029SArnaldo Carvalho de Melo 		return evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt,
364422197fb2SNamhyung Kim 					   env, warn_lost_event);
3645aca7a94dSNamhyung Kim 	}
3646d4ccbacbSArnaldo Carvalho de Melo 	}
3647aca7a94dSNamhyung Kim 
3648fc24d7c2SNamhyung Kim 	if (symbol_conf.event_group) {
364932dcd021SJiri Olsa 		struct evsel *pos;
3650fc24d7c2SNamhyung Kim 
3651fc24d7c2SNamhyung Kim 		nr_entries = 0;
3652e5cadb93SArnaldo Carvalho de Melo 		evlist__for_each_entry(evlist, pos) {
3653c754c382SArnaldo Carvalho de Melo 			if (evsel__is_group_leader(pos))
3654fc24d7c2SNamhyung Kim 				nr_entries++;
36550050f7aaSArnaldo Carvalho de Melo 		}
3656fc24d7c2SNamhyung Kim 
3657fc24d7c2SNamhyung Kim 		if (nr_entries == 1)
3658fc24d7c2SNamhyung Kim 			goto single_entry;
3659fc24d7c2SNamhyung Kim 	}
3660fc24d7c2SNamhyung Kim 
3661f4bd0b4aSArnaldo Carvalho de Melo 	return __evlist__tui_browse_hists(evlist, nr_entries, help, hbt, min_pcnt, env,
366222197fb2SNamhyung Kim 					  warn_lost_event);
3663aca7a94dSNamhyung Kim }
36645cb456afSJin Yao 
block_hists_browser__title(struct hist_browser * browser,char * bf,size_t size)36655cb456afSJin Yao static int block_hists_browser__title(struct hist_browser *browser, char *bf,
36665cb456afSJin Yao 				      size_t size)
36675cb456afSJin Yao {
36685cb456afSJin Yao 	struct hists *hists = evsel__hists(browser->block_evsel);
36698ab2e96dSArnaldo Carvalho de Melo 	const char *evname = evsel__name(browser->block_evsel);
36700f0abbacSNamhyung Kim 	unsigned long nr_samples = hists->stats.nr_samples;
36715cb456afSJin Yao 	int ret;
36725cb456afSJin Yao 
36735cb456afSJin Yao 	ret = scnprintf(bf, size, "# Samples: %lu", nr_samples);
36745cb456afSJin Yao 	if (evname)
36755cb456afSJin Yao 		scnprintf(bf + ret, size -  ret, " of event '%s'", evname);
36765cb456afSJin Yao 
36775cb456afSJin Yao 	return 0;
36785cb456afSJin Yao }
36795cb456afSJin Yao 
block_hists_tui_browse(struct block_hist * bh,struct evsel * evsel,float min_percent,struct perf_env * env)36805cb456afSJin Yao int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
368122197fb2SNamhyung Kim 			   float min_percent, struct perf_env *env)
36825cb456afSJin Yao {
36835cb456afSJin Yao 	struct hists *hists = &bh->block_hists;
36845cb456afSJin Yao 	struct hist_browser *browser;
36855cb456afSJin Yao 	int key = -1;
3686848a5e50SJin Yao 	struct popup_action action;
368720d6f555SKan Liang 	char *br_cntr_text = NULL;
36885cb456afSJin Yao 	static const char help[] =
368920d6f555SKan Liang 	" q             Quit \n"
369020d6f555SKan Liang 	" B             Branch counter abbr list (Optional)\n";
36915cb456afSJin Yao 
36925cb456afSJin Yao 	browser = hist_browser__new(hists);
36935cb456afSJin Yao 	if (!browser)
36945cb456afSJin Yao 		return -1;
36955cb456afSJin Yao 
36965cb456afSJin Yao 	browser->block_evsel = evsel;
36975cb456afSJin Yao 	browser->title = block_hists_browser__title;
36985cb456afSJin Yao 	browser->min_pcnt = min_percent;
3699848a5e50SJin Yao 	browser->env = env;
37005cb456afSJin Yao 
37015cb456afSJin Yao 	/* reset abort key so that it can get Ctrl-C as a key */
37025cb456afSJin Yao 	SLang_reset_tty();
37035cb456afSJin Yao 	SLang_init_tty(0, 0, 0);
37046af6d224SAhelenia Ziemiańska 	SLtty_set_suspend_state(true);
37055cb456afSJin Yao 
3706848a5e50SJin Yao 	memset(&action, 0, sizeof(action));
3707848a5e50SJin Yao 
3708*e6952dceSKan Liang 	if (!annotation_br_cntr_abbr_list(&br_cntr_text, evsel, false))
3709*e6952dceSKan Liang 		annotate_opts.show_br_cntr = true;
371020d6f555SKan Liang 
37115cb456afSJin Yao 	while (1) {
3712d10ec006SArnaldo Carvalho de Melo 		key = hist_browser__run(browser, "? - help", true, 0);
37135cb456afSJin Yao 
37145cb456afSJin Yao 		switch (key) {
37155cb456afSJin Yao 		case 'q':
37165cb456afSJin Yao 			goto out;
37175cb456afSJin Yao 		case '?':
37185cb456afSJin Yao 			ui_browser__help_window(&browser->b, help);
37195cb456afSJin Yao 			break;
3720848a5e50SJin Yao 		case 'a':
3721848a5e50SJin Yao 		case K_ENTER:
3722848a5e50SJin Yao 			if (!browser->selection ||
3723848a5e50SJin Yao 			    !browser->selection->sym) {
3724848a5e50SJin Yao 				continue;
3725848a5e50SJin Yao 			}
3726848a5e50SJin Yao 
3727848a5e50SJin Yao 			action.ms.map = browser->selection->map;
3728848a5e50SJin Yao 			action.ms.sym = browser->selection->sym;
3729848a5e50SJin Yao 			do_annotate(browser, &action);
3730848a5e50SJin Yao 			continue;
373120d6f555SKan Liang 		case 'B':
373220d6f555SKan Liang 			if (br_cntr_text) {
373320d6f555SKan Liang 				ui__question_window("Branch counter abbr list",
373420d6f555SKan Liang 						    br_cntr_text, "Press any key...", 0);
373520d6f555SKan Liang 			} else {
373620d6f555SKan Liang 				ui__question_window("Branch counter abbr list",
373720d6f555SKan Liang 						    "\n The branch counter is not available.\n",
373820d6f555SKan Liang 						    "Press any key...", 0);
373920d6f555SKan Liang 			}
374020d6f555SKan Liang 			continue;
37415cb456afSJin Yao 		default:
37425cb456afSJin Yao 			break;
37435cb456afSJin Yao 		}
37445cb456afSJin Yao 	}
37455cb456afSJin Yao 
37465cb456afSJin Yao out:
37475cb456afSJin Yao 	hist_browser__delete(browser);
374820d6f555SKan Liang 	free(br_cntr_text);
37495cb456afSJin Yao 	return 0;
37505cb456afSJin Yao }
3751