blob: 8d22905a468760ecd8b7ebb1c5095bfdfbc47afe [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 Kim42337a22014-08-12 17:16:06 +090013#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090014#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030015
16#include "../browser.h"
17#include "../helpline.h"
18#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020019#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030020#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020021#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030023struct hist_browser {
24 struct ui_browser b;
25 struct hists *hists;
26 struct hist_entry *he_selection;
27 struct map_symbol *selection;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030028 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030029 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020030 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090031 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090032 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090033 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030034};
35
Namhyung Kimf5951d52012-09-03 11:53:09 +090036extern void hist_browser__init_hpp(void);
37
Taeung Song1e378eb2014-10-07 16:13:15 +090038static int hists__browser_title(struct hists *hists,
39 struct hist_browser_timer *hbt,
40 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090041static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030042
Namhyung Kimc3b78952014-04-22 15:56:17 +090043static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090044 float min_pcnt);
45
Namhyung Kim268397c2014-04-22 14:49:31 +090046static bool hist_browser__has_filter(struct hist_browser *hb)
47{
48 return hists__has_filter(hb->hists) || hb->min_pcnt;
49}
50
Namhyung Kimc3b78952014-04-22 15:56:17 +090051static u32 hist_browser__nr_entries(struct hist_browser *hb)
52{
53 u32 nr_entries;
54
55 if (hist_browser__has_filter(hb))
56 nr_entries = hb->nr_non_filtered_entries;
57 else
58 nr_entries = hb->hists->nr_entries;
59
60 return nr_entries + hb->nr_callchain_rows;
61}
62
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020063static void hist_browser__update_rows(struct hist_browser *hb)
64{
65 struct ui_browser *browser = &hb->b;
66 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
67
68 browser->rows = browser->height - header_offset;
69 /*
70 * Verify if we were at the last line and that line isn't
71 * visibe because we now show the header line(s).
72 */
73 index_row = browser->index - browser->top_idx;
74 if (index_row >= browser->rows)
75 browser->index -= index_row - browser->rows + 1;
76}
77
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030078static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030079{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030080 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
81
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030082 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030083 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
84 /*
85 * FIXME: Just keeping existing behaviour, but this really should be
86 * before updating browser->width, as it will invalidate the
87 * calculation above. Fix this and the fallout in another
88 * changeset.
89 */
90 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020091 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030092}
93
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030094static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
95{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020096 u16 header_offset = browser->show_headers ? 1 : 0;
97
98 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030099}
100
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300101static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300102{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900103 /*
104 * The hists__remove_entry_filter() already folds non-filtered
105 * entries so we can assume it has 0 callchain rows.
106 */
107 browser->nr_callchain_rows = 0;
108
Namhyung Kim268397c2014-04-22 14:49:31 +0900109 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900110 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300111 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300112 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300113}
114
115static char tree__folded_sign(bool unfolded)
116{
117 return unfolded ? '-' : '+';
118}
119
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300120static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300121{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300122 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300123}
124
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300125static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300126{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300127 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300128}
129
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300130static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300131{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133}
134
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300135static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300136{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300138}
139
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300140static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300141{
142 int n = 0;
143 struct rb_node *nd;
144
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300145 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300146 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
147 struct callchain_list *chain;
148 char folded_sign = ' '; /* No children */
149
150 list_for_each_entry(chain, &child->val, list) {
151 ++n;
152 /* We need this because we may not have children */
153 folded_sign = callchain_list__folded(chain);
154 if (folded_sign == '+')
155 break;
156 }
157
158 if (folded_sign == '-') /* Have children and they're unfolded */
159 n += callchain_node__count_rows_rb_tree(child);
160 }
161
162 return n;
163}
164
165static int callchain_node__count_rows(struct callchain_node *node)
166{
167 struct callchain_list *chain;
168 bool unfolded = false;
169 int n = 0;
170
171 list_for_each_entry(chain, &node->val, list) {
172 ++n;
173 unfolded = chain->ms.unfolded;
174 }
175
176 if (unfolded)
177 n += callchain_node__count_rows_rb_tree(node);
178
179 return n;
180}
181
182static int callchain__count_rows(struct rb_root *chain)
183{
184 struct rb_node *nd;
185 int n = 0;
186
187 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
188 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
189 n += callchain_node__count_rows(node);
190 }
191
192 return n;
193}
194
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300195static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300196{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300197 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200198 return false;
199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300200 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300201 return false;
202
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300203 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300204 return true;
205}
206
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300207static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300208{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300209 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300210
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300211 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300212 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
213 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300214 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300215
216 list_for_each_entry(chain, &child->val, list) {
217 if (first) {
218 first = false;
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 } else
222 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300223 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300224 }
225
226 callchain_node__init_have_children_rb_tree(child);
227 }
228}
229
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300230static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300231{
232 struct callchain_list *chain;
233
Namhyung Kim82162b52014-08-13 15:02:41 +0900234 if (!list_empty(&node->val)) {
235 chain = list_entry(node->val.prev, struct callchain_list, list);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300236 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900237 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300238
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300239 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300240}
241
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300242static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300243{
244 struct rb_node *nd;
245
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300246 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300247 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
248 callchain_node__init_have_children(node);
249 }
250}
251
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300252static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300253{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300254 if (!he->init_have_children) {
255 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
256 callchain__init_have_children(&he->sorted_chain);
257 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300258 }
259}
260
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300261static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300262{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300263 if (map_symbol__toggle_fold(browser->selection)) {
264 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300265
266 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900267 browser->b.nr_entries -= he->nr_rows;
268 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300269
270 if (he->ms.unfolded)
271 he->nr_rows = callchain__count_rows(&he->sorted_chain);
272 else
273 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900274
275 browser->b.nr_entries += he->nr_rows;
276 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300277
278 return true;
279 }
280
281 /* If it doesn't have children, no toggling performed */
282 return false;
283}
284
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300285static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300286{
287 int n = 0;
288 struct rb_node *nd;
289
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300290 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300291 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
292 struct callchain_list *chain;
293 bool has_children = false;
294
295 list_for_each_entry(chain, &child->val, list) {
296 ++n;
297 map_symbol__set_folding(&chain->ms, unfold);
298 has_children = chain->ms.has_children;
299 }
300
301 if (has_children)
302 n += callchain_node__set_folding_rb_tree(child, unfold);
303 }
304
305 return n;
306}
307
308static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
309{
310 struct callchain_list *chain;
311 bool has_children = false;
312 int n = 0;
313
314 list_for_each_entry(chain, &node->val, list) {
315 ++n;
316 map_symbol__set_folding(&chain->ms, unfold);
317 has_children = chain->ms.has_children;
318 }
319
320 if (has_children)
321 n += callchain_node__set_folding_rb_tree(node, unfold);
322
323 return n;
324}
325
326static int callchain__set_folding(struct rb_root *chain, bool unfold)
327{
328 struct rb_node *nd;
329 int n = 0;
330
331 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
332 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
333 n += callchain_node__set_folding(node, unfold);
334 }
335
336 return n;
337}
338
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300339static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300340{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300341 hist_entry__init_have_children(he);
342 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300343
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300344 if (he->ms.has_children) {
345 int n = callchain__set_folding(&he->sorted_chain, unfold);
346 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300347 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300348 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300349}
350
Namhyung Kimc3b78952014-04-22 15:56:17 +0900351static void
352__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300353{
354 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900355 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300356
Namhyung Kimc3b78952014-04-22 15:56:17 +0900357 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900358 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900359 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300360 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
361 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900362 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300363 }
364}
365
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300367{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900368 browser->nr_callchain_rows = 0;
369 __hist_browser__set_folding(browser, unfold);
370
371 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300372 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300373 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300374}
375
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200376static void ui_browser__warn_lost_events(struct ui_browser *browser)
377{
378 ui_browser__warning(browser, 4,
379 "Events are being lost, check IO/CPU overload!\n\n"
380 "You may want to run 'perf' using a RT scheduler policy:\n\n"
381 " perf top -r 80\n\n"
382 "Or reduce the sampling frequency.");
383}
384
Jiri Olsadd00d482014-06-19 13:41:13 +0200385static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900386 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300387{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300388 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300389 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900390 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300391
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300392 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900393 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394
Taeung Song1e378eb2014-10-07 16:13:15 +0900395 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300396
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300397 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300398 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300399 return -1;
400
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300402 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300403
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300404 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900405 case K_TIMER: {
406 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900407 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900408
Namhyung Kimc3b78952014-04-22 15:56:17 +0900409 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900410 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900411
Namhyung Kimc3b78952014-04-22 15:56:17 +0900412 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900413 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200414
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300415 if (browser->hists->stats.nr_lost_warned !=
416 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
417 browser->hists->stats.nr_lost_warned =
418 browser->hists->stats.nr_events[PERF_RECORD_LOST];
419 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200420 }
421
Taeung Song1e378eb2014-10-07 16:13:15 +0900422 hists__browser_title(browser->hists,
423 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300424 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300425 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900426 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300427 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300429 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300430 struct hist_entry, rb_node);
431 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300432 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 -0300433 seq++, browser->b.nr_entries,
434 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300435 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300436 browser->b.index,
437 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300438 h->row_offset, h->nr_rows);
439 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300440 break;
441 case 'C':
442 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300443 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300444 break;
445 case 'E':
446 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300447 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300448 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200449 case 'H':
450 browser->show_headers = !browser->show_headers;
451 hist_browser__update_rows(browser);
452 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200453 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300454 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300455 break;
456 /* fall thru */
457 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300458 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300459 }
460 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300461out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300462 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300463 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300464}
465
Namhyung Kim39ee5332014-08-22 09:13:21 +0900466struct callchain_print_arg {
467 /* for hists browser */
468 off_t row_offset;
469 bool is_current_entry;
470
471 /* for file dump */
472 FILE *fp;
473 int printed;
474};
475
476typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
477 struct callchain_list *chain,
478 const char *str, int offset,
479 unsigned short row,
480 struct callchain_print_arg *arg);
481
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900482static void hist_browser__show_callchain_entry(struct hist_browser *browser,
483 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900484 const char *str, int offset,
485 unsigned short row,
486 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900487{
488 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900489 char folded_sign = callchain_list__folded(chain);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900490
491 color = HE_COLORSET_NORMAL;
492 width = browser->b.width - (offset + 2);
493 if (ui_browser__is_current_entry(&browser->b, row)) {
494 browser->selection = &chain->ms;
495 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900496 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900497 }
498
499 ui_browser__set_color(&browser->b, color);
500 hist_browser__gotorc(browser, row, 0);
501 slsmg_write_nstring(" ", offset);
502 slsmg_printf("%c ", folded_sign);
503 slsmg_write_nstring(str, width);
504}
505
Namhyung Kim39ee5332014-08-22 09:13:21 +0900506static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
507 struct callchain_list *chain,
508 const char *str, int offset,
509 unsigned short row __maybe_unused,
510 struct callchain_print_arg *arg)
511{
512 char folded_sign = callchain_list__folded(chain);
513
514 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
515 folded_sign, str);
516}
517
518typedef bool (*check_output_full_fn)(struct hist_browser *browser,
519 unsigned short row);
520
521static bool hist_browser__check_output_full(struct hist_browser *browser,
522 unsigned short row)
523{
524 return browser->b.rows == row;
525}
526
527static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
528 unsigned short row __maybe_unused)
529{
530 return false;
531}
532
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300533#define LEVEL_OFFSET_STEP 3
534
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900535static int hist_browser__show_callchain(struct hist_browser *browser,
536 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900537 unsigned short row, u64 total,
538 print_callchain_entry_fn print,
539 struct callchain_print_arg *arg,
540 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300541{
542 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900543 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900544 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900545 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300546
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900547 node = rb_first(root);
Namhyung Kim4087d112014-11-24 17:13:26 +0900548 need_percent = !!rb_next(node);
549
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300550 while (node) {
551 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
552 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100553 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300554 struct callchain_list *chain;
555 char folded_sign = ' ';
556 int first = true;
557 int extra_offset = 0;
558
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300559 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300560 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300561 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300562 bool was_first = first;
563
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300564 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300565 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900566 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300567 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300568
569 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900570 if (arg->row_offset != 0) {
571 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300572 goto do_next;
573 }
574
575 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300576 str = callchain_list__sym_name(chain, bf, sizeof(bf),
577 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900578
Namhyung Kim4087d112014-11-24 17:13:26 +0900579 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900580 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300581
582 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
583 str = "Not enough memory!";
584 else
585 str = alloc_str;
586 }
587
Namhyung Kim39ee5332014-08-22 09:13:21 +0900588 print(browser, chain, str, offset + extra_offset, row, arg);
589
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590 free(alloc_str);
591
Namhyung Kim39ee5332014-08-22 09:13:21 +0900592 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300593 goto out;
594do_next:
595 if (folded_sign == '+')
596 break;
597 }
598
599 if (folded_sign == '-') {
600 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900601
602 if (callchain_param.mode == CHAIN_GRAPH_REL)
603 new_total = child->children_hit;
604 else
605 new_total = total;
606
607 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900608 new_level, row, new_total,
609 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300610 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900611 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900612 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300613 node = next;
614 }
615out:
616 return row - first_row;
617}
618
Namhyung Kim89701462013-01-22 18:09:38 +0900619struct hpp_arg {
620 struct ui_browser *b;
621 char folded_sign;
622 bool current_entry;
623};
624
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900625static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
626{
627 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900628 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900629 va_list args;
630 double percent;
631
632 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900633 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900634 percent = va_arg(args, double);
635 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900636
Namhyung Kim89701462013-01-22 18:09:38 +0900637 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900638
Namhyung Kimd6751072014-07-31 14:47:36 +0900639 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900640 slsmg_printf("%s", hpp->buf);
641
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900642 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900643 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900644}
645
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900646#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900647static u64 __hpp_get_##_field(struct hist_entry *he) \
648{ \
649 return he->stat._field; \
650} \
651 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100652static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900653hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100654 struct perf_hpp *hpp, \
655 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900656{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900657 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
658 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900659}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900660
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900661#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
662static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
663{ \
664 return he->stat_acc->_field; \
665} \
666 \
667static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900668hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900669 struct perf_hpp *hpp, \
670 struct hist_entry *he) \
671{ \
672 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900673 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900674 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900675 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900676 slsmg_printf("%s", hpp->buf); \
677 \
678 return ret; \
679 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900680 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
681 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900682}
683
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900684__HPP_COLOR_PERCENT_FN(overhead, period)
685__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
686__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
687__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
688__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900689__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900690
691#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900692#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900693
694void hist_browser__init_hpp(void)
695{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900696 perf_hpp__format[PERF_HPP__OVERHEAD].color =
697 hist_browser__hpp_color_overhead;
698 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
699 hist_browser__hpp_color_overhead_sys;
700 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
701 hist_browser__hpp_color_overhead_us;
702 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
703 hist_browser__hpp_color_overhead_guest_sys;
704 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
705 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900706 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
707 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900708}
709
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300710static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300711 struct hist_entry *entry,
712 unsigned short row)
713{
714 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200715 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900716 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300717 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300718 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300719 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300720 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200721 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300722
723 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300724 browser->he_selection = entry;
725 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300726 }
727
728 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300729 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300730 folded_sign = hist_entry__folded(entry);
731 }
732
733 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900734 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900735 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900736 .folded_sign = folded_sign,
737 .current_entry = current_entry,
738 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900739 struct perf_hpp hpp = {
740 .buf = s,
741 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900742 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900743 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300744
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300745 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900746
Jiri Olsa12400052012-10-13 00:06:16 +0200747 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900748 if (perf_hpp__should_skip(fmt))
749 continue;
750
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900751 if (current_entry && browser->b.navkeypressed) {
752 ui_browser__set_color(&browser->b,
753 HE_COLORSET_SELECTED);
754 } else {
755 ui_browser__set_color(&browser->b,
756 HE_COLORSET_NORMAL);
757 }
758
759 if (first) {
760 if (symbol_conf.use_callchain) {
761 slsmg_printf("%c ", folded_sign);
762 width -= 2;
763 }
764 first = false;
765 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900766 slsmg_printf(" ");
767 width -= 2;
768 }
769
Jiri Olsa12400052012-10-13 00:06:16 +0200770 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100771 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900772 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100773 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900774 slsmg_printf("%s", s);
775 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300776 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200777
778 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300779 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200780 width += 1;
781
Namhyung Kim26d8b332014-03-03 16:16:20 +0900782 slsmg_write_nstring("", width);
783
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300784 ++row;
785 ++printed;
786 } else
787 --row_offset;
788
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300789 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900790 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900791 struct callchain_print_arg arg = {
792 .row_offset = row_offset,
793 .is_current_entry = current_entry,
794 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900795
Namhyung Kim4087d112014-11-24 17:13:26 +0900796 if (callchain_param.mode == CHAIN_GRAPH_REL) {
797 if (symbol_conf.cumulate_callchain)
798 total = entry->stat_acc->period;
799 else
800 total = entry->stat.period;
801 }
802
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900803 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900804 &entry->sorted_chain, 1, row, total,
805 hist_browser__show_callchain_entry, &arg,
806 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900807
Namhyung Kim39ee5332014-08-22 09:13:21 +0900808 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300809 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300810 }
811
812 return printed;
813}
814
Jiri Olsa81a888f2014-06-14 15:44:52 +0200815static int advance_hpp_check(struct perf_hpp *hpp, int inc)
816{
817 advance_hpp(hpp, inc);
818 return hpp->size <= 0;
819}
820
821static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
822{
823 struct perf_hpp dummy_hpp = {
824 .buf = buf,
825 .size = size,
826 };
827 struct perf_hpp_fmt *fmt;
828 size_t ret = 0;
829
830 if (symbol_conf.use_callchain) {
831 ret = scnprintf(buf, size, " ");
832 if (advance_hpp_check(&dummy_hpp, ret))
833 return ret;
834 }
835
836 perf_hpp__for_each_format(fmt) {
837 if (perf_hpp__should_skip(fmt))
838 continue;
839
Jiri Olsa81a888f2014-06-14 15:44:52 +0200840 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
841 if (advance_hpp_check(&dummy_hpp, ret))
842 break;
843
844 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
845 if (advance_hpp_check(&dummy_hpp, ret))
846 break;
847 }
848
849 return ret;
850}
851
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200852static void hist_browser__show_headers(struct hist_browser *browser)
853{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200854 char headers[1024];
855
856 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200857 ui_browser__gotorc(&browser->b, 0, 0);
858 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200859 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200860}
861
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300862static void ui_browser__hists_init_top(struct ui_browser *browser)
863{
864 if (browser->top == NULL) {
865 struct hist_browser *hb;
866
867 hb = container_of(browser, struct hist_browser, b);
868 browser->top = rb_first(&hb->hists->entries);
869 }
870}
871
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300872static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300873{
874 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200875 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300876 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300877 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300878
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200879 if (hb->show_headers) {
880 hist_browser__show_headers(hb);
881 header_offset = 1;
882 }
883
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300884 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300885
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300886 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300887 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900888 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300889
890 if (h->filtered)
891 continue;
892
Namhyung Kim14135662013-10-31 10:17:39 +0900893 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900894 if (percent < hb->min_pcnt)
895 continue;
896
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300897 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300898 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300899 break;
900 }
901
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200902 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300903}
904
Namhyung Kim064f1982013-05-14 11:09:04 +0900905static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900906 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300907{
908 while (nd != NULL) {
909 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900910 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900911
Namhyung Kimc0f15272014-04-16 11:16:33 +0900912 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300913 return nd;
914
915 nd = rb_next(nd);
916 }
917
918 return NULL;
919}
920
Namhyung Kim064f1982013-05-14 11:09:04 +0900921static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900922 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300923{
924 while (nd != NULL) {
925 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900926 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900927
928 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300929 return nd;
930
931 nd = rb_prev(nd);
932 }
933
934 return NULL;
935}
936
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300937static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300938 off_t offset, int whence)
939{
940 struct hist_entry *h;
941 struct rb_node *nd;
942 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900943 struct hist_browser *hb;
944
945 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300946
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300947 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300948 return;
949
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300950 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300951
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300952 switch (whence) {
953 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900954 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900955 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300956 break;
957 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300958 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300959 goto do_offset;
960 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900961 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900962 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300963 first = false;
964 break;
965 default:
966 return;
967 }
968
969 /*
970 * Moves not relative to the first visible entry invalidates its
971 * row_offset:
972 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300973 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300974 h->row_offset = 0;
975
976 /*
977 * Here we have to check if nd is expanded (+), if it is we can't go
978 * the next top level hist_entry, instead we must compute an offset of
979 * what _not_ to show and not change the first visible entry.
980 *
981 * This offset increments when we are going from top to bottom and
982 * decreases when we're going from bottom to top.
983 *
984 * As we don't have backpointers to the top level in the callchains
985 * structure, we need to always print the whole hist_entry callchain,
986 * skipping the first ones that are before the first visible entry
987 * and stop when we printed enough lines to fill the screen.
988 */
989do_offset:
990 if (offset > 0) {
991 do {
992 h = rb_entry(nd, struct hist_entry, rb_node);
993 if (h->ms.unfolded) {
994 u16 remaining = h->nr_rows - h->row_offset;
995 if (offset > remaining) {
996 offset -= remaining;
997 h->row_offset = 0;
998 } else {
999 h->row_offset += offset;
1000 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001001 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001002 break;
1003 }
1004 }
Namhyung Kim14135662013-10-31 10:17:39 +09001005 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001006 if (nd == NULL)
1007 break;
1008 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001009 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001010 } while (offset != 0);
1011 } else if (offset < 0) {
1012 while (1) {
1013 h = rb_entry(nd, struct hist_entry, rb_node);
1014 if (h->ms.unfolded) {
1015 if (first) {
1016 if (-offset > h->row_offset) {
1017 offset += h->row_offset;
1018 h->row_offset = 0;
1019 } else {
1020 h->row_offset += offset;
1021 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001022 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001023 break;
1024 }
1025 } else {
1026 if (-offset > h->nr_rows) {
1027 offset += h->nr_rows;
1028 h->row_offset = 0;
1029 } else {
1030 h->row_offset = h->nr_rows + offset;
1031 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001032 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001033 break;
1034 }
1035 }
1036 }
1037
Namhyung Kim14135662013-10-31 10:17:39 +09001038 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001039 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001040 if (nd == NULL)
1041 break;
1042 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001043 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001044 if (offset == 0) {
1045 /*
1046 * Last unfiltered hist_entry, check if it is
1047 * unfolded, if it is then we should have
1048 * row_offset at its last entry.
1049 */
1050 h = rb_entry(nd, struct hist_entry, rb_node);
1051 if (h->ms.unfolded)
1052 h->row_offset = h->nr_rows;
1053 break;
1054 }
1055 first = false;
1056 }
1057 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001058 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001059 h = rb_entry(nd, struct hist_entry, rb_node);
1060 h->row_offset = 0;
1061 }
1062}
1063
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001064static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001065 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001066{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001067 u64 total = hists__total_period(he->hists);
1068 struct callchain_print_arg arg = {
1069 .fp = fp,
1070 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001071
Namhyung Kim39ee5332014-08-22 09:13:21 +09001072 if (symbol_conf.cumulate_callchain)
1073 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001074
Namhyung Kim39ee5332014-08-22 09:13:21 +09001075 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1076 hist_browser__fprintf_callchain_entry, &arg,
1077 hist_browser__check_dump_full);
1078 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001079}
1080
1081static int hist_browser__fprintf_entry(struct hist_browser *browser,
1082 struct hist_entry *he, FILE *fp)
1083{
1084 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001085 int printed = 0;
1086 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001087 struct perf_hpp hpp = {
1088 .buf = s,
1089 .size = sizeof(s),
1090 };
1091 struct perf_hpp_fmt *fmt;
1092 bool first = true;
1093 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001094
1095 if (symbol_conf.use_callchain)
1096 folded_sign = hist_entry__folded(he);
1097
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001098 if (symbol_conf.use_callchain)
1099 printed += fprintf(fp, "%c ", folded_sign);
1100
Namhyung Kim26d8b332014-03-03 16:16:20 +09001101 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001102 if (perf_hpp__should_skip(fmt))
1103 continue;
1104
Namhyung Kim26d8b332014-03-03 16:16:20 +09001105 if (!first) {
1106 ret = scnprintf(hpp.buf, hpp.size, " ");
1107 advance_hpp(&hpp, ret);
1108 } else
1109 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001110
Namhyung Kim26d8b332014-03-03 16:16:20 +09001111 ret = fmt->entry(fmt, &hpp, he);
1112 advance_hpp(&hpp, ret);
1113 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001114 printed += fprintf(fp, "%s\n", rtrim(s));
1115
1116 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001117 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001118
1119 return printed;
1120}
1121
1122static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1123{
Namhyung Kim064f1982013-05-14 11:09:04 +09001124 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001125 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001126 int printed = 0;
1127
1128 while (nd) {
1129 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1130
1131 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001132 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001133 }
1134
1135 return printed;
1136}
1137
1138static int hist_browser__dump(struct hist_browser *browser)
1139{
1140 char filename[64];
1141 FILE *fp;
1142
1143 while (1) {
1144 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1145 if (access(filename, F_OK))
1146 break;
1147 /*
1148 * XXX: Just an arbitrary lazy upper limit
1149 */
1150 if (++browser->print_seq == 8192) {
1151 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1152 return -1;
1153 }
1154 }
1155
1156 fp = fopen(filename, "w");
1157 if (fp == NULL) {
1158 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001159 const char *err = strerror_r(errno, bf, sizeof(bf));
1160 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001161 return -1;
1162 }
1163
1164 ++browser->print_seq;
1165 hist_browser__fprintf(browser, fp);
1166 fclose(fp);
1167 ui_helpline__fpush("%s written!", filename);
1168
1169 return 0;
1170}
1171
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001172static struct hist_browser *hist_browser__new(struct hists *hists)
1173{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001174 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001175
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001176 if (browser) {
1177 browser->hists = hists;
1178 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001179 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001180 browser->b.seek = ui_browser__hists_seek;
1181 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001182 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001183 }
1184
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001185 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001186}
1187
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001188static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001189{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001190 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001191}
1192
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001193static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001194{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001195 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196}
1197
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001198static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001200 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201}
1202
Taeung Song1e378eb2014-10-07 16:13:15 +09001203/* Check whether the browser is for 'top' or 'report' */
1204static inline bool is_report_browser(void *timer)
1205{
1206 return timer == NULL;
1207}
1208
1209static int hists__browser_title(struct hists *hists,
1210 struct hist_browser_timer *hbt,
1211 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001212{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001213 char unit;
1214 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001215 const struct dso *dso = hists->dso_filter;
1216 const struct thread *thread = hists->thread_filter;
1217 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1218 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001219 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001220 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001221 char buf[512];
1222 size_t buflen = sizeof(buf);
1223
Namhyung Kimf2148332014-01-14 11:52:48 +09001224 if (symbol_conf.filter_relative) {
1225 nr_samples = hists->stats.nr_non_filtered_samples;
1226 nr_events = hists->stats.total_non_filtered_period;
1227 }
1228
Namhyung Kim759ff492013-03-05 14:53:26 +09001229 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001230 struct perf_evsel *pos;
1231
1232 perf_evsel__group_desc(evsel, buf, buflen);
1233 ev_name = buf;
1234
1235 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001236 struct hists *pos_hists = evsel__hists(pos);
1237
Namhyung Kimf2148332014-01-14 11:52:48 +09001238 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001239 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1240 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001241 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001242 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1243 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001244 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001245 }
1246 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001247
Ashay Ranecc686282012-04-05 21:01:01 -05001248 nr_samples = convert_unit(nr_samples, &unit);
1249 printed = scnprintf(bf, size,
1250 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1251 nr_samples, unit, ev_name, nr_events);
1252
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001254 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001255 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001256 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001257 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001258 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001259 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001260 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001261 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001262 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001263 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001264 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001265 if (!is_report_browser(hbt)) {
1266 struct perf_top *top = hbt->arg;
1267
1268 if (top->zero)
1269 printed += scnprintf(bf + printed, size - printed, " [z]");
1270 }
1271
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001272 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001273}
1274
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001275static inline void free_popup_options(char **options, int n)
1276{
1277 int i;
1278
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001279 for (i = 0; i < n; ++i)
1280 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001281}
1282
Feng Tang341487ab2013-02-03 14:38:20 +08001283/*
1284 * Only runtime switching of perf data file will make "input_name" point
1285 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1286 * whether we need to call free() for current "input_name" during the switch.
1287 */
1288static bool is_input_name_malloced = false;
1289
1290static int switch_data_file(void)
1291{
1292 char *pwd, *options[32], *abs_path[32], *tmp;
1293 DIR *pwd_dir;
1294 int nr_options = 0, choice = -1, ret = -1;
1295 struct dirent *dent;
1296
1297 pwd = getenv("PWD");
1298 if (!pwd)
1299 return ret;
1300
1301 pwd_dir = opendir(pwd);
1302 if (!pwd_dir)
1303 return ret;
1304
1305 memset(options, 0, sizeof(options));
1306 memset(options, 0, sizeof(abs_path));
1307
1308 while ((dent = readdir(pwd_dir))) {
1309 char path[PATH_MAX];
1310 u64 magic;
1311 char *name = dent->d_name;
1312 FILE *file;
1313
1314 if (!(dent->d_type == DT_REG))
1315 continue;
1316
1317 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1318
1319 file = fopen(path, "r");
1320 if (!file)
1321 continue;
1322
1323 if (fread(&magic, 1, 8, file) < 8)
1324 goto close_file_and_continue;
1325
1326 if (is_perf_magic(magic)) {
1327 options[nr_options] = strdup(name);
1328 if (!options[nr_options])
1329 goto close_file_and_continue;
1330
1331 abs_path[nr_options] = strdup(path);
1332 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001333 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001334 ui__warning("Can't search all data files due to memory shortage.\n");
1335 fclose(file);
1336 break;
1337 }
1338
1339 nr_options++;
1340 }
1341
1342close_file_and_continue:
1343 fclose(file);
1344 if (nr_options >= 32) {
1345 ui__warning("Too many perf data files in PWD!\n"
1346 "Only the first 32 files will be listed.\n");
1347 break;
1348 }
1349 }
1350 closedir(pwd_dir);
1351
1352 if (nr_options) {
1353 choice = ui__popup_menu(nr_options, options);
1354 if (choice < nr_options && choice >= 0) {
1355 tmp = strdup(abs_path[choice]);
1356 if (tmp) {
1357 if (is_input_name_malloced)
1358 free((void *)input_name);
1359 input_name = tmp;
1360 is_input_name_malloced = true;
1361 ret = 0;
1362 } else
1363 ui__warning("Data switch failed due to memory shortage!\n");
1364 }
1365 }
1366
1367 free_popup_options(options, nr_options);
1368 free_popup_options(abs_path, nr_options);
1369 return ret;
1370}
1371
Namhyung Kim112f7612014-04-22 14:05:35 +09001372static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001373{
1374 u64 nr_entries = 0;
1375 struct rb_node *nd = rb_first(&hb->hists->entries);
1376
Namhyung Kim268397c2014-04-22 14:49:31 +09001377 if (hb->min_pcnt == 0) {
1378 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1379 return;
1380 }
1381
Namhyung Kim14135662013-10-31 10:17:39 +09001382 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001383 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001384 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001385 }
1386
Namhyung Kim112f7612014-04-22 14:05:35 +09001387 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001388}
Feng Tang341487ab2013-02-03 14:38:20 +08001389
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001390static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001391 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001392 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001393 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001394 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001395 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001396{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001397 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001398 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001399 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001400 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001401 char *options[16];
1402 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001403 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001404 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001405 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001406 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001407 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001408
Namhyung Kime8e684a2013-12-26 14:37:58 +09001409#define HIST_BROWSER_HELP_COMMON \
1410 "h/?/F1 Show this window\n" \
1411 "UP/DOWN/PGUP\n" \
1412 "PGDN/SPACE Navigate\n" \
1413 "q/ESC/CTRL+C Exit browser\n\n" \
1414 "For multiple event sessions:\n\n" \
1415 "TAB/UNTAB Switch events\n\n" \
1416 "For symbolic views (--sort has sym):\n\n" \
1417 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1418 "<- Zoom out\n" \
1419 "a Annotate current symbol\n" \
1420 "C Collapse all callchains\n" \
1421 "d Zoom into current DSO\n" \
1422 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001423 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001424 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001425
1426 /* help messages are sorted by lexical order of the hotkey */
1427 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001428 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001429 "P Print histograms to perf.hist.N\n"
1430 "r Run available scripts\n"
1431 "s Switch to another data file in PWD\n"
1432 "t Zoom into current Thread\n"
1433 "V Verbose (DSO names in callchains, etc)\n"
1434 "/ Filter symbol by name";
1435 const char top_help[] = HIST_BROWSER_HELP_COMMON
1436 "P Print histograms to perf.hist.N\n"
1437 "t Zoom into current Thread\n"
1438 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001439 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001440 "/ Filter symbol by name";
1441
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001442 if (browser == NULL)
1443 return -1;
1444
Namhyung Kim064f1982013-05-14 11:09:04 +09001445 if (min_pcnt) {
1446 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001447 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001448 }
1449
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001450 fstack = pstack__new(2);
1451 if (fstack == NULL)
1452 goto out;
1453
1454 ui_helpline__push(helpline);
1455
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001456 memset(options, 0, sizeof(options));
1457
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001458 perf_hpp__for_each_format(fmt)
1459 perf_hpp__reset_width(fmt, hists);
1460
Namhyung Kim5b591662014-07-31 14:47:38 +09001461 if (symbol_conf.col_width_list_str)
1462 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1463
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001464 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001465 const struct thread *thread = NULL;
1466 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001467 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001468 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001469 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001470 int scripts_comm = -2, scripts_symbol = -2,
1471 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001472
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001473 nr_options = 0;
1474
Jiri Olsadd00d482014-06-19 13:41:13 +02001475 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001476
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001477 if (browser->he_selection != NULL) {
1478 thread = hist_browser__selected_thread(browser);
1479 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1480 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001481 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001482 case K_TAB:
1483 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001484 if (nr_events == 1)
1485 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001486 /*
1487 * Exit the browser, let hists__browser_tree
1488 * go to the next or previous
1489 */
1490 goto out_free_stack;
1491 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001492 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001493 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001494 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001495 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001496 continue;
1497 }
1498
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001499 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001500 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001501 browser->selection->map->dso->annotate_warned)
1502 continue;
1503 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001504 case 'P':
1505 hist_browser__dump(browser);
1506 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001507 case 'd':
1508 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001509 case 'V':
1510 browser->show_dso = !browser->show_dso;
1511 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001512 case 't':
1513 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001514 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001515 if (ui_browser__input_window("Symbol to show",
1516 "Please enter the name of symbol you want to see",
1517 buf, "ENTER: OK, ESC: Cancel",
1518 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001519 hists->symbol_filter_str = *buf ? buf : NULL;
1520 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001521 hist_browser__reset(browser);
1522 }
1523 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001524 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001525 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001526 goto do_scripts;
1527 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001528 case 's':
1529 if (is_report_browser(hbt))
1530 goto do_data_switch;
1531 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001532 case 'i':
1533 /* env->arch is NULL for live-mode (i.e. perf top) */
1534 if (env->arch)
1535 tui__header_window(env);
1536 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001537 case 'F':
1538 symbol_conf.filter_relative ^= 1;
1539 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001540 case 'z':
1541 if (!is_report_browser(hbt)) {
1542 struct perf_top *top = hbt->arg;
1543
1544 top->zero = !top->zero;
1545 }
1546 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001547 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001548 case 'h':
1549 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001550 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001551 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001552 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001553 case K_ENTER:
1554 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001555 /* menu */
1556 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001557 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001558 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001559
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001560 if (pstack__empty(fstack)) {
1561 /*
1562 * Go back to the perf_evsel_menu__run or other user
1563 */
1564 if (left_exits)
1565 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001566 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001567 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001568 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001569 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001570 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001571 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001572 goto zoom_out_thread;
1573 continue;
1574 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001575 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001576 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001577 !ui_browser__dialog_yesno(&browser->b,
1578 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001579 continue;
1580 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001581 case 'q':
1582 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001583 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001584 default:
1585 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001586 }
1587
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001588 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001589 goto add_exit_option;
1590
Namhyung Kim55369fc2013-04-01 20:35:20 +09001591 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001592 bi = browser->he_selection->branch_info;
1593 if (browser->selection != NULL &&
1594 bi &&
1595 bi->from.sym != NULL &&
1596 !bi->from.map->dso->annotate_warned &&
1597 asprintf(&options[nr_options], "Annotate %s",
1598 bi->from.sym->name) > 0)
1599 annotate_f = nr_options++;
1600
1601 if (browser->selection != NULL &&
1602 bi &&
1603 bi->to.sym != NULL &&
1604 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001605 (bi->to.sym != bi->from.sym ||
1606 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001607 asprintf(&options[nr_options], "Annotate %s",
1608 bi->to.sym->name) > 0)
1609 annotate_t = nr_options++;
1610 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001611 if (browser->selection != NULL &&
1612 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001613 !browser->selection->map->dso->annotate_warned) {
1614 struct annotation *notes;
1615
1616 notes = symbol__annotation(browser->selection->sym);
1617
1618 if (notes->src &&
1619 asprintf(&options[nr_options], "Annotate %s",
1620 browser->selection->sym->name) > 0)
1621 annotate = nr_options++;
1622 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001623 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001624
1625 if (thread != NULL &&
1626 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001627 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001628 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001629 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001630 zoom_thread = nr_options++;
1631
1632 if (dso != NULL &&
1633 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001634 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001635 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1636 zoom_dso = nr_options++;
1637
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001638 if (browser->selection != NULL &&
1639 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001640 asprintf(&options[nr_options], "Browse map details") > 0)
1641 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001642
1643 /* perf script support */
1644 if (browser->he_selection) {
1645 struct symbol *sym;
1646
1647 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001648 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001649 scripts_comm = nr_options++;
1650
1651 sym = browser->he_selection->ms.sym;
1652 if (sym && sym->namelen &&
1653 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1654 sym->name) > 0)
1655 scripts_symbol = nr_options++;
1656 }
1657
1658 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1659 scripts_all = nr_options++;
1660
Feng Tang341487ab2013-02-03 14:38:20 +08001661 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1662 "Switch to another data file in PWD") > 0)
1663 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001664add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001665 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001666retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001667 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001668
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001669 if (choice == nr_options - 1)
1670 break;
1671
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001672 if (choice == -1) {
1673 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001674 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001675 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001676
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001677 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001678 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001679 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001680 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001681do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001682 if (!objdump_path && perf_session_env__lookup_objdump(env))
1683 continue;
1684
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001685 he = hist_browser__selected_entry(browser);
1686 if (he == NULL)
1687 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001688
1689 /*
1690 * we stash the branch_info symbol + map into the
1691 * the ms so we don't have to rewrite all the annotation
1692 * code to use branch_info.
1693 * in branch mode, the ms struct is not used
1694 */
1695 if (choice == annotate_f) {
1696 he->ms.sym = he->branch_info->from.sym;
1697 he->ms.map = he->branch_info->from.map;
1698 } else if (choice == annotate_t) {
1699 he->ms.sym = he->branch_info->to.sym;
1700 he->ms.map = he->branch_info->to.map;
1701 }
1702
Jiri Olsad7553302014-06-15 10:22:15 +02001703 notes = symbol__annotation(he->ms.sym);
1704 if (!notes->src)
1705 continue;
1706
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001707 /*
1708 * Don't let this be freed, say, by hists__decay_entry.
1709 */
1710 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001711 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001712 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001713 /*
1714 * offer option to annotate the other branch source or target
1715 * (if they exists) when returning from annotate
1716 */
1717 if ((err == 'q' || err == CTRL('c'))
1718 && annotate_t != -2 && annotate_f != -2)
1719 goto retry_popup_menu;
1720
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001721 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001722 if (err)
1723 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001724
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001725 } else if (choice == browse_map)
1726 map__browse(browser->selection->map);
1727 else if (choice == zoom_dso) {
1728zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001729 if (browser->hists->dso_filter) {
1730 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001731zoom_out_dso:
1732 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001733 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001734 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001735 } else {
1736 if (dso == NULL)
1737 continue;
1738 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1739 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001740 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001741 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001742 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001743 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001744 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001745 hist_browser__reset(browser);
1746 } else if (choice == zoom_thread) {
1747zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001748 if (browser->hists->thread_filter) {
1749 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001750zoom_out_thread:
1751 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001752 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001753 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001754 } else {
1755 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001756 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001757 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001758 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001759 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001760 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001762 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001763 hist_browser__reset(browser);
1764 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001765 /* perf scripts support */
1766 else if (choice == scripts_all || choice == scripts_comm ||
1767 choice == scripts_symbol) {
1768do_scripts:
1769 memset(script_opt, 0, 64);
1770
1771 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001772 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001773
1774 if (choice == scripts_symbol)
1775 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1776
1777 script_browse(script_opt);
1778 }
Feng Tang341487ab2013-02-03 14:38:20 +08001779 /* Switch to another data file */
1780 else if (choice == switch_data) {
1781do_data_switch:
1782 if (!switch_data_file()) {
1783 key = K_SWITCH_INPUT_DATA;
1784 break;
1785 } else
1786 ui__warning("Won't switch the data files due to\n"
1787 "no valid data file get selected!\n");
1788 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001789 }
1790out_free_stack:
1791 pstack__delete(fstack);
1792out:
1793 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001794 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001795 return key;
1796}
1797
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001798struct perf_evsel_menu {
1799 struct ui_browser b;
1800 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001801 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001802 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001803 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001804};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001805
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001806static void perf_evsel_menu__write(struct ui_browser *browser,
1807 void *entry, int row)
1808{
1809 struct perf_evsel_menu *menu = container_of(browser,
1810 struct perf_evsel_menu, b);
1811 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001812 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001813 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001814 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001815 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001816 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001817 const char *warn = " ";
1818 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001819
1820 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1821 HE_COLORSET_NORMAL);
1822
Namhyung Kim759ff492013-03-05 14:53:26 +09001823 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001824 struct perf_evsel *pos;
1825
1826 ev_name = perf_evsel__group_name(evsel);
1827
1828 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001829 struct hists *pos_hists = evsel__hists(pos);
1830 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001831 }
1832 }
1833
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001834 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001835 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001836 unit, unit == ' ' ? "" : " ", ev_name);
1837 slsmg_printf("%s", bf);
1838
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001839 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001840 if (nr_events != 0) {
1841 menu->lost_events = true;
1842 if (!current_entry)
1843 ui_browser__set_color(browser, HE_COLORSET_TOP);
1844 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001845 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1846 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001847 warn = bf;
1848 }
1849
1850 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001851
1852 if (current_entry)
1853 menu->selection = evsel;
1854}
1855
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001856static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1857 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001858 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001859{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001860 struct perf_evlist *evlist = menu->b.priv;
1861 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001862 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001863 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001864 int key;
1865
1866 if (ui_browser__show(&menu->b, title,
1867 "ESC: exit, ENTER|->: Browse histograms") < 0)
1868 return -1;
1869
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001870 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001871 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001872
1873 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001874 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001875 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001876
1877 if (!menu->lost_events_warned && menu->lost_events) {
1878 ui_browser__warn_lost_events(&menu->b);
1879 menu->lost_events_warned = true;
1880 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001881 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001882 case K_RIGHT:
1883 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001884 if (!menu->selection)
1885 continue;
1886 pos = menu->selection;
1887browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001888 perf_evlist__set_selected(evlist, pos);
1889 /*
1890 * Give the calling tool a chance to populate the non
1891 * default evsel resorted hists tree.
1892 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001893 if (hbt)
1894 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001895 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001896 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001897 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001898 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001899 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001900 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001901 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001902 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001903 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001904 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001905 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001906 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001907 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001908 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001909 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001910 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001911 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001912 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001913 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001914 if (!ui_browser__dialog_yesno(&menu->b,
1915 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001916 continue;
1917 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001918 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001919 case 'q':
1920 case CTRL('c'):
1921 goto out;
1922 default:
1923 continue;
1924 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001925 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001926 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001927 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001928 if (!ui_browser__dialog_yesno(&menu->b,
1929 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001930 continue;
1931 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001932 case 'q':
1933 case CTRL('c'):
1934 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001935 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001936 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001937 }
1938 }
1939
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001940out:
1941 ui_browser__hide(&menu->b);
1942 return key;
1943}
1944
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001945static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001946 void *entry)
1947{
1948 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1949
1950 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1951 return true;
1952
1953 return false;
1954}
1955
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001956static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001957 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001958 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001959 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001960 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001961{
1962 struct perf_evsel *pos;
1963 struct perf_evsel_menu menu = {
1964 .b = {
1965 .entries = &evlist->entries,
1966 .refresh = ui_browser__list_head_refresh,
1967 .seek = ui_browser__list_head_seek,
1968 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001969 .filter = filter_group_entries,
1970 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001971 .priv = evlist,
1972 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001973 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001974 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001975 };
1976
1977 ui_helpline__push("Press ESC to exit");
1978
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001979 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001980 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001981 size_t line_len = strlen(ev_name) + 7;
1982
1983 if (menu.b.width < line_len)
1984 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001985 }
1986
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001987 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001988}
1989
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001990int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001991 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001992 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001993 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001994{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001995 int nr_entries = evlist->nr_entries;
1996
1997single_entry:
1998 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001999 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002000
2001 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002002 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002003 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002004 }
2005
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002006 if (symbol_conf.event_group) {
2007 struct perf_evsel *pos;
2008
2009 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002010 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002011 if (perf_evsel__is_group_leader(pos))
2012 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002013 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002014
2015 if (nr_entries == 1)
2016 goto single_entry;
2017 }
2018
2019 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002020 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002021}