blob: c44af461a68f29f470655440087291c3b2c58597 [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 Kimc3b78952014-04-22 15:56:17 +090035 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030036};
37
Namhyung Kimf5951d52012-09-03 11:53:09 +090038extern void hist_browser__init_hpp(void);
39
Taeung Song1e378eb2014-10-07 16:13:15 +090040static int hists__browser_title(struct hists *hists,
41 struct hist_browser_timer *hbt,
42 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090043static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030044
Namhyung Kimc3b78952014-04-22 15:56:17 +090045static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090046 float min_pcnt);
47
Namhyung Kim268397c2014-04-22 14:49:31 +090048static bool hist_browser__has_filter(struct hist_browser *hb)
49{
Arnaldo Carvalho de Melo9c0fa8d2015-07-13 08:26:35 -030050 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090051}
52
He Kuang4fabf3d2015-03-12 15:21:49 +080053static int hist_browser__get_folding(struct hist_browser *browser)
54{
55 struct rb_node *nd;
56 struct hists *hists = browser->hists;
57 int unfolded_rows = 0;
58
59 for (nd = rb_first(&hists->entries);
60 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
61 nd = rb_next(nd)) {
62 struct hist_entry *he =
63 rb_entry(nd, struct hist_entry, rb_node);
64
Namhyung Kim3698dab2015-05-05 23:55:46 +090065 if (he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080066 unfolded_rows += he->nr_rows;
67 }
68 return unfolded_rows;
69}
70
Namhyung Kimc3b78952014-04-22 15:56:17 +090071static u32 hist_browser__nr_entries(struct hist_browser *hb)
72{
73 u32 nr_entries;
74
75 if (hist_browser__has_filter(hb))
76 nr_entries = hb->nr_non_filtered_entries;
77 else
78 nr_entries = hb->hists->nr_entries;
79
He Kuang4fabf3d2015-03-12 15:21:49 +080080 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090081 return nr_entries + hb->nr_callchain_rows;
82}
83
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020084static void hist_browser__update_rows(struct hist_browser *hb)
85{
86 struct ui_browser *browser = &hb->b;
87 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
88
89 browser->rows = browser->height - header_offset;
90 /*
91 * Verify if we were at the last line and that line isn't
92 * visibe because we now show the header line(s).
93 */
94 index_row = browser->index - browser->top_idx;
95 if (index_row >= browser->rows)
96 browser->index -= index_row - browser->rows + 1;
97}
98
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030099static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300100{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300101 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
102
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300103 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300104 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
105 /*
106 * FIXME: Just keeping existing behaviour, but this really should be
107 * before updating browser->width, as it will invalidate the
108 * calculation above. Fix this and the fallout in another
109 * changeset.
110 */
111 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200112 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300113}
114
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300115static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
116{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200117 u16 header_offset = browser->show_headers ? 1 : 0;
118
119 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300120}
121
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300122static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300123{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900124 /*
125 * The hists__remove_entry_filter() already folds non-filtered
126 * entries so we can assume it has 0 callchain rows.
127 */
128 browser->nr_callchain_rows = 0;
129
Namhyung Kim268397c2014-04-22 14:49:31 +0900130 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900131 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300132 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300133 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300134}
135
136static char tree__folded_sign(bool unfolded)
137{
138 return unfolded ? '-' : '+';
139}
140
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300141static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300142{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900143 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144}
145
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300146static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300147{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900148 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300149}
150
Namhyung Kim3698dab2015-05-05 23:55:46 +0900151static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300152{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900153 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300154}
155
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300156static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300157{
158 int n = 0;
159 struct rb_node *nd;
160
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300161 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300162 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
163 struct callchain_list *chain;
164 char folded_sign = ' '; /* No children */
165
166 list_for_each_entry(chain, &child->val, list) {
167 ++n;
168 /* We need this because we may not have children */
169 folded_sign = callchain_list__folded(chain);
170 if (folded_sign == '+')
171 break;
172 }
173
174 if (folded_sign == '-') /* Have children and they're unfolded */
175 n += callchain_node__count_rows_rb_tree(child);
176 }
177
178 return n;
179}
180
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900181static int callchain_node__count_flat_rows(struct callchain_node *node)
182{
183 struct callchain_list *chain;
184 char folded_sign = 0;
185 int n = 0;
186
187 list_for_each_entry(chain, &node->parent_val, list) {
188 if (!folded_sign) {
189 /* only check first chain list entry */
190 folded_sign = callchain_list__folded(chain);
191 if (folded_sign == '+')
192 return 1;
193 }
194 n++;
195 }
196
197 list_for_each_entry(chain, &node->val, list) {
198 if (!folded_sign) {
199 /* node->parent_val list might be empty */
200 folded_sign = callchain_list__folded(chain);
201 if (folded_sign == '+')
202 return 1;
203 }
204 n++;
205 }
206
207 return n;
208}
209
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300210static int callchain_node__count_rows(struct callchain_node *node)
211{
212 struct callchain_list *chain;
213 bool unfolded = false;
214 int n = 0;
215
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900216 if (callchain_param.mode == CHAIN_FLAT)
217 return callchain_node__count_flat_rows(node);
218
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300219 list_for_each_entry(chain, &node->val, list) {
220 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900221 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300222 }
223
224 if (unfolded)
225 n += callchain_node__count_rows_rb_tree(node);
226
227 return n;
228}
229
230static int callchain__count_rows(struct rb_root *chain)
231{
232 struct rb_node *nd;
233 int n = 0;
234
235 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
236 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
237 n += callchain_node__count_rows(node);
238 }
239
240 return n;
241}
242
Namhyung Kim3698dab2015-05-05 23:55:46 +0900243static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300244{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900245 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200246 return false;
247
Namhyung Kim3698dab2015-05-05 23:55:46 +0900248 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300249 return false;
250
Namhyung Kim3698dab2015-05-05 23:55:46 +0900251 he->unfolded = !he->unfolded;
252 return true;
253}
254
255static bool callchain_list__toggle_fold(struct callchain_list *cl)
256{
257 if (!cl)
258 return false;
259
260 if (!cl->has_children)
261 return false;
262
263 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300264 return true;
265}
266
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300267static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300268{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300269 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300270
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300271 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300272 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
273 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300274 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300275
276 list_for_each_entry(chain, &child->val, list) {
277 if (first) {
278 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900279 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300280 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300281 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900282 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300283 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300284 }
285
286 callchain_node__init_have_children_rb_tree(child);
287 }
288}
289
Namhyung Kima7444af2014-11-24 17:13:27 +0900290static void callchain_node__init_have_children(struct callchain_node *node,
291 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300292{
293 struct callchain_list *chain;
294
Namhyung Kima7444af2014-11-24 17:13:27 +0900295 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900296 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900297
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900298 if (node->val.next != node->val.prev) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900299 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900300 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900301 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300302
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300303 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300304}
305
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300306static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300307{
Namhyung Kima7444af2014-11-24 17:13:27 +0900308 struct rb_node *nd = rb_first(root);
309 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300310
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300311 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300312 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900313 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900314 if (callchain_param.mode == CHAIN_FLAT)
315 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300316 }
317}
318
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300319static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300320{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300321 if (!he->init_have_children) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900322 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300323 callchain__init_have_children(&he->sorted_chain);
324 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300325 }
326}
327
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300328static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300329{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900330 struct hist_entry *he = browser->he_selection;
331 struct map_symbol *ms = browser->selection;
332 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
333 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300334
Namhyung Kim3698dab2015-05-05 23:55:46 +0900335 if (ms == &he->ms)
336 has_children = hist_entry__toggle_fold(he);
337 else
338 has_children = callchain_list__toggle_fold(cl);
339
340 if (has_children) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300341 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900342 browser->b.nr_entries -= he->nr_rows;
343 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300344
Namhyung Kim3698dab2015-05-05 23:55:46 +0900345 if (he->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300346 he->nr_rows = callchain__count_rows(&he->sorted_chain);
347 else
348 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900349
350 browser->b.nr_entries += he->nr_rows;
351 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300352
353 return true;
354 }
355
356 /* If it doesn't have children, no toggling performed */
357 return false;
358}
359
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300360static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300361{
362 int n = 0;
363 struct rb_node *nd;
364
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300365 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300366 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
367 struct callchain_list *chain;
368 bool has_children = false;
369
370 list_for_each_entry(chain, &child->val, list) {
371 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900372 callchain_list__set_folding(chain, unfold);
373 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300374 }
375
376 if (has_children)
377 n += callchain_node__set_folding_rb_tree(child, unfold);
378 }
379
380 return n;
381}
382
383static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
384{
385 struct callchain_list *chain;
386 bool has_children = false;
387 int n = 0;
388
389 list_for_each_entry(chain, &node->val, list) {
390 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900391 callchain_list__set_folding(chain, unfold);
392 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300393 }
394
395 if (has_children)
396 n += callchain_node__set_folding_rb_tree(node, unfold);
397
398 return n;
399}
400
401static int callchain__set_folding(struct rb_root *chain, bool unfold)
402{
403 struct rb_node *nd;
404 int n = 0;
405
406 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
407 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
408 n += callchain_node__set_folding(node, unfold);
409 }
410
411 return n;
412}
413
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300414static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300415{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300416 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900417 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300418
Namhyung Kim3698dab2015-05-05 23:55:46 +0900419 if (he->has_children) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300420 int n = callchain__set_folding(&he->sorted_chain, unfold);
421 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300422 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300423 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300424}
425
Namhyung Kimc3b78952014-04-22 15:56:17 +0900426static void
427__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300428{
429 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900430 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300431
Namhyung Kimc3b78952014-04-22 15:56:17 +0900432 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900433 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900434 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300435 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
436 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900437 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300438 }
439}
440
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300441static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300442{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900443 browser->nr_callchain_rows = 0;
444 __hist_browser__set_folding(browser, unfold);
445
446 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300447 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300448 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300449}
450
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200451static void ui_browser__warn_lost_events(struct ui_browser *browser)
452{
453 ui_browser__warning(browser, 4,
454 "Events are being lost, check IO/CPU overload!\n\n"
455 "You may want to run 'perf' using a RT scheduler policy:\n\n"
456 " perf top -r 80\n\n"
457 "Or reduce the sampling frequency.");
458}
459
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300460static int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300461{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300462 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300463 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900464 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900465 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300466
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300467 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900468 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300469
Taeung Song1e378eb2014-10-07 16:13:15 +0900470 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300471
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300472 if (ui_browser__show(&browser->b, title, help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300473 return -1;
474
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300475 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300476 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300477
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300478 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900479 case K_TIMER: {
480 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900481 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900482
Namhyung Kimc3b78952014-04-22 15:56:17 +0900483 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900484 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900485
Namhyung Kimc3b78952014-04-22 15:56:17 +0900486 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900487 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200488
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300489 if (browser->hists->stats.nr_lost_warned !=
490 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
491 browser->hists->stats.nr_lost_warned =
492 browser->hists->stats.nr_events[PERF_RECORD_LOST];
493 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200494 }
495
Taeung Song1e378eb2014-10-07 16:13:15 +0900496 hists__browser_title(browser->hists,
497 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300498 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300499 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900500 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300501 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300502 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300503 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300504 struct hist_entry, rb_node);
505 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300506 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 -0300507 seq++, browser->b.nr_entries,
508 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300509 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300510 browser->b.index,
511 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300512 h->row_offset, h->nr_rows);
513 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300514 break;
515 case 'C':
516 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300517 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300518 break;
519 case 'E':
520 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300521 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300522 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200523 case 'H':
524 browser->show_headers = !browser->show_headers;
525 hist_browser__update_rows(browser);
526 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200527 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300528 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300529 break;
530 /* fall thru */
531 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300532 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300533 }
534 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300535out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300536 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300537 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300538}
539
Namhyung Kim39ee5332014-08-22 09:13:21 +0900540struct callchain_print_arg {
541 /* for hists browser */
542 off_t row_offset;
543 bool is_current_entry;
544
545 /* for file dump */
546 FILE *fp;
547 int printed;
548};
549
550typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
551 struct callchain_list *chain,
552 const char *str, int offset,
553 unsigned short row,
554 struct callchain_print_arg *arg);
555
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900556static void hist_browser__show_callchain_entry(struct hist_browser *browser,
557 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900558 const char *str, int offset,
559 unsigned short row,
560 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900561{
562 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900563 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300564 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900565
566 color = HE_COLORSET_NORMAL;
567 width = browser->b.width - (offset + 2);
568 if (ui_browser__is_current_entry(&browser->b, row)) {
569 browser->selection = &chain->ms;
570 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900571 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900572 }
573
574 ui_browser__set_color(&browser->b, color);
575 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300576 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300577 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300578 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300579 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900580}
581
Namhyung Kim39ee5332014-08-22 09:13:21 +0900582static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
583 struct callchain_list *chain,
584 const char *str, int offset,
585 unsigned short row __maybe_unused,
586 struct callchain_print_arg *arg)
587{
588 char folded_sign = callchain_list__folded(chain);
589
590 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
591 folded_sign, str);
592}
593
594typedef bool (*check_output_full_fn)(struct hist_browser *browser,
595 unsigned short row);
596
597static bool hist_browser__check_output_full(struct hist_browser *browser,
598 unsigned short row)
599{
600 return browser->b.rows == row;
601}
602
603static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
604 unsigned short row __maybe_unused)
605{
606 return false;
607}
608
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300609#define LEVEL_OFFSET_STEP 3
610
Namhyung Kim18bb8382015-11-09 14:45:42 +0900611static int hist_browser__show_callchain_list(struct hist_browser *browser,
612 struct callchain_node *node,
613 struct callchain_list *chain,
614 unsigned short row, u64 total,
615 bool need_percent, int offset,
616 print_callchain_entry_fn print,
617 struct callchain_print_arg *arg)
618{
619 char bf[1024], *alloc_str;
620 const char *str;
621
622 if (arg->row_offset != 0) {
623 arg->row_offset--;
624 return 0;
625 }
626
627 alloc_str = NULL;
628 str = callchain_list__sym_name(chain, bf, sizeof(bf),
629 browser->show_dso);
630
631 if (need_percent) {
632 char buf[64];
633
634 callchain_node__scnprintf_value(node, buf, sizeof(buf),
635 total);
636
637 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
638 str = "Not enough memory!";
639 else
640 str = alloc_str;
641 }
642
643 print(browser, chain, str, offset, row, arg);
644
645 free(alloc_str);
646 return 1;
647}
648
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900649static int hist_browser__show_callchain_flat(struct hist_browser *browser,
650 struct rb_root *root,
651 unsigned short row, u64 total,
652 print_callchain_entry_fn print,
653 struct callchain_print_arg *arg,
654 check_output_full_fn is_output_full)
655{
656 struct rb_node *node;
657 int first_row = row, offset = LEVEL_OFFSET_STEP;
658 bool need_percent;
659
660 node = rb_first(root);
661 need_percent = node && rb_next(node);
662
663 while (node) {
664 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
665 struct rb_node *next = rb_next(node);
666 struct callchain_list *chain;
667 char folded_sign = ' ';
668 int first = true;
669 int extra_offset = 0;
670
671 list_for_each_entry(chain, &child->parent_val, list) {
672 bool was_first = first;
673
674 if (first)
675 first = false;
676 else if (need_percent)
677 extra_offset = LEVEL_OFFSET_STEP;
678
679 folded_sign = callchain_list__folded(chain);
680
681 row += hist_browser__show_callchain_list(browser, child,
682 chain, row, total,
683 was_first && need_percent,
684 offset + extra_offset,
685 print, arg);
686
687 if (is_output_full(browser, row))
688 goto out;
689
690 if (folded_sign == '+')
691 goto next;
692 }
693
694 list_for_each_entry(chain, &child->val, list) {
695 bool was_first = first;
696
697 if (first)
698 first = false;
699 else if (need_percent)
700 extra_offset = LEVEL_OFFSET_STEP;
701
702 folded_sign = callchain_list__folded(chain);
703
704 row += hist_browser__show_callchain_list(browser, child,
705 chain, row, total,
706 was_first && need_percent,
707 offset + extra_offset,
708 print, arg);
709
710 if (is_output_full(browser, row))
711 goto out;
712
713 if (folded_sign == '+')
714 break;
715 }
716
717next:
718 if (is_output_full(browser, row))
719 break;
720 node = next;
721 }
722out:
723 return row - first_row;
724}
725
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900726static int hist_browser__show_callchain(struct hist_browser *browser,
727 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900728 unsigned short row, u64 total,
729 print_callchain_entry_fn print,
730 struct callchain_print_arg *arg,
731 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300732{
733 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900734 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900735 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900736 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300737
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900738 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900739 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900740
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300741 while (node) {
742 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
743 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300744 struct callchain_list *chain;
745 char folded_sign = ' ';
746 int first = true;
747 int extra_offset = 0;
748
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300749 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300750 bool was_first = first;
751
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300752 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300753 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900754 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300755 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300756
757 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300758
Namhyung Kim18bb8382015-11-09 14:45:42 +0900759 row += hist_browser__show_callchain_list(browser, child,
760 chain, row, total,
761 was_first && need_percent,
762 offset + extra_offset,
763 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900764
Namhyung Kim18bb8382015-11-09 14:45:42 +0900765 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300766 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900767
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300768 if (folded_sign == '+')
769 break;
770 }
771
772 if (folded_sign == '-') {
773 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900774
775 if (callchain_param.mode == CHAIN_GRAPH_REL)
776 new_total = child->children_hit;
777 else
778 new_total = total;
779
780 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900781 new_level, row, new_total,
782 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300783 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900784 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900785 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300786 node = next;
787 }
788out:
789 return row - first_row;
790}
791
Namhyung Kim89701462013-01-22 18:09:38 +0900792struct hpp_arg {
793 struct ui_browser *b;
794 char folded_sign;
795 bool current_entry;
796};
797
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900798static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
799{
800 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900801 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900802 va_list args;
803 double percent;
804
805 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900806 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900807 percent = va_arg(args, double);
808 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900809
Namhyung Kim89701462013-01-22 18:09:38 +0900810 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900811
Namhyung Kimd6751072014-07-31 14:47:36 +0900812 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300813 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +0900814
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900815 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900816 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900817}
818
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900819#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900820static u64 __hpp_get_##_field(struct hist_entry *he) \
821{ \
822 return he->stat._field; \
823} \
824 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100825static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900826hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100827 struct perf_hpp *hpp, \
828 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900829{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900830 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
831 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900832}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900833
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900834#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
835static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
836{ \
837 return he->stat_acc->_field; \
838} \
839 \
840static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900841hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900842 struct perf_hpp *hpp, \
843 struct hist_entry *he) \
844{ \
845 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300846 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +0900847 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900848 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900849 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300850 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900851 \
852 return ret; \
853 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900854 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
855 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900856}
857
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900858__HPP_COLOR_PERCENT_FN(overhead, period)
859__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
860__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
861__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
862__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900863__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900864
865#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900866#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900867
868void hist_browser__init_hpp(void)
869{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900870 perf_hpp__format[PERF_HPP__OVERHEAD].color =
871 hist_browser__hpp_color_overhead;
872 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
873 hist_browser__hpp_color_overhead_sys;
874 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
875 hist_browser__hpp_color_overhead_us;
876 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
877 hist_browser__hpp_color_overhead_guest_sys;
878 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
879 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900880 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
881 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900882}
883
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300884static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300885 struct hist_entry *entry,
886 unsigned short row)
887{
888 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200889 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900890 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300891 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300892 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300893 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300894 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200895 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300896
897 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300898 browser->he_selection = entry;
899 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300900 }
901
902 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300903 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904 folded_sign = hist_entry__folded(entry);
905 }
906
907 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900908 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900909 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900910 .folded_sign = folded_sign,
911 .current_entry = current_entry,
912 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900913 struct perf_hpp hpp = {
914 .buf = s,
915 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900916 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900917 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300918 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300919
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300920 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900921
Jiri Olsa12400052012-10-13 00:06:16 +0200922 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300923 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +0900924 continue;
925
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900926 if (current_entry && browser->b.navkeypressed) {
927 ui_browser__set_color(&browser->b,
928 HE_COLORSET_SELECTED);
929 } else {
930 ui_browser__set_color(&browser->b,
931 HE_COLORSET_NORMAL);
932 }
933
934 if (first) {
935 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300936 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900937 width -= 2;
938 }
939 first = false;
940 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300941 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +0900942 width -= 2;
943 }
944
Jiri Olsa12400052012-10-13 00:06:16 +0200945 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100946 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900947 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100948 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300949 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900950 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300951 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200952
953 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300954 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200955 width += 1;
956
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300957 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +0900958
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300959 ++row;
960 ++printed;
961 } else
962 --row_offset;
963
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300964 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900965 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900966 struct callchain_print_arg arg = {
967 .row_offset = row_offset,
968 .is_current_entry = current_entry,
969 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900970
Namhyung Kim4087d112014-11-24 17:13:26 +0900971 if (callchain_param.mode == CHAIN_GRAPH_REL) {
972 if (symbol_conf.cumulate_callchain)
973 total = entry->stat_acc->period;
974 else
975 total = entry->stat.period;
976 }
977
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900978 if (callchain_param.mode == CHAIN_FLAT) {
979 printed += hist_browser__show_callchain_flat(browser,
980 &entry->sorted_chain, row, total,
981 hist_browser__show_callchain_entry, &arg,
982 hist_browser__check_output_full);
983 } else {
984 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900985 &entry->sorted_chain, 1, row, total,
986 hist_browser__show_callchain_entry, &arg,
987 hist_browser__check_output_full);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900988 }
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900989
Namhyung Kim39ee5332014-08-22 09:13:21 +0900990 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300991 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300992 }
993
994 return printed;
995}
996
Jiri Olsa81a888f2014-06-14 15:44:52 +0200997static int advance_hpp_check(struct perf_hpp *hpp, int inc)
998{
999 advance_hpp(hpp, inc);
1000 return hpp->size <= 0;
1001}
1002
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001003static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001004{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001005 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001006 struct perf_hpp dummy_hpp = {
1007 .buf = buf,
1008 .size = size,
1009 };
1010 struct perf_hpp_fmt *fmt;
1011 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001012 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001013
1014 if (symbol_conf.use_callchain) {
1015 ret = scnprintf(buf, size, " ");
1016 if (advance_hpp_check(&dummy_hpp, ret))
1017 return ret;
1018 }
1019
1020 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001021 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001022 continue;
1023
Jiri Olsa81a888f2014-06-14 15:44:52 +02001024 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1025 if (advance_hpp_check(&dummy_hpp, ret))
1026 break;
1027
1028 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1029 if (advance_hpp_check(&dummy_hpp, ret))
1030 break;
1031 }
1032
1033 return ret;
1034}
1035
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001036static void hist_browser__show_headers(struct hist_browser *browser)
1037{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001038 char headers[1024];
1039
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001040 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001041 ui_browser__gotorc(&browser->b, 0, 0);
1042 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001043 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001044}
1045
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001046static void ui_browser__hists_init_top(struct ui_browser *browser)
1047{
1048 if (browser->top == NULL) {
1049 struct hist_browser *hb;
1050
1051 hb = container_of(browser, struct hist_browser, b);
1052 browser->top = rb_first(&hb->hists->entries);
1053 }
1054}
1055
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001056static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001057{
1058 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001059 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001060 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001061 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001062
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001063 if (hb->show_headers) {
1064 hist_browser__show_headers(hb);
1065 header_offset = 1;
1066 }
1067
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001068 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001069
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001070 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001071 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001072 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001073
1074 if (h->filtered)
1075 continue;
1076
Namhyung Kim14135662013-10-31 10:17:39 +09001077 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001078 if (percent < hb->min_pcnt)
1079 continue;
1080
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001081 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001082 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001083 break;
1084 }
1085
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001086 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001087}
1088
Namhyung Kim064f1982013-05-14 11:09:04 +09001089static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001090 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001091{
1092 while (nd != NULL) {
1093 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001094 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001095
Namhyung Kimc0f15272014-04-16 11:16:33 +09001096 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001097 return nd;
1098
1099 nd = rb_next(nd);
1100 }
1101
1102 return NULL;
1103}
1104
Namhyung Kim064f1982013-05-14 11:09:04 +09001105static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001106 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001107{
1108 while (nd != NULL) {
1109 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001110 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001111
1112 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001113 return nd;
1114
1115 nd = rb_prev(nd);
1116 }
1117
1118 return NULL;
1119}
1120
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001121static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001122 off_t offset, int whence)
1123{
1124 struct hist_entry *h;
1125 struct rb_node *nd;
1126 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001127 struct hist_browser *hb;
1128
1129 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001130
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001131 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001132 return;
1133
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001134 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001135
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001136 switch (whence) {
1137 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001138 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001139 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001140 break;
1141 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001142 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001143 goto do_offset;
1144 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001145 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001146 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001147 first = false;
1148 break;
1149 default:
1150 return;
1151 }
1152
1153 /*
1154 * Moves not relative to the first visible entry invalidates its
1155 * row_offset:
1156 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001157 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001158 h->row_offset = 0;
1159
1160 /*
1161 * Here we have to check if nd is expanded (+), if it is we can't go
1162 * the next top level hist_entry, instead we must compute an offset of
1163 * what _not_ to show and not change the first visible entry.
1164 *
1165 * This offset increments when we are going from top to bottom and
1166 * decreases when we're going from bottom to top.
1167 *
1168 * As we don't have backpointers to the top level in the callchains
1169 * structure, we need to always print the whole hist_entry callchain,
1170 * skipping the first ones that are before the first visible entry
1171 * and stop when we printed enough lines to fill the screen.
1172 */
1173do_offset:
1174 if (offset > 0) {
1175 do {
1176 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001177 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001178 u16 remaining = h->nr_rows - h->row_offset;
1179 if (offset > remaining) {
1180 offset -= remaining;
1181 h->row_offset = 0;
1182 } else {
1183 h->row_offset += offset;
1184 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001185 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001186 break;
1187 }
1188 }
Namhyung Kim14135662013-10-31 10:17:39 +09001189 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001190 if (nd == NULL)
1191 break;
1192 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001193 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001194 } while (offset != 0);
1195 } else if (offset < 0) {
1196 while (1) {
1197 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001198 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199 if (first) {
1200 if (-offset > h->row_offset) {
1201 offset += h->row_offset;
1202 h->row_offset = 0;
1203 } else {
1204 h->row_offset += offset;
1205 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001206 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207 break;
1208 }
1209 } else {
1210 if (-offset > h->nr_rows) {
1211 offset += h->nr_rows;
1212 h->row_offset = 0;
1213 } else {
1214 h->row_offset = h->nr_rows + offset;
1215 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001216 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001217 break;
1218 }
1219 }
1220 }
1221
Namhyung Kim14135662013-10-31 10:17:39 +09001222 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001223 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001224 if (nd == NULL)
1225 break;
1226 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001227 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001228 if (offset == 0) {
1229 /*
1230 * Last unfiltered hist_entry, check if it is
1231 * unfolded, if it is then we should have
1232 * row_offset at its last entry.
1233 */
1234 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001235 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001236 h->row_offset = h->nr_rows;
1237 break;
1238 }
1239 first = false;
1240 }
1241 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001242 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001243 h = rb_entry(nd, struct hist_entry, rb_node);
1244 h->row_offset = 0;
1245 }
1246}
1247
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001248static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001249 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001250{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001251 u64 total = hists__total_period(he->hists);
1252 struct callchain_print_arg arg = {
1253 .fp = fp,
1254 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001255
Namhyung Kim39ee5332014-08-22 09:13:21 +09001256 if (symbol_conf.cumulate_callchain)
1257 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001258
Namhyung Kim39ee5332014-08-22 09:13:21 +09001259 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1260 hist_browser__fprintf_callchain_entry, &arg,
1261 hist_browser__check_dump_full);
1262 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001263}
1264
1265static int hist_browser__fprintf_entry(struct hist_browser *browser,
1266 struct hist_entry *he, FILE *fp)
1267{
1268 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001269 int printed = 0;
1270 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001271 struct perf_hpp hpp = {
1272 .buf = s,
1273 .size = sizeof(s),
1274 };
1275 struct perf_hpp_fmt *fmt;
1276 bool first = true;
1277 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001278
1279 if (symbol_conf.use_callchain)
1280 folded_sign = hist_entry__folded(he);
1281
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001282 if (symbol_conf.use_callchain)
1283 printed += fprintf(fp, "%c ", folded_sign);
1284
Namhyung Kim26d8b332014-03-03 16:16:20 +09001285 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001286 if (perf_hpp__should_skip(fmt))
1287 continue;
1288
Namhyung Kim26d8b332014-03-03 16:16:20 +09001289 if (!first) {
1290 ret = scnprintf(hpp.buf, hpp.size, " ");
1291 advance_hpp(&hpp, ret);
1292 } else
1293 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001294
Namhyung Kim26d8b332014-03-03 16:16:20 +09001295 ret = fmt->entry(fmt, &hpp, he);
1296 advance_hpp(&hpp, ret);
1297 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001298 printed += fprintf(fp, "%s\n", rtrim(s));
1299
1300 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001301 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001302
1303 return printed;
1304}
1305
1306static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1307{
Namhyung Kim064f1982013-05-14 11:09:04 +09001308 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001309 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001310 int printed = 0;
1311
1312 while (nd) {
1313 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1314
1315 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001316 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001317 }
1318
1319 return printed;
1320}
1321
1322static int hist_browser__dump(struct hist_browser *browser)
1323{
1324 char filename[64];
1325 FILE *fp;
1326
1327 while (1) {
1328 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1329 if (access(filename, F_OK))
1330 break;
1331 /*
1332 * XXX: Just an arbitrary lazy upper limit
1333 */
1334 if (++browser->print_seq == 8192) {
1335 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1336 return -1;
1337 }
1338 }
1339
1340 fp = fopen(filename, "w");
1341 if (fp == NULL) {
1342 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001343 const char *err = strerror_r(errno, bf, sizeof(bf));
1344 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001345 return -1;
1346 }
1347
1348 ++browser->print_seq;
1349 hist_browser__fprintf(browser, fp);
1350 fclose(fp);
1351 ui_helpline__fpush("%s written!", filename);
1352
1353 return 0;
1354}
1355
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001356static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001357 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001358 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001359{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001360 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001361
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001362 if (browser) {
1363 browser->hists = hists;
1364 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001365 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001366 browser->b.seek = ui_browser__hists_seek;
1367 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001368 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001369 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001370 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001371 }
1372
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001373 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001374}
1375
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001376static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001377{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001378 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001379}
1380
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001381static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001382{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001383 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001384}
1385
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001386static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001387{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001388 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001389}
1390
Taeung Song1e378eb2014-10-07 16:13:15 +09001391/* Check whether the browser is for 'top' or 'report' */
1392static inline bool is_report_browser(void *timer)
1393{
1394 return timer == NULL;
1395}
1396
1397static int hists__browser_title(struct hists *hists,
1398 struct hist_browser_timer *hbt,
1399 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001400{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001401 char unit;
1402 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001403 const struct dso *dso = hists->dso_filter;
1404 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001405 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001406 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1407 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001408 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001409 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001410 char buf[512];
1411 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001412 char ref[30] = " show reference callgraph, ";
1413 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001414
Namhyung Kimf2148332014-01-14 11:52:48 +09001415 if (symbol_conf.filter_relative) {
1416 nr_samples = hists->stats.nr_non_filtered_samples;
1417 nr_events = hists->stats.total_non_filtered_period;
1418 }
1419
Namhyung Kim759ff492013-03-05 14:53:26 +09001420 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001421 struct perf_evsel *pos;
1422
1423 perf_evsel__group_desc(evsel, buf, buflen);
1424 ev_name = buf;
1425
1426 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001427 struct hists *pos_hists = evsel__hists(pos);
1428
Namhyung Kimf2148332014-01-14 11:52:48 +09001429 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001430 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1431 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001432 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001433 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1434 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001435 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001436 }
1437 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001438
Kan Liang9e207dd2015-08-11 06:30:49 -04001439 if (symbol_conf.show_ref_callgraph &&
1440 strstr(ev_name, "call-graph=no"))
1441 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05001442 nr_samples = convert_unit(nr_samples, &unit);
1443 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001444 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1445 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05001446
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001447
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001448 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001449 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001450 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001451 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001452 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001453 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001454 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001455 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001456 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001457 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001458 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001459 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001460 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001461 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001462 if (!is_report_browser(hbt)) {
1463 struct perf_top *top = hbt->arg;
1464
1465 if (top->zero)
1466 printed += scnprintf(bf + printed, size - printed, " [z]");
1467 }
1468
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001469 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001470}
1471
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001472static inline void free_popup_options(char **options, int n)
1473{
1474 int i;
1475
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001476 for (i = 0; i < n; ++i)
1477 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001478}
1479
Feng Tang341487ab2013-02-03 14:38:20 +08001480/*
1481 * Only runtime switching of perf data file will make "input_name" point
1482 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1483 * whether we need to call free() for current "input_name" during the switch.
1484 */
1485static bool is_input_name_malloced = false;
1486
1487static int switch_data_file(void)
1488{
1489 char *pwd, *options[32], *abs_path[32], *tmp;
1490 DIR *pwd_dir;
1491 int nr_options = 0, choice = -1, ret = -1;
1492 struct dirent *dent;
1493
1494 pwd = getenv("PWD");
1495 if (!pwd)
1496 return ret;
1497
1498 pwd_dir = opendir(pwd);
1499 if (!pwd_dir)
1500 return ret;
1501
1502 memset(options, 0, sizeof(options));
1503 memset(options, 0, sizeof(abs_path));
1504
1505 while ((dent = readdir(pwd_dir))) {
1506 char path[PATH_MAX];
1507 u64 magic;
1508 char *name = dent->d_name;
1509 FILE *file;
1510
1511 if (!(dent->d_type == DT_REG))
1512 continue;
1513
1514 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1515
1516 file = fopen(path, "r");
1517 if (!file)
1518 continue;
1519
1520 if (fread(&magic, 1, 8, file) < 8)
1521 goto close_file_and_continue;
1522
1523 if (is_perf_magic(magic)) {
1524 options[nr_options] = strdup(name);
1525 if (!options[nr_options])
1526 goto close_file_and_continue;
1527
1528 abs_path[nr_options] = strdup(path);
1529 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001530 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001531 ui__warning("Can't search all data files due to memory shortage.\n");
1532 fclose(file);
1533 break;
1534 }
1535
1536 nr_options++;
1537 }
1538
1539close_file_and_continue:
1540 fclose(file);
1541 if (nr_options >= 32) {
1542 ui__warning("Too many perf data files in PWD!\n"
1543 "Only the first 32 files will be listed.\n");
1544 break;
1545 }
1546 }
1547 closedir(pwd_dir);
1548
1549 if (nr_options) {
1550 choice = ui__popup_menu(nr_options, options);
1551 if (choice < nr_options && choice >= 0) {
1552 tmp = strdup(abs_path[choice]);
1553 if (tmp) {
1554 if (is_input_name_malloced)
1555 free((void *)input_name);
1556 input_name = tmp;
1557 is_input_name_malloced = true;
1558 ret = 0;
1559 } else
1560 ui__warning("Data switch failed due to memory shortage!\n");
1561 }
1562 }
1563
1564 free_popup_options(options, nr_options);
1565 free_popup_options(abs_path, nr_options);
1566 return ret;
1567}
1568
Namhyung Kimea7cd592015-04-22 16:18:19 +09001569struct popup_action {
1570 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001571 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001572 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001573
1574 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1575};
1576
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001577static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001578do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001579{
1580 struct perf_evsel *evsel;
1581 struct annotation *notes;
1582 struct hist_entry *he;
1583 int err;
1584
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001585 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001586 return 0;
1587
Namhyung Kimea7cd592015-04-22 16:18:19 +09001588 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001589 if (!notes->src)
1590 return 0;
1591
1592 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001593 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001594 he = hist_browser__selected_entry(browser);
1595 /*
1596 * offer option to annotate the other branch source or target
1597 * (if they exists) when returning from annotate
1598 */
1599 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1600 return 1;
1601
1602 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1603 if (err)
1604 ui_browser__handle_resize(&browser->b);
1605 return 0;
1606}
1607
1608static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001609add_annotate_opt(struct hist_browser *browser __maybe_unused,
1610 struct popup_action *act, char **optstr,
1611 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001612{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001613 if (sym == NULL || map->dso->annotate_warned)
1614 return 0;
1615
1616 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1617 return 0;
1618
1619 act->ms.map = map;
1620 act->ms.sym = sym;
1621 act->fn = do_annotate;
1622 return 1;
1623}
1624
1625static int
1626do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1627{
1628 struct thread *thread = act->thread;
1629
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001630 if (browser->hists->thread_filter) {
1631 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1632 perf_hpp__set_elide(HISTC_THREAD, false);
1633 thread__zput(browser->hists->thread_filter);
1634 ui_helpline__pop();
1635 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001636 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001637 thread->comm_set ? thread__comm_str(thread) : "",
1638 thread->tid);
1639 browser->hists->thread_filter = thread__get(thread);
1640 perf_hpp__set_elide(HISTC_THREAD, false);
1641 pstack__push(browser->pstack, &browser->hists->thread_filter);
1642 }
1643
1644 hists__filter_by_thread(browser->hists);
1645 hist_browser__reset(browser);
1646 return 0;
1647}
1648
1649static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001650add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1651 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001652{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001653 if (thread == NULL)
1654 return 0;
1655
1656 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1657 browser->hists->thread_filter ? "out of" : "into",
1658 thread->comm_set ? thread__comm_str(thread) : "",
1659 thread->tid) < 0)
1660 return 0;
1661
1662 act->thread = thread;
1663 act->fn = do_zoom_thread;
1664 return 1;
1665}
1666
1667static int
1668do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1669{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001670 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001671
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001672 if (browser->hists->dso_filter) {
1673 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1674 perf_hpp__set_elide(HISTC_DSO, false);
1675 browser->hists->dso_filter = NULL;
1676 ui_helpline__pop();
1677 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001678 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001679 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001680 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001681 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1682 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001683 perf_hpp__set_elide(HISTC_DSO, true);
1684 pstack__push(browser->pstack, &browser->hists->dso_filter);
1685 }
1686
1687 hists__filter_by_dso(browser->hists);
1688 hist_browser__reset(browser);
1689 return 0;
1690}
1691
1692static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001693add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001694 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001695{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001696 if (map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001697 return 0;
1698
1699 if (asprintf(optstr, "Zoom %s %s DSO",
1700 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001701 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001702 return 0;
1703
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001704 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001705 act->fn = do_zoom_dso;
1706 return 1;
1707}
1708
1709static int
1710do_browse_map(struct hist_browser *browser __maybe_unused,
1711 struct popup_action *act)
1712{
1713 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001714 return 0;
1715}
1716
1717static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001718add_map_opt(struct hist_browser *browser __maybe_unused,
1719 struct popup_action *act, char **optstr, struct map *map)
1720{
1721 if (map == NULL)
1722 return 0;
1723
1724 if (asprintf(optstr, "Browse map details") < 0)
1725 return 0;
1726
1727 act->ms.map = map;
1728 act->fn = do_browse_map;
1729 return 1;
1730}
1731
1732static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001733do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001734 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001735{
1736 char script_opt[64];
1737 memset(script_opt, 0, sizeof(script_opt));
1738
Namhyung Kimea7cd592015-04-22 16:18:19 +09001739 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001740 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001741 thread__comm_str(act->thread));
1742 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001743 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001744 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001745 }
1746
1747 script_browse(script_opt);
1748 return 0;
1749}
1750
1751static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001752add_script_opt(struct hist_browser *browser __maybe_unused,
1753 struct popup_action *act, char **optstr,
1754 struct thread *thread, struct symbol *sym)
1755{
1756 if (thread) {
1757 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1758 thread__comm_str(thread)) < 0)
1759 return 0;
1760 } else if (sym) {
1761 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1762 sym->name) < 0)
1763 return 0;
1764 } else {
1765 if (asprintf(optstr, "Run scripts for all samples") < 0)
1766 return 0;
1767 }
1768
1769 act->thread = thread;
1770 act->ms.sym = sym;
1771 act->fn = do_run_script;
1772 return 1;
1773}
1774
1775static int
1776do_switch_data(struct hist_browser *browser __maybe_unused,
1777 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001778{
1779 if (switch_data_file()) {
1780 ui__warning("Won't switch the data files due to\n"
1781 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001782 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001783 }
1784
1785 return K_SWITCH_INPUT_DATA;
1786}
1787
Namhyung Kimea7cd592015-04-22 16:18:19 +09001788static int
1789add_switch_opt(struct hist_browser *browser,
1790 struct popup_action *act, char **optstr)
1791{
1792 if (!is_report_browser(browser->hbt))
1793 return 0;
1794
1795 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1796 return 0;
1797
1798 act->fn = do_switch_data;
1799 return 1;
1800}
1801
1802static int
1803do_exit_browser(struct hist_browser *browser __maybe_unused,
1804 struct popup_action *act __maybe_unused)
1805{
1806 return 0;
1807}
1808
1809static int
1810add_exit_opt(struct hist_browser *browser __maybe_unused,
1811 struct popup_action *act, char **optstr)
1812{
1813 if (asprintf(optstr, "Exit") < 0)
1814 return 0;
1815
1816 act->fn = do_exit_browser;
1817 return 1;
1818}
1819
Kan Liang84734b02015-09-04 10:45:45 -04001820static int
1821do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1822{
1823 if (browser->hists->socket_filter > -1) {
1824 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1825 browser->hists->socket_filter = -1;
1826 perf_hpp__set_elide(HISTC_SOCKET, false);
1827 } else {
1828 browser->hists->socket_filter = act->socket;
1829 perf_hpp__set_elide(HISTC_SOCKET, true);
1830 pstack__push(browser->pstack, &browser->hists->socket_filter);
1831 }
1832
1833 hists__filter_by_socket(browser->hists);
1834 hist_browser__reset(browser);
1835 return 0;
1836}
1837
1838static int
1839add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1840 char **optstr, int socket_id)
1841{
1842 if (socket_id < 0)
1843 return 0;
1844
1845 if (asprintf(optstr, "Zoom %s Processor Socket %d",
1846 (browser->hists->socket_filter > -1) ? "out of" : "into",
1847 socket_id) < 0)
1848 return 0;
1849
1850 act->socket = socket_id;
1851 act->fn = do_zoom_socket;
1852 return 1;
1853}
1854
Namhyung Kim112f7612014-04-22 14:05:35 +09001855static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001856{
1857 u64 nr_entries = 0;
1858 struct rb_node *nd = rb_first(&hb->hists->entries);
1859
Namhyung Kim268397c2014-04-22 14:49:31 +09001860 if (hb->min_pcnt == 0) {
1861 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1862 return;
1863 }
1864
Namhyung Kim14135662013-10-31 10:17:39 +09001865 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001866 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001867 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001868 }
1869
Namhyung Kim112f7612014-04-22 14:05:35 +09001870 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001871}
Feng Tang341487ab2013-02-03 14:38:20 +08001872
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001873static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001874 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001875 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001876 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001877 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001878 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001879{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001880 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001881 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001882 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001883#define MAX_OPTIONS 16
1884 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09001885 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001886 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001887 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001888 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001889 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001890 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001891
Namhyung Kime8e684a2013-12-26 14:37:58 +09001892#define HIST_BROWSER_HELP_COMMON \
1893 "h/?/F1 Show this window\n" \
1894 "UP/DOWN/PGUP\n" \
1895 "PGDN/SPACE Navigate\n" \
1896 "q/ESC/CTRL+C Exit browser\n\n" \
1897 "For multiple event sessions:\n\n" \
1898 "TAB/UNTAB Switch events\n\n" \
1899 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001900 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
1901 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001902 "a Annotate current symbol\n" \
1903 "C Collapse all callchains\n" \
1904 "d Zoom into current DSO\n" \
1905 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001906 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001907 "H Display column headers\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09001908 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04001909 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001910
1911 /* help messages are sorted by lexical order of the hotkey */
1912 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001913 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001914 "P Print histograms to perf.hist.N\n"
1915 "r Run available scripts\n"
1916 "s Switch to another data file in PWD\n"
1917 "t Zoom into current Thread\n"
1918 "V Verbose (DSO names in callchains, etc)\n"
1919 "/ Filter symbol by name";
1920 const char top_help[] = HIST_BROWSER_HELP_COMMON
1921 "P Print histograms to perf.hist.N\n"
1922 "t Zoom into current Thread\n"
1923 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001924 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001925 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001926 "/ Filter symbol by name";
1927
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001928 if (browser == NULL)
1929 return -1;
1930
Namhyung Kimed426912015-05-29 21:53:44 +09001931 /* reset abort key so that it can get Ctrl-C as a key */
1932 SLang_reset_tty();
1933 SLang_init_tty(0, 0, 0);
1934
Namhyung Kim064f1982013-05-14 11:09:04 +09001935 if (min_pcnt) {
1936 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001937 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001938 }
1939
Kan Liang84734b02015-09-04 10:45:45 -04001940 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001941 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001942 goto out;
1943
1944 ui_helpline__push(helpline);
1945
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001946 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09001947 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001948
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001949 perf_hpp__for_each_format(fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001950 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001951 /*
1952 * This is done just once, and activates the horizontal scrolling
1953 * code in the ui_browser code, it would be better to have a the
1954 * counter in the perf_hpp code, but I couldn't find doing it here
1955 * works, FIXME by setting this in hist_browser__new, for now, be
1956 * clever 8-)
1957 */
1958 ++browser->b.columns;
1959 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001960
Namhyung Kim5b591662014-07-31 14:47:38 +09001961 if (symbol_conf.col_width_list_str)
1962 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1963
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001964 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001965 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001966 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001967 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04001968 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001969
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001970 nr_options = 0;
1971
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03001972 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001973
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001974 if (browser->he_selection != NULL) {
1975 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001976 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04001977 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001978 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001979 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001980 case K_TAB:
1981 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001982 if (nr_events == 1)
1983 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001984 /*
1985 * Exit the browser, let hists__browser_tree
1986 * go to the next or previous
1987 */
1988 goto out_free_stack;
1989 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001990 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001991 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001992 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001993 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001994 continue;
1995 }
1996
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001997 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001998 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001999 browser->selection->map->dso->annotate_warned)
2000 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002001
Namhyung Kimea7cd592015-04-22 16:18:19 +09002002 actions->ms.map = browser->selection->map;
2003 actions->ms.sym = browser->selection->sym;
2004 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002005 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002006 case 'P':
2007 hist_browser__dump(browser);
2008 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002009 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002010 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002011 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002012 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002013 case 'V':
2014 browser->show_dso = !browser->show_dso;
2015 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002016 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002017 actions->thread = thread;
2018 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002019 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002020 case 'S':
2021 actions->socket = socked_id;
2022 do_zoom_socket(browser, actions);
2023 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002024 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002025 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002026 "Please enter the name of symbol you want to see.\n"
2027 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002028 buf, "ENTER: OK, ESC: Cancel",
2029 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002030 hists->symbol_filter_str = *buf ? buf : NULL;
2031 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002032 hist_browser__reset(browser);
2033 }
2034 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002035 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002036 if (is_report_browser(hbt)) {
2037 actions->thread = NULL;
2038 actions->ms.sym = NULL;
2039 do_run_script(browser, actions);
2040 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002041 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002042 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002043 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002044 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002045 if (key == K_SWITCH_INPUT_DATA)
2046 goto out_free_stack;
2047 }
Feng Tang341487ab2013-02-03 14:38:20 +08002048 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002049 case 'i':
2050 /* env->arch is NULL for live-mode (i.e. perf top) */
2051 if (env->arch)
2052 tui__header_window(env);
2053 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002054 case 'F':
2055 symbol_conf.filter_relative ^= 1;
2056 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002057 case 'z':
2058 if (!is_report_browser(hbt)) {
2059 struct perf_top *top = hbt->arg;
2060
2061 top->zero = !top->zero;
2062 }
2063 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002064 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002065 case 'h':
2066 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002067 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002068 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002069 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002070 case K_ENTER:
2071 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002072 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002073 /* menu */
2074 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002075 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002076 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002077 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002078
Namhyung Kim01f00a12015-04-22 16:18:16 +09002079 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002080 /*
2081 * Go back to the perf_evsel_menu__run or other user
2082 */
2083 if (left_exits)
2084 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002085
2086 if (key == K_ESC &&
2087 ui_browser__dialog_yesno(&browser->b,
2088 "Do you really want to exit?"))
2089 goto out_free_stack;
2090
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002091 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002092 }
Namhyung Kim64221842015-04-24 10:15:33 +09002093 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002094 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002095 /*
2096 * No need to set actions->dso here since
2097 * it's just to remove the current filter.
2098 * Ditto for thread below.
2099 */
2100 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002101 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002102 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002103 } else if (top == &browser->hists->socket_filter) {
2104 do_zoom_socket(browser, actions);
2105 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002106 continue;
2107 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002108 case 'q':
2109 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002110 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002111 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002112 if (!is_report_browser(hbt)) {
2113 struct perf_top *top = hbt->arg;
2114
2115 perf_evlist__toggle_enable(top->evlist);
2116 /*
2117 * No need to refresh, resort/decay histogram
2118 * entries if we are not collecting samples:
2119 */
2120 if (top->evlist->enabled) {
2121 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2122 hbt->refresh = delay_secs;
2123 } else {
2124 helpline = "Press 'f' again to re-enable the events";
2125 hbt->refresh = 0;
2126 }
2127 continue;
2128 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002129 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002130 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002131 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002132 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002133 }
2134
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002135 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002136 goto add_exit_option;
2137
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002138 if (browser->selection == NULL)
2139 goto skip_annotation;
2140
Namhyung Kim55369fc2013-04-01 20:35:20 +09002141 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002142 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002143
2144 if (bi == NULL)
2145 goto skip_annotation;
2146
Namhyung Kimea7cd592015-04-22 16:18:19 +09002147 nr_options += add_annotate_opt(browser,
2148 &actions[nr_options],
2149 &options[nr_options],
2150 bi->from.map,
2151 bi->from.sym);
2152 if (bi->to.sym != bi->from.sym)
2153 nr_options += add_annotate_opt(browser,
2154 &actions[nr_options],
2155 &options[nr_options],
2156 bi->to.map,
2157 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002158 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002159 nr_options += add_annotate_opt(browser,
2160 &actions[nr_options],
2161 &options[nr_options],
2162 browser->selection->map,
2163 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002164 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002165skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002166 nr_options += add_thread_opt(browser, &actions[nr_options],
2167 &options[nr_options], thread);
2168 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002169 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002170 nr_options += add_map_opt(browser, &actions[nr_options],
2171 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002172 browser->selection ?
2173 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002174 nr_options += add_socket_opt(browser, &actions[nr_options],
2175 &options[nr_options],
2176 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002177 /* perf script support */
2178 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002179 nr_options += add_script_opt(browser,
2180 &actions[nr_options],
2181 &options[nr_options],
2182 thread, NULL);
Wang Nanbd315aa2015-09-14 10:23:55 +00002183 /*
2184 * Note that browser->selection != NULL
2185 * when browser->he_selection is not NULL,
2186 * so we don't need to check browser->selection
2187 * before fetching browser->selection->sym like what
2188 * we do before fetching browser->selection->map.
2189 *
2190 * See hist_browser__show_entry.
2191 */
Namhyung Kimea7cd592015-04-22 16:18:19 +09002192 nr_options += add_script_opt(browser,
2193 &actions[nr_options],
2194 &options[nr_options],
2195 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002196 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002197 nr_options += add_script_opt(browser, &actions[nr_options],
2198 &options[nr_options], NULL, NULL);
2199 nr_options += add_switch_opt(browser, &actions[nr_options],
2200 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002201add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002202 nr_options += add_exit_opt(browser, &actions[nr_options],
2203 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002204
Namhyung Kimea7cd592015-04-22 16:18:19 +09002205 do {
2206 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002207
Namhyung Kimea7cd592015-04-22 16:18:19 +09002208 choice = ui__popup_menu(nr_options, options);
2209 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002210 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002211
2212 act = &actions[choice];
2213 key = act->fn(browser, act);
2214 } while (key == 1);
2215
2216 if (key == K_SWITCH_INPUT_DATA)
2217 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002218 }
2219out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002220 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002221out:
2222 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002223 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002224 return key;
2225}
2226
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002227struct perf_evsel_menu {
2228 struct ui_browser b;
2229 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002230 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002231 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002232 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002233};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002234
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002235static void perf_evsel_menu__write(struct ui_browser *browser,
2236 void *entry, int row)
2237{
2238 struct perf_evsel_menu *menu = container_of(browser,
2239 struct perf_evsel_menu, b);
2240 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002241 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002242 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002243 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002244 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002245 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002246 const char *warn = " ";
2247 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002248
2249 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2250 HE_COLORSET_NORMAL);
2251
Namhyung Kim759ff492013-03-05 14:53:26 +09002252 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002253 struct perf_evsel *pos;
2254
2255 ev_name = perf_evsel__group_name(evsel);
2256
2257 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002258 struct hists *pos_hists = evsel__hists(pos);
2259 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002260 }
2261 }
2262
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002263 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002264 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002265 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002266 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002267
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002268 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002269 if (nr_events != 0) {
2270 menu->lost_events = true;
2271 if (!current_entry)
2272 ui_browser__set_color(browser, HE_COLORSET_TOP);
2273 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002274 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2275 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002276 warn = bf;
2277 }
2278
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002279 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002280
2281 if (current_entry)
2282 menu->selection = evsel;
2283}
2284
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002285static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2286 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002287 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002288{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002289 struct perf_evlist *evlist = menu->b.priv;
2290 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002291 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002292 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002293 int key;
2294
2295 if (ui_browser__show(&menu->b, title,
2296 "ESC: exit, ENTER|->: Browse histograms") < 0)
2297 return -1;
2298
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002299 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002300 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002301
2302 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002303 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002304 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002305
2306 if (!menu->lost_events_warned && menu->lost_events) {
2307 ui_browser__warn_lost_events(&menu->b);
2308 menu->lost_events_warned = true;
2309 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002310 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002311 case K_RIGHT:
2312 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002313 if (!menu->selection)
2314 continue;
2315 pos = menu->selection;
2316browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002317 perf_evlist__set_selected(evlist, pos);
2318 /*
2319 * Give the calling tool a chance to populate the non
2320 * default evsel resorted hists tree.
2321 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002322 if (hbt)
2323 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002324 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002325 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002326 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002327 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002328 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002329 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002330 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002331 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002332 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002333 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002334 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002335 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002336 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002337 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002338 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002339 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002340 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002341 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002342 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002343 case 'q':
2344 case CTRL('c'):
2345 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002346 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002347 default:
2348 continue;
2349 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002350 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002351 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002352 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002353 if (!ui_browser__dialog_yesno(&menu->b,
2354 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002355 continue;
2356 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002357 case 'q':
2358 case CTRL('c'):
2359 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002360 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002361 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002362 }
2363 }
2364
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002365out:
2366 ui_browser__hide(&menu->b);
2367 return key;
2368}
2369
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002370static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002371 void *entry)
2372{
2373 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2374
2375 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2376 return true;
2377
2378 return false;
2379}
2380
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002381static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002382 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002383 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002384 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002385 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002386{
2387 struct perf_evsel *pos;
2388 struct perf_evsel_menu menu = {
2389 .b = {
2390 .entries = &evlist->entries,
2391 .refresh = ui_browser__list_head_refresh,
2392 .seek = ui_browser__list_head_seek,
2393 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002394 .filter = filter_group_entries,
2395 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002396 .priv = evlist,
2397 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002398 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002399 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002400 };
2401
2402 ui_helpline__push("Press ESC to exit");
2403
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002404 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002405 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002406 size_t line_len = strlen(ev_name) + 7;
2407
2408 if (menu.b.width < line_len)
2409 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002410 }
2411
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002412 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002413}
2414
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002415int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002416 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002417 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002418 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002419{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002420 int nr_entries = evlist->nr_entries;
2421
2422single_entry:
2423 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002424 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002425
2426 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002427 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002428 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002429 }
2430
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002431 if (symbol_conf.event_group) {
2432 struct perf_evsel *pos;
2433
2434 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002435 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002436 if (perf_evsel__is_group_leader(pos))
2437 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002438 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002439
2440 if (nr_entries == 1)
2441 goto single_entry;
2442 }
2443
2444 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002445 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002446}