1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdio.h>
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../libslang.h"
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdlib.h>
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <string.h>
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <linux/rbtree.h>
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/evsel.h"
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/evlist.h"
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/hist.h"
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/pstack.h"
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/sort.h"
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/util.h"
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../arch/common.h"
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../browser.h"
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../helpline.h"
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../util.h"
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../ui.h"
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "map.h"
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct hist_browser {
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct ui_browser   b;
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hists	    *hists;
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hist_entry   *he_selection;
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_symbol   *selection;
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		     print_seq;
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool		     show_dso;
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	float		     min_pcnt;
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		     nr_pcnt_entries;
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengextern void hist_browser__init_hpp(void);
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hists__browser_title(struct hists *hists, char *bf, size_t size,
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				const char *ev_name);
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hist_browser__refresh_dimensions(struct hist_browser *browser)
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* 3 == +/- toggle symbol before actual hist_entry rendering */
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     sizeof("[k]"));
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hist_browser__reset(struct hist_browser *browser)
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.nr_entries = browser->hists->nr_entries;
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hist_browser__refresh_dimensions(browser);
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__reset_index(&browser->b);
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char tree__folded_sign(bool unfolded)
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return unfolded ? '-' : '+';
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char map_symbol__folded(const struct map_symbol *ms)
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char hist_entry__folded(const struct hist_entry *he)
62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return map_symbol__folded(&he->ms);
64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char callchain_list__folded(const struct callchain_list *cl)
67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return map_symbol__folded(&cl->ms);
69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ms->unfolded = unfold ? ms->has_children : false;
74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int callchain_node__count_rows_rb_tree(struct callchain_node *node)
77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int n = 0;
79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_list *chain;
84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char folded_sign = ' '; /* No children */
85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		list_for_each_entry(chain, &child->val, list) {
87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			++n;
88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/* We need this because we may not have children */
89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			folded_sign = callchain_list__folded(chain);
90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (folded_sign == '+')
91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (folded_sign == '-') /* Have children and they're unfolded */
95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			n += callchain_node__count_rows_rb_tree(child);
96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return n;
99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int callchain_node__count_rows(struct callchain_node *node)
102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct callchain_list *chain;
104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool unfolded = false;
105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int n = 0;
106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(chain, &node->val, list) {
108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		++n;
109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		unfolded = chain->ms.unfolded;
110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (unfolded)
113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		n += callchain_node__count_rows_rb_tree(node);
114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return n;
116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int callchain__count_rows(struct rb_root *chain)
119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int n = 0;
122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		n += callchain_node__count_rows(node);
126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return n;
129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool map_symbol__toggle_fold(struct map_symbol *ms)
132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!ms)
134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return false;
135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!ms->has_children)
137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return false;
138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ms->unfolded = !ms->unfolded;
140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return true;
141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd = rb_first(&node->rb_root);
146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_list *chain;
150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		bool first = true;
151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		list_for_each_entry(chain, &child->val, list) {
153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (first) {
154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				first = false;
155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				chain->ms.has_children = chain->list.next != &child->val ||
156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							 !RB_EMPTY_ROOT(&child->rb_root);
157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else
158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				chain->ms.has_children = chain->list.next == &child->val &&
159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							 !RB_EMPTY_ROOT(&child->rb_root);
160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		callchain_node__init_have_children_rb_tree(child);
163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void callchain_node__init_have_children(struct callchain_node *node)
167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct callchain_list *chain;
169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(chain, &node->val, list)
171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	callchain_node__init_have_children_rb_tree(node);
174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void callchain__init_have_children(struct rb_root *root)
177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		callchain_node__init_have_children(node);
183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hist_entry__init_have_children(struct hist_entry *he)
187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!he->init_have_children) {
189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		callchain__init_have_children(&he->sorted_chain);
191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		he->init_have_children = true;
192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool hist_browser__toggle_fold(struct hist_browser *browser)
196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (map_symbol__toggle_fold(browser->selection)) {
198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hist_entry *he = browser->he_selection;
199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		hist_entry__init_have_children(he);
201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->hists->nr_entries -= he->nr_rows;
202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (he->ms.unfolded)
204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			he->nr_rows = callchain__count_rows(&he->sorted_chain);
205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else
206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			he->nr_rows = 0;
207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->hists->nr_entries += he->nr_rows;
208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.nr_entries = browser->hists->nr_entries;
209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return true;
211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* If it doesn't have children, no toggling performed */
214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return false;
215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int n = 0;
220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_list *chain;
225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		bool has_children = false;
226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		list_for_each_entry(chain, &child->val, list) {
228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			++n;
229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			map_symbol__set_folding(&chain->ms, unfold);
230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			has_children = chain->ms.has_children;
231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (has_children)
234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			n += callchain_node__set_folding_rb_tree(child, unfold);
235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return n;
238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int callchain_node__set_folding(struct callchain_node *node, bool unfold)
241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct callchain_list *chain;
243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool has_children = false;
244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int n = 0;
245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(chain, &node->val, list) {
247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		++n;
248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		map_symbol__set_folding(&chain->ms, unfold);
249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		has_children = chain->ms.has_children;
250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (has_children)
253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		n += callchain_node__set_folding_rb_tree(node, unfold);
254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return n;
256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int callchain__set_folding(struct rb_root *chain, bool unfold)
259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int n = 0;
262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		n += callchain_node__set_folding(node, unfold);
266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return n;
269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hist_entry__set_folding(struct hist_entry *he, bool unfold)
272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hist_entry__init_have_children(he);
274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	map_symbol__set_folding(&he->ms, unfold);
275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (he->ms.has_children) {
277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int n = callchain__set_folding(&he->sorted_chain, unfold);
278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		he->nr_rows = unfold ? n : 0;
279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else
280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		he->nr_rows = 0;
281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hists__set_folding(struct hists *hists, bool unfold)
284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hists->nr_entries = 0;
288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		hist_entry__set_folding(he, unfold);
292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		hists->nr_entries += 1 + he->nr_rows;
293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hists__set_folding(browser->hists, unfold);
299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.nr_entries = browser->hists->nr_entries;
300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* Go to the start, we may be way after valid entries after a collapse */
301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__reset_index(&browser->b);
302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void ui_browser__warn_lost_events(struct ui_browser *browser)
305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__warning(browser, 4,
307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"Events are being lost, check IO/CPU overload!\n\n"
308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"You may want to run 'perf' using a RT scheduler policy:\n\n"
309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		" perf top -r 80\n\n"
310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"Or reduce the sampling frequency.");
311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hist_browser__update_pcnt_entries(struct hist_browser *hb);
314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__run(struct hist_browser *browser, const char *ev_name,
316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     struct hist_browser_timer *hbt)
317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int key;
319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char title[160];
320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int delay_secs = hbt ? hbt->refresh : 0;
321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.entries = &browser->hists->entries;
323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	browser->b.nr_entries = browser->hists->nr_entries;
324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (browser->min_pcnt)
325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.nr_entries = browser->nr_pcnt_entries;
326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hist_browser__refresh_dimensions(browser);
328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hists__browser_title(browser->hists, title, sizeof(title), ev_name);
329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ui_browser__show(&browser->b, title,
331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     "Press '?' for help on key bindings") < 0)
332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (1) {
335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		key = ui_browser__run(&browser->b, delay_secs);
336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		switch (key) {
338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_TIMER: {
339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			u64 nr_entries;
340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hbt->timer(hbt->arg);
341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->min_pcnt) {
343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hist_browser__update_pcnt_entries(browser);
344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				nr_entries = browser->nr_pcnt_entries;
345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else {
346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				nr_entries = browser->hists->nr_entries;
347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__update_nr_entries(&browser->b, nr_entries);
350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->hists->stats.nr_lost_warned !=
352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				browser->hists->stats.nr_lost_warned =
354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					browser->hists->stats.nr_events[PERF_RECORD_LOST];
355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_browser__warn_lost_events(&browser->b);
356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hists__browser_title(browser->hists, title, sizeof(title), ev_name);
359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__show_title(&browser->b, title);
360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'D': { /* Debug */
363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			static int seq;
364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			struct hist_entry *h = rb_entry(browser->b.top,
365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							struct hist_entry, rb_node);
366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_helpline__pop();
367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   seq++, browser->b.nr_entries,
369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->hists->nr_entries,
370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->b.height,
371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->b.index,
372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->b.top_idx,
373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   h->row_offset, h->nr_rows);
374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'C':
377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/* Collapse the whole world. */
378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hist_browser__set_folding(browser, false);
379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'E':
381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/* Expand the whole world. */
382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hist_browser__set_folding(browser, true);
383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_ENTER:
385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (hist_browser__toggle_fold(browser))
386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/* fall thru */
388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		default:
389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out;
390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__hide(&browser->b);
394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return key;
395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char *callchain_list__sym_name(struct callchain_list *cl,
398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      char *bf, size_t bfsize, bool show_dso)
399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int printed;
401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (cl->ms.sym)
403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (show_dso)
408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		scnprintf(bf + printed, bfsize - printed, " %s",
409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			  cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return bf;
412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define LEVEL_OFFSET_STEP 3
415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						     struct callchain_node *chain_node,
418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						     u64 total, int level,
419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						     unsigned short row,
420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						     off_t *row_offset,
421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						     bool *is_current_entry)
422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *node;
424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 new_total, remaining;
426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (callchain_param.mode == CHAIN_GRAPH_REL)
428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		new_total = chain_node->children_hit;
429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		new_total = total;
431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	remaining = new_total;
433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	node = rb_first(&chain_node->rb_root);
434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (node) {
435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct rb_node *next = rb_next(node);
437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		u64 cumul = callchain_cumul_hits(child);
438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_list *chain;
439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char folded_sign = ' ';
440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int first = true;
441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int extra_offset = 0;
442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		remaining -= cumul;
444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		list_for_each_entry(chain, &child->val, list) {
446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			char bf[1024], *alloc_str;
447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			const char *str;
448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			int color;
449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			bool was_first = first;
450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (first)
452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				first = false;
453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			else
454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				extra_offset = LEVEL_OFFSET_STEP;
455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			folded_sign = callchain_list__folded(chain);
457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (*row_offset != 0) {
458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				--*row_offset;
459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto do_next;
460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			alloc_str = NULL;
463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			str = callchain_list__sym_name(chain, bf, sizeof(bf),
464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						       browser->show_dso);
465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (was_first) {
466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				double percent = cumul * 100.0 / new_total;
467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
469e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					str = "Not enough memory!";
470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				else
471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					str = alloc_str;
472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			color = HE_COLORSET_NORMAL;
475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			width = browser->b.width - (offset + extra_offset + 2);
476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (ui_browser__is_current_entry(&browser->b, row)) {
477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				browser->selection = &chain->ms;
478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				color = HE_COLORSET_SELECTED;
479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				*is_current_entry = true;
480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__set_color(&browser->b, color);
483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__gotorc(&browser->b, row, 0);
484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			slsmg_write_nstring(" ", offset + extra_offset);
485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			slsmg_printf("%c ", folded_sign);
486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			slsmg_write_nstring(str, width);
487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			free(alloc_str);
488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (++row == browser->b.height)
490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto out;
491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengdo_next:
492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (folded_sign == '+')
493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (folded_sign == '-') {
497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			const int new_level = level + (extra_offset ? 2 : 1);
498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng									 new_level, row, row_offset,
500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng									 is_current_entry);
501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (row == browser->b.height)
503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out;
504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		node = next;
505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return row - first_row;
508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__show_callchain_node(struct hist_browser *browser,
511e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					     struct callchain_node *node,
512e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					     int level, unsigned short row,
513e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					     off_t *row_offset,
514e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					     bool *is_current_entry)
515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct callchain_list *chain;
517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int first_row = row,
518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	     offset = level * LEVEL_OFFSET_STEP,
519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	     width = browser->b.width - offset;
520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char folded_sign = ' ';
521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(chain, &node->val, list) {
523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char bf[1024], *s;
524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int color;
525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		folded_sign = callchain_list__folded(chain);
527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (*row_offset != 0) {
529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			--*row_offset;
530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		color = HE_COLORSET_NORMAL;
534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (ui_browser__is_current_entry(&browser->b, row)) {
535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browser->selection = &chain->ms;
536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			color = HE_COLORSET_SELECTED;
537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			*is_current_entry = true;
538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		s = callchain_list__sym_name(chain, bf, sizeof(bf),
541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					     browser->show_dso);
542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_browser__gotorc(&browser->b, row, 0);
543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_browser__set_color(&browser->b, color);
544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(" ", offset);
545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_printf("%c ", folded_sign);
546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(s, width - 2);
547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (++row == browser->b.height)
549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out;
550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (folded_sign == '-')
553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		row += hist_browser__show_callchain_node_rb_tree(browser, node,
554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng								 browser->hists->stats.total_period,
555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng								 level + 1, row,
556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng								 row_offset,
557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng								 is_current_entry);
558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return row - first_row;
560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__show_callchain(struct hist_browser *browser,
563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					struct rb_root *chain,
564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					int level, unsigned short row,
565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					off_t *row_offset,
566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					bool *is_current_entry)
567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int first_row = row;
570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
572e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
573e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
574e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		row += hist_browser__show_callchain_node(browser, node, level,
575e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							 row, row_offset,
576e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							 is_current_entry);
577e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (row == browser->b.height)
578e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
579e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
580e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
581e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return row - first_row;
582e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
583e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
584e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct hpp_arg {
585e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct ui_browser *b;
586e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char folded_sign;
587e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool current_entry;
588e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
589e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
590e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int __hpp__color_callchain(struct hpp_arg *arg)
591e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
592e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!symbol_conf.use_callchain)
593e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
594e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
595e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	slsmg_printf("%c ", arg->folded_sign);
596e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 2;
597e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
598e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
599e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
600e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    u64 (*get_field)(struct hist_entry *),
601e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    int (*callchain_cb)(struct hpp_arg *))
602e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
603e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret = 0;
604e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	double percent = 0.0;
605e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hists *hists = he->hists;
606e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hpp_arg *arg = hpp->ptr;
607e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
608e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (hists->stats.total_period)
609e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		percent = 100.0 * get_field(he) / hists->stats.total_period;
610e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
611e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
612e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
613e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (callchain_cb)
614e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ret += callchain_cb(arg);
615e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
616e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
617e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	slsmg_printf("%s", hpp->buf);
618e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
619e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol_conf.event_group) {
620e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int prev_idx, idx_delta;
621e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct perf_evsel *evsel = hists_to_evsel(hists);
622e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hist_entry *pair;
623e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int nr_members = evsel->nr_members;
624e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
625e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (nr_members <= 1)
626e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out;
627e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
628e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		prev_idx = perf_evsel__group_idx(evsel);
629e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
630e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		list_for_each_entry(pair, &he->pairs.head, pairs.node) {
631e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			u64 period = get_field(pair);
632e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			u64 total = pair->hists->stats.total_period;
633e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
634e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!total)
635e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
636e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
637e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			evsel = hists_to_evsel(pair->hists);
638e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
639e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
640e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			while (idx_delta--) {
641e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				/*
642e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 * zero-fill group members in the middle which
643e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 * have no sample
644e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 */
645e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_browser__set_percent_color(arg->b, 0.0,
646e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							arg->current_entry);
647e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ret += scnprintf(hpp->buf, hpp->size,
648e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						 " %6.2f%%", 0.0);
649e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				slsmg_printf("%s", hpp->buf);
650e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
651e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
652e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			percent = 100.0 * period / total;
653e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__set_percent_color(arg->b, percent,
654e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						      arg->current_entry);
655e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ret += scnprintf(hpp->buf, hpp->size,
656e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 " %6.2f%%", percent);
657e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			slsmg_printf("%s", hpp->buf);
658e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
659e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			prev_idx = perf_evsel__group_idx(evsel);
660e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
661e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
662e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		idx_delta = nr_members - prev_idx - 1;
663e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
664e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		while (idx_delta--) {
665e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/*
666e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * zero-fill group members at last which have no sample
667e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 */
668e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__set_percent_color(arg->b, 0.0,
669e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						      arg->current_entry);
670e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ret += scnprintf(hpp->buf, hpp->size,
671e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 " %6.2f%%", 0.0);
672e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			slsmg_printf("%s", hpp->buf);
673e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
674e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
675e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
676e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!arg->current_entry || !arg->b->navkeypressed)
677e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
678e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
679e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ret;
680e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
681e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
682e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb)			\
683e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic u64 __hpp_get_##_field(struct hist_entry *he)			\
684e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{									\
685e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return he->stat._field;						\
686e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}									\
687e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng									\
688e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int								\
689e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chenghist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
690e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct perf_hpp *hpp,			\
691e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct hist_entry *he)			\
692e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{									\
693e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb);	\
694e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
695e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
696e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
697e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
698e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
699e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
700e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
701e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
702e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#undef __HPP_COLOR_PERCENT_FN
703e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
704e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid hist_browser__init_hpp(void)
705e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
706e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_hpp__init();
707e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
708e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_hpp__format[PERF_HPP__OVERHEAD].color =
709e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hist_browser__hpp_color_overhead;
710e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
711e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hist_browser__hpp_color_overhead_sys;
712e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
713e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hist_browser__hpp_color_overhead_us;
714e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
715e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hist_browser__hpp_color_overhead_guest_sys;
716e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
717e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hist_browser__hpp_color_overhead_guest_us;
718e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
719e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
720e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__show_entry(struct hist_browser *browser,
721e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    struct hist_entry *entry,
722e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    unsigned short row)
723e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
724e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char s[256];
725e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int printed = 0;
726e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int width = browser->b.width;
727e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char folded_sign = ' ';
728e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
729e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	off_t row_offset = entry->row_offset;
730e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool first = true;
731e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_hpp_fmt *fmt;
732e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
733e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (current_entry) {
734e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->he_selection = entry;
735e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->selection = &entry->ms;
736e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
737e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
738e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol_conf.use_callchain) {
739e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		hist_entry__init_have_children(entry);
740e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		folded_sign = hist_entry__folded(entry);
741e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
742e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
743e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (row_offset == 0) {
744e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hpp_arg arg = {
745e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.b 		= &browser->b,
746e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.folded_sign	= folded_sign,
747e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.current_entry	= current_entry,
748e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		};
749e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct perf_hpp hpp = {
750e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.buf		= s,
751e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.size		= sizeof(s),
752e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.ptr		= &arg,
753e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		};
754e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
755e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_browser__gotorc(&browser->b, row, 0);
756e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
757e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		perf_hpp__for_each_format(fmt) {
758e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!first) {
759e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				slsmg_printf("  ");
760e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				width -= 2;
761e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
762e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			first = false;
763e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
764e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (fmt->color) {
765e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				width -= fmt->color(fmt, &hpp, entry);
766e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else {
767e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				width -= fmt->entry(fmt, &hpp, entry);
768e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				slsmg_printf("%s", s);
769e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
770e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
771e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
772e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		/* The scroll bar isn't being used */
773e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!browser->b.navkeypressed)
774e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			width += 1;
775e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
776e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists);
777e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(s, width);
778e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		++row;
779e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		++printed;
780e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else
781e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		--row_offset;
782e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
783e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (folded_sign == '-' && row != browser->b.height) {
784e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
785e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							1, row, &row_offset,
786e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							&current_entry);
787e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (current_entry)
788e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browser->he_selection = entry;
789e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
790e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
791e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return printed;
792e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
793e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
794e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void ui_browser__hists_init_top(struct ui_browser *browser)
795e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
796e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (browser->top == NULL) {
797e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hist_browser *hb;
798e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
799e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		hb = container_of(browser, struct hist_browser, b);
800e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->top = rb_first(&hb->hists->entries);
801e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
802e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
803e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
804e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic unsigned int hist_browser__refresh(struct ui_browser *browser)
805e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
806e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned row = 0;
807e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
808e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
809e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
810e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__hists_init_top(browser);
811e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
812e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = browser->top; nd; nd = rb_next(nd)) {
813e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
814e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		float percent = h->stat.period * 100.0 /
815e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					hb->hists->stats.total_period;
816e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
817e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (h->filtered)
818e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
819e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
820e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (percent < hb->min_pcnt)
821e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
822e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
823e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		row += hist_browser__show_entry(hb, h, row);
824e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (row == browser->height)
825e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
826e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
827e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
828e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return row;
829e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
830e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
831e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct rb_node *hists__filter_entries(struct rb_node *nd,
832e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					     struct hists *hists,
833e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					     float min_pcnt)
834e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
835e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (nd != NULL) {
836e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
837e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		float percent = h->stat.period * 100.0 /
838e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					hists->stats.total_period;
839e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
840e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (percent < min_pcnt)
841e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return NULL;
842e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
843e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!h->filtered)
844e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return nd;
845e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
846e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nd = rb_next(nd);
847e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
848e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
849e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return NULL;
850e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
851e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
852e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
853e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						  struct hists *hists,
854e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						  float min_pcnt)
855e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
856e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (nd != NULL) {
857e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
858e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		float percent = h->stat.period * 100.0 /
859e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					hists->stats.total_period;
860e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
861e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!h->filtered && percent >= min_pcnt)
862e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return nd;
863e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
864e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nd = rb_prev(nd);
865e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
866e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
867e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return NULL;
868e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
869e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
870e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void ui_browser__hists_seek(struct ui_browser *browser,
871e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   off_t offset, int whence)
872e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
873e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hist_entry *h;
874e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
875e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool first = true;
876e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hist_browser *hb;
877e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
878e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hb = container_of(browser, struct hist_browser, b);
879e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
880e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (browser->nr_entries == 0)
881e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
882e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
883e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__hists_init_top(browser);
884e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
885e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	switch (whence) {
886e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case SEEK_SET:
887e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nd = hists__filter_entries(rb_first(browser->entries),
888e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   hb->hists, hb->min_pcnt);
889e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
890e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case SEEK_CUR:
891e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nd = browser->top;
892e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		goto do_offset;
893e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case SEEK_END:
894e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nd = hists__filter_prev_entries(rb_last(browser->entries),
895e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						hb->hists, hb->min_pcnt);
896e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		first = false;
897e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
898e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	default:
899e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
900e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
901e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
902e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
903e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * Moves not relative to the first visible entry invalidates its
904e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * row_offset:
905e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
906e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	h = rb_entry(browser->top, struct hist_entry, rb_node);
907e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	h->row_offset = 0;
908e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
909e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
910e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * Here we have to check if nd is expanded (+), if it is we can't go
911e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * the next top level hist_entry, instead we must compute an offset of
912e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * what _not_ to show and not change the first visible entry.
913e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 *
914e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * This offset increments when we are going from top to bottom and
915e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * decreases when we're going from bottom to top.
916e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 *
917e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * As we don't have backpointers to the top level in the callchains
918e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * structure, we need to always print the whole hist_entry callchain,
919e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * skipping the first ones that are before the first visible entry
920e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * and stop when we printed enough lines to fill the screen.
921e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
922e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengdo_offset:
923e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (offset > 0) {
924e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		do {
925e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			h = rb_entry(nd, struct hist_entry, rb_node);
926e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (h->ms.unfolded) {
927e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				u16 remaining = h->nr_rows - h->row_offset;
928e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (offset > remaining) {
929e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					offset -= remaining;
930e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					h->row_offset = 0;
931e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				} else {
932e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					h->row_offset += offset;
933e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					offset = 0;
934e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					browser->top = nd;
935e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					break;
936e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				}
937e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
938e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			nd = hists__filter_entries(rb_next(nd), hb->hists,
939e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						   hb->min_pcnt);
940e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (nd == NULL)
941e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
942e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			--offset;
943e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browser->top = nd;
944e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} while (offset != 0);
945e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else if (offset < 0) {
946e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		while (1) {
947e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			h = rb_entry(nd, struct hist_entry, rb_node);
948e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (h->ms.unfolded) {
949e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (first) {
950e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					if (-offset > h->row_offset) {
951e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						offset += h->row_offset;
952e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						h->row_offset = 0;
953e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					} else {
954e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						h->row_offset += offset;
955e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						offset = 0;
956e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						browser->top = nd;
957e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						break;
958e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					}
959e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				} else {
960e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					if (-offset > h->nr_rows) {
961e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						offset += h->nr_rows;
962e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						h->row_offset = 0;
963e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					} else {
964e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						h->row_offset = h->nr_rows + offset;
965e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						offset = 0;
966e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						browser->top = nd;
967e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						break;
968e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					}
969e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				}
970e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
971e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
972e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
973e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							hb->min_pcnt);
974e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (nd == NULL)
975e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
976e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			++offset;
977e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browser->top = nd;
978e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (offset == 0) {
979e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				/*
980e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 * Last unfiltered hist_entry, check if it is
981e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 * unfolded, if it is then we should have
982e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 * row_offset at its last entry.
983e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 */
984e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				h = rb_entry(nd, struct hist_entry, rb_node);
985e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (h->ms.unfolded)
986e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					h->row_offset = h->nr_rows;
987e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
988e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
989e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			first = false;
990e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
991e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else {
992e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->top = nd;
993e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		h = rb_entry(nd, struct hist_entry, rb_node);
994e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		h->row_offset = 0;
995e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
996e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
997e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
998e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
999e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							struct callchain_node *chain_node,
1000e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							u64 total, int level,
1001e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng							FILE *fp)
1002e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1003e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *node;
1004e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int offset = level * LEVEL_OFFSET_STEP;
1005e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 new_total, remaining;
1006e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int printed = 0;
1007e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1008e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (callchain_param.mode == CHAIN_GRAPH_REL)
1009e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		new_total = chain_node->children_hit;
1010e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
1011e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		new_total = total;
1012e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1013e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	remaining = new_total;
1014e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	node = rb_first(&chain_node->rb_root);
1015e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (node) {
1016e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1017e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct rb_node *next = rb_next(node);
1018e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		u64 cumul = callchain_cumul_hits(child);
1019e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_list *chain;
1020e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char folded_sign = ' ';
1021e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int first = true;
1022e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int extra_offset = 0;
1023e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1024e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		remaining -= cumul;
1025e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1026e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		list_for_each_entry(chain, &child->val, list) {
1027e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			char bf[1024], *alloc_str;
1028e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			const char *str;
1029e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			bool was_first = first;
1030e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1031e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (first)
1032e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				first = false;
1033e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			else
1034e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				extra_offset = LEVEL_OFFSET_STEP;
1035e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1036e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			folded_sign = callchain_list__folded(chain);
1037e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1038e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			alloc_str = NULL;
1039e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			str = callchain_list__sym_name(chain, bf, sizeof(bf),
1040e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						       browser->show_dso);
1041e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (was_first) {
1042e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				double percent = cumul * 100.0 / new_total;
1043e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1044e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1045e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					str = "Not enough memory!";
1046e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				else
1047e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					str = alloc_str;
1048e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1049e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1050e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1051e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			free(alloc_str);
1052e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (folded_sign == '+')
1053e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
1054e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1055e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1056e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (folded_sign == '-') {
1057e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			const int new_level = level + (extra_offset ? 2 : 1);
1058e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1059e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng										new_level, fp);
1060e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1061e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1062e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		node = next;
1063e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1064e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1065e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return printed;
1066e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1067e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1068e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1069e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						struct callchain_node *node,
1070e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						int level, FILE *fp)
1071e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1072e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct callchain_list *chain;
1073e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int offset = level * LEVEL_OFFSET_STEP;
1074e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char folded_sign = ' ';
1075e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int printed = 0;
1076e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1077e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(chain, &node->val, list) {
1078e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char bf[1024], *s;
1079e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1080e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		folded_sign = callchain_list__folded(chain);
1081e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
1082e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1083e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1084e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1085e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (folded_sign == '-')
1086e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1087e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng									browser->hists->stats.total_period,
1088e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng									level + 1,  fp);
1089e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return printed;
1090e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1091e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1092e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__fprintf_callchain(struct hist_browser *browser,
1093e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   struct rb_root *chain, int level, FILE *fp)
1094e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1095e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
1096e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int printed = 0;
1097e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1098e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1099e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return printed;
1105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__fprintf_entry(struct hist_browser *browser,
1108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				       struct hist_entry *he, FILE *fp)
1109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char s[8192];
1111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	double percent;
1112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int printed = 0;
1113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char folded_sign = ' ';
1114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol_conf.use_callchain)
1116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		folded_sign = hist_entry__folded(he);
1117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
1119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
1120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol_conf.use_callchain)
1122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += fprintf(fp, "%c ", folded_sign);
1123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printed += fprintf(fp, " %5.2f%%", percent);
1125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol_conf.show_nr_samples)
1127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += fprintf(fp, " %11u", he->stat.nr_events);
1128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol_conf.show_total_period)
1130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += fprintf(fp, " %12" PRIu64, he->stat.period);
1131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printed += fprintf(fp, "%s\n", rtrim(s));
1133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (folded_sign == '-')
1135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return printed;
1138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						   browser->hists,
1144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						   browser->min_pcnt);
1145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int printed = 0;
1146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (nd) {
1148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += hist_browser__fprintf_entry(browser, h, fp);
1151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nd = hists__filter_entries(rb_next(nd), browser->hists,
1152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   browser->min_pcnt);
1153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return printed;
1156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hist_browser__dump(struct hist_browser *browser)
1159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char filename[64];
1161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	FILE *fp;
1162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (1) {
1164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (access(filename, F_OK))
1166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
1167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		/*
1168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 		 * XXX: Just an arbitrary lazy upper limit
1169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 		 */
1170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (++browser->print_seq == 8192) {
1171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fp = fopen(filename, "w");
1177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (fp == NULL) {
1178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char bf[64];
1179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		const char *err = strerror_r(errno, bf, sizeof(bf));
1180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
1181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	++browser->print_seq;
1185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hist_browser__fprintf(browser, fp);
1186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fclose(fp);
1187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_helpline__fpush("%s written!", filename);
1188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct hist_browser *hist_browser__new(struct hists *hists)
1193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hist_browser *browser = zalloc(sizeof(*browser));
1195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (browser) {
1197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->hists = hists;
1198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.refresh = hist_browser__refresh;
1199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.seek = ui_browser__hists_seek;
1200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->b.use_navkeypressed = true;
1201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return browser;
1204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hist_browser__delete(struct hist_browser *browser)
1207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(browser);
1209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
1212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return browser->he_selection;
1214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct thread *hist_browser__selected_thread(struct hist_browser *browser)
1217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return browser->he_selection->thread;
1219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int hists__browser_title(struct hists *hists, char *bf, size_t size,
1222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				const char *ev_name)
1223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char unit;
1225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int printed;
1226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const struct dso *dso = hists->dso_filter;
1227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const struct thread *thread = hists->thread_filter;
1228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 nr_events = hists->stats.total_period;
1230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evsel *evsel = hists_to_evsel(hists);
1231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char buf[512];
1232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size_t buflen = sizeof(buf);
1233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (perf_evsel__is_group_event(evsel)) {
1235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct perf_evsel *pos;
1236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		perf_evsel__group_desc(evsel, buf, buflen);
1238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ev_name = buf;
1239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		for_each_group_member(pos, evsel) {
1241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			nr_events += pos->hists.stats.total_period;
1243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	nr_samples = convert_unit(nr_samples, &unit);
1247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printed = scnprintf(bf, size,
1248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			   "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			   nr_samples, unit, ev_name, nr_events);
1250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (hists->uid_filter_str)
1253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += snprintf(bf + printed, size - printed,
1254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    ", UID: %s", hists->uid_filter_str);
1255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (thread)
1256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += scnprintf(bf + printed, size - printed,
1257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    ", Thread: %s(%d)",
1258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    (thread->comm_set ? thread->comm : ""),
1259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    thread->tid);
1260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (dso)
1261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += scnprintf(bf + printed, size - printed,
1262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    ", DSO: %s", dso->short_name);
1263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return printed;
1264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline void free_popup_options(char **options, int n)
1267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i;
1269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < n; ++i) {
1271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		free(options[i]);
1272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		options[i] = NULL;
1273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Check whether the browser is for 'top' or 'report' */
1277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline bool is_report_browser(void *timer)
1278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return timer == NULL;
1280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/*
1283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Only runtime switching of perf data file will make "input_name" point
1284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * whether we need to call free() for current "input_name" during the switch.
1286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */
1287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool is_input_name_malloced = false;
1288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int switch_data_file(void)
1290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char *pwd, *options[32], *abs_path[32], *tmp;
1292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	DIR *pwd_dir;
1293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int nr_options = 0, choice = -1, ret = -1;
1294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct dirent *dent;
1295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pwd = getenv("PWD");
1297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!pwd)
1298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return ret;
1299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pwd_dir = opendir(pwd);
1301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!pwd_dir)
1302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return ret;
1303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	memset(options, 0, sizeof(options));
1305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	memset(options, 0, sizeof(abs_path));
1306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while ((dent = readdir(pwd_dir))) {
1308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char path[PATH_MAX];
1309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		u64 magic;
1310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char *name = dent->d_name;
1311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		FILE *file;
1312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!(dent->d_type == DT_REG))
1314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		snprintf(path, sizeof(path), "%s/%s", pwd, name);
1317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		file = fopen(path, "r");
1319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!file)
1320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (fread(&magic, 1, 8, file) < 8)
1323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto close_file_and_continue;
1324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (is_perf_magic(magic)) {
1326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			options[nr_options] = strdup(name);
1327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!options[nr_options])
1328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto close_file_and_continue;
1329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			abs_path[nr_options] = strdup(path);
1331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!abs_path[nr_options]) {
1332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				free(options[nr_options]);
1333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui__warning("Can't search all data files due to memory shortage.\n");
1334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				fclose(file);
1335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
1336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			nr_options++;
1339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengclose_file_and_continue:
1342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		fclose(file);
1343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (nr_options >= 32) {
1344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui__warning("Too many perf data files in PWD!\n"
1345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    "Only the first 32 files will be listed.\n");
1346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
1347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	closedir(pwd_dir);
1350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (nr_options) {
1352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		choice = ui__popup_menu(nr_options, options);
1353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (choice < nr_options && choice >= 0) {
1354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			tmp = strdup(abs_path[choice]);
1355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (tmp) {
1356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (is_input_name_malloced)
1357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					free((void *)input_name);
1358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				input_name = tmp;
1359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				is_input_name_malloced = true;
1360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ret = 0;
1361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else
1362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui__warning("Data switch failed due to memory shortage!\n");
1363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free_popup_options(options, nr_options);
1367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free_popup_options(abs_path, nr_options);
1368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ret;
1369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void hist_browser__update_pcnt_entries(struct hist_browser *hb)
1372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 nr_entries = 0;
1374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd = rb_first(&hb->hists->entries);
1375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (nd) {
1377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nr_entries++;
1378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nd = hists__filter_entries(rb_next(nd), hb->hists,
1379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   hb->min_pcnt);
1380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hb->nr_pcnt_entries = nr_entries;
1383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    const char *helpline, const char *ev_name,
1387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    bool left_exits,
1388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    struct hist_browser_timer *hbt,
1389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    float min_pcnt,
1390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    struct perf_session_env *env)
1391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hists *hists = &evsel->hists;
1393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct hist_browser *browser = hist_browser__new(hists);
1394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct branch_info *bi;
1395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct pstack *fstack;
1396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char *options[16];
1397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int nr_options = 0;
1398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int key = -1;
1399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char buf[64];
1400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char script_opt[64];
1401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int delay_secs = hbt ? hbt->refresh : 0;
1402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (browser == NULL)
1404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (min_pcnt) {
1407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		browser->min_pcnt = min_pcnt;
1408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		hist_browser__update_pcnt_entries(browser);
1409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fstack = pstack__new(2);
1412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (fstack == NULL)
1413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		goto out;
1414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_helpline__push(helpline);
1416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	memset(options, 0, sizeof(options));
1418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (1) {
1420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		const struct thread *thread = NULL;
1421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		const struct dso *dso = NULL;
1422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int choice = 0,
1423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    annotate = -2, zoom_dso = -2, zoom_thread = -2,
1424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    annotate_f = -2, annotate_t = -2, browse_map = -2;
1425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int scripts_comm = -2, scripts_symbol = -2,
1426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    scripts_all = -2, switch_data = -2;
1427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nr_options = 0;
1429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		key = hist_browser__run(browser, ev_name, hbt);
1431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (browser->he_selection != NULL) {
1433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			thread = hist_browser__selected_thread(browser);
1434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			dso = browser->selection->map ? browser->selection->map->dso : NULL;
1435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		switch (key) {
1437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_TAB:
1438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_UNTAB:
1439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (nr_events == 1)
1440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/*
1442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * Exit the browser, let hists__browser_tree
1443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * go to the next or previous
1444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 */
1445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_free_stack;
1446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'a':
1447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!sort__has_sym) {
1448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_browser__warning(&browser->b, delay_secs * 2,
1449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			"Annotation is only available for symbolic views, "
1450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			"include \"sym*\" in --sort to use it.");
1451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->selection == NULL ||
1455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    browser->selection->sym == NULL ||
1456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    browser->selection->map->dso->annotate_warned)
1457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto do_annotate;
1459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'P':
1460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hist_browser__dump(browser);
1461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'd':
1463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto zoom_dso;
1464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'V':
1465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browser->show_dso = !browser->show_dso;
1466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 't':
1468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto zoom_thread;
1469e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case '/':
1470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (ui_browser__input_window("Symbol to show",
1471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"Please enter the name of symbol you want to see",
1472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					buf, "ENTER: OK, ESC: Cancel",
1473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					delay_secs * 2) == K_ENTER) {
1474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hists->symbol_filter_str = *buf ? buf : NULL;
1475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hists__filter_by_symbol(hists);
1476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hist_browser__reset(browser);
1477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'r':
1480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (is_report_browser(hbt))
1481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto do_scripts;
1482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 's':
1484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (is_report_browser(hbt))
1485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto do_data_switch;
1486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_F1:
1488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'h':
1489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case '?':
1490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__help_window(&browser->b,
1491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"h/?/F1        Show this window\n"
1492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"UP/DOWN/PGUP\n"
1493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"PGDN/SPACE    Navigate\n"
1494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"q/ESC/CTRL+C  Exit browser\n\n"
1495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"For multiple event sessions:\n\n"
1496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"TAB/UNTAB Switch events\n\n"
1497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"For symbolic views (--sort has sym):\n\n"
1498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"->            Zoom into DSO/Threads & Annotate current symbol\n"
1499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"<-            Zoom out\n"
1500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"a             Annotate current symbol\n"
1501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"C             Collapse all callchains\n"
1502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"E             Expand all callchains\n"
1503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"d             Zoom into current DSO\n"
1504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"t             Zoom into current Thread\n"
1505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"r             Run available scripts('perf report' only)\n"
1506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"s             Switch to another data file in PWD ('perf report' only)\n"
1507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"P             Print histograms to perf.hist.N\n"
1508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"V             Verbose (DSO names in callchains, etc)\n"
1509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"/             Filter symbol by name");
1510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1511e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_ENTER:
1512e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_RIGHT:
1513e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/* menu */
1514e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
1515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_LEFT: {
1516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			const void *top;
1517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (pstack__empty(fstack)) {
1519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				/*
1520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 * Go back to the perf_evsel_menu__run or other user
1521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 */
1522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (left_exits)
1523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					goto out_free_stack;
1524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			top = pstack__pop(fstack);
1527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (top == &browser->hists->dso_filter)
1528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto zoom_out_dso;
1529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (top == &browser->hists->thread_filter)
1530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto zoom_out_thread;
1531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_ESC:
1534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!left_exits &&
1535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    !ui_browser__dialog_yesno(&browser->b,
1536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					       "Do you really want to exit?"))
1537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/* Fall thru */
1539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'q':
1540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case CTRL('c'):
1541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_free_stack;
1542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		default:
1543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!sort__has_sym)
1547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto add_exit_option;
1548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (sort__mode == SORT_MODE__BRANCH) {
1550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			bi = browser->he_selection->branch_info;
1551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->selection != NULL &&
1552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    bi &&
1553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    bi->from.sym != NULL &&
1554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    !bi->from.map->dso->annotate_warned &&
1555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				asprintf(&options[nr_options], "Annotate %s",
1556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 bi->from.sym->name) > 0)
1557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				annotate_f = nr_options++;
1558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->selection != NULL &&
1560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    bi &&
1561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    bi->to.sym != NULL &&
1562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    !bi->to.map->dso->annotate_warned &&
1563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    (bi->to.sym != bi->from.sym ||
1564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     bi->to.map->dso != bi->from.map->dso) &&
1565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				asprintf(&options[nr_options], "Annotate %s",
1566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 bi->to.sym->name) > 0)
1567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				annotate_t = nr_options++;
1568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} else {
1569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->selection != NULL &&
1571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    browser->selection->sym != NULL &&
1572e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    !browser->selection->map->dso->annotate_warned &&
1573e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				asprintf(&options[nr_options], "Annotate %s",
1574e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 browser->selection->sym->name) > 0)
1575e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				annotate = nr_options++;
1576e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1577e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1578e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (thread != NULL &&
1579e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
1580e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     (browser->hists->thread_filter ? "out of" : "into"),
1581e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     (thread->comm_set ? thread->comm : ""),
1582e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     thread->tid) > 0)
1583e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			zoom_thread = nr_options++;
1584e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1585e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (dso != NULL &&
1586e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    asprintf(&options[nr_options], "Zoom %s %s DSO",
1587e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     (browser->hists->dso_filter ? "out of" : "into"),
1588e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1589e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			zoom_dso = nr_options++;
1590e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1591e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (browser->selection != NULL &&
1592e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    browser->selection->map != NULL &&
1593e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    asprintf(&options[nr_options], "Browse map details") > 0)
1594e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			browse_map = nr_options++;
1595e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1596e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		/* perf script support */
1597e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (browser->he_selection) {
1598e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			struct symbol *sym;
1599e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1600e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
1601e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				browser->he_selection->thread->comm) > 0)
1602e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				scripts_comm = nr_options++;
1603e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1604e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sym = browser->he_selection->ms.sym;
1605e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (sym && sym->namelen &&
1606e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1607e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						sym->name) > 0)
1608e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				scripts_symbol = nr_options++;
1609e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1610e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1611e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1612e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			scripts_all = nr_options++;
1613e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1614e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (is_report_browser(hbt) && asprintf(&options[nr_options],
1615e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				"Switch to another data file in PWD") > 0)
1616e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			switch_data = nr_options++;
1617e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengadd_exit_option:
1618e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		options[nr_options++] = (char *)"Exit";
1619e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengretry_popup_menu:
1620e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		choice = ui__popup_menu(nr_options, options);
1621e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1622e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (choice == nr_options - 1)
1623e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
1624e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1625e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (choice == -1) {
1626e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			free_popup_options(options, nr_options - 1);
1627e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1628e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1629e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1630e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (choice == annotate || choice == annotate_t || choice == annotate_f) {
1631e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			struct hist_entry *he;
1632e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			int err;
1633e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengdo_annotate:
1634e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!objdump_path && perf_session_env__lookup_objdump(env))
1635e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1636e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1637e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			he = hist_browser__selected_entry(browser);
1638e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (he == NULL)
1639e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1640e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1641e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/*
1642e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * we stash the branch_info symbol + map into the
1643e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * the ms so we don't have to rewrite all the annotation
1644e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * code to use branch_info.
1645e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * in branch mode, the ms struct is not used
1646e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 */
1647e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (choice == annotate_f) {
1648e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				he->ms.sym = he->branch_info->from.sym;
1649e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				he->ms.map = he->branch_info->from.map;
1650e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}  else if (choice == annotate_t) {
1651e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				he->ms.sym = he->branch_info->to.sym;
1652e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				he->ms.map = he->branch_info->to.map;
1653e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1654e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1655e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/*
1656e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * Don't let this be freed, say, by hists__decay_entry.
1657e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 */
1658e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			he->used = true;
1659e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			err = hist_entry__tui_annotate(he, evsel, hbt);
1660e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			he->used = false;
1661e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/*
1662e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * offer option to annotate the other branch source or target
1663e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * (if they exists) when returning from annotate
1664e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 */
1665e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if ((err == 'q' || err == CTRL('c'))
1666e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    && annotate_t != -2 && annotate_f != -2)
1667e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto retry_popup_menu;
1668e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1669e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1670e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (err)
1671e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_browser__handle_resize(&browser->b);
1672e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1673e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} else if (choice == browse_map)
1674e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			map__browse(browser->selection->map);
1675e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else if (choice == zoom_dso) {
1676e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengzoom_dso:
1677e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->hists->dso_filter) {
1678e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				pstack__remove(fstack, &browser->hists->dso_filter);
1679e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengzoom_out_dso:
1680e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__pop();
1681e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				browser->hists->dso_filter = NULL;
1682e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				sort_dso.elide = false;
1683e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else {
1684e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (dso == NULL)
1685e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					continue;
1686e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1687e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						   dso->kernel ? "the Kernel" : dso->short_name);
1688e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				browser->hists->dso_filter = dso;
1689e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				sort_dso.elide = true;
1690e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				pstack__push(fstack, &browser->hists->dso_filter);
1691e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1692e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hists__filter_by_dso(hists);
1693e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hist_browser__reset(browser);
1694e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} else if (choice == zoom_thread) {
1695e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengzoom_thread:
1696e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (browser->hists->thread_filter) {
1697e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				pstack__remove(fstack, &browser->hists->thread_filter);
1698e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengzoom_out_thread:
1699e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__pop();
1700e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				browser->hists->thread_filter = NULL;
1701e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				sort_thread.elide = false;
1702e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else {
1703e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1704e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						   thread->comm_set ? thread->comm : "",
1705e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						   thread->tid);
1706e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				browser->hists->thread_filter = thread;
1707e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				sort_thread.elide = true;
1708e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				pstack__push(fstack, &browser->hists->thread_filter);
1709e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1710e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hists__filter_by_thread(hists);
1711e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hist_browser__reset(browser);
1712e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1713e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		/* perf scripts support */
1714e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else if (choice == scripts_all || choice == scripts_comm ||
1715e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				choice == scripts_symbol) {
1716e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengdo_scripts:
1717e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			memset(script_opt, 0, 64);
1718e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1719e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (choice == scripts_comm)
1720e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm);
1721e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1722e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (choice == scripts_symbol)
1723e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1724e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1725e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			script_browse(script_opt);
1726e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1727e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		/* Switch to another data file */
1728e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else if (choice == switch_data) {
1729e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengdo_data_switch:
1730e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!switch_data_file()) {
1731e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				key = K_SWITCH_INPUT_DATA;
1732e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				break;
1733e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else
1734e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui__warning("Won't switch the data files due to\n"
1735e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					"no valid data file get selected!\n");
1736e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1737e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1738e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_stack:
1739e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pstack__delete(fstack);
1740e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
1741e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hist_browser__delete(browser);
1742e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free_popup_options(options, nr_options - 1);
1743e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return key;
1744e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1745e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1746e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct perf_evsel_menu {
1747e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct ui_browser b;
1748e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evsel *selection;
1749e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool lost_events, lost_events_warned;
1750e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	float min_pcnt;
1751e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_session_env *env;
1752e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
1753e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1754e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void perf_evsel_menu__write(struct ui_browser *browser,
1755e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   void *entry, int row)
1756e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1757e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evsel_menu *menu = container_of(browser,
1758e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						    struct perf_evsel_menu, b);
1759e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1760e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool current_entry = ui_browser__is_current_entry(browser, row);
1761e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1762e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *ev_name = perf_evsel__name(evsel);
1763e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char bf[256], unit;
1764e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *warn = " ";
1765e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size_t printed;
1766e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1767e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1768e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						       HE_COLORSET_NORMAL);
1769e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1770e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (perf_evsel__is_group_event(evsel)) {
1771e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct perf_evsel *pos;
1772e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1773e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ev_name = perf_evsel__group_name(evsel);
1774e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1775e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		for_each_group_member(pos, evsel) {
1776e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1777e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1778e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1779e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1780e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	nr_events = convert_unit(nr_events, &unit);
1781e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1782e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			   unit, unit == ' ' ? "" : " ", ev_name);
1783e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	slsmg_printf("%s", bf);
1784e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1785e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1786e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (nr_events != 0) {
1787e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		menu->lost_events = true;
1788e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!current_entry)
1789e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__set_color(browser, HE_COLORSET_TOP);
1790e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nr_events = convert_unit(nr_events, &unit);
1791e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1792e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				     nr_events, unit, unit == ' ' ? "" : " ");
1793e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		warn = bf;
1794e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1795e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1796e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	slsmg_write_nstring(warn, browser->width - printed);
1797e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1798e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (current_entry)
1799e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		menu->selection = evsel;
1800e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1801e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1802e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1803e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				int nr_events, const char *help,
1804e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct hist_browser_timer *hbt)
1805e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1806e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evlist *evlist = menu->b.priv;
1807e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evsel *pos;
1808e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *ev_name, *title = "Available samples";
1809e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int delay_secs = hbt ? hbt->refresh : 0;
1810e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int key;
1811e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1812e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ui_browser__show(&menu->b, title,
1813e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     "ESC: exit, ENTER|->: Browse histograms") < 0)
1814e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1815e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1816e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (1) {
1817e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		key = ui_browser__run(&menu->b, delay_secs);
1818e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1819e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		switch (key) {
1820e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_TIMER:
1821e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			hbt->timer(hbt->arg);
1822e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1823e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!menu->lost_events_warned && menu->lost_events) {
1824e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ui_browser__warn_lost_events(&menu->b);
1825e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				menu->lost_events_warned = true;
1826e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1827e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1828e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_RIGHT:
1829e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_ENTER:
1830e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!menu->selection)
1831e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1832e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pos = menu->selection;
1833e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbrowse_hists:
1834e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			perf_evlist__set_selected(evlist, pos);
1835e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/*
1836e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * Give the calling tool a chance to populate the non
1837e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 * default evsel resorted hists tree.
1838e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 */
1839e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (hbt)
1840e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				hbt->timer(hbt->arg);
1841e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ev_name = perf_evsel__name(pos);
1842e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			key = perf_evsel__hists_browse(pos, nr_events, help,
1843e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						       ev_name, true, hbt,
1844e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						       menu->min_pcnt,
1845e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						       menu->env);
1846e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui_browser__show_title(&menu->b, title);
1847e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			switch (key) {
1848e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			case K_TAB:
1849e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (pos->node.next == &evlist->entries)
1850e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1851e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				else
1852e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					pos = list_entry(pos->node.next, struct perf_evsel, node);
1853e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto browse_hists;
1854e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			case K_UNTAB:
1855e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (pos->node.prev == &evlist->entries)
1856e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1857e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				else
1858e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					pos = list_entry(pos->node.prev, struct perf_evsel, node);
1859e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto browse_hists;
1860e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			case K_ESC:
1861e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				if (!ui_browser__dialog_yesno(&menu->b,
1862e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						"Do you really want to exit?"))
1863e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					continue;
1864e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				/* Fall thru */
1865e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			case K_SWITCH_INPUT_DATA:
1866e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			case 'q':
1867e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			case CTRL('c'):
1868e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto out;
1869e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			default:
1870e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1871e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1872e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_LEFT:
1873e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1874e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case K_ESC:
1875e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (!ui_browser__dialog_yesno(&menu->b,
1876e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					       "Do you really want to exit?"))
1877e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				continue;
1878e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			/* Fall thru */
1879e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case 'q':
1880e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case CTRL('c'):
1881e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out;
1882e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		default:
1883e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
1884e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1885e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1886e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1887e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
1888e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__hide(&menu->b);
1889e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return key;
1890e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1891e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1892e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool filter_group_entries(struct ui_browser *self __maybe_unused,
1893e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 void *entry)
1894e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1895e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1896e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1897e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1898e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return true;
1899e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1900e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return false;
1901e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1902e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1903e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1904e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   int nr_entries, const char *help,
1905e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   struct hist_browser_timer *hbt,
1906e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   float min_pcnt,
1907e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   struct perf_session_env *env)
1908e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1909e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evsel *pos;
1910e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_evsel_menu menu = {
1911e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.b = {
1912e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.entries    = &evlist->entries,
1913e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.refresh    = ui_browser__list_head_refresh,
1914e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.seek	    = ui_browser__list_head_seek,
1915e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.write	    = perf_evsel_menu__write,
1916e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.filter	    = filter_group_entries,
1917e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.nr_entries = nr_entries,
1918e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.priv	    = evlist,
1919e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		},
1920e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.min_pcnt = min_pcnt,
1921e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.env = env,
1922e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1923e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1924e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_helpline__push("Press ESC to exit");
1925e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1926e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(pos, &evlist->entries, node) {
1927e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		const char *ev_name = perf_evsel__name(pos);
1928e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		size_t line_len = strlen(ev_name) + 7;
1929e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1930e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (menu.b.width < line_len)
1931e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			menu.b.width = line_len;
1932e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1933e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1934e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
1935e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1936e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1937e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1938e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  struct hist_browser_timer *hbt,
1939e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  float min_pcnt,
1940e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  struct perf_session_env *env)
1941e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1942e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int nr_entries = evlist->nr_entries;
1943e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1944e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengsingle_entry:
1945e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (nr_entries == 1) {
1946e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct perf_evsel *first = list_entry(evlist->entries.next,
1947e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						      struct perf_evsel, node);
1948e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		const char *ev_name = perf_evsel__name(first);
1949e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1950e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return perf_evsel__hists_browse(first, nr_entries, help,
1951e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						ev_name, false, hbt, min_pcnt,
1952e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						env);
1953e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1954e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1955e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (symbol_conf.event_group) {
1956e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct perf_evsel *pos;
1957e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1958e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nr_entries = 0;
1959e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		list_for_each_entry(pos, &evlist->entries, node)
1960e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (perf_evsel__is_group_leader(pos))
1961e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				nr_entries++;
1962e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1963e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (nr_entries == 1)
1964e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto single_entry;
1965e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1966e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1967e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
1968e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					       hbt, min_pcnt, env);
1969e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1970