blob: cfb976b3de3a0a1593b96f33c2c4136acdccf6aa [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
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300466static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300467 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300468{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300469 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300470
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300471 if (cl->ms.sym)
472 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
473 else
474 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
475
476 if (show_dso)
477 scnprintf(bf + printed, bfsize - printed, " %s",
478 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
479
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300480 return bf;
481}
482
Namhyung Kim39ee5332014-08-22 09:13:21 +0900483struct callchain_print_arg {
484 /* for hists browser */
485 off_t row_offset;
486 bool is_current_entry;
487
488 /* for file dump */
489 FILE *fp;
490 int printed;
491};
492
493typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
494 struct callchain_list *chain,
495 const char *str, int offset,
496 unsigned short row,
497 struct callchain_print_arg *arg);
498
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900499static void hist_browser__show_callchain_entry(struct hist_browser *browser,
500 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900501 const char *str, int offset,
502 unsigned short row,
503 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900504{
505 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900506 char folded_sign = callchain_list__folded(chain);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900507
508 color = HE_COLORSET_NORMAL;
509 width = browser->b.width - (offset + 2);
510 if (ui_browser__is_current_entry(&browser->b, row)) {
511 browser->selection = &chain->ms;
512 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900513 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900514 }
515
516 ui_browser__set_color(&browser->b, color);
517 hist_browser__gotorc(browser, row, 0);
518 slsmg_write_nstring(" ", offset);
519 slsmg_printf("%c ", folded_sign);
520 slsmg_write_nstring(str, width);
521}
522
Namhyung Kim39ee5332014-08-22 09:13:21 +0900523static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
524 struct callchain_list *chain,
525 const char *str, int offset,
526 unsigned short row __maybe_unused,
527 struct callchain_print_arg *arg)
528{
529 char folded_sign = callchain_list__folded(chain);
530
531 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
532 folded_sign, str);
533}
534
535typedef bool (*check_output_full_fn)(struct hist_browser *browser,
536 unsigned short row);
537
538static bool hist_browser__check_output_full(struct hist_browser *browser,
539 unsigned short row)
540{
541 return browser->b.rows == row;
542}
543
544static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
545 unsigned short row __maybe_unused)
546{
547 return false;
548}
549
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300550#define LEVEL_OFFSET_STEP 3
551
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900552static int hist_browser__show_callchain(struct hist_browser *browser,
553 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900554 unsigned short row, u64 total,
555 print_callchain_entry_fn print,
556 struct callchain_print_arg *arg,
557 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300558{
559 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900560 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900561 u64 new_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300562
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900563 node = rb_first(root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300564 while (node) {
565 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
566 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100567 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300568 struct callchain_list *chain;
569 char folded_sign = ' ';
570 int first = true;
571 int extra_offset = 0;
572
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300573 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300574 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300575 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300576 bool was_first = first;
577
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300578 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300579 first = false;
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900580 else if (level > 1)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300581 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300582
583 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900584 if (arg->row_offset != 0) {
585 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300586 goto do_next;
587 }
588
589 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300590 str = callchain_list__sym_name(chain, bf, sizeof(bf),
591 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900592
593 if (was_first && level > 1) {
594 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300595
596 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
597 str = "Not enough memory!";
598 else
599 str = alloc_str;
600 }
601
Namhyung Kim39ee5332014-08-22 09:13:21 +0900602 print(browser, chain, str, offset + extra_offset, row, arg);
603
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300604 free(alloc_str);
605
Namhyung Kim39ee5332014-08-22 09:13:21 +0900606 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607 goto out;
608do_next:
609 if (folded_sign == '+')
610 break;
611 }
612
613 if (folded_sign == '-') {
614 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900615
616 if (callchain_param.mode == CHAIN_GRAPH_REL)
617 new_total = child->children_hit;
618 else
619 new_total = total;
620
621 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900622 new_level, row, new_total,
623 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300624 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900625 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900626 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300627 node = next;
628 }
629out:
630 return row - first_row;
631}
632
Namhyung Kim89701462013-01-22 18:09:38 +0900633struct hpp_arg {
634 struct ui_browser *b;
635 char folded_sign;
636 bool current_entry;
637};
638
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900639static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
640{
641 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900642 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900643 va_list args;
644 double percent;
645
646 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900647 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900648 percent = va_arg(args, double);
649 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900650
Namhyung Kim89701462013-01-22 18:09:38 +0900651 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900652
Namhyung Kimd6751072014-07-31 14:47:36 +0900653 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900654 slsmg_printf("%s", hpp->buf);
655
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900656 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900657 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900658}
659
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900660#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900661static u64 __hpp_get_##_field(struct hist_entry *he) \
662{ \
663 return he->stat._field; \
664} \
665 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100666static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900667hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100668 struct perf_hpp *hpp, \
669 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900670{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900671 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
672 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900673}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900674
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900675#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
676static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
677{ \
678 return he->stat_acc->_field; \
679} \
680 \
681static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900682hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900683 struct perf_hpp *hpp, \
684 struct hist_entry *he) \
685{ \
686 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900687 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900688 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900689 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900690 slsmg_printf("%s", hpp->buf); \
691 \
692 return ret; \
693 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900694 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
695 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900696}
697
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900698__HPP_COLOR_PERCENT_FN(overhead, period)
699__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
700__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
701__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
702__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900703__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900704
705#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900706#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900707
708void hist_browser__init_hpp(void)
709{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900710 perf_hpp__format[PERF_HPP__OVERHEAD].color =
711 hist_browser__hpp_color_overhead;
712 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
713 hist_browser__hpp_color_overhead_sys;
714 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
715 hist_browser__hpp_color_overhead_us;
716 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
717 hist_browser__hpp_color_overhead_guest_sys;
718 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
719 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900720 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
721 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900722}
723
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300724static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300725 struct hist_entry *entry,
726 unsigned short row)
727{
728 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200729 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900730 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300731 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300732 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300733 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300734 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200735 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300736
737 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300738 browser->he_selection = entry;
739 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300740 }
741
742 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300743 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300744 folded_sign = hist_entry__folded(entry);
745 }
746
747 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900748 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900749 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900750 .folded_sign = folded_sign,
751 .current_entry = current_entry,
752 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900753 struct perf_hpp hpp = {
754 .buf = s,
755 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900756 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900757 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300758
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300759 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900760
Jiri Olsa12400052012-10-13 00:06:16 +0200761 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900762 if (perf_hpp__should_skip(fmt))
763 continue;
764
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900765 if (current_entry && browser->b.navkeypressed) {
766 ui_browser__set_color(&browser->b,
767 HE_COLORSET_SELECTED);
768 } else {
769 ui_browser__set_color(&browser->b,
770 HE_COLORSET_NORMAL);
771 }
772
773 if (first) {
774 if (symbol_conf.use_callchain) {
775 slsmg_printf("%c ", folded_sign);
776 width -= 2;
777 }
778 first = false;
779 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900780 slsmg_printf(" ");
781 width -= 2;
782 }
783
Jiri Olsa12400052012-10-13 00:06:16 +0200784 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100785 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900786 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100787 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900788 slsmg_printf("%s", s);
789 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300790 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200791
792 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300793 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200794 width += 1;
795
Namhyung Kim26d8b332014-03-03 16:16:20 +0900796 slsmg_write_nstring("", width);
797
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300798 ++row;
799 ++printed;
800 } else
801 --row_offset;
802
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300803 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900804 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900805 struct callchain_print_arg arg = {
806 .row_offset = row_offset,
807 .is_current_entry = current_entry,
808 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900809
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900810 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900811 &entry->sorted_chain, 1, row, total,
812 hist_browser__show_callchain_entry, &arg,
813 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900814
Namhyung Kim39ee5332014-08-22 09:13:21 +0900815 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300816 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300817 }
818
819 return printed;
820}
821
Jiri Olsa81a888f2014-06-14 15:44:52 +0200822static int advance_hpp_check(struct perf_hpp *hpp, int inc)
823{
824 advance_hpp(hpp, inc);
825 return hpp->size <= 0;
826}
827
828static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
829{
830 struct perf_hpp dummy_hpp = {
831 .buf = buf,
832 .size = size,
833 };
834 struct perf_hpp_fmt *fmt;
835 size_t ret = 0;
836
837 if (symbol_conf.use_callchain) {
838 ret = scnprintf(buf, size, " ");
839 if (advance_hpp_check(&dummy_hpp, ret))
840 return ret;
841 }
842
843 perf_hpp__for_each_format(fmt) {
844 if (perf_hpp__should_skip(fmt))
845 continue;
846
Jiri Olsa81a888f2014-06-14 15:44:52 +0200847 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
848 if (advance_hpp_check(&dummy_hpp, ret))
849 break;
850
851 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
852 if (advance_hpp_check(&dummy_hpp, ret))
853 break;
854 }
855
856 return ret;
857}
858
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200859static void hist_browser__show_headers(struct hist_browser *browser)
860{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200861 char headers[1024];
862
863 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200864 ui_browser__gotorc(&browser->b, 0, 0);
865 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200866 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200867}
868
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300869static void ui_browser__hists_init_top(struct ui_browser *browser)
870{
871 if (browser->top == NULL) {
872 struct hist_browser *hb;
873
874 hb = container_of(browser, struct hist_browser, b);
875 browser->top = rb_first(&hb->hists->entries);
876 }
877}
878
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300879static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300880{
881 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200882 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300883 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300884 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300885
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200886 if (hb->show_headers) {
887 hist_browser__show_headers(hb);
888 header_offset = 1;
889 }
890
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300891 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300892
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300893 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300894 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900895 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300896
897 if (h->filtered)
898 continue;
899
Namhyung Kim14135662013-10-31 10:17:39 +0900900 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900901 if (percent < hb->min_pcnt)
902 continue;
903
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300905 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300906 break;
907 }
908
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200909 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300910}
911
Namhyung Kim064f1982013-05-14 11:09:04 +0900912static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900913 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300914{
915 while (nd != NULL) {
916 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900917 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900918
Namhyung Kimc0f15272014-04-16 11:16:33 +0900919 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300920 return nd;
921
922 nd = rb_next(nd);
923 }
924
925 return NULL;
926}
927
Namhyung Kim064f1982013-05-14 11:09:04 +0900928static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900929 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300930{
931 while (nd != NULL) {
932 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900933 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900934
935 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300936 return nd;
937
938 nd = rb_prev(nd);
939 }
940
941 return NULL;
942}
943
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300944static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300945 off_t offset, int whence)
946{
947 struct hist_entry *h;
948 struct rb_node *nd;
949 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900950 struct hist_browser *hb;
951
952 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300953
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300954 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300955 return;
956
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300957 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300958
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300959 switch (whence) {
960 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900961 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900962 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300963 break;
964 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300965 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300966 goto do_offset;
967 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900968 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900969 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300970 first = false;
971 break;
972 default:
973 return;
974 }
975
976 /*
977 * Moves not relative to the first visible entry invalidates its
978 * row_offset:
979 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300980 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300981 h->row_offset = 0;
982
983 /*
984 * Here we have to check if nd is expanded (+), if it is we can't go
985 * the next top level hist_entry, instead we must compute an offset of
986 * what _not_ to show and not change the first visible entry.
987 *
988 * This offset increments when we are going from top to bottom and
989 * decreases when we're going from bottom to top.
990 *
991 * As we don't have backpointers to the top level in the callchains
992 * structure, we need to always print the whole hist_entry callchain,
993 * skipping the first ones that are before the first visible entry
994 * and stop when we printed enough lines to fill the screen.
995 */
996do_offset:
997 if (offset > 0) {
998 do {
999 h = rb_entry(nd, struct hist_entry, rb_node);
1000 if (h->ms.unfolded) {
1001 u16 remaining = h->nr_rows - h->row_offset;
1002 if (offset > remaining) {
1003 offset -= remaining;
1004 h->row_offset = 0;
1005 } else {
1006 h->row_offset += offset;
1007 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001008 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001009 break;
1010 }
1011 }
Namhyung Kim14135662013-10-31 10:17:39 +09001012 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001013 if (nd == NULL)
1014 break;
1015 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001016 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001017 } while (offset != 0);
1018 } else if (offset < 0) {
1019 while (1) {
1020 h = rb_entry(nd, struct hist_entry, rb_node);
1021 if (h->ms.unfolded) {
1022 if (first) {
1023 if (-offset > h->row_offset) {
1024 offset += h->row_offset;
1025 h->row_offset = 0;
1026 } else {
1027 h->row_offset += offset;
1028 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001029 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001030 break;
1031 }
1032 } else {
1033 if (-offset > h->nr_rows) {
1034 offset += h->nr_rows;
1035 h->row_offset = 0;
1036 } else {
1037 h->row_offset = h->nr_rows + offset;
1038 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001039 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001040 break;
1041 }
1042 }
1043 }
1044
Namhyung Kim14135662013-10-31 10:17:39 +09001045 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001046 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001047 if (nd == NULL)
1048 break;
1049 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001050 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001051 if (offset == 0) {
1052 /*
1053 * Last unfiltered hist_entry, check if it is
1054 * unfolded, if it is then we should have
1055 * row_offset at its last entry.
1056 */
1057 h = rb_entry(nd, struct hist_entry, rb_node);
1058 if (h->ms.unfolded)
1059 h->row_offset = h->nr_rows;
1060 break;
1061 }
1062 first = false;
1063 }
1064 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001065 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001066 h = rb_entry(nd, struct hist_entry, rb_node);
1067 h->row_offset = 0;
1068 }
1069}
1070
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001071static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001072 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001073{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001074 u64 total = hists__total_period(he->hists);
1075 struct callchain_print_arg arg = {
1076 .fp = fp,
1077 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001078
Namhyung Kim39ee5332014-08-22 09:13:21 +09001079 if (symbol_conf.cumulate_callchain)
1080 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001081
Namhyung Kim39ee5332014-08-22 09:13:21 +09001082 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1083 hist_browser__fprintf_callchain_entry, &arg,
1084 hist_browser__check_dump_full);
1085 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001086}
1087
1088static int hist_browser__fprintf_entry(struct hist_browser *browser,
1089 struct hist_entry *he, FILE *fp)
1090{
1091 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001092 int printed = 0;
1093 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001094 struct perf_hpp hpp = {
1095 .buf = s,
1096 .size = sizeof(s),
1097 };
1098 struct perf_hpp_fmt *fmt;
1099 bool first = true;
1100 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001101
1102 if (symbol_conf.use_callchain)
1103 folded_sign = hist_entry__folded(he);
1104
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001105 if (symbol_conf.use_callchain)
1106 printed += fprintf(fp, "%c ", folded_sign);
1107
Namhyung Kim26d8b332014-03-03 16:16:20 +09001108 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001109 if (perf_hpp__should_skip(fmt))
1110 continue;
1111
Namhyung Kim26d8b332014-03-03 16:16:20 +09001112 if (!first) {
1113 ret = scnprintf(hpp.buf, hpp.size, " ");
1114 advance_hpp(&hpp, ret);
1115 } else
1116 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001117
Namhyung Kim26d8b332014-03-03 16:16:20 +09001118 ret = fmt->entry(fmt, &hpp, he);
1119 advance_hpp(&hpp, ret);
1120 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001121 printed += fprintf(fp, "%s\n", rtrim(s));
1122
1123 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001124 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001125
1126 return printed;
1127}
1128
1129static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1130{
Namhyung Kim064f1982013-05-14 11:09:04 +09001131 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001132 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001133 int printed = 0;
1134
1135 while (nd) {
1136 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1137
1138 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001139 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001140 }
1141
1142 return printed;
1143}
1144
1145static int hist_browser__dump(struct hist_browser *browser)
1146{
1147 char filename[64];
1148 FILE *fp;
1149
1150 while (1) {
1151 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1152 if (access(filename, F_OK))
1153 break;
1154 /*
1155 * XXX: Just an arbitrary lazy upper limit
1156 */
1157 if (++browser->print_seq == 8192) {
1158 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1159 return -1;
1160 }
1161 }
1162
1163 fp = fopen(filename, "w");
1164 if (fp == NULL) {
1165 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001166 const char *err = strerror_r(errno, bf, sizeof(bf));
1167 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001168 return -1;
1169 }
1170
1171 ++browser->print_seq;
1172 hist_browser__fprintf(browser, fp);
1173 fclose(fp);
1174 ui_helpline__fpush("%s written!", filename);
1175
1176 return 0;
1177}
1178
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001179static struct hist_browser *hist_browser__new(struct hists *hists)
1180{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001181 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001182
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001183 if (browser) {
1184 browser->hists = hists;
1185 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001186 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001187 browser->b.seek = ui_browser__hists_seek;
1188 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001189 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001190 }
1191
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001192 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001193}
1194
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001195static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001197 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198}
1199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001200static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001202 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001203}
1204
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001205static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001207 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001208}
1209
Taeung Song1e378eb2014-10-07 16:13:15 +09001210/* Check whether the browser is for 'top' or 'report' */
1211static inline bool is_report_browser(void *timer)
1212{
1213 return timer == NULL;
1214}
1215
1216static int hists__browser_title(struct hists *hists,
1217 struct hist_browser_timer *hbt,
1218 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001220 char unit;
1221 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001222 const struct dso *dso = hists->dso_filter;
1223 const struct thread *thread = hists->thread_filter;
1224 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1225 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001226 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001227 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001228 char buf[512];
1229 size_t buflen = sizeof(buf);
1230
Namhyung Kimf2148332014-01-14 11:52:48 +09001231 if (symbol_conf.filter_relative) {
1232 nr_samples = hists->stats.nr_non_filtered_samples;
1233 nr_events = hists->stats.total_non_filtered_period;
1234 }
1235
Namhyung Kim759ff492013-03-05 14:53:26 +09001236 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001237 struct perf_evsel *pos;
1238
1239 perf_evsel__group_desc(evsel, buf, buflen);
1240 ev_name = buf;
1241
1242 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001243 struct hists *pos_hists = evsel__hists(pos);
1244
Namhyung Kimf2148332014-01-14 11:52:48 +09001245 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001246 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1247 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001248 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001249 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1250 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001251 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001252 }
1253 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001254
Ashay Ranecc6862802012-04-05 21:01:01 -05001255 nr_samples = convert_unit(nr_samples, &unit);
1256 printed = scnprintf(bf, size,
1257 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1258 nr_samples, unit, ev_name, nr_events);
1259
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001260
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001261 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001262 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001263 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001264 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001265 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001266 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001267 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001268 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001269 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001270 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001271 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001272 if (!is_report_browser(hbt)) {
1273 struct perf_top *top = hbt->arg;
1274
1275 if (top->zero)
1276 printed += scnprintf(bf + printed, size - printed, " [z]");
1277 }
1278
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001279 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001280}
1281
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001282static inline void free_popup_options(char **options, int n)
1283{
1284 int i;
1285
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001286 for (i = 0; i < n; ++i)
1287 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001288}
1289
Feng Tang341487ab2013-02-03 14:38:20 +08001290/*
1291 * Only runtime switching of perf data file will make "input_name" point
1292 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1293 * whether we need to call free() for current "input_name" during the switch.
1294 */
1295static bool is_input_name_malloced = false;
1296
1297static int switch_data_file(void)
1298{
1299 char *pwd, *options[32], *abs_path[32], *tmp;
1300 DIR *pwd_dir;
1301 int nr_options = 0, choice = -1, ret = -1;
1302 struct dirent *dent;
1303
1304 pwd = getenv("PWD");
1305 if (!pwd)
1306 return ret;
1307
1308 pwd_dir = opendir(pwd);
1309 if (!pwd_dir)
1310 return ret;
1311
1312 memset(options, 0, sizeof(options));
1313 memset(options, 0, sizeof(abs_path));
1314
1315 while ((dent = readdir(pwd_dir))) {
1316 char path[PATH_MAX];
1317 u64 magic;
1318 char *name = dent->d_name;
1319 FILE *file;
1320
1321 if (!(dent->d_type == DT_REG))
1322 continue;
1323
1324 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1325
1326 file = fopen(path, "r");
1327 if (!file)
1328 continue;
1329
1330 if (fread(&magic, 1, 8, file) < 8)
1331 goto close_file_and_continue;
1332
1333 if (is_perf_magic(magic)) {
1334 options[nr_options] = strdup(name);
1335 if (!options[nr_options])
1336 goto close_file_and_continue;
1337
1338 abs_path[nr_options] = strdup(path);
1339 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001340 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001341 ui__warning("Can't search all data files due to memory shortage.\n");
1342 fclose(file);
1343 break;
1344 }
1345
1346 nr_options++;
1347 }
1348
1349close_file_and_continue:
1350 fclose(file);
1351 if (nr_options >= 32) {
1352 ui__warning("Too many perf data files in PWD!\n"
1353 "Only the first 32 files will be listed.\n");
1354 break;
1355 }
1356 }
1357 closedir(pwd_dir);
1358
1359 if (nr_options) {
1360 choice = ui__popup_menu(nr_options, options);
1361 if (choice < nr_options && choice >= 0) {
1362 tmp = strdup(abs_path[choice]);
1363 if (tmp) {
1364 if (is_input_name_malloced)
1365 free((void *)input_name);
1366 input_name = tmp;
1367 is_input_name_malloced = true;
1368 ret = 0;
1369 } else
1370 ui__warning("Data switch failed due to memory shortage!\n");
1371 }
1372 }
1373
1374 free_popup_options(options, nr_options);
1375 free_popup_options(abs_path, nr_options);
1376 return ret;
1377}
1378
Namhyung Kim112f7612014-04-22 14:05:35 +09001379static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001380{
1381 u64 nr_entries = 0;
1382 struct rb_node *nd = rb_first(&hb->hists->entries);
1383
Namhyung Kim268397c2014-04-22 14:49:31 +09001384 if (hb->min_pcnt == 0) {
1385 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1386 return;
1387 }
1388
Namhyung Kim14135662013-10-31 10:17:39 +09001389 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001390 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001391 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001392 }
1393
Namhyung Kim112f7612014-04-22 14:05:35 +09001394 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001395}
Feng Tang341487ab2013-02-03 14:38:20 +08001396
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001397static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001398 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001399 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001400 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001401 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001402 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001403{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001404 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001405 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001406 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001407 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001408 char *options[16];
1409 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001410 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001411 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001412 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001413 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001414 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001415
Namhyung Kime8e684a2013-12-26 14:37:58 +09001416#define HIST_BROWSER_HELP_COMMON \
1417 "h/?/F1 Show this window\n" \
1418 "UP/DOWN/PGUP\n" \
1419 "PGDN/SPACE Navigate\n" \
1420 "q/ESC/CTRL+C Exit browser\n\n" \
1421 "For multiple event sessions:\n\n" \
1422 "TAB/UNTAB Switch events\n\n" \
1423 "For symbolic views (--sort has sym):\n\n" \
1424 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1425 "<- Zoom out\n" \
1426 "a Annotate current symbol\n" \
1427 "C Collapse all callchains\n" \
1428 "d Zoom into current DSO\n" \
1429 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001430 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001431 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001432
1433 /* help messages are sorted by lexical order of the hotkey */
1434 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001435 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001436 "P Print histograms to perf.hist.N\n"
1437 "r Run available scripts\n"
1438 "s Switch to another data file in PWD\n"
1439 "t Zoom into current Thread\n"
1440 "V Verbose (DSO names in callchains, etc)\n"
1441 "/ Filter symbol by name";
1442 const char top_help[] = HIST_BROWSER_HELP_COMMON
1443 "P Print histograms to perf.hist.N\n"
1444 "t Zoom into current Thread\n"
1445 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001446 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001447 "/ Filter symbol by name";
1448
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001449 if (browser == NULL)
1450 return -1;
1451
Namhyung Kim064f1982013-05-14 11:09:04 +09001452 if (min_pcnt) {
1453 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001454 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001455 }
1456
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001457 fstack = pstack__new(2);
1458 if (fstack == NULL)
1459 goto out;
1460
1461 ui_helpline__push(helpline);
1462
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001463 memset(options, 0, sizeof(options));
1464
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001465 perf_hpp__for_each_format(fmt)
1466 perf_hpp__reset_width(fmt, hists);
1467
Namhyung Kim5b591662014-07-31 14:47:38 +09001468 if (symbol_conf.col_width_list_str)
1469 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1470
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001471 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001472 const struct thread *thread = NULL;
1473 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001474 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001475 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001476 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001477 int scripts_comm = -2, scripts_symbol = -2,
1478 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001479
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001480 nr_options = 0;
1481
Jiri Olsadd00d482014-06-19 13:41:13 +02001482 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001483
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001484 if (browser->he_selection != NULL) {
1485 thread = hist_browser__selected_thread(browser);
1486 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1487 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001488 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001489 case K_TAB:
1490 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001491 if (nr_events == 1)
1492 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001493 /*
1494 * Exit the browser, let hists__browser_tree
1495 * go to the next or previous
1496 */
1497 goto out_free_stack;
1498 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001499 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001500 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001501 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001502 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001503 continue;
1504 }
1505
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001506 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001507 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001508 browser->selection->map->dso->annotate_warned)
1509 continue;
1510 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001511 case 'P':
1512 hist_browser__dump(browser);
1513 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001514 case 'd':
1515 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001516 case 'V':
1517 browser->show_dso = !browser->show_dso;
1518 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001519 case 't':
1520 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001521 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001522 if (ui_browser__input_window("Symbol to show",
1523 "Please enter the name of symbol you want to see",
1524 buf, "ENTER: OK, ESC: Cancel",
1525 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001526 hists->symbol_filter_str = *buf ? buf : NULL;
1527 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001528 hist_browser__reset(browser);
1529 }
1530 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001531 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001532 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001533 goto do_scripts;
1534 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001535 case 's':
1536 if (is_report_browser(hbt))
1537 goto do_data_switch;
1538 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001539 case 'i':
1540 /* env->arch is NULL for live-mode (i.e. perf top) */
1541 if (env->arch)
1542 tui__header_window(env);
1543 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001544 case 'F':
1545 symbol_conf.filter_relative ^= 1;
1546 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001547 case 'z':
1548 if (!is_report_browser(hbt)) {
1549 struct perf_top *top = hbt->arg;
1550
1551 top->zero = !top->zero;
1552 }
1553 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001554 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001555 case 'h':
1556 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001557 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001558 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001559 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001560 case K_ENTER:
1561 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001562 /* menu */
1563 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001564 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001565 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001566
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001567 if (pstack__empty(fstack)) {
1568 /*
1569 * Go back to the perf_evsel_menu__run or other user
1570 */
1571 if (left_exits)
1572 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001573 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001574 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001575 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001576 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001577 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001578 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001579 goto zoom_out_thread;
1580 continue;
1581 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001582 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001583 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001584 !ui_browser__dialog_yesno(&browser->b,
1585 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001586 continue;
1587 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001588 case 'q':
1589 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001590 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001591 default:
1592 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001593 }
1594
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001595 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001596 goto add_exit_option;
1597
Namhyung Kim55369fc2013-04-01 20:35:20 +09001598 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001599 bi = browser->he_selection->branch_info;
1600 if (browser->selection != NULL &&
1601 bi &&
1602 bi->from.sym != NULL &&
1603 !bi->from.map->dso->annotate_warned &&
1604 asprintf(&options[nr_options], "Annotate %s",
1605 bi->from.sym->name) > 0)
1606 annotate_f = nr_options++;
1607
1608 if (browser->selection != NULL &&
1609 bi &&
1610 bi->to.sym != NULL &&
1611 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001612 (bi->to.sym != bi->from.sym ||
1613 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001614 asprintf(&options[nr_options], "Annotate %s",
1615 bi->to.sym->name) > 0)
1616 annotate_t = nr_options++;
1617 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001618 if (browser->selection != NULL &&
1619 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001620 !browser->selection->map->dso->annotate_warned) {
1621 struct annotation *notes;
1622
1623 notes = symbol__annotation(browser->selection->sym);
1624
1625 if (notes->src &&
1626 asprintf(&options[nr_options], "Annotate %s",
1627 browser->selection->sym->name) > 0)
1628 annotate = nr_options++;
1629 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001630 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001631
1632 if (thread != NULL &&
1633 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001634 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001635 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001636 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001637 zoom_thread = nr_options++;
1638
1639 if (dso != NULL &&
1640 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001641 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001642 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1643 zoom_dso = nr_options++;
1644
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001645 if (browser->selection != NULL &&
1646 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001647 asprintf(&options[nr_options], "Browse map details") > 0)
1648 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001649
1650 /* perf script support */
1651 if (browser->he_selection) {
1652 struct symbol *sym;
1653
1654 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001655 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001656 scripts_comm = nr_options++;
1657
1658 sym = browser->he_selection->ms.sym;
1659 if (sym && sym->namelen &&
1660 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1661 sym->name) > 0)
1662 scripts_symbol = nr_options++;
1663 }
1664
1665 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1666 scripts_all = nr_options++;
1667
Feng Tang341487ab2013-02-03 14:38:20 +08001668 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1669 "Switch to another data file in PWD") > 0)
1670 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001671add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001672 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001673retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001674 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001675
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001676 if (choice == nr_options - 1)
1677 break;
1678
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001679 if (choice == -1) {
1680 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001681 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001682 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001683
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001684 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001685 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001686 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001687 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001688do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001689 if (!objdump_path && perf_session_env__lookup_objdump(env))
1690 continue;
1691
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001692 he = hist_browser__selected_entry(browser);
1693 if (he == NULL)
1694 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001695
1696 /*
1697 * we stash the branch_info symbol + map into the
1698 * the ms so we don't have to rewrite all the annotation
1699 * code to use branch_info.
1700 * in branch mode, the ms struct is not used
1701 */
1702 if (choice == annotate_f) {
1703 he->ms.sym = he->branch_info->from.sym;
1704 he->ms.map = he->branch_info->from.map;
1705 } else if (choice == annotate_t) {
1706 he->ms.sym = he->branch_info->to.sym;
1707 he->ms.map = he->branch_info->to.map;
1708 }
1709
Jiri Olsad7553302014-06-15 10:22:15 +02001710 notes = symbol__annotation(he->ms.sym);
1711 if (!notes->src)
1712 continue;
1713
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001714 /*
1715 * Don't let this be freed, say, by hists__decay_entry.
1716 */
1717 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001718 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001719 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001720 /*
1721 * offer option to annotate the other branch source or target
1722 * (if they exists) when returning from annotate
1723 */
1724 if ((err == 'q' || err == CTRL('c'))
1725 && annotate_t != -2 && annotate_f != -2)
1726 goto retry_popup_menu;
1727
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001728 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001729 if (err)
1730 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001731
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001732 } else if (choice == browse_map)
1733 map__browse(browser->selection->map);
1734 else if (choice == zoom_dso) {
1735zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001736 if (browser->hists->dso_filter) {
1737 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001738zoom_out_dso:
1739 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001740 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001741 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001742 } else {
1743 if (dso == NULL)
1744 continue;
1745 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1746 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001747 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001748 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001749 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001750 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001751 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001752 hist_browser__reset(browser);
1753 } else if (choice == zoom_thread) {
1754zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001755 if (browser->hists->thread_filter) {
1756 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757zoom_out_thread:
1758 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001759 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001760 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761 } else {
1762 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001763 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001764 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001765 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001766 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001767 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001768 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001769 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001770 hist_browser__reset(browser);
1771 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001772 /* perf scripts support */
1773 else if (choice == scripts_all || choice == scripts_comm ||
1774 choice == scripts_symbol) {
1775do_scripts:
1776 memset(script_opt, 0, 64);
1777
1778 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001779 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001780
1781 if (choice == scripts_symbol)
1782 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1783
1784 script_browse(script_opt);
1785 }
Feng Tang341487ab2013-02-03 14:38:20 +08001786 /* Switch to another data file */
1787 else if (choice == switch_data) {
1788do_data_switch:
1789 if (!switch_data_file()) {
1790 key = K_SWITCH_INPUT_DATA;
1791 break;
1792 } else
1793 ui__warning("Won't switch the data files due to\n"
1794 "no valid data file get selected!\n");
1795 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001796 }
1797out_free_stack:
1798 pstack__delete(fstack);
1799out:
1800 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001801 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001802 return key;
1803}
1804
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001805struct perf_evsel_menu {
1806 struct ui_browser b;
1807 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001808 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001809 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001810 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001811};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001812
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001813static void perf_evsel_menu__write(struct ui_browser *browser,
1814 void *entry, int row)
1815{
1816 struct perf_evsel_menu *menu = container_of(browser,
1817 struct perf_evsel_menu, b);
1818 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001819 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001820 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001821 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001822 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001823 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001824 const char *warn = " ";
1825 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001826
1827 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1828 HE_COLORSET_NORMAL);
1829
Namhyung Kim759ff492013-03-05 14:53:26 +09001830 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001831 struct perf_evsel *pos;
1832
1833 ev_name = perf_evsel__group_name(evsel);
1834
1835 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001836 struct hists *pos_hists = evsel__hists(pos);
1837 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001838 }
1839 }
1840
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001841 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001842 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001843 unit, unit == ' ' ? "" : " ", ev_name);
1844 slsmg_printf("%s", bf);
1845
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001846 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001847 if (nr_events != 0) {
1848 menu->lost_events = true;
1849 if (!current_entry)
1850 ui_browser__set_color(browser, HE_COLORSET_TOP);
1851 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001852 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1853 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001854 warn = bf;
1855 }
1856
1857 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001858
1859 if (current_entry)
1860 menu->selection = evsel;
1861}
1862
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001863static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1864 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001865 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001866{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001867 struct perf_evlist *evlist = menu->b.priv;
1868 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001869 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001870 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001871 int key;
1872
1873 if (ui_browser__show(&menu->b, title,
1874 "ESC: exit, ENTER|->: Browse histograms") < 0)
1875 return -1;
1876
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001877 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001878 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001879
1880 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001881 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001882 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001883
1884 if (!menu->lost_events_warned && menu->lost_events) {
1885 ui_browser__warn_lost_events(&menu->b);
1886 menu->lost_events_warned = true;
1887 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001888 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001889 case K_RIGHT:
1890 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001891 if (!menu->selection)
1892 continue;
1893 pos = menu->selection;
1894browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001895 perf_evlist__set_selected(evlist, pos);
1896 /*
1897 * Give the calling tool a chance to populate the non
1898 * default evsel resorted hists tree.
1899 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001900 if (hbt)
1901 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001902 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001903 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001904 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001905 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001906 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001907 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001908 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001909 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001910 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001911 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001912 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001913 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001914 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001915 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001916 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001917 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001918 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001919 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001920 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001921 if (!ui_browser__dialog_yesno(&menu->b,
1922 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001923 continue;
1924 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001925 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001926 case 'q':
1927 case CTRL('c'):
1928 goto out;
1929 default:
1930 continue;
1931 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001932 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001933 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001934 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001935 if (!ui_browser__dialog_yesno(&menu->b,
1936 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001937 continue;
1938 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001939 case 'q':
1940 case CTRL('c'):
1941 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001942 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001943 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001944 }
1945 }
1946
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001947out:
1948 ui_browser__hide(&menu->b);
1949 return key;
1950}
1951
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001952static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001953 void *entry)
1954{
1955 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1956
1957 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1958 return true;
1959
1960 return false;
1961}
1962
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001963static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001964 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001965 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001966 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001967 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001968{
1969 struct perf_evsel *pos;
1970 struct perf_evsel_menu menu = {
1971 .b = {
1972 .entries = &evlist->entries,
1973 .refresh = ui_browser__list_head_refresh,
1974 .seek = ui_browser__list_head_seek,
1975 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001976 .filter = filter_group_entries,
1977 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001978 .priv = evlist,
1979 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001980 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001981 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001982 };
1983
1984 ui_helpline__push("Press ESC to exit");
1985
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001986 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001987 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001988 size_t line_len = strlen(ev_name) + 7;
1989
1990 if (menu.b.width < line_len)
1991 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001992 }
1993
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001994 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001995}
1996
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001997int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001998 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001999 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002000 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002001{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002002 int nr_entries = evlist->nr_entries;
2003
2004single_entry:
2005 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002006 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002007
2008 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002009 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002010 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002011 }
2012
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002013 if (symbol_conf.event_group) {
2014 struct perf_evsel *pos;
2015
2016 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002017 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002018 if (perf_evsel__is_group_leader(pos))
2019 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002020 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002021
2022 if (nr_entries == 1)
2023 goto single_entry;
2024 }
2025
2026 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002027 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002028}