blob: 6bcd7670ce5f43c7a52fa80f865de65342f0396a [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include <stdlib.h>
3#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <linux/rbtree.h>
5
Namhyung Kimaca7a942012-04-04 00:14:26 -07006#include "../../util/evsel.h"
7#include "../../util/evlist.h"
8#include "../../util/hist.h"
9#include "../../util/pstack.h"
10#include "../../util/sort.h"
11#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090012#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020020#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022struct hist_browser {
23 struct ui_browser b;
24 struct hists *hists;
25 struct hist_entry *he_selection;
26 struct map_symbol *selection;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +090027 struct hist_browser_timer *hbt;
Namhyung Kim01f00a12015-04-22 16:18:16 +090028 struct pstack *pstack;
Kan Liangce80d3b2015-08-28 05:48:04 -040029 struct perf_env *env;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030030 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030031 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020032 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090033 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090034 u64 nr_non_filtered_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090035 u64 nr_hierarchy_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090036 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030037};
38
Namhyung Kimf5951d52012-09-03 11:53:09 +090039extern void hist_browser__init_hpp(void);
40
Taeung Song1e378eb2014-10-07 16:13:15 +090041static int hists__browser_title(struct hists *hists,
42 struct hist_browser_timer *hbt,
43 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090044static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030045
Namhyung Kimc3b78952014-04-22 15:56:17 +090046static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090047 float min_pcnt);
48
Namhyung Kim268397c2014-04-22 14:49:31 +090049static bool hist_browser__has_filter(struct hist_browser *hb)
50{
Arnaldo Carvalho de Melo9c0fa8d2015-07-13 08:26:35 -030051 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090052}
53
He Kuang4fabf3d2015-03-12 15:21:49 +080054static int hist_browser__get_folding(struct hist_browser *browser)
55{
56 struct rb_node *nd;
57 struct hists *hists = browser->hists;
58 int unfolded_rows = 0;
59
60 for (nd = rb_first(&hists->entries);
61 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090062 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080063 struct hist_entry *he =
64 rb_entry(nd, struct hist_entry, rb_node);
65
Namhyung Kimf5b763f2016-02-25 00:13:43 +090066 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080067 unfolded_rows += he->nr_rows;
68 }
69 return unfolded_rows;
70}
71
Namhyung Kimc3b78952014-04-22 15:56:17 +090072static u32 hist_browser__nr_entries(struct hist_browser *hb)
73{
74 u32 nr_entries;
75
Namhyung Kimf5b763f2016-02-25 00:13:43 +090076 if (symbol_conf.report_hierarchy)
77 nr_entries = hb->nr_hierarchy_entries;
78 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090079 nr_entries = hb->nr_non_filtered_entries;
80 else
81 nr_entries = hb->hists->nr_entries;
82
He Kuang4fabf3d2015-03-12 15:21:49 +080083 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090084 return nr_entries + hb->nr_callchain_rows;
85}
86
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020087static void hist_browser__update_rows(struct hist_browser *hb)
88{
89 struct ui_browser *browser = &hb->b;
90 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
91
92 browser->rows = browser->height - header_offset;
93 /*
94 * Verify if we were at the last line and that line isn't
95 * visibe because we now show the header line(s).
96 */
97 index_row = browser->index - browser->top_idx;
98 if (index_row >= browser->rows)
99 browser->index -= index_row - browser->rows + 1;
100}
101
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300102static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300103{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300104 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
105
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300106 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300107 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
108 /*
109 * FIXME: Just keeping existing behaviour, but this really should be
110 * before updating browser->width, as it will invalidate the
111 * calculation above. Fix this and the fallout in another
112 * changeset.
113 */
114 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200115 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300116}
117
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300118static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
119{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200120 u16 header_offset = browser->show_headers ? 1 : 0;
121
122 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300123}
124
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300125static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300126{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900127 /*
128 * The hists__remove_entry_filter() already folds non-filtered
129 * entries so we can assume it has 0 callchain rows.
130 */
131 browser->nr_callchain_rows = 0;
132
Namhyung Kim268397c2014-04-22 14:49:31 +0900133 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900134 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300135 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300136 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300137}
138
139static char tree__folded_sign(bool unfolded)
140{
141 return unfolded ? '-' : '+';
142}
143
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300144static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900146 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300147}
148
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300149static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300150{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900151 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300152}
153
Namhyung Kim3698dab2015-05-05 23:55:46 +0900154static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300155{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900156 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300157}
158
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300159static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300160{
161 int n = 0;
162 struct rb_node *nd;
163
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300164 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300165 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
166 struct callchain_list *chain;
167 char folded_sign = ' '; /* No children */
168
169 list_for_each_entry(chain, &child->val, list) {
170 ++n;
171 /* We need this because we may not have children */
172 folded_sign = callchain_list__folded(chain);
173 if (folded_sign == '+')
174 break;
175 }
176
177 if (folded_sign == '-') /* Have children and they're unfolded */
178 n += callchain_node__count_rows_rb_tree(child);
179 }
180
181 return n;
182}
183
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900184static int callchain_node__count_flat_rows(struct callchain_node *node)
185{
186 struct callchain_list *chain;
187 char folded_sign = 0;
188 int n = 0;
189
190 list_for_each_entry(chain, &node->parent_val, list) {
191 if (!folded_sign) {
192 /* only check first chain list entry */
193 folded_sign = callchain_list__folded(chain);
194 if (folded_sign == '+')
195 return 1;
196 }
197 n++;
198 }
199
200 list_for_each_entry(chain, &node->val, list) {
201 if (!folded_sign) {
202 /* node->parent_val list might be empty */
203 folded_sign = callchain_list__folded(chain);
204 if (folded_sign == '+')
205 return 1;
206 }
207 n++;
208 }
209
210 return n;
211}
212
Namhyung Kim8c430a32015-11-09 14:45:44 +0900213static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
214{
215 return 1;
216}
217
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300218static int callchain_node__count_rows(struct callchain_node *node)
219{
220 struct callchain_list *chain;
221 bool unfolded = false;
222 int n = 0;
223
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900224 if (callchain_param.mode == CHAIN_FLAT)
225 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900226 else if (callchain_param.mode == CHAIN_FOLDED)
227 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900228
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229 list_for_each_entry(chain, &node->val, list) {
230 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900231 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300232 }
233
234 if (unfolded)
235 n += callchain_node__count_rows_rb_tree(node);
236
237 return n;
238}
239
240static int callchain__count_rows(struct rb_root *chain)
241{
242 struct rb_node *nd;
243 int n = 0;
244
245 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
246 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
247 n += callchain_node__count_rows(node);
248 }
249
250 return n;
251}
252
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900253static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
254 bool include_children)
255{
256 int count = 0;
257 struct rb_node *node;
258 struct hist_entry *child;
259
260 if (he->leaf)
261 return callchain__count_rows(&he->sorted_chain);
262
263 node = rb_first(&he->hroot_out);
264 while (node) {
265 float percent;
266
267 child = rb_entry(node, struct hist_entry, rb_node);
268 percent = hist_entry__get_percent_limit(child);
269
270 if (!child->filtered && percent >= hb->min_pcnt) {
271 count++;
272
273 if (include_children && child->unfolded)
274 count += hierarchy_count_rows(hb, child, true);
275 }
276
277 node = rb_next(node);
278 }
279 return count;
280}
281
Namhyung Kim3698dab2015-05-05 23:55:46 +0900282static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300283{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900284 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200285 return false;
286
Namhyung Kim3698dab2015-05-05 23:55:46 +0900287 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300288 return false;
289
Namhyung Kim3698dab2015-05-05 23:55:46 +0900290 he->unfolded = !he->unfolded;
291 return true;
292}
293
294static bool callchain_list__toggle_fold(struct callchain_list *cl)
295{
296 if (!cl)
297 return false;
298
299 if (!cl->has_children)
300 return false;
301
302 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300303 return true;
304}
305
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300306static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300307{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300308 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300309
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300310 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300311 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
312 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300313 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300314
315 list_for_each_entry(chain, &child->val, list) {
316 if (first) {
317 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900318 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300319 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300320 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900321 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300322 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300323 }
324
325 callchain_node__init_have_children_rb_tree(child);
326 }
327}
328
Namhyung Kima7444af2014-11-24 17:13:27 +0900329static void callchain_node__init_have_children(struct callchain_node *node,
330 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300331{
332 struct callchain_list *chain;
333
Namhyung Kima7444af2014-11-24 17:13:27 +0900334 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900335 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900336
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900337 if (node->val.next != node->val.prev) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900338 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900339 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900340 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300341
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300342 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300343}
344
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300345static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300346{
Namhyung Kima7444af2014-11-24 17:13:27 +0900347 struct rb_node *nd = rb_first(root);
348 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300349
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300350 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300351 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900352 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900353 if (callchain_param.mode == CHAIN_FLAT ||
354 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900355 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300356 }
357}
358
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300359static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300360{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900361 if (he->init_have_children)
362 return;
363
364 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900365 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900367 } else {
368 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300369 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900370
371 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372}
373
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300374static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300375{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900376 struct hist_entry *he = browser->he_selection;
377 struct map_symbol *ms = browser->selection;
378 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
379 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300380
Wang Nan4938cf02015-12-07 02:35:44 +0000381 if (!he || !ms)
382 return false;
383
Namhyung Kim3698dab2015-05-05 23:55:46 +0900384 if (ms == &he->ms)
385 has_children = hist_entry__toggle_fold(he);
386 else
387 has_children = callchain_list__toggle_fold(cl);
388
389 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900390 int child_rows = 0;
391
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900393 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900395 if (he->leaf)
396 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300397 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900398 browser->nr_hierarchy_entries -= he->nr_rows;
399
400 if (symbol_conf.report_hierarchy)
401 child_rows = hierarchy_count_rows(browser, he, true);
402
403 if (he->unfolded) {
404 if (he->leaf)
405 he->nr_rows = callchain__count_rows(&he->sorted_chain);
406 else
407 he->nr_rows = hierarchy_count_rows(browser, he, false);
408
409 /* account grand children */
410 if (symbol_conf.report_hierarchy)
411 browser->b.nr_entries += child_rows - he->nr_rows;
412 } else {
413 if (symbol_conf.report_hierarchy)
414 browser->b.nr_entries -= child_rows - he->nr_rows;
415
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300416 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900417 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900418
419 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900420
421 if (he->leaf)
422 browser->nr_callchain_rows += he->nr_rows;
423 else
424 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300425
426 return true;
427 }
428
429 /* If it doesn't have children, no toggling performed */
430 return false;
431}
432
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300433static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300434{
435 int n = 0;
436 struct rb_node *nd;
437
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300438 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300439 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
440 struct callchain_list *chain;
441 bool has_children = false;
442
443 list_for_each_entry(chain, &child->val, list) {
444 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900445 callchain_list__set_folding(chain, unfold);
446 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300447 }
448
449 if (has_children)
450 n += callchain_node__set_folding_rb_tree(child, unfold);
451 }
452
453 return n;
454}
455
456static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
457{
458 struct callchain_list *chain;
459 bool has_children = false;
460 int n = 0;
461
462 list_for_each_entry(chain, &node->val, list) {
463 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900464 callchain_list__set_folding(chain, unfold);
465 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300466 }
467
468 if (has_children)
469 n += callchain_node__set_folding_rb_tree(node, unfold);
470
471 return n;
472}
473
474static int callchain__set_folding(struct rb_root *chain, bool unfold)
475{
476 struct rb_node *nd;
477 int n = 0;
478
479 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
480 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
481 n += callchain_node__set_folding(node, unfold);
482 }
483
484 return n;
485}
486
Namhyung Kim492b1012016-02-25 00:13:44 +0900487static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
488 bool unfold __maybe_unused)
489{
490 float percent;
491 struct rb_node *nd;
492 struct hist_entry *child;
493 int n = 0;
494
495 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
496 child = rb_entry(nd, struct hist_entry, rb_node);
497 percent = hist_entry__get_percent_limit(child);
498 if (!child->filtered && percent >= hb->min_pcnt)
499 n++;
500 }
501
502 return n;
503}
504
505static void hist_entry__set_folding(struct hist_entry *he,
506 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300507{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300508 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900509 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300510
Namhyung Kim3698dab2015-05-05 23:55:46 +0900511 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900512 int n;
513
514 if (he->leaf)
515 n = callchain__set_folding(&he->sorted_chain, unfold);
516 else
517 n = hierarchy_set_folding(hb, he, unfold);
518
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300519 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300520 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300521 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300522}
523
Namhyung Kimc3b78952014-04-22 15:56:17 +0900524static void
525__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300526{
527 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900528 struct hist_entry *he;
529 double percent;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300530
Namhyung Kim492b1012016-02-25 00:13:44 +0900531 nd = rb_first(&browser->hists->entries);
532 while (nd) {
533 he = rb_entry(nd, struct hist_entry, rb_node);
534
535 /* set folding state even if it's currently folded */
536 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
537
538 hist_entry__set_folding(he, browser, unfold);
539
540 percent = hist_entry__get_percent_limit(he);
541 if (he->filtered || percent < browser->min_pcnt)
542 continue;
543
544 if (!he->depth || unfold)
545 browser->nr_hierarchy_entries++;
546 if (he->leaf)
547 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300548 }
549}
550
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300551static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300552{
Namhyung Kim492b1012016-02-25 00:13:44 +0900553 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900554 browser->nr_callchain_rows = 0;
555 __hist_browser__set_folding(browser, unfold);
556
557 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300558 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300559 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300560}
561
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200562static void ui_browser__warn_lost_events(struct ui_browser *browser)
563{
564 ui_browser__warning(browser, 4,
565 "Events are being lost, check IO/CPU overload!\n\n"
566 "You may want to run 'perf' using a RT scheduler policy:\n\n"
567 " perf top -r 80\n\n"
568 "Or reduce the sampling frequency.");
569}
570
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300571static int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300572{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300573 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300574 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900575 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900576 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300577
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300578 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900579 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300580
Taeung Song1e378eb2014-10-07 16:13:15 +0900581 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300582
Namhyung Kim090cff32016-01-11 19:53:14 +0900583 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300584 return -1;
585
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300586 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300587 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300588
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300589 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900590 case K_TIMER: {
591 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900592 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900593
Namhyung Kimc3b78952014-04-22 15:56:17 +0900594 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900595 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900596
Namhyung Kimc3b78952014-04-22 15:56:17 +0900597 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900598 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200599
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300600 if (browser->hists->stats.nr_lost_warned !=
601 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
602 browser->hists->stats.nr_lost_warned =
603 browser->hists->stats.nr_events[PERF_RECORD_LOST];
604 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200605 }
606
Taeung Song1e378eb2014-10-07 16:13:15 +0900607 hists__browser_title(browser->hists,
608 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300609 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300610 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900611 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300612 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300613 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300614 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300615 struct hist_entry, rb_node);
616 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300617 ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300618 seq++, browser->b.nr_entries,
619 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300620 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300621 browser->b.index,
622 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300623 h->row_offset, h->nr_rows);
624 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300625 break;
626 case 'C':
627 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300628 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300629 break;
630 case 'E':
631 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300632 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300633 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200634 case 'H':
635 browser->show_headers = !browser->show_headers;
636 hist_browser__update_rows(browser);
637 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200638 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300639 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300640 break;
641 /* fall thru */
642 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300643 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300644 }
645 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300646out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300647 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300648 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300649}
650
Namhyung Kim39ee5332014-08-22 09:13:21 +0900651struct callchain_print_arg {
652 /* for hists browser */
653 off_t row_offset;
654 bool is_current_entry;
655
656 /* for file dump */
657 FILE *fp;
658 int printed;
659};
660
661typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
662 struct callchain_list *chain,
663 const char *str, int offset,
664 unsigned short row,
665 struct callchain_print_arg *arg);
666
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900667static void hist_browser__show_callchain_entry(struct hist_browser *browser,
668 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900669 const char *str, int offset,
670 unsigned short row,
671 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900672{
673 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900674 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300675 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900676
677 color = HE_COLORSET_NORMAL;
678 width = browser->b.width - (offset + 2);
679 if (ui_browser__is_current_entry(&browser->b, row)) {
680 browser->selection = &chain->ms;
681 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900682 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900683 }
684
685 ui_browser__set_color(&browser->b, color);
686 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300687 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300688 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300689 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300690 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900691}
692
Namhyung Kim39ee5332014-08-22 09:13:21 +0900693static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
694 struct callchain_list *chain,
695 const char *str, int offset,
696 unsigned short row __maybe_unused,
697 struct callchain_print_arg *arg)
698{
699 char folded_sign = callchain_list__folded(chain);
700
701 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
702 folded_sign, str);
703}
704
705typedef bool (*check_output_full_fn)(struct hist_browser *browser,
706 unsigned short row);
707
708static bool hist_browser__check_output_full(struct hist_browser *browser,
709 unsigned short row)
710{
711 return browser->b.rows == row;
712}
713
714static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
715 unsigned short row __maybe_unused)
716{
717 return false;
718}
719
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300720#define LEVEL_OFFSET_STEP 3
721
Namhyung Kim18bb8382015-11-09 14:45:42 +0900722static int hist_browser__show_callchain_list(struct hist_browser *browser,
723 struct callchain_node *node,
724 struct callchain_list *chain,
725 unsigned short row, u64 total,
726 bool need_percent, int offset,
727 print_callchain_entry_fn print,
728 struct callchain_print_arg *arg)
729{
730 char bf[1024], *alloc_str;
731 const char *str;
732
733 if (arg->row_offset != 0) {
734 arg->row_offset--;
735 return 0;
736 }
737
738 alloc_str = NULL;
739 str = callchain_list__sym_name(chain, bf, sizeof(bf),
740 browser->show_dso);
741
742 if (need_percent) {
743 char buf[64];
744
745 callchain_node__scnprintf_value(node, buf, sizeof(buf),
746 total);
747
748 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
749 str = "Not enough memory!";
750 else
751 str = alloc_str;
752 }
753
754 print(browser, chain, str, offset, row, arg);
755
756 free(alloc_str);
757 return 1;
758}
759
Namhyung Kim59c624e2016-01-28 00:40:56 +0900760static bool check_percent_display(struct rb_node *node, u64 parent_total)
761{
762 struct callchain_node *child;
763
764 if (node == NULL)
765 return false;
766
767 if (rb_next(node))
768 return true;
769
770 child = rb_entry(node, struct callchain_node, rb_node);
771 return callchain_cumul_hits(child) != parent_total;
772}
773
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900774static int hist_browser__show_callchain_flat(struct hist_browser *browser,
775 struct rb_root *root,
776 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900777 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900778 print_callchain_entry_fn print,
779 struct callchain_print_arg *arg,
780 check_output_full_fn is_output_full)
781{
782 struct rb_node *node;
783 int first_row = row, offset = LEVEL_OFFSET_STEP;
784 bool need_percent;
785
786 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900787 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900788
789 while (node) {
790 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
791 struct rb_node *next = rb_next(node);
792 struct callchain_list *chain;
793 char folded_sign = ' ';
794 int first = true;
795 int extra_offset = 0;
796
797 list_for_each_entry(chain, &child->parent_val, list) {
798 bool was_first = first;
799
800 if (first)
801 first = false;
802 else if (need_percent)
803 extra_offset = LEVEL_OFFSET_STEP;
804
805 folded_sign = callchain_list__folded(chain);
806
807 row += hist_browser__show_callchain_list(browser, child,
808 chain, row, total,
809 was_first && need_percent,
810 offset + extra_offset,
811 print, arg);
812
813 if (is_output_full(browser, row))
814 goto out;
815
816 if (folded_sign == '+')
817 goto next;
818 }
819
820 list_for_each_entry(chain, &child->val, list) {
821 bool was_first = first;
822
823 if (first)
824 first = false;
825 else if (need_percent)
826 extra_offset = LEVEL_OFFSET_STEP;
827
828 folded_sign = callchain_list__folded(chain);
829
830 row += hist_browser__show_callchain_list(browser, child,
831 chain, row, total,
832 was_first && need_percent,
833 offset + extra_offset,
834 print, arg);
835
836 if (is_output_full(browser, row))
837 goto out;
838
839 if (folded_sign == '+')
840 break;
841 }
842
843next:
844 if (is_output_full(browser, row))
845 break;
846 node = next;
847 }
848out:
849 return row - first_row;
850}
851
Namhyung Kim8c430a32015-11-09 14:45:44 +0900852static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
853 struct callchain_list *chain,
854 char *value_str, char *old_str)
855{
856 char bf[1024];
857 const char *str;
858 char *new;
859
860 str = callchain_list__sym_name(chain, bf, sizeof(bf),
861 browser->show_dso);
862 if (old_str) {
863 if (asprintf(&new, "%s%s%s", old_str,
864 symbol_conf.field_sep ?: ";", str) < 0)
865 new = NULL;
866 } else {
867 if (value_str) {
868 if (asprintf(&new, "%s %s", value_str, str) < 0)
869 new = NULL;
870 } else {
871 if (asprintf(&new, "%s", str) < 0)
872 new = NULL;
873 }
874 }
875 return new;
876}
877
878static int hist_browser__show_callchain_folded(struct hist_browser *browser,
879 struct rb_root *root,
880 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900881 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900882 print_callchain_entry_fn print,
883 struct callchain_print_arg *arg,
884 check_output_full_fn is_output_full)
885{
886 struct rb_node *node;
887 int first_row = row, offset = LEVEL_OFFSET_STEP;
888 bool need_percent;
889
890 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900891 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900892
893 while (node) {
894 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
895 struct rb_node *next = rb_next(node);
896 struct callchain_list *chain, *first_chain = NULL;
897 int first = true;
898 char *value_str = NULL, *value_str_alloc = NULL;
899 char *chain_str = NULL, *chain_str_alloc = NULL;
900
901 if (arg->row_offset != 0) {
902 arg->row_offset--;
903 goto next;
904 }
905
906 if (need_percent) {
907 char buf[64];
908
909 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
910 if (asprintf(&value_str, "%s", buf) < 0) {
911 value_str = (char *)"<...>";
912 goto do_print;
913 }
914 value_str_alloc = value_str;
915 }
916
917 list_for_each_entry(chain, &child->parent_val, list) {
918 chain_str = hist_browser__folded_callchain_str(browser,
919 chain, value_str, chain_str);
920 if (first) {
921 first = false;
922 first_chain = chain;
923 }
924
925 if (chain_str == NULL) {
926 chain_str = (char *)"Not enough memory!";
927 goto do_print;
928 }
929
930 chain_str_alloc = chain_str;
931 }
932
933 list_for_each_entry(chain, &child->val, list) {
934 chain_str = hist_browser__folded_callchain_str(browser,
935 chain, value_str, chain_str);
936 if (first) {
937 first = false;
938 first_chain = chain;
939 }
940
941 if (chain_str == NULL) {
942 chain_str = (char *)"Not enough memory!";
943 goto do_print;
944 }
945
946 chain_str_alloc = chain_str;
947 }
948
949do_print:
950 print(browser, first_chain, chain_str, offset, row++, arg);
951 free(value_str_alloc);
952 free(chain_str_alloc);
953
954next:
955 if (is_output_full(browser, row))
956 break;
957 node = next;
958 }
959
960 return row - first_row;
961}
962
Namhyung Kim0c841c62016-01-28 00:40:54 +0900963static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900964 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900965 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900966 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900967 print_callchain_entry_fn print,
968 struct callchain_print_arg *arg,
969 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300970{
971 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900972 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +0900973 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +0900974 u64 percent_total = total;
975
976 if (callchain_param.mode == CHAIN_GRAPH_REL)
977 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300978
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900979 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900980 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +0900981
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300982 while (node) {
983 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
984 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300985 struct callchain_list *chain;
986 char folded_sign = ' ';
987 int first = true;
988 int extra_offset = 0;
989
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300990 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300991 bool was_first = first;
992
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300993 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300994 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900995 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300996 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300997
998 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300999
Namhyung Kim18bb8382015-11-09 14:45:42 +09001000 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001001 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001002 was_first && need_percent,
1003 offset + extra_offset,
1004 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001005
Namhyung Kim18bb8382015-11-09 14:45:42 +09001006 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001007 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001008
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001009 if (folded_sign == '+')
1010 break;
1011 }
1012
1013 if (folded_sign == '-') {
1014 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001015
Namhyung Kim0c841c62016-01-28 00:40:54 +09001016 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001017 new_level, row, total,
1018 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001019 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001020 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001021 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001022 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001023 node = next;
1024 }
1025out:
1026 return row - first_row;
1027}
1028
Namhyung Kim0c841c62016-01-28 00:40:54 +09001029static int hist_browser__show_callchain(struct hist_browser *browser,
1030 struct hist_entry *entry, int level,
1031 unsigned short row,
1032 print_callchain_entry_fn print,
1033 struct callchain_print_arg *arg,
1034 check_output_full_fn is_output_full)
1035{
1036 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001037 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001038 int printed;
1039
Namhyung Kim5eca1042016-01-28 00:40:55 +09001040 if (symbol_conf.cumulate_callchain)
1041 parent_total = entry->stat_acc->period;
1042 else
1043 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001044
1045 if (callchain_param.mode == CHAIN_FLAT) {
1046 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001047 &entry->sorted_chain, row,
1048 total, parent_total, print, arg,
1049 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001050 } else if (callchain_param.mode == CHAIN_FOLDED) {
1051 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001052 &entry->sorted_chain, row,
1053 total, parent_total, print, arg,
1054 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001055 } else {
1056 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001057 &entry->sorted_chain, level, row,
1058 total, parent_total, print, arg,
1059 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001060 }
1061
1062 if (arg->is_current_entry)
1063 browser->he_selection = entry;
1064
1065 return printed;
1066}
1067
Namhyung Kim89701462013-01-22 18:09:38 +09001068struct hpp_arg {
1069 struct ui_browser *b;
1070 char folded_sign;
1071 bool current_entry;
1072};
1073
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001074static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
1075{
1076 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001077 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001078 va_list args;
1079 double percent;
1080
1081 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001082 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001083 percent = va_arg(args, double);
1084 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001085
Namhyung Kim89701462013-01-22 18:09:38 +09001086 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001087
Namhyung Kimd6751072014-07-31 14:47:36 +09001088 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001089 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001090
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001091 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001092 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001093}
1094
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001095#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001096static u64 __hpp_get_##_field(struct hist_entry *he) \
1097{ \
1098 return he->stat._field; \
1099} \
1100 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001101static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001102hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001103 struct perf_hpp *hpp, \
1104 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001105{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001106 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1107 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001108}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001109
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001110#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1111static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1112{ \
1113 return he->stat_acc->_field; \
1114} \
1115 \
1116static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001117hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001118 struct perf_hpp *hpp, \
1119 struct hist_entry *he) \
1120{ \
1121 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001122 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001123 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001124 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001125 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001126 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001127 \
1128 return ret; \
1129 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001130 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1131 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001132}
1133
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001134__HPP_COLOR_PERCENT_FN(overhead, period)
1135__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1136__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1137__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1138__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001139__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001140
1141#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001142#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001143
1144void hist_browser__init_hpp(void)
1145{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001146 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1147 hist_browser__hpp_color_overhead;
1148 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1149 hist_browser__hpp_color_overhead_sys;
1150 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1151 hist_browser__hpp_color_overhead_us;
1152 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1153 hist_browser__hpp_color_overhead_guest_sys;
1154 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1155 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001156 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1157 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001158}
1159
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001160static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001161 struct hist_entry *entry,
1162 unsigned short row)
1163{
Jiri Olsa12400052012-10-13 00:06:16 +02001164 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001165 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001166 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001167 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001168 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001169 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001170 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001171
1172 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001173 browser->he_selection = entry;
1174 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001175 }
1176
1177 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001178 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001179 folded_sign = hist_entry__folded(entry);
1180 }
1181
1182 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001183 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001184 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001185 .folded_sign = folded_sign,
1186 .current_entry = current_entry,
1187 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001188 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001189
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001190 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001191
Jiri Olsaf0786af2016-01-18 10:24:23 +01001192 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001193 char s[2048];
1194 struct perf_hpp hpp = {
1195 .buf = s,
1196 .size = sizeof(s),
1197 .ptr = &arg,
1198 };
1199
Namhyung Kim361459f2015-12-23 02:07:08 +09001200 if (perf_hpp__should_skip(fmt, entry->hists) ||
1201 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001202 continue;
1203
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001204 if (current_entry && browser->b.navkeypressed) {
1205 ui_browser__set_color(&browser->b,
1206 HE_COLORSET_SELECTED);
1207 } else {
1208 ui_browser__set_color(&browser->b,
1209 HE_COLORSET_NORMAL);
1210 }
1211
1212 if (first) {
1213 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001214 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001215 width -= 2;
1216 }
1217 first = false;
1218 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001219 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001220 width -= 2;
1221 }
1222
Jiri Olsa12400052012-10-13 00:06:16 +02001223 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001224 int ret = fmt->color(fmt, &hpp, entry);
1225 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1226 /*
1227 * fmt->color() already used ui_browser to
1228 * print the non alignment bits, skip it (+ret):
1229 */
1230 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001231 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001232 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001233 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001234 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001235 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001236 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001237
1238 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001239 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001240 width += 1;
1241
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001242 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001243
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001244 ++row;
1245 ++printed;
1246 } else
1247 --row_offset;
1248
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001249 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001250 struct callchain_print_arg arg = {
1251 .row_offset = row_offset,
1252 .is_current_entry = current_entry,
1253 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001254
Namhyung Kim0c841c62016-01-28 00:40:54 +09001255 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001256 hist_browser__show_callchain_entry, &arg,
1257 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001258 }
1259
1260 return printed;
1261}
1262
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001263static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1264 struct hist_entry *entry,
1265 unsigned short row,
1266 int level, int nr_sort_keys)
1267{
1268 int printed = 0;
1269 int width = browser->b.width;
1270 char folded_sign = ' ';
1271 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1272 off_t row_offset = entry->row_offset;
1273 bool first = true;
1274 struct perf_hpp_fmt *fmt;
1275 struct hpp_arg arg = {
1276 .b = &browser->b,
1277 .current_entry = current_entry,
1278 };
1279 int column = 0;
1280 int hierarchy_indent = (nr_sort_keys - 1) * HIERARCHY_INDENT;
1281
1282 if (current_entry) {
1283 browser->he_selection = entry;
1284 browser->selection = &entry->ms;
1285 }
1286
1287 hist_entry__init_have_children(entry);
1288 folded_sign = hist_entry__folded(entry);
1289 arg.folded_sign = folded_sign;
1290
1291 if (entry->leaf && row_offset) {
1292 row_offset--;
1293 goto show_callchain;
1294 }
1295
1296 hist_browser__gotorc(browser, row, 0);
1297
1298 if (current_entry && browser->b.navkeypressed)
1299 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1300 else
1301 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1302
1303 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1304 width -= level * HIERARCHY_INDENT;
1305
1306 hists__for_each_format(entry->hists, fmt) {
1307 char s[2048];
1308 struct perf_hpp hpp = {
1309 .buf = s,
1310 .size = sizeof(s),
1311 .ptr = &arg,
1312 };
1313
1314 if (perf_hpp__should_skip(fmt, entry->hists) ||
1315 column++ < browser->b.horiz_scroll)
1316 continue;
1317
1318 if (perf_hpp__is_sort_entry(fmt) ||
1319 perf_hpp__is_dynamic_entry(fmt))
1320 break;
1321
1322 if (current_entry && browser->b.navkeypressed) {
1323 ui_browser__set_color(&browser->b,
1324 HE_COLORSET_SELECTED);
1325 } else {
1326 ui_browser__set_color(&browser->b,
1327 HE_COLORSET_NORMAL);
1328 }
1329
1330 if (first) {
1331 ui_browser__printf(&browser->b, "%c", folded_sign);
1332 width--;
1333 first = false;
1334 } else {
1335 ui_browser__printf(&browser->b, " ");
1336 width -= 2;
1337 }
1338
1339 if (fmt->color) {
1340 int ret = fmt->color(fmt, &hpp, entry);
1341 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1342 /*
1343 * fmt->color() already used ui_browser to
1344 * print the non alignment bits, skip it (+ret):
1345 */
1346 ui_browser__printf(&browser->b, "%s", s + ret);
1347 } else {
1348 int ret = fmt->entry(fmt, &hpp, entry);
1349 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1350 ui_browser__printf(&browser->b, "%s", s);
1351 }
1352 width -= hpp.buf - s;
1353 }
1354
1355 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1356 width -= hierarchy_indent;
1357
1358 if (column >= browser->b.horiz_scroll) {
1359 char s[2048];
1360 struct perf_hpp hpp = {
1361 .buf = s,
1362 .size = sizeof(s),
1363 .ptr = &arg,
1364 };
1365
1366 if (current_entry && browser->b.navkeypressed) {
1367 ui_browser__set_color(&browser->b,
1368 HE_COLORSET_SELECTED);
1369 } else {
1370 ui_browser__set_color(&browser->b,
1371 HE_COLORSET_NORMAL);
1372 }
1373
1374 ui_browser__write_nstring(&browser->b, "", 2);
1375 width -= 2;
1376
1377 /*
1378 * No need to call hist_entry__snprintf_alignment()
1379 * since this fmt is always the last column in the
1380 * hierarchy mode.
1381 */
1382 fmt = entry->fmt;
1383 if (fmt->color) {
1384 width -= fmt->color(fmt, &hpp, entry);
1385 } else {
1386 width -= fmt->entry(fmt, &hpp, entry);
1387 ui_browser__printf(&browser->b, "%s", s);
1388 }
1389 }
1390
1391 /* The scroll bar isn't being used */
1392 if (!browser->b.navkeypressed)
1393 width += 1;
1394
1395 ui_browser__write_nstring(&browser->b, "", width);
1396
1397 ++row;
1398 ++printed;
1399
1400show_callchain:
1401 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1402 struct callchain_print_arg carg = {
1403 .row_offset = row_offset,
1404 };
1405
1406 printed += hist_browser__show_callchain(browser, entry,
1407 level + 1, row,
1408 hist_browser__show_callchain_entry, &carg,
1409 hist_browser__check_output_full);
1410 }
1411
1412 return printed;
1413}
1414
Jiri Olsa81a888f2014-06-14 15:44:52 +02001415static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1416{
1417 advance_hpp(hpp, inc);
1418 return hpp->size <= 0;
1419}
1420
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001421static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001422{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001423 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001424 struct perf_hpp dummy_hpp = {
1425 .buf = buf,
1426 .size = size,
1427 };
1428 struct perf_hpp_fmt *fmt;
1429 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001430 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001431
1432 if (symbol_conf.use_callchain) {
1433 ret = scnprintf(buf, size, " ");
1434 if (advance_hpp_check(&dummy_hpp, ret))
1435 return ret;
1436 }
1437
Jiri Olsaf0786af2016-01-18 10:24:23 +01001438 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001439 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001440 continue;
1441
Jiri Olsa81a888f2014-06-14 15:44:52 +02001442 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1443 if (advance_hpp_check(&dummy_hpp, ret))
1444 break;
1445
1446 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1447 if (advance_hpp_check(&dummy_hpp, ret))
1448 break;
1449 }
1450
1451 return ret;
1452}
1453
Namhyung Kimd8b92402016-02-25 00:13:46 +09001454static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1455{
1456 struct hists *hists = browser->hists;
1457 struct perf_hpp dummy_hpp = {
1458 .buf = buf,
1459 .size = size,
1460 };
1461 struct perf_hpp_fmt *fmt;
1462 size_t ret = 0;
1463 int column = 0;
1464 int nr_sort_keys = hists->hpp_list->nr_sort_keys;
1465 bool first = true;
1466
1467 ret = scnprintf(buf, size, " ");
1468 if (advance_hpp_check(&dummy_hpp, ret))
1469 return ret;
1470
1471 hists__for_each_format(hists, fmt) {
1472 if (column++ < browser->b.horiz_scroll)
1473 continue;
1474
1475 if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
1476 break;
1477
1478 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1479 if (advance_hpp_check(&dummy_hpp, ret))
1480 break;
1481
1482 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1483 if (advance_hpp_check(&dummy_hpp, ret))
1484 break;
1485 }
1486
1487 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1488 (nr_sort_keys - 1) * HIERARCHY_INDENT, "");
1489 if (advance_hpp_check(&dummy_hpp, ret))
1490 return ret;
1491
1492 hists__for_each_format(hists, fmt) {
1493 if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
1494 continue;
1495 if (perf_hpp__should_skip(fmt, hists))
1496 continue;
1497
1498 if (first) {
1499 first = false;
1500 } else {
1501 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1502 if (advance_hpp_check(&dummy_hpp, ret))
1503 break;
1504 }
1505
1506 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1507 dummy_hpp.buf[ret] = '\0';
1508 rtrim(dummy_hpp.buf);
1509
1510 ret = strlen(dummy_hpp.buf);
1511 if (advance_hpp_check(&dummy_hpp, ret))
1512 break;
1513 }
1514
1515 return ret;
1516}
1517
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001518static void hist_browser__show_headers(struct hist_browser *browser)
1519{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001520 char headers[1024];
1521
Namhyung Kimd8b92402016-02-25 00:13:46 +09001522 if (symbol_conf.report_hierarchy)
1523 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1524 sizeof(headers));
1525 else
1526 hists_browser__scnprintf_headers(browser, headers,
1527 sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001528 ui_browser__gotorc(&browser->b, 0, 0);
1529 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001530 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001531}
1532
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001533static void ui_browser__hists_init_top(struct ui_browser *browser)
1534{
1535 if (browser->top == NULL) {
1536 struct hist_browser *hb;
1537
1538 hb = container_of(browser, struct hist_browser, b);
1539 browser->top = rb_first(&hb->hists->entries);
1540 }
1541}
1542
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001543static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001544{
1545 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001546 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001547 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001548 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001549 int nr_sort = hb->hists->hpp_list->nr_sort_keys;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001550
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001551 if (hb->show_headers) {
1552 hist_browser__show_headers(hb);
1553 header_offset = 1;
1554 }
1555
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001556 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001557 hb->he_selection = NULL;
1558 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001559
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001560 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001561 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001562 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001563
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001564 if (h->filtered) {
1565 /* let it move to sibling */
1566 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001567 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001568 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001569
Namhyung Kim14135662013-10-31 10:17:39 +09001570 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001571 if (percent < hb->min_pcnt)
1572 continue;
1573
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001574 if (symbol_conf.report_hierarchy) {
1575 row += hist_browser__show_hierarchy_entry(hb, h, row,
1576 h->depth,
1577 nr_sort);
1578 } else {
1579 row += hist_browser__show_entry(hb, h, row);
1580 }
1581
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001582 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001583 break;
1584 }
1585
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001586 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001587}
1588
Namhyung Kim064f1982013-05-14 11:09:04 +09001589static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001590 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001591{
1592 while (nd != NULL) {
1593 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001594 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001595
Namhyung Kimc0f15272014-04-16 11:16:33 +09001596 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001597 return nd;
1598
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001599 /*
1600 * If it's filtered, its all children also were filtered.
1601 * So move to sibling node.
1602 */
1603 if (rb_next(nd))
1604 nd = rb_next(nd);
1605 else
1606 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001607 }
1608
1609 return NULL;
1610}
1611
Namhyung Kim064f1982013-05-14 11:09:04 +09001612static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001613 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001614{
1615 while (nd != NULL) {
1616 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001617 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001618
1619 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001620 return nd;
1621
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001622 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001623 }
1624
1625 return NULL;
1626}
1627
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001628static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001629 off_t offset, int whence)
1630{
1631 struct hist_entry *h;
1632 struct rb_node *nd;
1633 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001634 struct hist_browser *hb;
1635
1636 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001637
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001638 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001639 return;
1640
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001641 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001642
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001643 switch (whence) {
1644 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001645 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001646 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001647 break;
1648 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001649 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001650 goto do_offset;
1651 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001652 nd = rb_hierarchy_last(rb_last(browser->entries));
1653 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001654 first = false;
1655 break;
1656 default:
1657 return;
1658 }
1659
1660 /*
1661 * Moves not relative to the first visible entry invalidates its
1662 * row_offset:
1663 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001664 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001665 h->row_offset = 0;
1666
1667 /*
1668 * Here we have to check if nd is expanded (+), if it is we can't go
1669 * the next top level hist_entry, instead we must compute an offset of
1670 * what _not_ to show and not change the first visible entry.
1671 *
1672 * This offset increments when we are going from top to bottom and
1673 * decreases when we're going from bottom to top.
1674 *
1675 * As we don't have backpointers to the top level in the callchains
1676 * structure, we need to always print the whole hist_entry callchain,
1677 * skipping the first ones that are before the first visible entry
1678 * and stop when we printed enough lines to fill the screen.
1679 */
1680do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001681 if (!nd)
1682 return;
1683
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001684 if (offset > 0) {
1685 do {
1686 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001687 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001688 u16 remaining = h->nr_rows - h->row_offset;
1689 if (offset > remaining) {
1690 offset -= remaining;
1691 h->row_offset = 0;
1692 } else {
1693 h->row_offset += offset;
1694 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001695 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001696 break;
1697 }
1698 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001699 nd = hists__filter_entries(rb_hierarchy_next(nd),
1700 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001701 if (nd == NULL)
1702 break;
1703 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001704 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001705 } while (offset != 0);
1706 } else if (offset < 0) {
1707 while (1) {
1708 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001709 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001710 if (first) {
1711 if (-offset > h->row_offset) {
1712 offset += h->row_offset;
1713 h->row_offset = 0;
1714 } else {
1715 h->row_offset += offset;
1716 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001717 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001718 break;
1719 }
1720 } else {
1721 if (-offset > h->nr_rows) {
1722 offset += h->nr_rows;
1723 h->row_offset = 0;
1724 } else {
1725 h->row_offset = h->nr_rows + offset;
1726 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001727 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001728 break;
1729 }
1730 }
1731 }
1732
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001733 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001734 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001735 if (nd == NULL)
1736 break;
1737 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001738 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001739 if (offset == 0) {
1740 /*
1741 * Last unfiltered hist_entry, check if it is
1742 * unfolded, if it is then we should have
1743 * row_offset at its last entry.
1744 */
1745 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001746 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001747 h->row_offset = h->nr_rows;
1748 break;
1749 }
1750 first = false;
1751 }
1752 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001753 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001754 h = rb_entry(nd, struct hist_entry, rb_node);
1755 h->row_offset = 0;
1756 }
1757}
1758
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001759static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001760 struct hist_entry *he, FILE *fp,
1761 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001762{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001763 struct callchain_print_arg arg = {
1764 .fp = fp,
1765 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001766
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001767 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001768 hist_browser__fprintf_callchain_entry, &arg,
1769 hist_browser__check_dump_full);
1770 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001771}
1772
1773static int hist_browser__fprintf_entry(struct hist_browser *browser,
1774 struct hist_entry *he, FILE *fp)
1775{
1776 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001777 int printed = 0;
1778 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001779 struct perf_hpp hpp = {
1780 .buf = s,
1781 .size = sizeof(s),
1782 };
1783 struct perf_hpp_fmt *fmt;
1784 bool first = true;
1785 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001786
1787 if (symbol_conf.use_callchain)
1788 folded_sign = hist_entry__folded(he);
1789
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001790 if (symbol_conf.use_callchain)
1791 printed += fprintf(fp, "%c ", folded_sign);
1792
Jiri Olsaf0786af2016-01-18 10:24:23 +01001793 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001794 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001795 continue;
1796
Namhyung Kim26d8b332014-03-03 16:16:20 +09001797 if (!first) {
1798 ret = scnprintf(hpp.buf, hpp.size, " ");
1799 advance_hpp(&hpp, ret);
1800 } else
1801 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001802
Namhyung Kim26d8b332014-03-03 16:16:20 +09001803 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001804 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001805 advance_hpp(&hpp, ret);
1806 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001807 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001808
1809 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001810 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1811
1812 return printed;
1813}
1814
1815
1816static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1817 struct hist_entry *he,
1818 FILE *fp, int level,
1819 int nr_sort_keys)
1820{
1821 char s[8192];
1822 int printed = 0;
1823 char folded_sign = ' ';
1824 struct perf_hpp hpp = {
1825 .buf = s,
1826 .size = sizeof(s),
1827 };
1828 struct perf_hpp_fmt *fmt;
1829 bool first = true;
1830 int ret;
1831 int hierarchy_indent = (nr_sort_keys + 1) * HIERARCHY_INDENT;
1832
1833 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1834
1835 folded_sign = hist_entry__folded(he);
1836 printed += fprintf(fp, "%c", folded_sign);
1837
1838 hists__for_each_format(he->hists, fmt) {
1839 if (perf_hpp__should_skip(fmt, he->hists))
1840 continue;
1841
1842 if (perf_hpp__is_sort_entry(fmt) ||
1843 perf_hpp__is_dynamic_entry(fmt))
1844 break;
1845
1846 if (!first) {
1847 ret = scnprintf(hpp.buf, hpp.size, " ");
1848 advance_hpp(&hpp, ret);
1849 } else
1850 first = false;
1851
1852 ret = fmt->entry(fmt, &hpp, he);
1853 advance_hpp(&hpp, ret);
1854 }
1855
1856 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1857 advance_hpp(&hpp, ret);
1858
1859 fmt = he->fmt;
1860 ret = fmt->entry(fmt, &hpp, he);
1861 advance_hpp(&hpp, ret);
1862
1863 printed += fprintf(fp, "%s\n", rtrim(s));
1864
1865 if (he->leaf && folded_sign == '-') {
1866 printed += hist_browser__fprintf_callchain(browser, he, fp,
1867 he->depth + 1);
1868 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001869
1870 return printed;
1871}
1872
1873static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1874{
Namhyung Kim064f1982013-05-14 11:09:04 +09001875 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001876 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001877 int printed = 0;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001878 int nr_sort = browser->hists->hpp_list->nr_sort_keys;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001879
1880 while (nd) {
1881 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1882
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001883 if (symbol_conf.report_hierarchy) {
1884 printed += hist_browser__fprintf_hierarchy_entry(browser,
1885 h, fp,
1886 h->depth,
1887 nr_sort);
1888 } else {
1889 printed += hist_browser__fprintf_entry(browser, h, fp);
1890 }
1891
1892 nd = hists__filter_entries(rb_hierarchy_next(nd),
1893 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001894 }
1895
1896 return printed;
1897}
1898
1899static int hist_browser__dump(struct hist_browser *browser)
1900{
1901 char filename[64];
1902 FILE *fp;
1903
1904 while (1) {
1905 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1906 if (access(filename, F_OK))
1907 break;
1908 /*
1909 * XXX: Just an arbitrary lazy upper limit
1910 */
1911 if (++browser->print_seq == 8192) {
1912 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1913 return -1;
1914 }
1915 }
1916
1917 fp = fopen(filename, "w");
1918 if (fp == NULL) {
1919 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001920 const char *err = strerror_r(errno, bf, sizeof(bf));
1921 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001922 return -1;
1923 }
1924
1925 ++browser->print_seq;
1926 hist_browser__fprintf(browser, fp);
1927 fclose(fp);
1928 ui_helpline__fpush("%s written!", filename);
1929
1930 return 0;
1931}
1932
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001933static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001934 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001935 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001936{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001937 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001938
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001939 if (browser) {
1940 browser->hists = hists;
1941 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001942 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001943 browser->b.seek = ui_browser__hists_seek;
1944 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001945 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001946 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001947 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001948 }
1949
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001950 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001951}
1952
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001953static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001954{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001955 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001956}
1957
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001958static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001959{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001960 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001961}
1962
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001963static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001964{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001965 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001966}
1967
Taeung Song1e378eb2014-10-07 16:13:15 +09001968/* Check whether the browser is for 'top' or 'report' */
1969static inline bool is_report_browser(void *timer)
1970{
1971 return timer == NULL;
1972}
1973
1974static int hists__browser_title(struct hists *hists,
1975 struct hist_browser_timer *hbt,
1976 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001977{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001978 char unit;
1979 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001980 const struct dso *dso = hists->dso_filter;
1981 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001982 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001983 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1984 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001985 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001986 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001987 char buf[512];
1988 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001989 char ref[30] = " show reference callgraph, ";
1990 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001991
Namhyung Kimf2148332014-01-14 11:52:48 +09001992 if (symbol_conf.filter_relative) {
1993 nr_samples = hists->stats.nr_non_filtered_samples;
1994 nr_events = hists->stats.total_non_filtered_period;
1995 }
1996
Namhyung Kim759ff492013-03-05 14:53:26 +09001997 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001998 struct perf_evsel *pos;
1999
2000 perf_evsel__group_desc(evsel, buf, buflen);
2001 ev_name = buf;
2002
2003 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002004 struct hists *pos_hists = evsel__hists(pos);
2005
Namhyung Kimf2148332014-01-14 11:52:48 +09002006 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002007 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2008 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002009 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002010 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2011 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002012 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002013 }
2014 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002015
Kan Liang9e207dd2015-08-11 06:30:49 -04002016 if (symbol_conf.show_ref_callgraph &&
2017 strstr(ev_name, "call-graph=no"))
2018 enable_ref = true;
Ashay Ranecc686282012-04-05 21:01:01 -05002019 nr_samples = convert_unit(nr_samples, &unit);
2020 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002021 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2022 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc686282012-04-05 21:01:01 -05002023
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002024
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002025 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002026 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002027 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002028 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002029 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002030 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002031 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002032 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002033 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002034 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002035 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002036 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002037 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002038 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002039 if (!is_report_browser(hbt)) {
2040 struct perf_top *top = hbt->arg;
2041
2042 if (top->zero)
2043 printed += scnprintf(bf + printed, size - printed, " [z]");
2044 }
2045
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002046 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002047}
2048
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002049static inline void free_popup_options(char **options, int n)
2050{
2051 int i;
2052
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002053 for (i = 0; i < n; ++i)
2054 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002055}
2056
Feng Tang341487ab2013-02-03 14:38:20 +08002057/*
2058 * Only runtime switching of perf data file will make "input_name" point
2059 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2060 * whether we need to call free() for current "input_name" during the switch.
2061 */
2062static bool is_input_name_malloced = false;
2063
2064static int switch_data_file(void)
2065{
2066 char *pwd, *options[32], *abs_path[32], *tmp;
2067 DIR *pwd_dir;
2068 int nr_options = 0, choice = -1, ret = -1;
2069 struct dirent *dent;
2070
2071 pwd = getenv("PWD");
2072 if (!pwd)
2073 return ret;
2074
2075 pwd_dir = opendir(pwd);
2076 if (!pwd_dir)
2077 return ret;
2078
2079 memset(options, 0, sizeof(options));
2080 memset(options, 0, sizeof(abs_path));
2081
2082 while ((dent = readdir(pwd_dir))) {
2083 char path[PATH_MAX];
2084 u64 magic;
2085 char *name = dent->d_name;
2086 FILE *file;
2087
2088 if (!(dent->d_type == DT_REG))
2089 continue;
2090
2091 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2092
2093 file = fopen(path, "r");
2094 if (!file)
2095 continue;
2096
2097 if (fread(&magic, 1, 8, file) < 8)
2098 goto close_file_and_continue;
2099
2100 if (is_perf_magic(magic)) {
2101 options[nr_options] = strdup(name);
2102 if (!options[nr_options])
2103 goto close_file_and_continue;
2104
2105 abs_path[nr_options] = strdup(path);
2106 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002107 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002108 ui__warning("Can't search all data files due to memory shortage.\n");
2109 fclose(file);
2110 break;
2111 }
2112
2113 nr_options++;
2114 }
2115
2116close_file_and_continue:
2117 fclose(file);
2118 if (nr_options >= 32) {
2119 ui__warning("Too many perf data files in PWD!\n"
2120 "Only the first 32 files will be listed.\n");
2121 break;
2122 }
2123 }
2124 closedir(pwd_dir);
2125
2126 if (nr_options) {
2127 choice = ui__popup_menu(nr_options, options);
2128 if (choice < nr_options && choice >= 0) {
2129 tmp = strdup(abs_path[choice]);
2130 if (tmp) {
2131 if (is_input_name_malloced)
2132 free((void *)input_name);
2133 input_name = tmp;
2134 is_input_name_malloced = true;
2135 ret = 0;
2136 } else
2137 ui__warning("Data switch failed due to memory shortage!\n");
2138 }
2139 }
2140
2141 free_popup_options(options, nr_options);
2142 free_popup_options(abs_path, nr_options);
2143 return ret;
2144}
2145
Namhyung Kimea7cd592015-04-22 16:18:19 +09002146struct popup_action {
2147 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002148 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002149 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002150
2151 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2152};
2153
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002154static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002155do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002156{
2157 struct perf_evsel *evsel;
2158 struct annotation *notes;
2159 struct hist_entry *he;
2160 int err;
2161
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002162 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002163 return 0;
2164
Namhyung Kimea7cd592015-04-22 16:18:19 +09002165 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002166 if (!notes->src)
2167 return 0;
2168
2169 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002170 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002171 he = hist_browser__selected_entry(browser);
2172 /*
2173 * offer option to annotate the other branch source or target
2174 * (if they exists) when returning from annotate
2175 */
2176 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2177 return 1;
2178
2179 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2180 if (err)
2181 ui_browser__handle_resize(&browser->b);
2182 return 0;
2183}
2184
2185static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002186add_annotate_opt(struct hist_browser *browser __maybe_unused,
2187 struct popup_action *act, char **optstr,
2188 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002189{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002190 if (sym == NULL || map->dso->annotate_warned)
2191 return 0;
2192
2193 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2194 return 0;
2195
2196 act->ms.map = map;
2197 act->ms.sym = sym;
2198 act->fn = do_annotate;
2199 return 1;
2200}
2201
2202static int
2203do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2204{
2205 struct thread *thread = act->thread;
2206
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002207 if (browser->hists->thread_filter) {
2208 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2209 perf_hpp__set_elide(HISTC_THREAD, false);
2210 thread__zput(browser->hists->thread_filter);
2211 ui_helpline__pop();
2212 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002213 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002214 thread->comm_set ? thread__comm_str(thread) : "",
2215 thread->tid);
2216 browser->hists->thread_filter = thread__get(thread);
2217 perf_hpp__set_elide(HISTC_THREAD, false);
2218 pstack__push(browser->pstack, &browser->hists->thread_filter);
2219 }
2220
2221 hists__filter_by_thread(browser->hists);
2222 hist_browser__reset(browser);
2223 return 0;
2224}
2225
2226static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002227add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2228 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002229{
Namhyung Kim2eafd412016-01-21 19:13:24 -03002230 if (!sort__has_thread || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002231 return 0;
2232
2233 if (asprintf(optstr, "Zoom %s %s(%d) thread",
2234 browser->hists->thread_filter ? "out of" : "into",
2235 thread->comm_set ? thread__comm_str(thread) : "",
2236 thread->tid) < 0)
2237 return 0;
2238
2239 act->thread = thread;
2240 act->fn = do_zoom_thread;
2241 return 1;
2242}
2243
2244static int
2245do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2246{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002247 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002248
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002249 if (browser->hists->dso_filter) {
2250 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2251 perf_hpp__set_elide(HISTC_DSO, false);
2252 browser->hists->dso_filter = NULL;
2253 ui_helpline__pop();
2254 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002255 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002256 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002257 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002258 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2259 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002260 perf_hpp__set_elide(HISTC_DSO, true);
2261 pstack__push(browser->pstack, &browser->hists->dso_filter);
2262 }
2263
2264 hists__filter_by_dso(browser->hists);
2265 hist_browser__reset(browser);
2266 return 0;
2267}
2268
2269static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002270add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002271 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002272{
Namhyung Kimb1447a542016-01-22 11:22:41 -03002273 if (!sort__has_dso || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002274 return 0;
2275
2276 if (asprintf(optstr, "Zoom %s %s DSO",
2277 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002278 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002279 return 0;
2280
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002281 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002282 act->fn = do_zoom_dso;
2283 return 1;
2284}
2285
2286static int
2287do_browse_map(struct hist_browser *browser __maybe_unused,
2288 struct popup_action *act)
2289{
2290 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002291 return 0;
2292}
2293
2294static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002295add_map_opt(struct hist_browser *browser __maybe_unused,
2296 struct popup_action *act, char **optstr, struct map *map)
2297{
Namhyung Kimb1447a542016-01-22 11:22:41 -03002298 if (!sort__has_dso || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002299 return 0;
2300
2301 if (asprintf(optstr, "Browse map details") < 0)
2302 return 0;
2303
2304 act->ms.map = map;
2305 act->fn = do_browse_map;
2306 return 1;
2307}
2308
2309static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002310do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002311 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002312{
2313 char script_opt[64];
2314 memset(script_opt, 0, sizeof(script_opt));
2315
Namhyung Kimea7cd592015-04-22 16:18:19 +09002316 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002317 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002318 thread__comm_str(act->thread));
2319 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002320 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002321 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002322 }
2323
2324 script_browse(script_opt);
2325 return 0;
2326}
2327
2328static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002329add_script_opt(struct hist_browser *browser __maybe_unused,
2330 struct popup_action *act, char **optstr,
2331 struct thread *thread, struct symbol *sym)
2332{
2333 if (thread) {
2334 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2335 thread__comm_str(thread)) < 0)
2336 return 0;
2337 } else if (sym) {
2338 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2339 sym->name) < 0)
2340 return 0;
2341 } else {
2342 if (asprintf(optstr, "Run scripts for all samples") < 0)
2343 return 0;
2344 }
2345
2346 act->thread = thread;
2347 act->ms.sym = sym;
2348 act->fn = do_run_script;
2349 return 1;
2350}
2351
2352static int
2353do_switch_data(struct hist_browser *browser __maybe_unused,
2354 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002355{
2356 if (switch_data_file()) {
2357 ui__warning("Won't switch the data files due to\n"
2358 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002359 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002360 }
2361
2362 return K_SWITCH_INPUT_DATA;
2363}
2364
Namhyung Kimea7cd592015-04-22 16:18:19 +09002365static int
2366add_switch_opt(struct hist_browser *browser,
2367 struct popup_action *act, char **optstr)
2368{
2369 if (!is_report_browser(browser->hbt))
2370 return 0;
2371
2372 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2373 return 0;
2374
2375 act->fn = do_switch_data;
2376 return 1;
2377}
2378
2379static int
2380do_exit_browser(struct hist_browser *browser __maybe_unused,
2381 struct popup_action *act __maybe_unused)
2382{
2383 return 0;
2384}
2385
2386static int
2387add_exit_opt(struct hist_browser *browser __maybe_unused,
2388 struct popup_action *act, char **optstr)
2389{
2390 if (asprintf(optstr, "Exit") < 0)
2391 return 0;
2392
2393 act->fn = do_exit_browser;
2394 return 1;
2395}
2396
Kan Liang84734b02015-09-04 10:45:45 -04002397static int
2398do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2399{
2400 if (browser->hists->socket_filter > -1) {
2401 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2402 browser->hists->socket_filter = -1;
2403 perf_hpp__set_elide(HISTC_SOCKET, false);
2404 } else {
2405 browser->hists->socket_filter = act->socket;
2406 perf_hpp__set_elide(HISTC_SOCKET, true);
2407 pstack__push(browser->pstack, &browser->hists->socket_filter);
2408 }
2409
2410 hists__filter_by_socket(browser->hists);
2411 hist_browser__reset(browser);
2412 return 0;
2413}
2414
2415static int
2416add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2417 char **optstr, int socket_id)
2418{
Namhyung Kimd9695d92016-01-22 12:20:18 -03002419 if (!sort__has_socket || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002420 return 0;
2421
2422 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2423 (browser->hists->socket_filter > -1) ? "out of" : "into",
2424 socket_id) < 0)
2425 return 0;
2426
2427 act->socket = socket_id;
2428 act->fn = do_zoom_socket;
2429 return 1;
2430}
2431
Namhyung Kim112f7612014-04-22 14:05:35 +09002432static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002433{
2434 u64 nr_entries = 0;
2435 struct rb_node *nd = rb_first(&hb->hists->entries);
2436
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002437 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002438 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2439 return;
2440 }
2441
Namhyung Kim14135662013-10-31 10:17:39 +09002442 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002443 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002444 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002445 }
2446
Namhyung Kim112f7612014-04-22 14:05:35 +09002447 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002448 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002449}
Feng Tang341487ab2013-02-03 14:38:20 +08002450
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002451static void hist_browser__update_percent_limit(struct hist_browser *hb,
2452 double percent)
2453{
2454 struct hist_entry *he;
2455 struct rb_node *nd = rb_first(&hb->hists->entries);
2456 u64 total = hists__total_period(hb->hists);
2457 u64 min_callchain_hits = total * (percent / 100);
2458
2459 hb->min_pcnt = callchain_param.min_percent = percent;
2460
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002461 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2462 he = rb_entry(nd, struct hist_entry, rb_node);
2463
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002464 if (!he->leaf || !symbol_conf.use_callchain)
2465 goto next;
2466
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002467 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2468 total = he->stat.period;
2469
2470 if (symbol_conf.cumulate_callchain)
2471 total = he->stat_acc->period;
2472
2473 min_callchain_hits = total * (percent / 100);
2474 }
2475
2476 callchain_param.sort(&he->sorted_chain, he->callchain,
2477 min_callchain_hits, &callchain_param);
2478
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002479next:
2480 /*
2481 * Tentatively set unfolded so that the rb_hierarchy_next()
2482 * can toggle children of folded entries too.
2483 */
2484 he->unfolded = he->has_children;
2485 nd = rb_hierarchy_next(nd);
2486
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002487 /* force to re-evaluate folding state of callchains */
2488 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002489 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002490 }
2491}
2492
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002493static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002494 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002495 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002496 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002497 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002498 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002499{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002500 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09002501 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002502 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002503#define MAX_OPTIONS 16
2504 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002505 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002506 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002507 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002508 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002509 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002510 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002511
Namhyung Kime8e684a2013-12-26 14:37:58 +09002512#define HIST_BROWSER_HELP_COMMON \
2513 "h/?/F1 Show this window\n" \
2514 "UP/DOWN/PGUP\n" \
2515 "PGDN/SPACE Navigate\n" \
2516 "q/ESC/CTRL+C Exit browser\n\n" \
2517 "For multiple event sessions:\n\n" \
2518 "TAB/UNTAB Switch events\n\n" \
2519 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002520 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2521 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002522 "a Annotate current symbol\n" \
2523 "C Collapse all callchains\n" \
2524 "d Zoom into current DSO\n" \
2525 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002526 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002527 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002528 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002529 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002530 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002531
2532 /* help messages are sorted by lexical order of the hotkey */
2533 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002534 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002535 "P Print histograms to perf.hist.N\n"
2536 "r Run available scripts\n"
2537 "s Switch to another data file in PWD\n"
2538 "t Zoom into current Thread\n"
2539 "V Verbose (DSO names in callchains, etc)\n"
2540 "/ Filter symbol by name";
2541 const char top_help[] = HIST_BROWSER_HELP_COMMON
2542 "P Print histograms to perf.hist.N\n"
2543 "t Zoom into current Thread\n"
2544 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002545 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002546 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002547 "/ Filter symbol by name";
2548
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002549 if (browser == NULL)
2550 return -1;
2551
Namhyung Kimed426912015-05-29 21:53:44 +09002552 /* reset abort key so that it can get Ctrl-C as a key */
2553 SLang_reset_tty();
2554 SLang_init_tty(0, 0, 0);
2555
Namhyung Kim03905042015-11-28 02:32:39 +09002556 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002557 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002558 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002559
Kan Liang84734b02015-09-04 10:45:45 -04002560 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002561 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002562 goto out;
2563
2564 ui_helpline__push(helpline);
2565
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002566 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002567 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002568
Jiri Olsaf0786af2016-01-18 10:24:23 +01002569 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002570 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002571 /*
2572 * This is done just once, and activates the horizontal scrolling
2573 * code in the ui_browser code, it would be better to have a the
2574 * counter in the perf_hpp code, but I couldn't find doing it here
2575 * works, FIXME by setting this in hist_browser__new, for now, be
2576 * clever 8-)
2577 */
2578 ++browser->b.columns;
2579 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002580
Namhyung Kim5b591662014-07-31 14:47:38 +09002581 if (symbol_conf.col_width_list_str)
2582 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2583
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002584 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002585 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002586 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002587 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002588 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002589
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002590 nr_options = 0;
2591
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002592 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002593
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002594 if (browser->he_selection != NULL) {
2595 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002596 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002597 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002598 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002599 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002600 case K_TAB:
2601 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002602 if (nr_events == 1)
2603 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002604 /*
2605 * Exit the browser, let hists__browser_tree
2606 * go to the next or previous
2607 */
2608 goto out_free_stack;
2609 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002610 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002611 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002612 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002613 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002614 continue;
2615 }
2616
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002617 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002618 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002619 browser->selection->map->dso->annotate_warned)
2620 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002621
Namhyung Kimea7cd592015-04-22 16:18:19 +09002622 actions->ms.map = browser->selection->map;
2623 actions->ms.sym = browser->selection->sym;
2624 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002625 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002626 case 'P':
2627 hist_browser__dump(browser);
2628 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002629 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002630 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002631 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002632 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002633 case 'V':
2634 browser->show_dso = !browser->show_dso;
2635 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002636 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002637 actions->thread = thread;
2638 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002639 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002640 case 'S':
2641 actions->socket = socked_id;
2642 do_zoom_socket(browser, actions);
2643 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002644 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002645 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e452015-10-12 14:02:29 -03002646 "Please enter the name of symbol you want to see.\n"
2647 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002648 buf, "ENTER: OK, ESC: Cancel",
2649 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002650 hists->symbol_filter_str = *buf ? buf : NULL;
2651 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002652 hist_browser__reset(browser);
2653 }
2654 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002655 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002656 if (is_report_browser(hbt)) {
2657 actions->thread = NULL;
2658 actions->ms.sym = NULL;
2659 do_run_script(browser, actions);
2660 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002661 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002662 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002663 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002664 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002665 if (key == K_SWITCH_INPUT_DATA)
2666 goto out_free_stack;
2667 }
Feng Tang341487ab2013-02-03 14:38:20 +08002668 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002669 case 'i':
2670 /* env->arch is NULL for live-mode (i.e. perf top) */
2671 if (env->arch)
2672 tui__header_window(env);
2673 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002674 case 'F':
2675 symbol_conf.filter_relative ^= 1;
2676 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002677 case 'z':
2678 if (!is_report_browser(hbt)) {
2679 struct perf_top *top = hbt->arg;
2680
2681 top->zero = !top->zero;
2682 }
2683 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002684 case 'L':
2685 if (ui_browser__input_window("Percent Limit",
2686 "Please enter the value you want to hide entries under that percent.",
2687 buf, "ENTER: OK, ESC: Cancel",
2688 delay_secs * 2) == K_ENTER) {
2689 char *end;
2690 double new_percent = strtod(buf, &end);
2691
2692 if (new_percent < 0 || new_percent > 100) {
2693 ui_browser__warning(&browser->b, delay_secs * 2,
2694 "Invalid percent: %.2f", new_percent);
2695 continue;
2696 }
2697
2698 hist_browser__update_percent_limit(browser, new_percent);
2699 hist_browser__reset(browser);
2700 }
2701 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002702 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002703 case 'h':
2704 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002705 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002706 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002707 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002708 case K_ENTER:
2709 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002710 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002711 /* menu */
2712 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002713 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002714 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002715 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002716
Namhyung Kim01f00a12015-04-22 16:18:16 +09002717 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002718 /*
2719 * Go back to the perf_evsel_menu__run or other user
2720 */
2721 if (left_exits)
2722 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002723
2724 if (key == K_ESC &&
2725 ui_browser__dialog_yesno(&browser->b,
2726 "Do you really want to exit?"))
2727 goto out_free_stack;
2728
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002729 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002730 }
Namhyung Kim64221842015-04-24 10:15:33 +09002731 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002732 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002733 /*
2734 * No need to set actions->dso here since
2735 * it's just to remove the current filter.
2736 * Ditto for thread below.
2737 */
2738 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002739 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002740 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002741 } else if (top == &browser->hists->socket_filter) {
2742 do_zoom_socket(browser, actions);
2743 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002744 continue;
2745 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002746 case 'q':
2747 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002748 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002749 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002750 if (!is_report_browser(hbt)) {
2751 struct perf_top *top = hbt->arg;
2752
2753 perf_evlist__toggle_enable(top->evlist);
2754 /*
2755 * No need to refresh, resort/decay histogram
2756 * entries if we are not collecting samples:
2757 */
2758 if (top->evlist->enabled) {
2759 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2760 hbt->refresh = delay_secs;
2761 } else {
2762 helpline = "Press 'f' again to re-enable the events";
2763 hbt->refresh = 0;
2764 }
2765 continue;
2766 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002767 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002768 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002769 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002770 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002771 }
2772
Namhyung Kim40561322016-01-22 12:26:06 -03002773 if (!sort__has_sym || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002774 goto skip_annotation;
2775
Namhyung Kim55369fc2013-04-01 20:35:20 +09002776 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002777 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002778
2779 if (bi == NULL)
2780 goto skip_annotation;
2781
Namhyung Kimea7cd592015-04-22 16:18:19 +09002782 nr_options += add_annotate_opt(browser,
2783 &actions[nr_options],
2784 &options[nr_options],
2785 bi->from.map,
2786 bi->from.sym);
2787 if (bi->to.sym != bi->from.sym)
2788 nr_options += add_annotate_opt(browser,
2789 &actions[nr_options],
2790 &options[nr_options],
2791 bi->to.map,
2792 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002793 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002794 nr_options += add_annotate_opt(browser,
2795 &actions[nr_options],
2796 &options[nr_options],
2797 browser->selection->map,
2798 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002799 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002800skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002801 nr_options += add_thread_opt(browser, &actions[nr_options],
2802 &options[nr_options], thread);
2803 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002804 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002805 nr_options += add_map_opt(browser, &actions[nr_options],
2806 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002807 browser->selection ?
2808 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002809 nr_options += add_socket_opt(browser, &actions[nr_options],
2810 &options[nr_options],
2811 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002812 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002813 if (!is_report_browser(hbt))
2814 goto skip_scripting;
2815
Feng Tangcdbab7c2012-10-30 11:56:06 +08002816 if (browser->he_selection) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002817 if (sort__has_thread && thread) {
2818 nr_options += add_script_opt(browser,
2819 &actions[nr_options],
2820 &options[nr_options],
2821 thread, NULL);
2822 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002823 /*
2824 * Note that browser->selection != NULL
2825 * when browser->he_selection is not NULL,
2826 * so we don't need to check browser->selection
2827 * before fetching browser->selection->sym like what
2828 * we do before fetching browser->selection->map.
2829 *
2830 * See hist_browser__show_entry.
2831 */
Namhyung Kimc221acb2016-01-21 19:50:09 -03002832 if (sort__has_sym && browser->selection->sym) {
2833 nr_options += add_script_opt(browser,
2834 &actions[nr_options],
2835 &options[nr_options],
2836 NULL, browser->selection->sym);
2837 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08002838 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002839 nr_options += add_script_opt(browser, &actions[nr_options],
2840 &options[nr_options], NULL, NULL);
2841 nr_options += add_switch_opt(browser, &actions[nr_options],
2842 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03002843skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002844 nr_options += add_exit_opt(browser, &actions[nr_options],
2845 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002846
Namhyung Kimea7cd592015-04-22 16:18:19 +09002847 do {
2848 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002849
Namhyung Kimea7cd592015-04-22 16:18:19 +09002850 choice = ui__popup_menu(nr_options, options);
2851 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002852 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002853
2854 act = &actions[choice];
2855 key = act->fn(browser, act);
2856 } while (key == 1);
2857
2858 if (key == K_SWITCH_INPUT_DATA)
2859 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002860 }
2861out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002862 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002863out:
2864 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002865 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002866 return key;
2867}
2868
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002869struct perf_evsel_menu {
2870 struct ui_browser b;
2871 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002872 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002873 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002874 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002875};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002876
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002877static void perf_evsel_menu__write(struct ui_browser *browser,
2878 void *entry, int row)
2879{
2880 struct perf_evsel_menu *menu = container_of(browser,
2881 struct perf_evsel_menu, b);
2882 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002883 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002884 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002885 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002886 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002887 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002888 const char *warn = " ";
2889 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002890
2891 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2892 HE_COLORSET_NORMAL);
2893
Namhyung Kim759ff492013-03-05 14:53:26 +09002894 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002895 struct perf_evsel *pos;
2896
2897 ev_name = perf_evsel__group_name(evsel);
2898
2899 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002900 struct hists *pos_hists = evsel__hists(pos);
2901 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002902 }
2903 }
2904
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002905 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002906 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002907 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002908 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002909
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002910 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002911 if (nr_events != 0) {
2912 menu->lost_events = true;
2913 if (!current_entry)
2914 ui_browser__set_color(browser, HE_COLORSET_TOP);
2915 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002916 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2917 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002918 warn = bf;
2919 }
2920
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002921 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002922
2923 if (current_entry)
2924 menu->selection = evsel;
2925}
2926
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002927static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2928 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002929 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002930{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002931 struct perf_evlist *evlist = menu->b.priv;
2932 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002933 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002934 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002935 int key;
2936
2937 if (ui_browser__show(&menu->b, title,
2938 "ESC: exit, ENTER|->: Browse histograms") < 0)
2939 return -1;
2940
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002941 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002942 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002943
2944 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002945 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002946 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002947
2948 if (!menu->lost_events_warned && menu->lost_events) {
2949 ui_browser__warn_lost_events(&menu->b);
2950 menu->lost_events_warned = true;
2951 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002952 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002953 case K_RIGHT:
2954 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002955 if (!menu->selection)
2956 continue;
2957 pos = menu->selection;
2958browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002959 perf_evlist__set_selected(evlist, pos);
2960 /*
2961 * Give the calling tool a chance to populate the non
2962 * default evsel resorted hists tree.
2963 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002964 if (hbt)
2965 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002966 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002967 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002968 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002969 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002970 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002971 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002972 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002973 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002974 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002975 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002976 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002977 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002978 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002979 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002980 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002981 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002982 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002983 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002984 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002985 case 'q':
2986 case CTRL('c'):
2987 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002988 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002989 default:
2990 continue;
2991 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002992 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002993 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002994 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002995 if (!ui_browser__dialog_yesno(&menu->b,
2996 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002997 continue;
2998 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002999 case 'q':
3000 case CTRL('c'):
3001 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003002 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003003 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003004 }
3005 }
3006
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003007out:
3008 ui_browser__hide(&menu->b);
3009 return key;
3010}
3011
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003012static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003013 void *entry)
3014{
3015 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3016
3017 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3018 return true;
3019
3020 return false;
3021}
3022
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003023static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003024 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003025 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003026 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003027 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003028{
3029 struct perf_evsel *pos;
3030 struct perf_evsel_menu menu = {
3031 .b = {
3032 .entries = &evlist->entries,
3033 .refresh = ui_browser__list_head_refresh,
3034 .seek = ui_browser__list_head_seek,
3035 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003036 .filter = filter_group_entries,
3037 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003038 .priv = evlist,
3039 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003040 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003041 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003042 };
3043
3044 ui_helpline__push("Press ESC to exit");
3045
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003046 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003047 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003048 size_t line_len = strlen(ev_name) + 7;
3049
3050 if (menu.b.width < line_len)
3051 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003052 }
3053
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003054 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003055}
3056
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003057int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003058 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003059 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003060 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003061{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003062 int nr_entries = evlist->nr_entries;
3063
3064single_entry:
3065 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003066 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003067
3068 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003069 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003070 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003071 }
3072
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003073 if (symbol_conf.event_group) {
3074 struct perf_evsel *pos;
3075
3076 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003077 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003078 if (perf_evsel__is_group_leader(pos))
3079 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003080 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003081
3082 if (nr_entries == 1)
3083 goto single_entry;
3084 }
3085
3086 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003087 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003088}