blob: ef7abf896f5ab46be546639c4cf7278e5db4dfbe [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 "../libslang.h"
3#include <stdlib.h>
4#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <linux/rbtree.h>
6
Namhyung Kimaca7a942012-04-04 00:14:26 -07007#include "../../util/evsel.h"
8#include "../../util/evlist.h"
9#include "../../util/hist.h"
10#include "../../util/pstack.h"
11#include "../../util/sort.h"
12#include "../../util/util.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;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030027 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030028 bool show_dso;
Namhyung Kim064f1982013-05-14 11:09:04 +090029 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090030 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090031 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030032};
33
Namhyung Kimf5951d52012-09-03 11:53:09 +090034extern void hist_browser__init_hpp(void);
35
Jiri Olsadd00d482014-06-19 13:41:13 +020036static int hists__browser_title(struct hists *hists, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090037static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030038
Namhyung Kimc3b78952014-04-22 15:56:17 +090039static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090040 float min_pcnt);
41
Namhyung Kim268397c2014-04-22 14:49:31 +090042static bool hist_browser__has_filter(struct hist_browser *hb)
43{
44 return hists__has_filter(hb->hists) || hb->min_pcnt;
45}
46
Namhyung Kimc3b78952014-04-22 15:56:17 +090047static u32 hist_browser__nr_entries(struct hist_browser *hb)
48{
49 u32 nr_entries;
50
51 if (hist_browser__has_filter(hb))
52 nr_entries = hb->nr_non_filtered_entries;
53 else
54 nr_entries = hb->hists->nr_entries;
55
56 return nr_entries + hb->nr_callchain_rows;
57}
58
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030059static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030060{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030061 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
62
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030063 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030064 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
65 /*
66 * FIXME: Just keeping existing behaviour, but this really should be
67 * before updating browser->width, as it will invalidate the
68 * calculation above. Fix this and the fallout in another
69 * changeset.
70 */
71 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030072}
73
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030074static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
75{
76 ui_browser__gotorc(&browser->b, row, column);
77}
78
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030079static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030080{
Namhyung Kimc3b78952014-04-22 15:56:17 +090081 /*
82 * The hists__remove_entry_filter() already folds non-filtered
83 * entries so we can assume it has 0 callchain rows.
84 */
85 browser->nr_callchain_rows = 0;
86
Namhyung Kim268397c2014-04-22 14:49:31 +090087 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +090088 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030089 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030090 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030091}
92
93static char tree__folded_sign(bool unfolded)
94{
95 return unfolded ? '-' : '+';
96}
97
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030098static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030099{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300100 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101}
102
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300103static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300104{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300105 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300106}
107
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300108static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300109{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300110 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300111}
112
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300113static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300114{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300115 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300116}
117
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300118static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300119{
120 int n = 0;
121 struct rb_node *nd;
122
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300123 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300124 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
125 struct callchain_list *chain;
126 char folded_sign = ' '; /* No children */
127
128 list_for_each_entry(chain, &child->val, list) {
129 ++n;
130 /* We need this because we may not have children */
131 folded_sign = callchain_list__folded(chain);
132 if (folded_sign == '+')
133 break;
134 }
135
136 if (folded_sign == '-') /* Have children and they're unfolded */
137 n += callchain_node__count_rows_rb_tree(child);
138 }
139
140 return n;
141}
142
143static int callchain_node__count_rows(struct callchain_node *node)
144{
145 struct callchain_list *chain;
146 bool unfolded = false;
147 int n = 0;
148
149 list_for_each_entry(chain, &node->val, list) {
150 ++n;
151 unfolded = chain->ms.unfolded;
152 }
153
154 if (unfolded)
155 n += callchain_node__count_rows_rb_tree(node);
156
157 return n;
158}
159
160static int callchain__count_rows(struct rb_root *chain)
161{
162 struct rb_node *nd;
163 int n = 0;
164
165 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
166 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
167 n += callchain_node__count_rows(node);
168 }
169
170 return n;
171}
172
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300173static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300174{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300175 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200176 return false;
177
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300178 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300179 return false;
180
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300181 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300182 return true;
183}
184
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300185static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300186{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300187 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300188
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300189 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300190 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
191 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300192 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300193
194 list_for_each_entry(chain, &child->val, list) {
195 if (first) {
196 first = false;
197 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300198 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300199 } else
200 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300201 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300202 }
203
204 callchain_node__init_have_children_rb_tree(child);
205 }
206}
207
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300208static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300209{
210 struct callchain_list *chain;
211
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300212 list_for_each_entry(chain, &node->val, list)
213 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300214
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300215 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300216}
217
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300218static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300219{
220 struct rb_node *nd;
221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300222 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300223 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
224 callchain_node__init_have_children(node);
225 }
226}
227
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300228static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300230 if (!he->init_have_children) {
231 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
232 callchain__init_have_children(&he->sorted_chain);
233 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300234 }
235}
236
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300237static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300238{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300239 if (map_symbol__toggle_fold(browser->selection)) {
240 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300241
242 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900243 browser->b.nr_entries -= he->nr_rows;
244 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300245
246 if (he->ms.unfolded)
247 he->nr_rows = callchain__count_rows(&he->sorted_chain);
248 else
249 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900250
251 browser->b.nr_entries += he->nr_rows;
252 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300253
254 return true;
255 }
256
257 /* If it doesn't have children, no toggling performed */
258 return false;
259}
260
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300261static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300262{
263 int n = 0;
264 struct rb_node *nd;
265
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300266 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300267 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
268 struct callchain_list *chain;
269 bool has_children = false;
270
271 list_for_each_entry(chain, &child->val, list) {
272 ++n;
273 map_symbol__set_folding(&chain->ms, unfold);
274 has_children = chain->ms.has_children;
275 }
276
277 if (has_children)
278 n += callchain_node__set_folding_rb_tree(child, unfold);
279 }
280
281 return n;
282}
283
284static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
285{
286 struct callchain_list *chain;
287 bool has_children = false;
288 int n = 0;
289
290 list_for_each_entry(chain, &node->val, list) {
291 ++n;
292 map_symbol__set_folding(&chain->ms, unfold);
293 has_children = chain->ms.has_children;
294 }
295
296 if (has_children)
297 n += callchain_node__set_folding_rb_tree(node, unfold);
298
299 return n;
300}
301
302static int callchain__set_folding(struct rb_root *chain, bool unfold)
303{
304 struct rb_node *nd;
305 int n = 0;
306
307 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
308 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
309 n += callchain_node__set_folding(node, unfold);
310 }
311
312 return n;
313}
314
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300315static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300316{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300317 hist_entry__init_have_children(he);
318 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300319
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300320 if (he->ms.has_children) {
321 int n = callchain__set_folding(&he->sorted_chain, unfold);
322 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300323 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300324 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300325}
326
Namhyung Kimc3b78952014-04-22 15:56:17 +0900327static void
328__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300329{
330 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900331 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300332
Namhyung Kimc3b78952014-04-22 15:56:17 +0900333 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900334 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900335 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300336 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
337 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900338 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300339 }
340}
341
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300342static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300343{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900344 browser->nr_callchain_rows = 0;
345 __hist_browser__set_folding(browser, unfold);
346
347 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300348 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300349 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300350}
351
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200352static void ui_browser__warn_lost_events(struct ui_browser *browser)
353{
354 ui_browser__warning(browser, 4,
355 "Events are being lost, check IO/CPU overload!\n\n"
356 "You may want to run 'perf' using a RT scheduler policy:\n\n"
357 " perf top -r 80\n\n"
358 "Or reduce the sampling frequency.");
359}
360
Jiri Olsadd00d482014-06-19 13:41:13 +0200361static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900362 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300364 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300365 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900366 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300367
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900369 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300370
Jiri Olsadd00d482014-06-19 13:41:13 +0200371 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300373 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300374 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300375 return -1;
376
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300377 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300378 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300379
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300380 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900381 case K_TIMER: {
382 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900383 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900384
Namhyung Kimc3b78952014-04-22 15:56:17 +0900385 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900386 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900387
Namhyung Kimc3b78952014-04-22 15:56:17 +0900388 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900389 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200390
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300391 if (browser->hists->stats.nr_lost_warned !=
392 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
393 browser->hists->stats.nr_lost_warned =
394 browser->hists->stats.nr_events[PERF_RECORD_LOST];
395 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200396 }
397
Jiri Olsadd00d482014-06-19 13:41:13 +0200398 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300399 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300400 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900401 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300402 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300403 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300404 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300405 struct hist_entry, rb_node);
406 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300407 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 -0300408 seq++, browser->b.nr_entries,
409 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300410 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300411 browser->b.index,
412 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300413 h->row_offset, h->nr_rows);
414 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300415 break;
416 case 'C':
417 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300418 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300419 break;
420 case 'E':
421 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300422 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300423 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200424 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300425 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300426 break;
427 /* fall thru */
428 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300429 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300430 }
431 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300432out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300433 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300434 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300435}
436
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300437static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300438 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300439{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300440 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300441
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300442 if (cl->ms.sym)
443 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
444 else
445 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
446
447 if (show_dso)
448 scnprintf(bf + printed, bfsize - printed, " %s",
449 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
450
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300451 return bf;
452}
453
454#define LEVEL_OFFSET_STEP 3
455
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300456static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300457 struct callchain_node *chain_node,
458 u64 total, int level,
459 unsigned short row,
460 off_t *row_offset,
461 bool *is_current_entry)
462{
463 struct rb_node *node;
464 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
465 u64 new_total, remaining;
466
467 if (callchain_param.mode == CHAIN_GRAPH_REL)
468 new_total = chain_node->children_hit;
469 else
470 new_total = total;
471
472 remaining = new_total;
473 node = rb_first(&chain_node->rb_root);
474 while (node) {
475 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
476 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100477 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300478 struct callchain_list *chain;
479 char folded_sign = ' ';
480 int first = true;
481 int extra_offset = 0;
482
483 remaining -= cumul;
484
485 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300486 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300487 const char *str;
488 int color;
489 bool was_first = first;
490
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300491 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300492 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300493 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300494 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300495
496 folded_sign = callchain_list__folded(chain);
497 if (*row_offset != 0) {
498 --*row_offset;
499 goto do_next;
500 }
501
502 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300503 str = callchain_list__sym_name(chain, bf, sizeof(bf),
504 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300505 if (was_first) {
506 double percent = cumul * 100.0 / new_total;
507
508 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
509 str = "Not enough memory!";
510 else
511 str = alloc_str;
512 }
513
514 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300515 width = browser->b.width - (offset + extra_offset + 2);
516 if (ui_browser__is_current_entry(&browser->b, row)) {
517 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300518 color = HE_COLORSET_SELECTED;
519 *is_current_entry = true;
520 }
521
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300522 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300523 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300524 slsmg_write_nstring(" ", offset + extra_offset);
525 slsmg_printf("%c ", folded_sign);
526 slsmg_write_nstring(str, width);
527 free(alloc_str);
528
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300529 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300530 goto out;
531do_next:
532 if (folded_sign == '+')
533 break;
534 }
535
536 if (folded_sign == '-') {
537 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300538 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300539 new_level, row, row_offset,
540 is_current_entry);
541 }
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300542 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300543 goto out;
544 node = next;
545 }
546out:
547 return row - first_row;
548}
549
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300550static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300551 struct callchain_node *node,
552 int level, unsigned short row,
553 off_t *row_offset,
554 bool *is_current_entry)
555{
556 struct callchain_list *chain;
557 int first_row = row,
558 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300559 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300560 char folded_sign = ' ';
561
562 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300563 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300564 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300565
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300566 folded_sign = callchain_list__folded(chain);
567
568 if (*row_offset != 0) {
569 --*row_offset;
570 continue;
571 }
572
573 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300574 if (ui_browser__is_current_entry(&browser->b, row)) {
575 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300576 color = HE_COLORSET_SELECTED;
577 *is_current_entry = true;
578 }
579
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300580 s = callchain_list__sym_name(chain, bf, sizeof(bf),
581 browser->show_dso);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300582 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300583 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300584 slsmg_write_nstring(" ", offset);
585 slsmg_printf("%c ", folded_sign);
586 slsmg_write_nstring(s, width - 2);
587
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300588 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300589 goto out;
590 }
591
592 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300593 row += hist_browser__show_callchain_node_rb_tree(browser, node,
594 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300595 level + 1, row,
596 row_offset,
597 is_current_entry);
598out:
599 return row - first_row;
600}
601
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300602static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300603 struct rb_root *chain,
604 int level, unsigned short row,
605 off_t *row_offset,
606 bool *is_current_entry)
607{
608 struct rb_node *nd;
609 int first_row = row;
610
611 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
612 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
613
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300614 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300615 row, row_offset,
616 is_current_entry);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300617 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300618 break;
619 }
620
621 return row - first_row;
622}
623
Namhyung Kim89701462013-01-22 18:09:38 +0900624struct hpp_arg {
625 struct ui_browser *b;
626 char folded_sign;
627 bool current_entry;
628};
629
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900630static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
631{
632 struct hpp_arg *arg = hpp->ptr;
633 int ret;
634 va_list args;
635 double percent;
636
637 va_start(args, fmt);
638 percent = va_arg(args, double);
639 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900640
Namhyung Kim89701462013-01-22 18:09:38 +0900641 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900642
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900643 ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900644 slsmg_printf("%s", hpp->buf);
645
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900646 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900647 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900648}
649
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900650#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900651static u64 __hpp_get_##_field(struct hist_entry *he) \
652{ \
653 return he->stat._field; \
654} \
655 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100656static int \
657hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
658 struct perf_hpp *hpp, \
659 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900660{ \
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900661 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900662 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900663}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900664
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900665#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
666static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
667{ \
668 return he->stat_acc->_field; \
669} \
670 \
671static int \
672hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
673 struct perf_hpp *hpp, \
674 struct hist_entry *he) \
675{ \
676 if (!symbol_conf.cumulate_callchain) { \
677 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
678 slsmg_printf("%s", hpp->buf); \
679 \
680 return ret; \
681 } \
682 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \
683 __hpp__slsmg_color_printf, true); \
684}
685
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900686__HPP_COLOR_PERCENT_FN(overhead, period)
687__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
688__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
689__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
690__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900691__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900692
693#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900694#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900695
696void hist_browser__init_hpp(void)
697{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900698 perf_hpp__format[PERF_HPP__OVERHEAD].color =
699 hist_browser__hpp_color_overhead;
700 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
701 hist_browser__hpp_color_overhead_sys;
702 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
703 hist_browser__hpp_color_overhead_us;
704 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
705 hist_browser__hpp_color_overhead_guest_sys;
706 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
707 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900708 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
709 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900710}
711
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300712static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300713 struct hist_entry *entry,
714 unsigned short row)
715{
716 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200717 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900718 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300719 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300720 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300721 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300722 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200723 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300724
725 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300726 browser->he_selection = entry;
727 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300728 }
729
730 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300731 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300732 folded_sign = hist_entry__folded(entry);
733 }
734
735 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900736 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900737 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900738 .folded_sign = folded_sign,
739 .current_entry = current_entry,
740 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900741 struct perf_hpp hpp = {
742 .buf = s,
743 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900744 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900745 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300746
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300747 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900748
Jiri Olsa12400052012-10-13 00:06:16 +0200749 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900750 if (perf_hpp__should_skip(fmt))
751 continue;
752
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900753 if (current_entry && browser->b.navkeypressed) {
754 ui_browser__set_color(&browser->b,
755 HE_COLORSET_SELECTED);
756 } else {
757 ui_browser__set_color(&browser->b,
758 HE_COLORSET_NORMAL);
759 }
760
761 if (first) {
762 if (symbol_conf.use_callchain) {
763 slsmg_printf("%c ", folded_sign);
764 width -= 2;
765 }
766 first = false;
767 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900768 slsmg_printf(" ");
769 width -= 2;
770 }
771
Jiri Olsa12400052012-10-13 00:06:16 +0200772 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100773 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900774 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100775 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900776 slsmg_printf("%s", s);
777 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300778 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200779
780 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300781 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200782 width += 1;
783
Namhyung Kim26d8b332014-03-03 16:16:20 +0900784 slsmg_write_nstring("", width);
785
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300786 ++row;
787 ++printed;
788 } else
789 --row_offset;
790
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300791 if (folded_sign == '-' && row != browser->b.rows) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300792 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300793 1, row, &row_offset,
794 &current_entry);
795 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300796 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300797 }
798
799 return printed;
800}
801
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300802static void ui_browser__hists_init_top(struct ui_browser *browser)
803{
804 if (browser->top == NULL) {
805 struct hist_browser *hb;
806
807 hb = container_of(browser, struct hist_browser, b);
808 browser->top = rb_first(&hb->hists->entries);
809 }
810}
811
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300812static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300813{
814 unsigned row = 0;
815 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300816 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300817
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300818 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300819
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300820 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300821 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900822 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300823
824 if (h->filtered)
825 continue;
826
Namhyung Kim14135662013-10-31 10:17:39 +0900827 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900828 if (percent < hb->min_pcnt)
829 continue;
830
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300831 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300832 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300833 break;
834 }
835
836 return row;
837}
838
Namhyung Kim064f1982013-05-14 11:09:04 +0900839static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900840 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300841{
842 while (nd != NULL) {
843 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900844 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900845
Namhyung Kimc0f15272014-04-16 11:16:33 +0900846 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300847 return nd;
848
849 nd = rb_next(nd);
850 }
851
852 return NULL;
853}
854
Namhyung Kim064f1982013-05-14 11:09:04 +0900855static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900856 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300857{
858 while (nd != NULL) {
859 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900860 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900861
862 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300863 return nd;
864
865 nd = rb_prev(nd);
866 }
867
868 return NULL;
869}
870
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300871static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300872 off_t offset, int whence)
873{
874 struct hist_entry *h;
875 struct rb_node *nd;
876 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900877 struct hist_browser *hb;
878
879 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300880
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300881 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300882 return;
883
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300884 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300885
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300886 switch (whence) {
887 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900888 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900889 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300890 break;
891 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300892 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300893 goto do_offset;
894 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900895 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900896 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300897 first = false;
898 break;
899 default:
900 return;
901 }
902
903 /*
904 * Moves not relative to the first visible entry invalidates its
905 * row_offset:
906 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300907 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300908 h->row_offset = 0;
909
910 /*
911 * Here we have to check if nd is expanded (+), if it is we can't go
912 * the next top level hist_entry, instead we must compute an offset of
913 * what _not_ to show and not change the first visible entry.
914 *
915 * This offset increments when we are going from top to bottom and
916 * decreases when we're going from bottom to top.
917 *
918 * As we don't have backpointers to the top level in the callchains
919 * structure, we need to always print the whole hist_entry callchain,
920 * skipping the first ones that are before the first visible entry
921 * and stop when we printed enough lines to fill the screen.
922 */
923do_offset:
924 if (offset > 0) {
925 do {
926 h = rb_entry(nd, struct hist_entry, rb_node);
927 if (h->ms.unfolded) {
928 u16 remaining = h->nr_rows - h->row_offset;
929 if (offset > remaining) {
930 offset -= remaining;
931 h->row_offset = 0;
932 } else {
933 h->row_offset += offset;
934 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300935 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300936 break;
937 }
938 }
Namhyung Kim14135662013-10-31 10:17:39 +0900939 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300940 if (nd == NULL)
941 break;
942 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300943 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300944 } while (offset != 0);
945 } else if (offset < 0) {
946 while (1) {
947 h = rb_entry(nd, struct hist_entry, rb_node);
948 if (h->ms.unfolded) {
949 if (first) {
950 if (-offset > h->row_offset) {
951 offset += h->row_offset;
952 h->row_offset = 0;
953 } else {
954 h->row_offset += offset;
955 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300956 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300957 break;
958 }
959 } else {
960 if (-offset > h->nr_rows) {
961 offset += h->nr_rows;
962 h->row_offset = 0;
963 } else {
964 h->row_offset = h->nr_rows + offset;
965 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300966 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300967 break;
968 }
969 }
970 }
971
Namhyung Kim14135662013-10-31 10:17:39 +0900972 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +0900973 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300974 if (nd == NULL)
975 break;
976 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300977 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300978 if (offset == 0) {
979 /*
980 * Last unfiltered hist_entry, check if it is
981 * unfolded, if it is then we should have
982 * row_offset at its last entry.
983 */
984 h = rb_entry(nd, struct hist_entry, rb_node);
985 if (h->ms.unfolded)
986 h->row_offset = h->nr_rows;
987 break;
988 }
989 first = false;
990 }
991 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300992 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300993 h = rb_entry(nd, struct hist_entry, rb_node);
994 h->row_offset = 0;
995 }
996}
997
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300998static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
999 struct callchain_node *chain_node,
1000 u64 total, int level,
1001 FILE *fp)
1002{
1003 struct rb_node *node;
1004 int offset = level * LEVEL_OFFSET_STEP;
1005 u64 new_total, remaining;
1006 int printed = 0;
1007
1008 if (callchain_param.mode == CHAIN_GRAPH_REL)
1009 new_total = chain_node->children_hit;
1010 else
1011 new_total = total;
1012
1013 remaining = new_total;
1014 node = rb_first(&chain_node->rb_root);
1015 while (node) {
1016 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1017 struct rb_node *next = rb_next(node);
1018 u64 cumul = callchain_cumul_hits(child);
1019 struct callchain_list *chain;
1020 char folded_sign = ' ';
1021 int first = true;
1022 int extra_offset = 0;
1023
1024 remaining -= cumul;
1025
1026 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001027 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001028 const char *str;
1029 bool was_first = first;
1030
1031 if (first)
1032 first = false;
1033 else
1034 extra_offset = LEVEL_OFFSET_STEP;
1035
1036 folded_sign = callchain_list__folded(chain);
1037
1038 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001039 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1040 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001041 if (was_first) {
1042 double percent = cumul * 100.0 / new_total;
1043
1044 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1045 str = "Not enough memory!";
1046 else
1047 str = alloc_str;
1048 }
1049
1050 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1051 free(alloc_str);
1052 if (folded_sign == '+')
1053 break;
1054 }
1055
1056 if (folded_sign == '-') {
1057 const int new_level = level + (extra_offset ? 2 : 1);
1058 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1059 new_level, fp);
1060 }
1061
1062 node = next;
1063 }
1064
1065 return printed;
1066}
1067
1068static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1069 struct callchain_node *node,
1070 int level, FILE *fp)
1071{
1072 struct callchain_list *chain;
1073 int offset = level * LEVEL_OFFSET_STEP;
1074 char folded_sign = ' ';
1075 int printed = 0;
1076
1077 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001078 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001079
1080 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001081 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001082 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1083 }
1084
1085 if (folded_sign == '-')
1086 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1087 browser->hists->stats.total_period,
1088 level + 1, fp);
1089 return printed;
1090}
1091
1092static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1093 struct rb_root *chain, int level, FILE *fp)
1094{
1095 struct rb_node *nd;
1096 int printed = 0;
1097
1098 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1099 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1100
1101 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1102 }
1103
1104 return printed;
1105}
1106
1107static int hist_browser__fprintf_entry(struct hist_browser *browser,
1108 struct hist_entry *he, FILE *fp)
1109{
1110 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001111 int printed = 0;
1112 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001113 struct perf_hpp hpp = {
1114 .buf = s,
1115 .size = sizeof(s),
1116 };
1117 struct perf_hpp_fmt *fmt;
1118 bool first = true;
1119 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001120
1121 if (symbol_conf.use_callchain)
1122 folded_sign = hist_entry__folded(he);
1123
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001124 if (symbol_conf.use_callchain)
1125 printed += fprintf(fp, "%c ", folded_sign);
1126
Namhyung Kim26d8b332014-03-03 16:16:20 +09001127 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001128 if (perf_hpp__should_skip(fmt))
1129 continue;
1130
Namhyung Kim26d8b332014-03-03 16:16:20 +09001131 if (!first) {
1132 ret = scnprintf(hpp.buf, hpp.size, " ");
1133 advance_hpp(&hpp, ret);
1134 } else
1135 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001136
Namhyung Kim26d8b332014-03-03 16:16:20 +09001137 ret = fmt->entry(fmt, &hpp, he);
1138 advance_hpp(&hpp, ret);
1139 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001140 printed += fprintf(fp, "%s\n", rtrim(s));
1141
1142 if (folded_sign == '-')
1143 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1144
1145 return printed;
1146}
1147
1148static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1149{
Namhyung Kim064f1982013-05-14 11:09:04 +09001150 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001151 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001152 int printed = 0;
1153
1154 while (nd) {
1155 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1156
1157 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001158 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001159 }
1160
1161 return printed;
1162}
1163
1164static int hist_browser__dump(struct hist_browser *browser)
1165{
1166 char filename[64];
1167 FILE *fp;
1168
1169 while (1) {
1170 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1171 if (access(filename, F_OK))
1172 break;
1173 /*
1174 * XXX: Just an arbitrary lazy upper limit
1175 */
1176 if (++browser->print_seq == 8192) {
1177 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1178 return -1;
1179 }
1180 }
1181
1182 fp = fopen(filename, "w");
1183 if (fp == NULL) {
1184 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001185 const char *err = strerror_r(errno, bf, sizeof(bf));
1186 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001187 return -1;
1188 }
1189
1190 ++browser->print_seq;
1191 hist_browser__fprintf(browser, fp);
1192 fclose(fp);
1193 ui_helpline__fpush("%s written!", filename);
1194
1195 return 0;
1196}
1197
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198static struct hist_browser *hist_browser__new(struct hists *hists)
1199{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001200 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001202 if (browser) {
1203 browser->hists = hists;
1204 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001205 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001206 browser->b.seek = ui_browser__hists_seek;
1207 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001208 }
1209
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001210 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001211}
1212
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001213static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001214{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001215 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001216}
1217
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001218static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001220 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001221}
1222
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001223static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001224{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001225 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001226}
1227
Jiri Olsadd00d482014-06-19 13:41:13 +02001228static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001229{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001230 char unit;
1231 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001232 const struct dso *dso = hists->dso_filter;
1233 const struct thread *thread = hists->thread_filter;
1234 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1235 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001236 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001237 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001238 char buf[512];
1239 size_t buflen = sizeof(buf);
1240
Namhyung Kimf2148332014-01-14 11:52:48 +09001241 if (symbol_conf.filter_relative) {
1242 nr_samples = hists->stats.nr_non_filtered_samples;
1243 nr_events = hists->stats.total_non_filtered_period;
1244 }
1245
Namhyung Kim759ff492013-03-05 14:53:26 +09001246 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001247 struct perf_evsel *pos;
1248
1249 perf_evsel__group_desc(evsel, buf, buflen);
1250 ev_name = buf;
1251
1252 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001253 if (symbol_conf.filter_relative) {
1254 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1255 nr_events += pos->hists.stats.total_non_filtered_period;
1256 } else {
1257 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1258 nr_events += pos->hists.stats.total_period;
1259 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001260 }
1261 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001262
Ashay Ranecc6862802012-04-05 21:01:01 -05001263 nr_samples = convert_unit(nr_samples, &unit);
1264 printed = scnprintf(bf, size,
1265 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1266 nr_samples, unit, ev_name, nr_events);
1267
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001268
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001269 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001270 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001271 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001272 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001273 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001274 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001275 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001276 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001277 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001278 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001279 ", DSO: %s", dso->short_name);
1280 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001281}
1282
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001283static inline void free_popup_options(char **options, int n)
1284{
1285 int i;
1286
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001287 for (i = 0; i < n; ++i)
1288 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001289}
1290
Feng Tangc77d8d72012-11-01 00:00:55 +08001291/* Check whether the browser is for 'top' or 'report' */
1292static inline bool is_report_browser(void *timer)
1293{
1294 return timer == NULL;
1295}
1296
Feng Tang341487ab2013-02-03 14:38:20 +08001297/*
1298 * Only runtime switching of perf data file will make "input_name" point
1299 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1300 * whether we need to call free() for current "input_name" during the switch.
1301 */
1302static bool is_input_name_malloced = false;
1303
1304static int switch_data_file(void)
1305{
1306 char *pwd, *options[32], *abs_path[32], *tmp;
1307 DIR *pwd_dir;
1308 int nr_options = 0, choice = -1, ret = -1;
1309 struct dirent *dent;
1310
1311 pwd = getenv("PWD");
1312 if (!pwd)
1313 return ret;
1314
1315 pwd_dir = opendir(pwd);
1316 if (!pwd_dir)
1317 return ret;
1318
1319 memset(options, 0, sizeof(options));
1320 memset(options, 0, sizeof(abs_path));
1321
1322 while ((dent = readdir(pwd_dir))) {
1323 char path[PATH_MAX];
1324 u64 magic;
1325 char *name = dent->d_name;
1326 FILE *file;
1327
1328 if (!(dent->d_type == DT_REG))
1329 continue;
1330
1331 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1332
1333 file = fopen(path, "r");
1334 if (!file)
1335 continue;
1336
1337 if (fread(&magic, 1, 8, file) < 8)
1338 goto close_file_and_continue;
1339
1340 if (is_perf_magic(magic)) {
1341 options[nr_options] = strdup(name);
1342 if (!options[nr_options])
1343 goto close_file_and_continue;
1344
1345 abs_path[nr_options] = strdup(path);
1346 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001347 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001348 ui__warning("Can't search all data files due to memory shortage.\n");
1349 fclose(file);
1350 break;
1351 }
1352
1353 nr_options++;
1354 }
1355
1356close_file_and_continue:
1357 fclose(file);
1358 if (nr_options >= 32) {
1359 ui__warning("Too many perf data files in PWD!\n"
1360 "Only the first 32 files will be listed.\n");
1361 break;
1362 }
1363 }
1364 closedir(pwd_dir);
1365
1366 if (nr_options) {
1367 choice = ui__popup_menu(nr_options, options);
1368 if (choice < nr_options && choice >= 0) {
1369 tmp = strdup(abs_path[choice]);
1370 if (tmp) {
1371 if (is_input_name_malloced)
1372 free((void *)input_name);
1373 input_name = tmp;
1374 is_input_name_malloced = true;
1375 ret = 0;
1376 } else
1377 ui__warning("Data switch failed due to memory shortage!\n");
1378 }
1379 }
1380
1381 free_popup_options(options, nr_options);
1382 free_popup_options(abs_path, nr_options);
1383 return ret;
1384}
1385
Namhyung Kim112f7612014-04-22 14:05:35 +09001386static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001387{
1388 u64 nr_entries = 0;
1389 struct rb_node *nd = rb_first(&hb->hists->entries);
1390
Namhyung Kim268397c2014-04-22 14:49:31 +09001391 if (hb->min_pcnt == 0) {
1392 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1393 return;
1394 }
1395
Namhyung Kim14135662013-10-31 10:17:39 +09001396 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001397 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001398 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001399 }
1400
Namhyung Kim112f7612014-04-22 14:05:35 +09001401 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001402}
Feng Tang341487ab2013-02-03 14:38:20 +08001403
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001404static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001405 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001406 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001407 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001408 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001409 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001410{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001411 struct hists *hists = &evsel->hists;
1412 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001413 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001414 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001415 char *options[16];
1416 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001417 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001418 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001419 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001420 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001421
Namhyung Kime8e684a2013-12-26 14:37:58 +09001422#define HIST_BROWSER_HELP_COMMON \
1423 "h/?/F1 Show this window\n" \
1424 "UP/DOWN/PGUP\n" \
1425 "PGDN/SPACE Navigate\n" \
1426 "q/ESC/CTRL+C Exit browser\n\n" \
1427 "For multiple event sessions:\n\n" \
1428 "TAB/UNTAB Switch events\n\n" \
1429 "For symbolic views (--sort has sym):\n\n" \
1430 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1431 "<- Zoom out\n" \
1432 "a Annotate current symbol\n" \
1433 "C Collapse all callchains\n" \
1434 "d Zoom into current DSO\n" \
1435 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001436 "F Toggle percentage of filtered entries\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001437
1438 /* help messages are sorted by lexical order of the hotkey */
1439 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001440 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001441 "P Print histograms to perf.hist.N\n"
1442 "r Run available scripts\n"
1443 "s Switch to another data file in PWD\n"
1444 "t Zoom into current Thread\n"
1445 "V Verbose (DSO names in callchains, etc)\n"
1446 "/ Filter symbol by name";
1447 const char top_help[] = HIST_BROWSER_HELP_COMMON
1448 "P Print histograms to perf.hist.N\n"
1449 "t Zoom into current Thread\n"
1450 "V Verbose (DSO names in callchains, etc)\n"
1451 "/ Filter symbol by name";
1452
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001453 if (browser == NULL)
1454 return -1;
1455
Namhyung Kim064f1982013-05-14 11:09:04 +09001456 if (min_pcnt) {
1457 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001458 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001459 }
1460
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001461 fstack = pstack__new(2);
1462 if (fstack == NULL)
1463 goto out;
1464
1465 ui_helpline__push(helpline);
1466
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001467 memset(options, 0, sizeof(options));
1468
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001469 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001470 const struct thread *thread = NULL;
1471 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001472 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001473 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001474 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001475 int scripts_comm = -2, scripts_symbol = -2,
1476 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001477
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001478 nr_options = 0;
1479
Jiri Olsadd00d482014-06-19 13:41:13 +02001480 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001481
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001482 if (browser->he_selection != NULL) {
1483 thread = hist_browser__selected_thread(browser);
1484 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1485 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001486 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001487 case K_TAB:
1488 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001489 if (nr_events == 1)
1490 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001491 /*
1492 * Exit the browser, let hists__browser_tree
1493 * go to the next or previous
1494 */
1495 goto out_free_stack;
1496 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001497 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001498 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001499 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001500 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001501 continue;
1502 }
1503
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001504 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001505 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001506 browser->selection->map->dso->annotate_warned)
1507 continue;
1508 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001509 case 'P':
1510 hist_browser__dump(browser);
1511 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001512 case 'd':
1513 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001514 case 'V':
1515 browser->show_dso = !browser->show_dso;
1516 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001517 case 't':
1518 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001519 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001520 if (ui_browser__input_window("Symbol to show",
1521 "Please enter the name of symbol you want to see",
1522 buf, "ENTER: OK, ESC: Cancel",
1523 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001524 hists->symbol_filter_str = *buf ? buf : NULL;
1525 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001526 hist_browser__reset(browser);
1527 }
1528 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001529 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001530 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001531 goto do_scripts;
1532 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001533 case 's':
1534 if (is_report_browser(hbt))
1535 goto do_data_switch;
1536 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001537 case 'i':
1538 /* env->arch is NULL for live-mode (i.e. perf top) */
1539 if (env->arch)
1540 tui__header_window(env);
1541 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001542 case 'F':
1543 symbol_conf.filter_relative ^= 1;
1544 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001545 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001546 case 'h':
1547 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001548 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001549 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001550 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001551 case K_ENTER:
1552 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001553 /* menu */
1554 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001555 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001556 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001557
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001558 if (pstack__empty(fstack)) {
1559 /*
1560 * Go back to the perf_evsel_menu__run or other user
1561 */
1562 if (left_exits)
1563 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001564 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001565 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001566 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001567 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001568 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001569 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001570 goto zoom_out_thread;
1571 continue;
1572 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001573 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001574 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001575 !ui_browser__dialog_yesno(&browser->b,
1576 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001577 continue;
1578 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001579 case 'q':
1580 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001581 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001582 default:
1583 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001584 }
1585
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001586 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001587 goto add_exit_option;
1588
Namhyung Kim55369fc2013-04-01 20:35:20 +09001589 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001590 bi = browser->he_selection->branch_info;
1591 if (browser->selection != NULL &&
1592 bi &&
1593 bi->from.sym != NULL &&
1594 !bi->from.map->dso->annotate_warned &&
1595 asprintf(&options[nr_options], "Annotate %s",
1596 bi->from.sym->name) > 0)
1597 annotate_f = nr_options++;
1598
1599 if (browser->selection != NULL &&
1600 bi &&
1601 bi->to.sym != NULL &&
1602 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001603 (bi->to.sym != bi->from.sym ||
1604 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001605 asprintf(&options[nr_options], "Annotate %s",
1606 bi->to.sym->name) > 0)
1607 annotate_t = nr_options++;
1608 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001609 if (browser->selection != NULL &&
1610 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001611 !browser->selection->map->dso->annotate_warned) {
1612 struct annotation *notes;
1613
1614 notes = symbol__annotation(browser->selection->sym);
1615
1616 if (notes->src &&
1617 asprintf(&options[nr_options], "Annotate %s",
1618 browser->selection->sym->name) > 0)
1619 annotate = nr_options++;
1620 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001621 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001622
1623 if (thread != NULL &&
1624 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001625 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001626 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001627 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001628 zoom_thread = nr_options++;
1629
1630 if (dso != NULL &&
1631 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001632 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001633 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1634 zoom_dso = nr_options++;
1635
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001636 if (browser->selection != NULL &&
1637 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001638 asprintf(&options[nr_options], "Browse map details") > 0)
1639 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001640
1641 /* perf script support */
1642 if (browser->he_selection) {
1643 struct symbol *sym;
1644
1645 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001646 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001647 scripts_comm = nr_options++;
1648
1649 sym = browser->he_selection->ms.sym;
1650 if (sym && sym->namelen &&
1651 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1652 sym->name) > 0)
1653 scripts_symbol = nr_options++;
1654 }
1655
1656 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1657 scripts_all = nr_options++;
1658
Feng Tang341487ab2013-02-03 14:38:20 +08001659 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1660 "Switch to another data file in PWD") > 0)
1661 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001662add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001663 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001664retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001665 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001666
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001667 if (choice == nr_options - 1)
1668 break;
1669
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001670 if (choice == -1) {
1671 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001672 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001673 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001674
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001675 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001676 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001677 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001678 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001679do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001680 if (!objdump_path && perf_session_env__lookup_objdump(env))
1681 continue;
1682
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001683 he = hist_browser__selected_entry(browser);
1684 if (he == NULL)
1685 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001686
1687 /*
1688 * we stash the branch_info symbol + map into the
1689 * the ms so we don't have to rewrite all the annotation
1690 * code to use branch_info.
1691 * in branch mode, the ms struct is not used
1692 */
1693 if (choice == annotate_f) {
1694 he->ms.sym = he->branch_info->from.sym;
1695 he->ms.map = he->branch_info->from.map;
1696 } else if (choice == annotate_t) {
1697 he->ms.sym = he->branch_info->to.sym;
1698 he->ms.map = he->branch_info->to.map;
1699 }
1700
Jiri Olsad7553302014-06-15 10:22:15 +02001701 notes = symbol__annotation(he->ms.sym);
1702 if (!notes->src)
1703 continue;
1704
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001705 /*
1706 * Don't let this be freed, say, by hists__decay_entry.
1707 */
1708 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001709 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001710 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001711 /*
1712 * offer option to annotate the other branch source or target
1713 * (if they exists) when returning from annotate
1714 */
1715 if ((err == 'q' || err == CTRL('c'))
1716 && annotate_t != -2 && annotate_f != -2)
1717 goto retry_popup_menu;
1718
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001719 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001720 if (err)
1721 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001722
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001723 } else if (choice == browse_map)
1724 map__browse(browser->selection->map);
1725 else if (choice == zoom_dso) {
1726zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001727 if (browser->hists->dso_filter) {
1728 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001729zoom_out_dso:
1730 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001731 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001732 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001733 } else {
1734 if (dso == NULL)
1735 continue;
1736 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1737 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001738 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001739 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001740 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001741 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001742 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001743 hist_browser__reset(browser);
1744 } else if (choice == zoom_thread) {
1745zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001746 if (browser->hists->thread_filter) {
1747 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001748zoom_out_thread:
1749 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001750 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001751 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001752 } else {
1753 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001754 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001755 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001756 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001757 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001758 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001759 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001760 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761 hist_browser__reset(browser);
1762 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001763 /* perf scripts support */
1764 else if (choice == scripts_all || choice == scripts_comm ||
1765 choice == scripts_symbol) {
1766do_scripts:
1767 memset(script_opt, 0, 64);
1768
1769 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001770 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001771
1772 if (choice == scripts_symbol)
1773 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1774
1775 script_browse(script_opt);
1776 }
Feng Tang341487ab2013-02-03 14:38:20 +08001777 /* Switch to another data file */
1778 else if (choice == switch_data) {
1779do_data_switch:
1780 if (!switch_data_file()) {
1781 key = K_SWITCH_INPUT_DATA;
1782 break;
1783 } else
1784 ui__warning("Won't switch the data files due to\n"
1785 "no valid data file get selected!\n");
1786 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001787 }
1788out_free_stack:
1789 pstack__delete(fstack);
1790out:
1791 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001792 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001793 return key;
1794}
1795
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001796struct perf_evsel_menu {
1797 struct ui_browser b;
1798 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001799 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001800 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001801 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001802};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001803
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001804static void perf_evsel_menu__write(struct ui_browser *browser,
1805 void *entry, int row)
1806{
1807 struct perf_evsel_menu *menu = container_of(browser,
1808 struct perf_evsel_menu, b);
1809 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1810 bool current_entry = ui_browser__is_current_entry(browser, row);
1811 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001812 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001813 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001814 const char *warn = " ";
1815 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001816
1817 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1818 HE_COLORSET_NORMAL);
1819
Namhyung Kim759ff492013-03-05 14:53:26 +09001820 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001821 struct perf_evsel *pos;
1822
1823 ev_name = perf_evsel__group_name(evsel);
1824
1825 for_each_group_member(pos, evsel) {
1826 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1827 }
1828 }
1829
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001830 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001831 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001832 unit, unit == ' ' ? "" : " ", ev_name);
1833 slsmg_printf("%s", bf);
1834
1835 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1836 if (nr_events != 0) {
1837 menu->lost_events = true;
1838 if (!current_entry)
1839 ui_browser__set_color(browser, HE_COLORSET_TOP);
1840 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001841 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1842 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001843 warn = bf;
1844 }
1845
1846 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001847
1848 if (current_entry)
1849 menu->selection = evsel;
1850}
1851
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001852static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1853 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001854 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001855{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001856 struct perf_evlist *evlist = menu->b.priv;
1857 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001858 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001859 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001860 int key;
1861
1862 if (ui_browser__show(&menu->b, title,
1863 "ESC: exit, ENTER|->: Browse histograms") < 0)
1864 return -1;
1865
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001866 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001867 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001868
1869 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001870 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001871 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001872
1873 if (!menu->lost_events_warned && menu->lost_events) {
1874 ui_browser__warn_lost_events(&menu->b);
1875 menu->lost_events_warned = true;
1876 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001877 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001878 case K_RIGHT:
1879 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001880 if (!menu->selection)
1881 continue;
1882 pos = menu->selection;
1883browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001884 perf_evlist__set_selected(evlist, pos);
1885 /*
1886 * Give the calling tool a chance to populate the non
1887 * default evsel resorted hists tree.
1888 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001889 if (hbt)
1890 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001891 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001892 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001893 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001894 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001895 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001896 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001897 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001898 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001899 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001900 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001901 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001902 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001903 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001904 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001905 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001906 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001907 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001908 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001909 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001910 if (!ui_browser__dialog_yesno(&menu->b,
1911 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001912 continue;
1913 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001914 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001915 case 'q':
1916 case CTRL('c'):
1917 goto out;
1918 default:
1919 continue;
1920 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001921 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001922 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001923 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001924 if (!ui_browser__dialog_yesno(&menu->b,
1925 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001926 continue;
1927 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001928 case 'q':
1929 case CTRL('c'):
1930 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001931 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001932 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001933 }
1934 }
1935
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001936out:
1937 ui_browser__hide(&menu->b);
1938 return key;
1939}
1940
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001941static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001942 void *entry)
1943{
1944 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1945
1946 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1947 return true;
1948
1949 return false;
1950}
1951
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001952static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001953 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001954 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001955 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001956 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001957{
1958 struct perf_evsel *pos;
1959 struct perf_evsel_menu menu = {
1960 .b = {
1961 .entries = &evlist->entries,
1962 .refresh = ui_browser__list_head_refresh,
1963 .seek = ui_browser__list_head_seek,
1964 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001965 .filter = filter_group_entries,
1966 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001967 .priv = evlist,
1968 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001969 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001970 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001971 };
1972
1973 ui_helpline__push("Press ESC to exit");
1974
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001975 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001976 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001977 size_t line_len = strlen(ev_name) + 7;
1978
1979 if (menu.b.width < line_len)
1980 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001981 }
1982
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001983 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001984}
1985
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001986int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001987 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001988 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001989 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001990{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001991 int nr_entries = evlist->nr_entries;
1992
1993single_entry:
1994 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001995 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001996
1997 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001998 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001999 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002000 }
2001
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002002 if (symbol_conf.event_group) {
2003 struct perf_evsel *pos;
2004
2005 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002006 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002007 if (perf_evsel__is_group_leader(pos))
2008 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002009 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002010
2011 if (nr_entries == 1)
2012 goto single_entry;
2013 }
2014
2015 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002016 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002017}