blob: 2be71bf17b7111f07c3f173d9dd565c351383902 [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;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020029 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090030 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090031 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090032 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030033};
34
Namhyung Kimf5951d52012-09-03 11:53:09 +090035extern void hist_browser__init_hpp(void);
36
Jiri Olsadd00d482014-06-19 13:41:13 +020037static int hists__browser_title(struct hists *hists, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090038static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030039
Namhyung Kimc3b78952014-04-22 15:56:17 +090040static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090041 float min_pcnt);
42
Namhyung Kim268397c2014-04-22 14:49:31 +090043static bool hist_browser__has_filter(struct hist_browser *hb)
44{
45 return hists__has_filter(hb->hists) || hb->min_pcnt;
46}
47
Namhyung Kimc3b78952014-04-22 15:56:17 +090048static u32 hist_browser__nr_entries(struct hist_browser *hb)
49{
50 u32 nr_entries;
51
52 if (hist_browser__has_filter(hb))
53 nr_entries = hb->nr_non_filtered_entries;
54 else
55 nr_entries = hb->hists->nr_entries;
56
57 return nr_entries + hb->nr_callchain_rows;
58}
59
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020060static void hist_browser__update_rows(struct hist_browser *hb)
61{
62 struct ui_browser *browser = &hb->b;
63 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
64
65 browser->rows = browser->height - header_offset;
66 /*
67 * Verify if we were at the last line and that line isn't
68 * visibe because we now show the header line(s).
69 */
70 index_row = browser->index - browser->top_idx;
71 if (index_row >= browser->rows)
72 browser->index -= index_row - browser->rows + 1;
73}
74
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030075static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030076{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030077 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
78
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030079 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030080 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
81 /*
82 * FIXME: Just keeping existing behaviour, but this really should be
83 * before updating browser->width, as it will invalidate the
84 * calculation above. Fix this and the fallout in another
85 * changeset.
86 */
87 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020088 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030089}
90
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030091static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
92{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020093 u16 header_offset = browser->show_headers ? 1 : 0;
94
95 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030096}
97
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030098static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030099{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900100 /*
101 * The hists__remove_entry_filter() already folds non-filtered
102 * entries so we can assume it has 0 callchain rows.
103 */
104 browser->nr_callchain_rows = 0;
105
Namhyung Kim268397c2014-04-22 14:49:31 +0900106 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900107 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300108 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300109 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300110}
111
112static char tree__folded_sign(bool unfolded)
113{
114 return unfolded ? '-' : '+';
115}
116
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300117static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300118{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300119 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300120}
121
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300122static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300123{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300124 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300125}
126
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300127static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300128{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300129 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300130}
131
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300133{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300134 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300135}
136
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300138{
139 int n = 0;
140 struct rb_node *nd;
141
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300142 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
144 struct callchain_list *chain;
145 char folded_sign = ' '; /* No children */
146
147 list_for_each_entry(chain, &child->val, list) {
148 ++n;
149 /* We need this because we may not have children */
150 folded_sign = callchain_list__folded(chain);
151 if (folded_sign == '+')
152 break;
153 }
154
155 if (folded_sign == '-') /* Have children and they're unfolded */
156 n += callchain_node__count_rows_rb_tree(child);
157 }
158
159 return n;
160}
161
162static int callchain_node__count_rows(struct callchain_node *node)
163{
164 struct callchain_list *chain;
165 bool unfolded = false;
166 int n = 0;
167
168 list_for_each_entry(chain, &node->val, list) {
169 ++n;
170 unfolded = chain->ms.unfolded;
171 }
172
173 if (unfolded)
174 n += callchain_node__count_rows_rb_tree(node);
175
176 return n;
177}
178
179static int callchain__count_rows(struct rb_root *chain)
180{
181 struct rb_node *nd;
182 int n = 0;
183
184 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
185 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
186 n += callchain_node__count_rows(node);
187 }
188
189 return n;
190}
191
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300192static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300193{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300194 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200195 return false;
196
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300197 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300198 return false;
199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300200 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300201 return true;
202}
203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300204static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300205{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300206 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300207
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300208 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300209 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
210 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300211 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300212
213 list_for_each_entry(chain, &child->val, list) {
214 if (first) {
215 first = false;
216 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300217 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300218 } else
219 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300220 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300221 }
222
223 callchain_node__init_have_children_rb_tree(child);
224 }
225}
226
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300227static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300228{
229 struct callchain_list *chain;
230
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300231 list_for_each_entry(chain, &node->val, list)
232 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300233
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300234 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300235}
236
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300237static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300238{
239 struct rb_node *nd;
240
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300241 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300242 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
243 callchain_node__init_have_children(node);
244 }
245}
246
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300247static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300248{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300249 if (!he->init_have_children) {
250 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
251 callchain__init_have_children(&he->sorted_chain);
252 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300253 }
254}
255
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300256static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300257{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300258 if (map_symbol__toggle_fold(browser->selection)) {
259 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300260
261 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900262 browser->b.nr_entries -= he->nr_rows;
263 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300264
265 if (he->ms.unfolded)
266 he->nr_rows = callchain__count_rows(&he->sorted_chain);
267 else
268 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900269
270 browser->b.nr_entries += he->nr_rows;
271 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300272
273 return true;
274 }
275
276 /* If it doesn't have children, no toggling performed */
277 return false;
278}
279
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300280static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300281{
282 int n = 0;
283 struct rb_node *nd;
284
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300285 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300286 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
287 struct callchain_list *chain;
288 bool has_children = false;
289
290 list_for_each_entry(chain, &child->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(child, unfold);
298 }
299
300 return n;
301}
302
303static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
304{
305 struct callchain_list *chain;
306 bool has_children = false;
307 int n = 0;
308
309 list_for_each_entry(chain, &node->val, list) {
310 ++n;
311 map_symbol__set_folding(&chain->ms, unfold);
312 has_children = chain->ms.has_children;
313 }
314
315 if (has_children)
316 n += callchain_node__set_folding_rb_tree(node, unfold);
317
318 return n;
319}
320
321static int callchain__set_folding(struct rb_root *chain, bool unfold)
322{
323 struct rb_node *nd;
324 int n = 0;
325
326 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
327 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
328 n += callchain_node__set_folding(node, unfold);
329 }
330
331 return n;
332}
333
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300334static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300335{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300336 hist_entry__init_have_children(he);
337 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300338
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300339 if (he->ms.has_children) {
340 int n = callchain__set_folding(&he->sorted_chain, unfold);
341 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300342 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300343 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300344}
345
Namhyung Kimc3b78952014-04-22 15:56:17 +0900346static void
347__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300348{
349 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900350 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300351
Namhyung Kimc3b78952014-04-22 15:56:17 +0900352 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900353 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900354 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300355 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
356 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900357 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300358 }
359}
360
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300361static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300362{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900363 browser->nr_callchain_rows = 0;
364 __hist_browser__set_folding(browser, unfold);
365
366 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300367 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300369}
370
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200371static void ui_browser__warn_lost_events(struct ui_browser *browser)
372{
373 ui_browser__warning(browser, 4,
374 "Events are being lost, check IO/CPU overload!\n\n"
375 "You may want to run 'perf' using a RT scheduler policy:\n\n"
376 " perf top -r 80\n\n"
377 "Or reduce the sampling frequency.");
378}
379
Jiri Olsadd00d482014-06-19 13:41:13 +0200380static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900381 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300382{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300383 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300384 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900385 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300386
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300387 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900388 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300389
Jiri Olsadd00d482014-06-19 13:41:13 +0200390 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300391
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300392 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300393 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394 return -1;
395
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300396 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300397 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300398
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300399 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900400 case K_TIMER: {
401 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900402 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900403
Namhyung Kimc3b78952014-04-22 15:56:17 +0900404 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900405 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900406
Namhyung Kimc3b78952014-04-22 15:56:17 +0900407 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900408 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200409
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300410 if (browser->hists->stats.nr_lost_warned !=
411 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
412 browser->hists->stats.nr_lost_warned =
413 browser->hists->stats.nr_events[PERF_RECORD_LOST];
414 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200415 }
416
Jiri Olsadd00d482014-06-19 13:41:13 +0200417 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300418 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300419 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900420 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300421 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300422 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300423 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300424 struct hist_entry, rb_node);
425 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300426 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 -0300427 seq++, browser->b.nr_entries,
428 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300429 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300430 browser->b.index,
431 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300432 h->row_offset, h->nr_rows);
433 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300434 break;
435 case 'C':
436 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300437 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300438 break;
439 case 'E':
440 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300441 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300442 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200443 case 'H':
444 browser->show_headers = !browser->show_headers;
445 hist_browser__update_rows(browser);
446 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200447 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300448 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300449 break;
450 /* fall thru */
451 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300452 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300453 }
454 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300455out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300456 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300457 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300458}
459
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300460static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300461 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300462{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300463 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300464
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300465 if (cl->ms.sym)
466 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
467 else
468 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
469
470 if (show_dso)
471 scnprintf(bf + printed, bfsize - printed, " %s",
472 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
473
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300474 return bf;
475}
476
477#define LEVEL_OFFSET_STEP 3
478
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300479static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300480 struct callchain_node *chain_node,
481 u64 total, int level,
482 unsigned short row,
483 off_t *row_offset,
484 bool *is_current_entry)
485{
486 struct rb_node *node;
487 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
488 u64 new_total, remaining;
489
490 if (callchain_param.mode == CHAIN_GRAPH_REL)
491 new_total = chain_node->children_hit;
492 else
493 new_total = total;
494
495 remaining = new_total;
496 node = rb_first(&chain_node->rb_root);
497 while (node) {
498 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
499 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100500 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300501 struct callchain_list *chain;
502 char folded_sign = ' ';
503 int first = true;
504 int extra_offset = 0;
505
506 remaining -= cumul;
507
508 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300509 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300510 const char *str;
511 int color;
512 bool was_first = first;
513
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300514 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300515 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300516 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300517 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300518
519 folded_sign = callchain_list__folded(chain);
520 if (*row_offset != 0) {
521 --*row_offset;
522 goto do_next;
523 }
524
525 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300526 str = callchain_list__sym_name(chain, bf, sizeof(bf),
527 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300528 if (was_first) {
529 double percent = cumul * 100.0 / new_total;
530
531 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
532 str = "Not enough memory!";
533 else
534 str = alloc_str;
535 }
536
537 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300538 width = browser->b.width - (offset + extra_offset + 2);
539 if (ui_browser__is_current_entry(&browser->b, row)) {
540 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300541 color = HE_COLORSET_SELECTED;
542 *is_current_entry = true;
543 }
544
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300545 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300546 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300547 slsmg_write_nstring(" ", offset + extra_offset);
548 slsmg_printf("%c ", folded_sign);
549 slsmg_write_nstring(str, width);
550 free(alloc_str);
551
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300552 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300553 goto out;
554do_next:
555 if (folded_sign == '+')
556 break;
557 }
558
559 if (folded_sign == '-') {
560 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300561 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300562 new_level, row, row_offset,
563 is_current_entry);
564 }
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300565 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300566 goto out;
567 node = next;
568 }
569out:
570 return row - first_row;
571}
572
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300573static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300574 struct callchain_node *node,
575 int level, unsigned short row,
576 off_t *row_offset,
577 bool *is_current_entry)
578{
579 struct callchain_list *chain;
580 int first_row = row,
581 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300582 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300583 char folded_sign = ' ';
584
585 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300586 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300587 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300588
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300589 folded_sign = callchain_list__folded(chain);
590
591 if (*row_offset != 0) {
592 --*row_offset;
593 continue;
594 }
595
596 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300597 if (ui_browser__is_current_entry(&browser->b, row)) {
598 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300599 color = HE_COLORSET_SELECTED;
600 *is_current_entry = true;
601 }
602
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300603 s = callchain_list__sym_name(chain, bf, sizeof(bf),
604 browser->show_dso);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300605 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300606 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607 slsmg_write_nstring(" ", offset);
608 slsmg_printf("%c ", folded_sign);
609 slsmg_write_nstring(s, width - 2);
610
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300611 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300612 goto out;
613 }
614
615 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300616 row += hist_browser__show_callchain_node_rb_tree(browser, node,
617 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300618 level + 1, row,
619 row_offset,
620 is_current_entry);
621out:
622 return row - first_row;
623}
624
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300625static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300626 struct rb_root *chain,
627 int level, unsigned short row,
628 off_t *row_offset,
629 bool *is_current_entry)
630{
631 struct rb_node *nd;
632 int first_row = row;
633
634 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
635 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
636
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300637 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300638 row, row_offset,
639 is_current_entry);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300640 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300641 break;
642 }
643
644 return row - first_row;
645}
646
Namhyung Kim89701462013-01-22 18:09:38 +0900647struct hpp_arg {
648 struct ui_browser *b;
649 char folded_sign;
650 bool current_entry;
651};
652
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900653static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
654{
655 struct hpp_arg *arg = hpp->ptr;
656 int ret;
657 va_list args;
658 double percent;
659
660 va_start(args, fmt);
661 percent = va_arg(args, double);
662 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900663
Namhyung Kim89701462013-01-22 18:09:38 +0900664 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900665
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900666 ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900667 slsmg_printf("%s", hpp->buf);
668
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900669 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900670 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900671}
672
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900673#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900674static u64 __hpp_get_##_field(struct hist_entry *he) \
675{ \
676 return he->stat._field; \
677} \
678 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100679static int \
680hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
681 struct perf_hpp *hpp, \
682 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900683{ \
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900684 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900685 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900686}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900687
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900688#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
689static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
690{ \
691 return he->stat_acc->_field; \
692} \
693 \
694static int \
695hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
696 struct perf_hpp *hpp, \
697 struct hist_entry *he) \
698{ \
699 if (!symbol_conf.cumulate_callchain) { \
700 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
701 slsmg_printf("%s", hpp->buf); \
702 \
703 return ret; \
704 } \
705 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \
706 __hpp__slsmg_color_printf, true); \
707}
708
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900709__HPP_COLOR_PERCENT_FN(overhead, period)
710__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
711__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
712__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
713__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900714__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900715
716#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900717#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900718
719void hist_browser__init_hpp(void)
720{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900721 perf_hpp__format[PERF_HPP__OVERHEAD].color =
722 hist_browser__hpp_color_overhead;
723 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
724 hist_browser__hpp_color_overhead_sys;
725 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
726 hist_browser__hpp_color_overhead_us;
727 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
728 hist_browser__hpp_color_overhead_guest_sys;
729 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
730 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900731 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
732 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900733}
734
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300735static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300736 struct hist_entry *entry,
737 unsigned short row)
738{
739 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200740 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900741 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300742 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300743 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300744 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300745 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200746 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300747
748 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300749 browser->he_selection = entry;
750 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300751 }
752
753 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300754 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300755 folded_sign = hist_entry__folded(entry);
756 }
757
758 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900759 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900760 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900761 .folded_sign = folded_sign,
762 .current_entry = current_entry,
763 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900764 struct perf_hpp hpp = {
765 .buf = s,
766 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900767 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900768 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300769
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300770 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900771
Jiri Olsa12400052012-10-13 00:06:16 +0200772 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900773 if (perf_hpp__should_skip(fmt))
774 continue;
775
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900776 if (current_entry && browser->b.navkeypressed) {
777 ui_browser__set_color(&browser->b,
778 HE_COLORSET_SELECTED);
779 } else {
780 ui_browser__set_color(&browser->b,
781 HE_COLORSET_NORMAL);
782 }
783
784 if (first) {
785 if (symbol_conf.use_callchain) {
786 slsmg_printf("%c ", folded_sign);
787 width -= 2;
788 }
789 first = false;
790 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900791 slsmg_printf(" ");
792 width -= 2;
793 }
794
Jiri Olsa12400052012-10-13 00:06:16 +0200795 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100796 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900797 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100798 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900799 slsmg_printf("%s", s);
800 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300801 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200802
803 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300804 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200805 width += 1;
806
Namhyung Kim26d8b332014-03-03 16:16:20 +0900807 slsmg_write_nstring("", width);
808
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300809 ++row;
810 ++printed;
811 } else
812 --row_offset;
813
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300814 if (folded_sign == '-' && row != browser->b.rows) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300815 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300816 1, row, &row_offset,
817 &current_entry);
818 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300819 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300820 }
821
822 return printed;
823}
824
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200825static void hist_browser__show_headers(struct hist_browser *browser)
826{
827 ui_browser__gotorc(&browser->b, 0, 0);
828 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
829 slsmg_write_nstring(" ", browser->b.width + 1);
830}
831
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300832static void ui_browser__hists_init_top(struct ui_browser *browser)
833{
834 if (browser->top == NULL) {
835 struct hist_browser *hb;
836
837 hb = container_of(browser, struct hist_browser, b);
838 browser->top = rb_first(&hb->hists->entries);
839 }
840}
841
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300842static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300843{
844 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200845 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300846 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300847 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300848
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200849 if (hb->show_headers) {
850 hist_browser__show_headers(hb);
851 header_offset = 1;
852 }
853
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300854 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300855
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300856 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300857 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900858 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300859
860 if (h->filtered)
861 continue;
862
Namhyung Kim14135662013-10-31 10:17:39 +0900863 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900864 if (percent < hb->min_pcnt)
865 continue;
866
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300867 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300868 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300869 break;
870 }
871
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200872 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300873}
874
Namhyung Kim064f1982013-05-14 11:09:04 +0900875static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900876 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300877{
878 while (nd != NULL) {
879 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900880 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900881
Namhyung Kimc0f15272014-04-16 11:16:33 +0900882 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300883 return nd;
884
885 nd = rb_next(nd);
886 }
887
888 return NULL;
889}
890
Namhyung Kim064f1982013-05-14 11:09:04 +0900891static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900892 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300893{
894 while (nd != NULL) {
895 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900896 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900897
898 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300899 return nd;
900
901 nd = rb_prev(nd);
902 }
903
904 return NULL;
905}
906
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300907static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300908 off_t offset, int whence)
909{
910 struct hist_entry *h;
911 struct rb_node *nd;
912 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900913 struct hist_browser *hb;
914
915 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300916
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300917 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300918 return;
919
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300920 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300921
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300922 switch (whence) {
923 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900924 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900925 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300926 break;
927 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300928 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300929 goto do_offset;
930 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900931 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900932 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300933 first = false;
934 break;
935 default:
936 return;
937 }
938
939 /*
940 * Moves not relative to the first visible entry invalidates its
941 * row_offset:
942 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300943 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300944 h->row_offset = 0;
945
946 /*
947 * Here we have to check if nd is expanded (+), if it is we can't go
948 * the next top level hist_entry, instead we must compute an offset of
949 * what _not_ to show and not change the first visible entry.
950 *
951 * This offset increments when we are going from top to bottom and
952 * decreases when we're going from bottom to top.
953 *
954 * As we don't have backpointers to the top level in the callchains
955 * structure, we need to always print the whole hist_entry callchain,
956 * skipping the first ones that are before the first visible entry
957 * and stop when we printed enough lines to fill the screen.
958 */
959do_offset:
960 if (offset > 0) {
961 do {
962 h = rb_entry(nd, struct hist_entry, rb_node);
963 if (h->ms.unfolded) {
964 u16 remaining = h->nr_rows - h->row_offset;
965 if (offset > remaining) {
966 offset -= remaining;
967 h->row_offset = 0;
968 } else {
969 h->row_offset += offset;
970 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300971 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300972 break;
973 }
974 }
Namhyung Kim14135662013-10-31 10:17:39 +0900975 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300976 if (nd == NULL)
977 break;
978 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300979 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300980 } while (offset != 0);
981 } else if (offset < 0) {
982 while (1) {
983 h = rb_entry(nd, struct hist_entry, rb_node);
984 if (h->ms.unfolded) {
985 if (first) {
986 if (-offset > h->row_offset) {
987 offset += h->row_offset;
988 h->row_offset = 0;
989 } else {
990 h->row_offset += offset;
991 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300992 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300993 break;
994 }
995 } else {
996 if (-offset > h->nr_rows) {
997 offset += h->nr_rows;
998 h->row_offset = 0;
999 } else {
1000 h->row_offset = h->nr_rows + offset;
1001 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001002 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001003 break;
1004 }
1005 }
1006 }
1007
Namhyung Kim14135662013-10-31 10:17:39 +09001008 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001009 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001010 if (nd == NULL)
1011 break;
1012 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001013 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001014 if (offset == 0) {
1015 /*
1016 * Last unfiltered hist_entry, check if it is
1017 * unfolded, if it is then we should have
1018 * row_offset at its last entry.
1019 */
1020 h = rb_entry(nd, struct hist_entry, rb_node);
1021 if (h->ms.unfolded)
1022 h->row_offset = h->nr_rows;
1023 break;
1024 }
1025 first = false;
1026 }
1027 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001028 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001029 h = rb_entry(nd, struct hist_entry, rb_node);
1030 h->row_offset = 0;
1031 }
1032}
1033
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001034static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
1035 struct callchain_node *chain_node,
1036 u64 total, int level,
1037 FILE *fp)
1038{
1039 struct rb_node *node;
1040 int offset = level * LEVEL_OFFSET_STEP;
1041 u64 new_total, remaining;
1042 int printed = 0;
1043
1044 if (callchain_param.mode == CHAIN_GRAPH_REL)
1045 new_total = chain_node->children_hit;
1046 else
1047 new_total = total;
1048
1049 remaining = new_total;
1050 node = rb_first(&chain_node->rb_root);
1051 while (node) {
1052 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1053 struct rb_node *next = rb_next(node);
1054 u64 cumul = callchain_cumul_hits(child);
1055 struct callchain_list *chain;
1056 char folded_sign = ' ';
1057 int first = true;
1058 int extra_offset = 0;
1059
1060 remaining -= cumul;
1061
1062 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001063 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001064 const char *str;
1065 bool was_first = first;
1066
1067 if (first)
1068 first = false;
1069 else
1070 extra_offset = LEVEL_OFFSET_STEP;
1071
1072 folded_sign = callchain_list__folded(chain);
1073
1074 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001075 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1076 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001077 if (was_first) {
1078 double percent = cumul * 100.0 / new_total;
1079
1080 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1081 str = "Not enough memory!";
1082 else
1083 str = alloc_str;
1084 }
1085
1086 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1087 free(alloc_str);
1088 if (folded_sign == '+')
1089 break;
1090 }
1091
1092 if (folded_sign == '-') {
1093 const int new_level = level + (extra_offset ? 2 : 1);
1094 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1095 new_level, fp);
1096 }
1097
1098 node = next;
1099 }
1100
1101 return printed;
1102}
1103
1104static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1105 struct callchain_node *node,
1106 int level, FILE *fp)
1107{
1108 struct callchain_list *chain;
1109 int offset = level * LEVEL_OFFSET_STEP;
1110 char folded_sign = ' ';
1111 int printed = 0;
1112
1113 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001114 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001115
1116 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001117 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001118 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1119 }
1120
1121 if (folded_sign == '-')
1122 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1123 browser->hists->stats.total_period,
1124 level + 1, fp);
1125 return printed;
1126}
1127
1128static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1129 struct rb_root *chain, int level, FILE *fp)
1130{
1131 struct rb_node *nd;
1132 int printed = 0;
1133
1134 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1135 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1136
1137 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1138 }
1139
1140 return printed;
1141}
1142
1143static int hist_browser__fprintf_entry(struct hist_browser *browser,
1144 struct hist_entry *he, FILE *fp)
1145{
1146 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001147 int printed = 0;
1148 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001149 struct perf_hpp hpp = {
1150 .buf = s,
1151 .size = sizeof(s),
1152 };
1153 struct perf_hpp_fmt *fmt;
1154 bool first = true;
1155 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001156
1157 if (symbol_conf.use_callchain)
1158 folded_sign = hist_entry__folded(he);
1159
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001160 if (symbol_conf.use_callchain)
1161 printed += fprintf(fp, "%c ", folded_sign);
1162
Namhyung Kim26d8b332014-03-03 16:16:20 +09001163 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001164 if (perf_hpp__should_skip(fmt))
1165 continue;
1166
Namhyung Kim26d8b332014-03-03 16:16:20 +09001167 if (!first) {
1168 ret = scnprintf(hpp.buf, hpp.size, " ");
1169 advance_hpp(&hpp, ret);
1170 } else
1171 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001172
Namhyung Kim26d8b332014-03-03 16:16:20 +09001173 ret = fmt->entry(fmt, &hpp, he);
1174 advance_hpp(&hpp, ret);
1175 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001176 printed += fprintf(fp, "%s\n", rtrim(s));
1177
1178 if (folded_sign == '-')
1179 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1180
1181 return printed;
1182}
1183
1184static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1185{
Namhyung Kim064f1982013-05-14 11:09:04 +09001186 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001187 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001188 int printed = 0;
1189
1190 while (nd) {
1191 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1192
1193 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001194 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001195 }
1196
1197 return printed;
1198}
1199
1200static int hist_browser__dump(struct hist_browser *browser)
1201{
1202 char filename[64];
1203 FILE *fp;
1204
1205 while (1) {
1206 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1207 if (access(filename, F_OK))
1208 break;
1209 /*
1210 * XXX: Just an arbitrary lazy upper limit
1211 */
1212 if (++browser->print_seq == 8192) {
1213 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1214 return -1;
1215 }
1216 }
1217
1218 fp = fopen(filename, "w");
1219 if (fp == NULL) {
1220 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001221 const char *err = strerror_r(errno, bf, sizeof(bf));
1222 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001223 return -1;
1224 }
1225
1226 ++browser->print_seq;
1227 hist_browser__fprintf(browser, fp);
1228 fclose(fp);
1229 ui_helpline__fpush("%s written!", filename);
1230
1231 return 0;
1232}
1233
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001234static struct hist_browser *hist_browser__new(struct hists *hists)
1235{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001236 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001237
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001238 if (browser) {
1239 browser->hists = hists;
1240 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001241 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001242 browser->b.seek = ui_browser__hists_seek;
1243 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001244 browser->show_headers = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001245 }
1246
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001247 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001248}
1249
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001250static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001251{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001252 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253}
1254
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001255static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001256{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001257 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001258}
1259
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001260static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001261{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001262 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001263}
1264
Jiri Olsadd00d482014-06-19 13:41:13 +02001265static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001266{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001267 char unit;
1268 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001269 const struct dso *dso = hists->dso_filter;
1270 const struct thread *thread = hists->thread_filter;
1271 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1272 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001273 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001274 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001275 char buf[512];
1276 size_t buflen = sizeof(buf);
1277
Namhyung Kimf2148332014-01-14 11:52:48 +09001278 if (symbol_conf.filter_relative) {
1279 nr_samples = hists->stats.nr_non_filtered_samples;
1280 nr_events = hists->stats.total_non_filtered_period;
1281 }
1282
Namhyung Kim759ff492013-03-05 14:53:26 +09001283 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001284 struct perf_evsel *pos;
1285
1286 perf_evsel__group_desc(evsel, buf, buflen);
1287 ev_name = buf;
1288
1289 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001290 if (symbol_conf.filter_relative) {
1291 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1292 nr_events += pos->hists.stats.total_non_filtered_period;
1293 } else {
1294 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1295 nr_events += pos->hists.stats.total_period;
1296 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001297 }
1298 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001299
Ashay Ranecc6862802012-04-05 21:01:01 -05001300 nr_samples = convert_unit(nr_samples, &unit);
1301 printed = scnprintf(bf, size,
1302 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1303 nr_samples, unit, ev_name, nr_events);
1304
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001305
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001306 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001307 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001308 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001309 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001310 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001311 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001312 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001313 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001314 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001315 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001316 ", DSO: %s", dso->short_name);
1317 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001318}
1319
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001320static inline void free_popup_options(char **options, int n)
1321{
1322 int i;
1323
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001324 for (i = 0; i < n; ++i)
1325 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001326}
1327
Feng Tangc77d8d72012-11-01 00:00:55 +08001328/* Check whether the browser is for 'top' or 'report' */
1329static inline bool is_report_browser(void *timer)
1330{
1331 return timer == NULL;
1332}
1333
Feng Tang341487ab2013-02-03 14:38:20 +08001334/*
1335 * Only runtime switching of perf data file will make "input_name" point
1336 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1337 * whether we need to call free() for current "input_name" during the switch.
1338 */
1339static bool is_input_name_malloced = false;
1340
1341static int switch_data_file(void)
1342{
1343 char *pwd, *options[32], *abs_path[32], *tmp;
1344 DIR *pwd_dir;
1345 int nr_options = 0, choice = -1, ret = -1;
1346 struct dirent *dent;
1347
1348 pwd = getenv("PWD");
1349 if (!pwd)
1350 return ret;
1351
1352 pwd_dir = opendir(pwd);
1353 if (!pwd_dir)
1354 return ret;
1355
1356 memset(options, 0, sizeof(options));
1357 memset(options, 0, sizeof(abs_path));
1358
1359 while ((dent = readdir(pwd_dir))) {
1360 char path[PATH_MAX];
1361 u64 magic;
1362 char *name = dent->d_name;
1363 FILE *file;
1364
1365 if (!(dent->d_type == DT_REG))
1366 continue;
1367
1368 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1369
1370 file = fopen(path, "r");
1371 if (!file)
1372 continue;
1373
1374 if (fread(&magic, 1, 8, file) < 8)
1375 goto close_file_and_continue;
1376
1377 if (is_perf_magic(magic)) {
1378 options[nr_options] = strdup(name);
1379 if (!options[nr_options])
1380 goto close_file_and_continue;
1381
1382 abs_path[nr_options] = strdup(path);
1383 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001384 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001385 ui__warning("Can't search all data files due to memory shortage.\n");
1386 fclose(file);
1387 break;
1388 }
1389
1390 nr_options++;
1391 }
1392
1393close_file_and_continue:
1394 fclose(file);
1395 if (nr_options >= 32) {
1396 ui__warning("Too many perf data files in PWD!\n"
1397 "Only the first 32 files will be listed.\n");
1398 break;
1399 }
1400 }
1401 closedir(pwd_dir);
1402
1403 if (nr_options) {
1404 choice = ui__popup_menu(nr_options, options);
1405 if (choice < nr_options && choice >= 0) {
1406 tmp = strdup(abs_path[choice]);
1407 if (tmp) {
1408 if (is_input_name_malloced)
1409 free((void *)input_name);
1410 input_name = tmp;
1411 is_input_name_malloced = true;
1412 ret = 0;
1413 } else
1414 ui__warning("Data switch failed due to memory shortage!\n");
1415 }
1416 }
1417
1418 free_popup_options(options, nr_options);
1419 free_popup_options(abs_path, nr_options);
1420 return ret;
1421}
1422
Namhyung Kim112f7612014-04-22 14:05:35 +09001423static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001424{
1425 u64 nr_entries = 0;
1426 struct rb_node *nd = rb_first(&hb->hists->entries);
1427
Namhyung Kim268397c2014-04-22 14:49:31 +09001428 if (hb->min_pcnt == 0) {
1429 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1430 return;
1431 }
1432
Namhyung Kim14135662013-10-31 10:17:39 +09001433 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001434 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001435 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001436 }
1437
Namhyung Kim112f7612014-04-22 14:05:35 +09001438 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001439}
Feng Tang341487ab2013-02-03 14:38:20 +08001440
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001441static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001442 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001443 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001444 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001445 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001446 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001447{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001448 struct hists *hists = &evsel->hists;
1449 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001450 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001451 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001452 char *options[16];
1453 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001454 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001455 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001456 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001457 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001458
Namhyung Kime8e684a2013-12-26 14:37:58 +09001459#define HIST_BROWSER_HELP_COMMON \
1460 "h/?/F1 Show this window\n" \
1461 "UP/DOWN/PGUP\n" \
1462 "PGDN/SPACE Navigate\n" \
1463 "q/ESC/CTRL+C Exit browser\n\n" \
1464 "For multiple event sessions:\n\n" \
1465 "TAB/UNTAB Switch events\n\n" \
1466 "For symbolic views (--sort has sym):\n\n" \
1467 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1468 "<- Zoom out\n" \
1469 "a Annotate current symbol\n" \
1470 "C Collapse all callchains\n" \
1471 "d Zoom into current DSO\n" \
1472 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001473 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001474 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001475
1476 /* help messages are sorted by lexical order of the hotkey */
1477 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001478 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001479 "P Print histograms to perf.hist.N\n"
1480 "r Run available scripts\n"
1481 "s Switch to another data file in PWD\n"
1482 "t Zoom into current Thread\n"
1483 "V Verbose (DSO names in callchains, etc)\n"
1484 "/ Filter symbol by name";
1485 const char top_help[] = HIST_BROWSER_HELP_COMMON
1486 "P Print histograms to perf.hist.N\n"
1487 "t Zoom into current Thread\n"
1488 "V Verbose (DSO names in callchains, etc)\n"
1489 "/ Filter symbol by name";
1490
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001491 if (browser == NULL)
1492 return -1;
1493
Namhyung Kim064f1982013-05-14 11:09:04 +09001494 if (min_pcnt) {
1495 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001496 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001497 }
1498
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001499 fstack = pstack__new(2);
1500 if (fstack == NULL)
1501 goto out;
1502
1503 ui_helpline__push(helpline);
1504
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001505 memset(options, 0, sizeof(options));
1506
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001507 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001508 const struct thread *thread = NULL;
1509 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001510 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001511 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001512 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001513 int scripts_comm = -2, scripts_symbol = -2,
1514 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001515
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001516 nr_options = 0;
1517
Jiri Olsadd00d482014-06-19 13:41:13 +02001518 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001519
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001520 if (browser->he_selection != NULL) {
1521 thread = hist_browser__selected_thread(browser);
1522 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1523 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001524 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001525 case K_TAB:
1526 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001527 if (nr_events == 1)
1528 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001529 /*
1530 * Exit the browser, let hists__browser_tree
1531 * go to the next or previous
1532 */
1533 goto out_free_stack;
1534 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001535 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001536 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001537 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001538 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001539 continue;
1540 }
1541
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001542 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001543 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001544 browser->selection->map->dso->annotate_warned)
1545 continue;
1546 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001547 case 'P':
1548 hist_browser__dump(browser);
1549 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001550 case 'd':
1551 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001552 case 'V':
1553 browser->show_dso = !browser->show_dso;
1554 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001555 case 't':
1556 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001557 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001558 if (ui_browser__input_window("Symbol to show",
1559 "Please enter the name of symbol you want to see",
1560 buf, "ENTER: OK, ESC: Cancel",
1561 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001562 hists->symbol_filter_str = *buf ? buf : NULL;
1563 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001564 hist_browser__reset(browser);
1565 }
1566 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001567 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001568 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001569 goto do_scripts;
1570 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001571 case 's':
1572 if (is_report_browser(hbt))
1573 goto do_data_switch;
1574 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001575 case 'i':
1576 /* env->arch is NULL for live-mode (i.e. perf top) */
1577 if (env->arch)
1578 tui__header_window(env);
1579 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001580 case 'F':
1581 symbol_conf.filter_relative ^= 1;
1582 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001583 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001584 case 'h':
1585 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001586 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001587 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001588 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001589 case K_ENTER:
1590 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001591 /* menu */
1592 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001593 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001594 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001595
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001596 if (pstack__empty(fstack)) {
1597 /*
1598 * Go back to the perf_evsel_menu__run or other user
1599 */
1600 if (left_exits)
1601 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001602 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001603 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001604 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001605 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001606 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001607 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001608 goto zoom_out_thread;
1609 continue;
1610 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001611 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001612 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001613 !ui_browser__dialog_yesno(&browser->b,
1614 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001615 continue;
1616 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001617 case 'q':
1618 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001619 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001620 default:
1621 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001622 }
1623
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001624 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001625 goto add_exit_option;
1626
Namhyung Kim55369fc2013-04-01 20:35:20 +09001627 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001628 bi = browser->he_selection->branch_info;
1629 if (browser->selection != NULL &&
1630 bi &&
1631 bi->from.sym != NULL &&
1632 !bi->from.map->dso->annotate_warned &&
1633 asprintf(&options[nr_options], "Annotate %s",
1634 bi->from.sym->name) > 0)
1635 annotate_f = nr_options++;
1636
1637 if (browser->selection != NULL &&
1638 bi &&
1639 bi->to.sym != NULL &&
1640 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001641 (bi->to.sym != bi->from.sym ||
1642 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001643 asprintf(&options[nr_options], "Annotate %s",
1644 bi->to.sym->name) > 0)
1645 annotate_t = nr_options++;
1646 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001647 if (browser->selection != NULL &&
1648 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001649 !browser->selection->map->dso->annotate_warned) {
1650 struct annotation *notes;
1651
1652 notes = symbol__annotation(browser->selection->sym);
1653
1654 if (notes->src &&
1655 asprintf(&options[nr_options], "Annotate %s",
1656 browser->selection->sym->name) > 0)
1657 annotate = nr_options++;
1658 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001659 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001660
1661 if (thread != NULL &&
1662 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001663 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001664 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001665 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001666 zoom_thread = nr_options++;
1667
1668 if (dso != NULL &&
1669 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001670 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001671 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1672 zoom_dso = nr_options++;
1673
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001674 if (browser->selection != NULL &&
1675 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001676 asprintf(&options[nr_options], "Browse map details") > 0)
1677 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001678
1679 /* perf script support */
1680 if (browser->he_selection) {
1681 struct symbol *sym;
1682
1683 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001684 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001685 scripts_comm = nr_options++;
1686
1687 sym = browser->he_selection->ms.sym;
1688 if (sym && sym->namelen &&
1689 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1690 sym->name) > 0)
1691 scripts_symbol = nr_options++;
1692 }
1693
1694 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1695 scripts_all = nr_options++;
1696
Feng Tang341487ab2013-02-03 14:38:20 +08001697 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1698 "Switch to another data file in PWD") > 0)
1699 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001700add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001701 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001702retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001703 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001704
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001705 if (choice == nr_options - 1)
1706 break;
1707
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001708 if (choice == -1) {
1709 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001710 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001711 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001712
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001713 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001714 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001715 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001716 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001717do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001718 if (!objdump_path && perf_session_env__lookup_objdump(env))
1719 continue;
1720
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001721 he = hist_browser__selected_entry(browser);
1722 if (he == NULL)
1723 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001724
1725 /*
1726 * we stash the branch_info symbol + map into the
1727 * the ms so we don't have to rewrite all the annotation
1728 * code to use branch_info.
1729 * in branch mode, the ms struct is not used
1730 */
1731 if (choice == annotate_f) {
1732 he->ms.sym = he->branch_info->from.sym;
1733 he->ms.map = he->branch_info->from.map;
1734 } else if (choice == annotate_t) {
1735 he->ms.sym = he->branch_info->to.sym;
1736 he->ms.map = he->branch_info->to.map;
1737 }
1738
Jiri Olsad7553302014-06-15 10:22:15 +02001739 notes = symbol__annotation(he->ms.sym);
1740 if (!notes->src)
1741 continue;
1742
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001743 /*
1744 * Don't let this be freed, say, by hists__decay_entry.
1745 */
1746 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001747 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001748 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001749 /*
1750 * offer option to annotate the other branch source or target
1751 * (if they exists) when returning from annotate
1752 */
1753 if ((err == 'q' || err == CTRL('c'))
1754 && annotate_t != -2 && annotate_f != -2)
1755 goto retry_popup_menu;
1756
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001757 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001758 if (err)
1759 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001760
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761 } else if (choice == browse_map)
1762 map__browse(browser->selection->map);
1763 else if (choice == zoom_dso) {
1764zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001765 if (browser->hists->dso_filter) {
1766 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001767zoom_out_dso:
1768 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001769 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001770 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001771 } else {
1772 if (dso == NULL)
1773 continue;
1774 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1775 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001776 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001777 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001778 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001779 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001780 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001781 hist_browser__reset(browser);
1782 } else if (choice == zoom_thread) {
1783zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001784 if (browser->hists->thread_filter) {
1785 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001786zoom_out_thread:
1787 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001788 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001789 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001790 } else {
1791 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001792 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001793 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001794 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001795 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001796 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001797 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001798 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001799 hist_browser__reset(browser);
1800 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001801 /* perf scripts support */
1802 else if (choice == scripts_all || choice == scripts_comm ||
1803 choice == scripts_symbol) {
1804do_scripts:
1805 memset(script_opt, 0, 64);
1806
1807 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001808 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001809
1810 if (choice == scripts_symbol)
1811 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1812
1813 script_browse(script_opt);
1814 }
Feng Tang341487ab2013-02-03 14:38:20 +08001815 /* Switch to another data file */
1816 else if (choice == switch_data) {
1817do_data_switch:
1818 if (!switch_data_file()) {
1819 key = K_SWITCH_INPUT_DATA;
1820 break;
1821 } else
1822 ui__warning("Won't switch the data files due to\n"
1823 "no valid data file get selected!\n");
1824 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001825 }
1826out_free_stack:
1827 pstack__delete(fstack);
1828out:
1829 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001830 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001831 return key;
1832}
1833
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001834struct perf_evsel_menu {
1835 struct ui_browser b;
1836 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001837 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001838 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001839 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001840};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001841
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001842static void perf_evsel_menu__write(struct ui_browser *browser,
1843 void *entry, int row)
1844{
1845 struct perf_evsel_menu *menu = container_of(browser,
1846 struct perf_evsel_menu, b);
1847 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1848 bool current_entry = ui_browser__is_current_entry(browser, row);
1849 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001850 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001851 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001852 const char *warn = " ";
1853 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001854
1855 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1856 HE_COLORSET_NORMAL);
1857
Namhyung Kim759ff492013-03-05 14:53:26 +09001858 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001859 struct perf_evsel *pos;
1860
1861 ev_name = perf_evsel__group_name(evsel);
1862
1863 for_each_group_member(pos, evsel) {
1864 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1865 }
1866 }
1867
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001868 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001869 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001870 unit, unit == ' ' ? "" : " ", ev_name);
1871 slsmg_printf("%s", bf);
1872
1873 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1874 if (nr_events != 0) {
1875 menu->lost_events = true;
1876 if (!current_entry)
1877 ui_browser__set_color(browser, HE_COLORSET_TOP);
1878 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001879 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1880 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001881 warn = bf;
1882 }
1883
1884 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001885
1886 if (current_entry)
1887 menu->selection = evsel;
1888}
1889
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001890static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1891 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001892 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001893{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001894 struct perf_evlist *evlist = menu->b.priv;
1895 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001896 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001897 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001898 int key;
1899
1900 if (ui_browser__show(&menu->b, title,
1901 "ESC: exit, ENTER|->: Browse histograms") < 0)
1902 return -1;
1903
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001904 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001905 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001906
1907 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001908 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001909 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001910
1911 if (!menu->lost_events_warned && menu->lost_events) {
1912 ui_browser__warn_lost_events(&menu->b);
1913 menu->lost_events_warned = true;
1914 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001915 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001916 case K_RIGHT:
1917 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001918 if (!menu->selection)
1919 continue;
1920 pos = menu->selection;
1921browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001922 perf_evlist__set_selected(evlist, pos);
1923 /*
1924 * Give the calling tool a chance to populate the non
1925 * default evsel resorted hists tree.
1926 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001927 if (hbt)
1928 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001929 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001930 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001931 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001932 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001933 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001934 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001935 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001936 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001937 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001938 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001939 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001940 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001941 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001942 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001943 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001944 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001945 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001946 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001947 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001948 if (!ui_browser__dialog_yesno(&menu->b,
1949 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001950 continue;
1951 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001952 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001953 case 'q':
1954 case CTRL('c'):
1955 goto out;
1956 default:
1957 continue;
1958 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001959 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001960 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001961 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001962 if (!ui_browser__dialog_yesno(&menu->b,
1963 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001964 continue;
1965 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001966 case 'q':
1967 case CTRL('c'):
1968 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001969 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001970 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001971 }
1972 }
1973
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001974out:
1975 ui_browser__hide(&menu->b);
1976 return key;
1977}
1978
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001979static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001980 void *entry)
1981{
1982 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1983
1984 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1985 return true;
1986
1987 return false;
1988}
1989
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001990static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001991 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001992 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001993 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001994 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001995{
1996 struct perf_evsel *pos;
1997 struct perf_evsel_menu menu = {
1998 .b = {
1999 .entries = &evlist->entries,
2000 .refresh = ui_browser__list_head_refresh,
2001 .seek = ui_browser__list_head_seek,
2002 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002003 .filter = filter_group_entries,
2004 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002005 .priv = evlist,
2006 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002007 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002008 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002009 };
2010
2011 ui_helpline__push("Press ESC to exit");
2012
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002013 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002014 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002015 size_t line_len = strlen(ev_name) + 7;
2016
2017 if (menu.b.width < line_len)
2018 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002019 }
2020
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002021 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002022}
2023
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002024int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002025 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002026 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002027 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002028{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002029 int nr_entries = evlist->nr_entries;
2030
2031single_entry:
2032 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002033 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002034
2035 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002036 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002037 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002038 }
2039
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002040 if (symbol_conf.event_group) {
2041 struct perf_evsel *pos;
2042
2043 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002044 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002045 if (perf_evsel__is_group_leader(pos))
2046 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002047 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002048
2049 if (nr_entries == 1)
2050 goto single_entry;
2051 }
2052
2053 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002054 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002055}