blob: 68eab9ea16345f8a8190856a400b18bf93defa19 [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
Jiri Olsadd00d482014-06-19 13:41:13 +020038static int hists__browser_title(struct hists *hists, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090039static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030040
Namhyung Kimc3b78952014-04-22 15:56:17 +090041static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090042 float min_pcnt);
43
Namhyung Kim268397c2014-04-22 14:49:31 +090044static bool hist_browser__has_filter(struct hist_browser *hb)
45{
46 return hists__has_filter(hb->hists) || hb->min_pcnt;
47}
48
Namhyung Kimc3b78952014-04-22 15:56:17 +090049static u32 hist_browser__nr_entries(struct hist_browser *hb)
50{
51 u32 nr_entries;
52
53 if (hist_browser__has_filter(hb))
54 nr_entries = hb->nr_non_filtered_entries;
55 else
56 nr_entries = hb->hists->nr_entries;
57
58 return nr_entries + hb->nr_callchain_rows;
59}
60
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020061static void hist_browser__update_rows(struct hist_browser *hb)
62{
63 struct ui_browser *browser = &hb->b;
64 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
65
66 browser->rows = browser->height - header_offset;
67 /*
68 * Verify if we were at the last line and that line isn't
69 * visibe because we now show the header line(s).
70 */
71 index_row = browser->index - browser->top_idx;
72 if (index_row >= browser->rows)
73 browser->index -= index_row - browser->rows + 1;
74}
75
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030076static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030077{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030078 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
79
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030080 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030081 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
82 /*
83 * FIXME: Just keeping existing behaviour, but this really should be
84 * before updating browser->width, as it will invalidate the
85 * calculation above. Fix this and the fallout in another
86 * changeset.
87 */
88 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020089 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030090}
91
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030092static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
93{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020094 u16 header_offset = browser->show_headers ? 1 : 0;
95
96 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030097}
98
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030099static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300100{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900101 /*
102 * The hists__remove_entry_filter() already folds non-filtered
103 * entries so we can assume it has 0 callchain rows.
104 */
105 browser->nr_callchain_rows = 0;
106
Namhyung Kim268397c2014-04-22 14:49:31 +0900107 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900108 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300109 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300110 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300111}
112
113static char tree__folded_sign(bool unfolded)
114{
115 return unfolded ? '-' : '+';
116}
117
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300118static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300119{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300120 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300121}
122
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300123static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300124{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300125 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300126}
127
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300128static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300129{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300130 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300131}
132
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300133static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300134{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300135 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300136}
137
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300138static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300139{
140 int n = 0;
141 struct rb_node *nd;
142
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300143 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
145 struct callchain_list *chain;
146 char folded_sign = ' '; /* No children */
147
148 list_for_each_entry(chain, &child->val, list) {
149 ++n;
150 /* We need this because we may not have children */
151 folded_sign = callchain_list__folded(chain);
152 if (folded_sign == '+')
153 break;
154 }
155
156 if (folded_sign == '-') /* Have children and they're unfolded */
157 n += callchain_node__count_rows_rb_tree(child);
158 }
159
160 return n;
161}
162
163static int callchain_node__count_rows(struct callchain_node *node)
164{
165 struct callchain_list *chain;
166 bool unfolded = false;
167 int n = 0;
168
169 list_for_each_entry(chain, &node->val, list) {
170 ++n;
171 unfolded = chain->ms.unfolded;
172 }
173
174 if (unfolded)
175 n += callchain_node__count_rows_rb_tree(node);
176
177 return n;
178}
179
180static int callchain__count_rows(struct rb_root *chain)
181{
182 struct rb_node *nd;
183 int n = 0;
184
185 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
186 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
187 n += callchain_node__count_rows(node);
188 }
189
190 return n;
191}
192
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300193static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300194{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300195 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200196 return false;
197
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300198 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300199 return false;
200
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300201 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300202 return true;
203}
204
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300205static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300206{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300207 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300208
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300209 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300210 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
211 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300212 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300213
214 list_for_each_entry(chain, &child->val, list) {
215 if (first) {
216 first = false;
217 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300218 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300219 } else
220 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300221 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300222 }
223
224 callchain_node__init_have_children_rb_tree(child);
225 }
226}
227
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300228static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229{
230 struct callchain_list *chain;
231
Namhyung Kim82162b52014-08-13 15:02:41 +0900232 if (!list_empty(&node->val)) {
233 chain = list_entry(node->val.prev, struct callchain_list, list);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300234 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900235 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300236
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300237 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300238}
239
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300240static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300241{
242 struct rb_node *nd;
243
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300244 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300245 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
246 callchain_node__init_have_children(node);
247 }
248}
249
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300250static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300251{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300252 if (!he->init_have_children) {
253 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
254 callchain__init_have_children(&he->sorted_chain);
255 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300256 }
257}
258
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300259static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300260{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300261 if (map_symbol__toggle_fold(browser->selection)) {
262 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300263
264 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900265 browser->b.nr_entries -= he->nr_rows;
266 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300267
268 if (he->ms.unfolded)
269 he->nr_rows = callchain__count_rows(&he->sorted_chain);
270 else
271 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900272
273 browser->b.nr_entries += he->nr_rows;
274 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300275
276 return true;
277 }
278
279 /* If it doesn't have children, no toggling performed */
280 return false;
281}
282
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300283static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300284{
285 int n = 0;
286 struct rb_node *nd;
287
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300288 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300289 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
290 struct callchain_list *chain;
291 bool has_children = false;
292
293 list_for_each_entry(chain, &child->val, list) {
294 ++n;
295 map_symbol__set_folding(&chain->ms, unfold);
296 has_children = chain->ms.has_children;
297 }
298
299 if (has_children)
300 n += callchain_node__set_folding_rb_tree(child, unfold);
301 }
302
303 return n;
304}
305
306static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
307{
308 struct callchain_list *chain;
309 bool has_children = false;
310 int n = 0;
311
312 list_for_each_entry(chain, &node->val, list) {
313 ++n;
314 map_symbol__set_folding(&chain->ms, unfold);
315 has_children = chain->ms.has_children;
316 }
317
318 if (has_children)
319 n += callchain_node__set_folding_rb_tree(node, unfold);
320
321 return n;
322}
323
324static int callchain__set_folding(struct rb_root *chain, bool unfold)
325{
326 struct rb_node *nd;
327 int n = 0;
328
329 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
330 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
331 n += callchain_node__set_folding(node, unfold);
332 }
333
334 return n;
335}
336
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300337static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300338{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300339 hist_entry__init_have_children(he);
340 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300341
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300342 if (he->ms.has_children) {
343 int n = callchain__set_folding(&he->sorted_chain, unfold);
344 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300345 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300346 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300347}
348
Namhyung Kimc3b78952014-04-22 15:56:17 +0900349static void
350__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300351{
352 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900353 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300354
Namhyung Kimc3b78952014-04-22 15:56:17 +0900355 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900356 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900357 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300358 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
359 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900360 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300361 }
362}
363
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300364static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300365{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900366 browser->nr_callchain_rows = 0;
367 __hist_browser__set_folding(browser, unfold);
368
369 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300370 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300372}
373
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200374static void ui_browser__warn_lost_events(struct ui_browser *browser)
375{
376 ui_browser__warning(browser, 4,
377 "Events are being lost, check IO/CPU overload!\n\n"
378 "You may want to run 'perf' using a RT scheduler policy:\n\n"
379 " perf top -r 80\n\n"
380 "Or reduce the sampling frequency.");
381}
382
Jiri Olsadd00d482014-06-19 13:41:13 +0200383static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900384 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300386 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300387 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900388 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300389
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300390 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900391 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392
Jiri Olsadd00d482014-06-19 13:41:13 +0200393 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300395 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300396 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300397 return -1;
398
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300399 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300400 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300402 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900403 case K_TIMER: {
404 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900405 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900406
Namhyung Kimc3b78952014-04-22 15:56:17 +0900407 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900408 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900409
Namhyung Kimc3b78952014-04-22 15:56:17 +0900410 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900411 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200412
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300413 if (browser->hists->stats.nr_lost_warned !=
414 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
415 browser->hists->stats.nr_lost_warned =
416 browser->hists->stats.nr_events[PERF_RECORD_LOST];
417 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200418 }
419
Jiri Olsadd00d482014-06-19 13:41:13 +0200420 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300421 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300422 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900423 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300424 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300425 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300426 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300427 struct hist_entry, rb_node);
428 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300429 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 -0300430 seq++, browser->b.nr_entries,
431 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300432 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300433 browser->b.index,
434 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300435 h->row_offset, h->nr_rows);
436 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300437 break;
438 case 'C':
439 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300440 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300441 break;
442 case 'E':
443 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300444 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300445 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200446 case 'H':
447 browser->show_headers = !browser->show_headers;
448 hist_browser__update_rows(browser);
449 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200450 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300451 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300452 break;
453 /* fall thru */
454 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300455 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300456 }
457 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300458out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300459 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300460 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300461}
462
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300463static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300464 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300465{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300466 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300467
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300468 if (cl->ms.sym)
469 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
470 else
471 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
472
473 if (show_dso)
474 scnprintf(bf + printed, bfsize - printed, " %s",
475 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
476
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300477 return bf;
478}
479
Namhyung Kim39ee5332014-08-22 09:13:21 +0900480struct callchain_print_arg {
481 /* for hists browser */
482 off_t row_offset;
483 bool is_current_entry;
484
485 /* for file dump */
486 FILE *fp;
487 int printed;
488};
489
490typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
491 struct callchain_list *chain,
492 const char *str, int offset,
493 unsigned short row,
494 struct callchain_print_arg *arg);
495
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900496static void hist_browser__show_callchain_entry(struct hist_browser *browser,
497 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900498 const char *str, int offset,
499 unsigned short row,
500 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900501{
502 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900503 char folded_sign = callchain_list__folded(chain);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900504
505 color = HE_COLORSET_NORMAL;
506 width = browser->b.width - (offset + 2);
507 if (ui_browser__is_current_entry(&browser->b, row)) {
508 browser->selection = &chain->ms;
509 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900510 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900511 }
512
513 ui_browser__set_color(&browser->b, color);
514 hist_browser__gotorc(browser, row, 0);
515 slsmg_write_nstring(" ", offset);
516 slsmg_printf("%c ", folded_sign);
517 slsmg_write_nstring(str, width);
518}
519
Namhyung Kim39ee5332014-08-22 09:13:21 +0900520static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
521 struct callchain_list *chain,
522 const char *str, int offset,
523 unsigned short row __maybe_unused,
524 struct callchain_print_arg *arg)
525{
526 char folded_sign = callchain_list__folded(chain);
527
528 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
529 folded_sign, str);
530}
531
532typedef bool (*check_output_full_fn)(struct hist_browser *browser,
533 unsigned short row);
534
535static bool hist_browser__check_output_full(struct hist_browser *browser,
536 unsigned short row)
537{
538 return browser->b.rows == row;
539}
540
541static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
542 unsigned short row __maybe_unused)
543{
544 return false;
545}
546
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300547#define LEVEL_OFFSET_STEP 3
548
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900549static int hist_browser__show_callchain(struct hist_browser *browser,
550 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900551 unsigned short row, u64 total,
552 print_callchain_entry_fn print,
553 struct callchain_print_arg *arg,
554 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300555{
556 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900557 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900558 u64 new_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300559
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900560 node = rb_first(root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300561 while (node) {
562 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
563 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100564 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300565 struct callchain_list *chain;
566 char folded_sign = ' ';
567 int first = true;
568 int extra_offset = 0;
569
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300570 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300571 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300572 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300573 bool was_first = first;
574
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300575 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300576 first = false;
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900577 else if (level > 1)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300578 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300579
580 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900581 if (arg->row_offset != 0) {
582 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300583 goto do_next;
584 }
585
586 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300587 str = callchain_list__sym_name(chain, bf, sizeof(bf),
588 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900589
590 if (was_first && level > 1) {
591 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592
593 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
594 str = "Not enough memory!";
595 else
596 str = alloc_str;
597 }
598
Namhyung Kim39ee5332014-08-22 09:13:21 +0900599 print(browser, chain, str, offset + extra_offset, row, arg);
600
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300601 free(alloc_str);
602
Namhyung Kim39ee5332014-08-22 09:13:21 +0900603 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300604 goto out;
605do_next:
606 if (folded_sign == '+')
607 break;
608 }
609
610 if (folded_sign == '-') {
611 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900612
613 if (callchain_param.mode == CHAIN_GRAPH_REL)
614 new_total = child->children_hit;
615 else
616 new_total = total;
617
618 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900619 new_level, row, new_total,
620 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300621 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900622 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900623 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300624 node = next;
625 }
626out:
627 return row - first_row;
628}
629
Namhyung Kim89701462013-01-22 18:09:38 +0900630struct hpp_arg {
631 struct ui_browser *b;
632 char folded_sign;
633 bool current_entry;
634};
635
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900636static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
637{
638 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900639 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900640 va_list args;
641 double percent;
642
643 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900644 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900645 percent = va_arg(args, double);
646 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900647
Namhyung Kim89701462013-01-22 18:09:38 +0900648 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900649
Namhyung Kimd6751072014-07-31 14:47:36 +0900650 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900651 slsmg_printf("%s", hpp->buf);
652
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900653 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900654 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900655}
656
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900657#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900658static u64 __hpp_get_##_field(struct hist_entry *he) \
659{ \
660 return he->stat._field; \
661} \
662 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100663static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900664hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100665 struct perf_hpp *hpp, \
666 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900667{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900668 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
669 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900670}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900671
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900672#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
673static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
674{ \
675 return he->stat_acc->_field; \
676} \
677 \
678static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900679hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900680 struct perf_hpp *hpp, \
681 struct hist_entry *he) \
682{ \
683 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900684 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900685 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900686 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900687 slsmg_printf("%s", hpp->buf); \
688 \
689 return ret; \
690 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900691 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
692 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900693}
694
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900695__HPP_COLOR_PERCENT_FN(overhead, period)
696__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
697__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
698__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
699__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900700__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900701
702#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900703#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900704
705void hist_browser__init_hpp(void)
706{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900707 perf_hpp__format[PERF_HPP__OVERHEAD].color =
708 hist_browser__hpp_color_overhead;
709 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
710 hist_browser__hpp_color_overhead_sys;
711 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
712 hist_browser__hpp_color_overhead_us;
713 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
714 hist_browser__hpp_color_overhead_guest_sys;
715 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
716 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900717 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
718 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900719}
720
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300721static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300722 struct hist_entry *entry,
723 unsigned short row)
724{
725 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200726 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900727 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300728 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300729 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300730 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300731 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200732 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300733
734 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300735 browser->he_selection = entry;
736 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300737 }
738
739 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300740 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300741 folded_sign = hist_entry__folded(entry);
742 }
743
744 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900745 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900746 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900747 .folded_sign = folded_sign,
748 .current_entry = current_entry,
749 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900750 struct perf_hpp hpp = {
751 .buf = s,
752 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900753 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900754 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300755
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300756 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900757
Jiri Olsa12400052012-10-13 00:06:16 +0200758 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900759 if (perf_hpp__should_skip(fmt))
760 continue;
761
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900762 if (current_entry && browser->b.navkeypressed) {
763 ui_browser__set_color(&browser->b,
764 HE_COLORSET_SELECTED);
765 } else {
766 ui_browser__set_color(&browser->b,
767 HE_COLORSET_NORMAL);
768 }
769
770 if (first) {
771 if (symbol_conf.use_callchain) {
772 slsmg_printf("%c ", folded_sign);
773 width -= 2;
774 }
775 first = false;
776 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900777 slsmg_printf(" ");
778 width -= 2;
779 }
780
Jiri Olsa12400052012-10-13 00:06:16 +0200781 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100782 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900783 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100784 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900785 slsmg_printf("%s", s);
786 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300787 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200788
789 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300790 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200791 width += 1;
792
Namhyung Kim26d8b332014-03-03 16:16:20 +0900793 slsmg_write_nstring("", width);
794
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300795 ++row;
796 ++printed;
797 } else
798 --row_offset;
799
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300800 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900801 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900802 struct callchain_print_arg arg = {
803 .row_offset = row_offset,
804 .is_current_entry = current_entry,
805 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900806
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900807 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900808 &entry->sorted_chain, 1, row, total,
809 hist_browser__show_callchain_entry, &arg,
810 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900811
Namhyung Kim39ee5332014-08-22 09:13:21 +0900812 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300813 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300814 }
815
816 return printed;
817}
818
Jiri Olsa81a888f2014-06-14 15:44:52 +0200819static int advance_hpp_check(struct perf_hpp *hpp, int inc)
820{
821 advance_hpp(hpp, inc);
822 return hpp->size <= 0;
823}
824
825static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
826{
827 struct perf_hpp dummy_hpp = {
828 .buf = buf,
829 .size = size,
830 };
831 struct perf_hpp_fmt *fmt;
832 size_t ret = 0;
833
834 if (symbol_conf.use_callchain) {
835 ret = scnprintf(buf, size, " ");
836 if (advance_hpp_check(&dummy_hpp, ret))
837 return ret;
838 }
839
840 perf_hpp__for_each_format(fmt) {
841 if (perf_hpp__should_skip(fmt))
842 continue;
843
Jiri Olsa81a888f2014-06-14 15:44:52 +0200844 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
845 if (advance_hpp_check(&dummy_hpp, ret))
846 break;
847
848 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
849 if (advance_hpp_check(&dummy_hpp, ret))
850 break;
851 }
852
853 return ret;
854}
855
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200856static void hist_browser__show_headers(struct hist_browser *browser)
857{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200858 char headers[1024];
859
860 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200861 ui_browser__gotorc(&browser->b, 0, 0);
862 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200863 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200864}
865
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300866static void ui_browser__hists_init_top(struct ui_browser *browser)
867{
868 if (browser->top == NULL) {
869 struct hist_browser *hb;
870
871 hb = container_of(browser, struct hist_browser, b);
872 browser->top = rb_first(&hb->hists->entries);
873 }
874}
875
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300876static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300877{
878 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200879 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300880 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300881 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300882
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200883 if (hb->show_headers) {
884 hist_browser__show_headers(hb);
885 header_offset = 1;
886 }
887
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300888 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300889
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300890 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300891 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900892 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300893
894 if (h->filtered)
895 continue;
896
Namhyung Kim14135662013-10-31 10:17:39 +0900897 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900898 if (percent < hb->min_pcnt)
899 continue;
900
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300901 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300902 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300903 break;
904 }
905
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200906 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300907}
908
Namhyung Kim064f1982013-05-14 11:09:04 +0900909static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900910 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300911{
912 while (nd != NULL) {
913 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900914 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900915
Namhyung Kimc0f15272014-04-16 11:16:33 +0900916 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300917 return nd;
918
919 nd = rb_next(nd);
920 }
921
922 return NULL;
923}
924
Namhyung Kim064f1982013-05-14 11:09:04 +0900925static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900926 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300927{
928 while (nd != NULL) {
929 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900930 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900931
932 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300933 return nd;
934
935 nd = rb_prev(nd);
936 }
937
938 return NULL;
939}
940
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300941static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300942 off_t offset, int whence)
943{
944 struct hist_entry *h;
945 struct rb_node *nd;
946 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900947 struct hist_browser *hb;
948
949 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300950
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300951 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300952 return;
953
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300954 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300955
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300956 switch (whence) {
957 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900958 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900959 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300960 break;
961 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300962 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300963 goto do_offset;
964 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900965 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900966 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300967 first = false;
968 break;
969 default:
970 return;
971 }
972
973 /*
974 * Moves not relative to the first visible entry invalidates its
975 * row_offset:
976 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300977 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300978 h->row_offset = 0;
979
980 /*
981 * Here we have to check if nd is expanded (+), if it is we can't go
982 * the next top level hist_entry, instead we must compute an offset of
983 * what _not_ to show and not change the first visible entry.
984 *
985 * This offset increments when we are going from top to bottom and
986 * decreases when we're going from bottom to top.
987 *
988 * As we don't have backpointers to the top level in the callchains
989 * structure, we need to always print the whole hist_entry callchain,
990 * skipping the first ones that are before the first visible entry
991 * and stop when we printed enough lines to fill the screen.
992 */
993do_offset:
994 if (offset > 0) {
995 do {
996 h = rb_entry(nd, struct hist_entry, rb_node);
997 if (h->ms.unfolded) {
998 u16 remaining = h->nr_rows - h->row_offset;
999 if (offset > remaining) {
1000 offset -= remaining;
1001 h->row_offset = 0;
1002 } else {
1003 h->row_offset += offset;
1004 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001005 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001006 break;
1007 }
1008 }
Namhyung Kim14135662013-10-31 10:17:39 +09001009 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001010 if (nd == NULL)
1011 break;
1012 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001013 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001014 } while (offset != 0);
1015 } else if (offset < 0) {
1016 while (1) {
1017 h = rb_entry(nd, struct hist_entry, rb_node);
1018 if (h->ms.unfolded) {
1019 if (first) {
1020 if (-offset > h->row_offset) {
1021 offset += h->row_offset;
1022 h->row_offset = 0;
1023 } else {
1024 h->row_offset += offset;
1025 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001026 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001027 break;
1028 }
1029 } else {
1030 if (-offset > h->nr_rows) {
1031 offset += h->nr_rows;
1032 h->row_offset = 0;
1033 } else {
1034 h->row_offset = h->nr_rows + offset;
1035 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001036 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001037 break;
1038 }
1039 }
1040 }
1041
Namhyung Kim14135662013-10-31 10:17:39 +09001042 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001043 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001044 if (nd == NULL)
1045 break;
1046 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001047 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001048 if (offset == 0) {
1049 /*
1050 * Last unfiltered hist_entry, check if it is
1051 * unfolded, if it is then we should have
1052 * row_offset at its last entry.
1053 */
1054 h = rb_entry(nd, struct hist_entry, rb_node);
1055 if (h->ms.unfolded)
1056 h->row_offset = h->nr_rows;
1057 break;
1058 }
1059 first = false;
1060 }
1061 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001062 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001063 h = rb_entry(nd, struct hist_entry, rb_node);
1064 h->row_offset = 0;
1065 }
1066}
1067
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001068static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001069 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001070{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001071 u64 total = hists__total_period(he->hists);
1072 struct callchain_print_arg arg = {
1073 .fp = fp,
1074 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001075
Namhyung Kim39ee5332014-08-22 09:13:21 +09001076 if (symbol_conf.cumulate_callchain)
1077 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001078
Namhyung Kim39ee5332014-08-22 09:13:21 +09001079 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1080 hist_browser__fprintf_callchain_entry, &arg,
1081 hist_browser__check_dump_full);
1082 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001083}
1084
1085static int hist_browser__fprintf_entry(struct hist_browser *browser,
1086 struct hist_entry *he, FILE *fp)
1087{
1088 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001089 int printed = 0;
1090 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001091 struct perf_hpp hpp = {
1092 .buf = s,
1093 .size = sizeof(s),
1094 };
1095 struct perf_hpp_fmt *fmt;
1096 bool first = true;
1097 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001098
1099 if (symbol_conf.use_callchain)
1100 folded_sign = hist_entry__folded(he);
1101
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001102 if (symbol_conf.use_callchain)
1103 printed += fprintf(fp, "%c ", folded_sign);
1104
Namhyung Kim26d8b332014-03-03 16:16:20 +09001105 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001106 if (perf_hpp__should_skip(fmt))
1107 continue;
1108
Namhyung Kim26d8b332014-03-03 16:16:20 +09001109 if (!first) {
1110 ret = scnprintf(hpp.buf, hpp.size, " ");
1111 advance_hpp(&hpp, ret);
1112 } else
1113 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001114
Namhyung Kim26d8b332014-03-03 16:16:20 +09001115 ret = fmt->entry(fmt, &hpp, he);
1116 advance_hpp(&hpp, ret);
1117 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001118 printed += fprintf(fp, "%s\n", rtrim(s));
1119
1120 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001121 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001122
1123 return printed;
1124}
1125
1126static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1127{
Namhyung Kim064f1982013-05-14 11:09:04 +09001128 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001129 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001130 int printed = 0;
1131
1132 while (nd) {
1133 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1134
1135 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001136 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001137 }
1138
1139 return printed;
1140}
1141
1142static int hist_browser__dump(struct hist_browser *browser)
1143{
1144 char filename[64];
1145 FILE *fp;
1146
1147 while (1) {
1148 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1149 if (access(filename, F_OK))
1150 break;
1151 /*
1152 * XXX: Just an arbitrary lazy upper limit
1153 */
1154 if (++browser->print_seq == 8192) {
1155 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1156 return -1;
1157 }
1158 }
1159
1160 fp = fopen(filename, "w");
1161 if (fp == NULL) {
1162 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001163 const char *err = strerror_r(errno, bf, sizeof(bf));
1164 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001165 return -1;
1166 }
1167
1168 ++browser->print_seq;
1169 hist_browser__fprintf(browser, fp);
1170 fclose(fp);
1171 ui_helpline__fpush("%s written!", filename);
1172
1173 return 0;
1174}
1175
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001176static struct hist_browser *hist_browser__new(struct hists *hists)
1177{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001178 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001179
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001180 if (browser) {
1181 browser->hists = hists;
1182 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001183 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001184 browser->b.seek = ui_browser__hists_seek;
1185 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001186 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001187 }
1188
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001189 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001190}
1191
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001192static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001193{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001194 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001195}
1196
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001197static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001199 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200}
1201
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001202static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001203{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001204 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001205}
1206
Jiri Olsadd00d482014-06-19 13:41:13 +02001207static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001208{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001209 char unit;
1210 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001211 const struct dso *dso = hists->dso_filter;
1212 const struct thread *thread = hists->thread_filter;
1213 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1214 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001215 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001216 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001217 char buf[512];
1218 size_t buflen = sizeof(buf);
1219
Namhyung Kimf2148332014-01-14 11:52:48 +09001220 if (symbol_conf.filter_relative) {
1221 nr_samples = hists->stats.nr_non_filtered_samples;
1222 nr_events = hists->stats.total_non_filtered_period;
1223 }
1224
Namhyung Kim759ff492013-03-05 14:53:26 +09001225 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001226 struct perf_evsel *pos;
1227
1228 perf_evsel__group_desc(evsel, buf, buflen);
1229 ev_name = buf;
1230
1231 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001232 struct hists *pos_hists = evsel__hists(pos);
1233
Namhyung Kimf2148332014-01-14 11:52:48 +09001234 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001235 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1236 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001237 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001238 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1239 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001240 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001241 }
1242 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001243
Ashay Ranecc686282012-04-05 21:01:01 -05001244 nr_samples = convert_unit(nr_samples, &unit);
1245 printed = scnprintf(bf, size,
1246 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1247 nr_samples, unit, ev_name, nr_events);
1248
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001249
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001250 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001251 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001252 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001254 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001255 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001256 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001257 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001258 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001259 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001260 ", DSO: %s", dso->short_name);
1261 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001262}
1263
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001264static inline void free_popup_options(char **options, int n)
1265{
1266 int i;
1267
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001268 for (i = 0; i < n; ++i)
1269 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001270}
1271
Feng Tangc77d8d72012-11-01 00:00:55 +08001272/* Check whether the browser is for 'top' or 'report' */
1273static inline bool is_report_browser(void *timer)
1274{
1275 return timer == NULL;
1276}
1277
Feng Tang341487ab2013-02-03 14:38:20 +08001278/*
1279 * Only runtime switching of perf data file will make "input_name" point
1280 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1281 * whether we need to call free() for current "input_name" during the switch.
1282 */
1283static bool is_input_name_malloced = false;
1284
1285static int switch_data_file(void)
1286{
1287 char *pwd, *options[32], *abs_path[32], *tmp;
1288 DIR *pwd_dir;
1289 int nr_options = 0, choice = -1, ret = -1;
1290 struct dirent *dent;
1291
1292 pwd = getenv("PWD");
1293 if (!pwd)
1294 return ret;
1295
1296 pwd_dir = opendir(pwd);
1297 if (!pwd_dir)
1298 return ret;
1299
1300 memset(options, 0, sizeof(options));
1301 memset(options, 0, sizeof(abs_path));
1302
1303 while ((dent = readdir(pwd_dir))) {
1304 char path[PATH_MAX];
1305 u64 magic;
1306 char *name = dent->d_name;
1307 FILE *file;
1308
1309 if (!(dent->d_type == DT_REG))
1310 continue;
1311
1312 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1313
1314 file = fopen(path, "r");
1315 if (!file)
1316 continue;
1317
1318 if (fread(&magic, 1, 8, file) < 8)
1319 goto close_file_and_continue;
1320
1321 if (is_perf_magic(magic)) {
1322 options[nr_options] = strdup(name);
1323 if (!options[nr_options])
1324 goto close_file_and_continue;
1325
1326 abs_path[nr_options] = strdup(path);
1327 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001328 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001329 ui__warning("Can't search all data files due to memory shortage.\n");
1330 fclose(file);
1331 break;
1332 }
1333
1334 nr_options++;
1335 }
1336
1337close_file_and_continue:
1338 fclose(file);
1339 if (nr_options >= 32) {
1340 ui__warning("Too many perf data files in PWD!\n"
1341 "Only the first 32 files will be listed.\n");
1342 break;
1343 }
1344 }
1345 closedir(pwd_dir);
1346
1347 if (nr_options) {
1348 choice = ui__popup_menu(nr_options, options);
1349 if (choice < nr_options && choice >= 0) {
1350 tmp = strdup(abs_path[choice]);
1351 if (tmp) {
1352 if (is_input_name_malloced)
1353 free((void *)input_name);
1354 input_name = tmp;
1355 is_input_name_malloced = true;
1356 ret = 0;
1357 } else
1358 ui__warning("Data switch failed due to memory shortage!\n");
1359 }
1360 }
1361
1362 free_popup_options(options, nr_options);
1363 free_popup_options(abs_path, nr_options);
1364 return ret;
1365}
1366
Namhyung Kim112f7612014-04-22 14:05:35 +09001367static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001368{
1369 u64 nr_entries = 0;
1370 struct rb_node *nd = rb_first(&hb->hists->entries);
1371
Namhyung Kim268397c2014-04-22 14:49:31 +09001372 if (hb->min_pcnt == 0) {
1373 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1374 return;
1375 }
1376
Namhyung Kim14135662013-10-31 10:17:39 +09001377 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001378 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001379 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001380 }
1381
Namhyung Kim112f7612014-04-22 14:05:35 +09001382 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001383}
Feng Tang341487ab2013-02-03 14:38:20 +08001384
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001385static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001386 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001387 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001388 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001389 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001390 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001391{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001392 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001393 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001394 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001395 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001396 char *options[16];
1397 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001398 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001399 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001400 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001401 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001402 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001403
Namhyung Kime8e684a2013-12-26 14:37:58 +09001404#define HIST_BROWSER_HELP_COMMON \
1405 "h/?/F1 Show this window\n" \
1406 "UP/DOWN/PGUP\n" \
1407 "PGDN/SPACE Navigate\n" \
1408 "q/ESC/CTRL+C Exit browser\n\n" \
1409 "For multiple event sessions:\n\n" \
1410 "TAB/UNTAB Switch events\n\n" \
1411 "For symbolic views (--sort has sym):\n\n" \
1412 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1413 "<- Zoom out\n" \
1414 "a Annotate current symbol\n" \
1415 "C Collapse all callchains\n" \
1416 "d Zoom into current DSO\n" \
1417 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001418 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001419 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001420
1421 /* help messages are sorted by lexical order of the hotkey */
1422 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001423 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001424 "P Print histograms to perf.hist.N\n"
1425 "r Run available scripts\n"
1426 "s Switch to another data file in PWD\n"
1427 "t Zoom into current Thread\n"
1428 "V Verbose (DSO names in callchains, etc)\n"
1429 "/ Filter symbol by name";
1430 const char top_help[] = HIST_BROWSER_HELP_COMMON
1431 "P Print histograms to perf.hist.N\n"
1432 "t Zoom into current Thread\n"
1433 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001434 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001435 "/ Filter symbol by name";
1436
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001437 if (browser == NULL)
1438 return -1;
1439
Namhyung Kim064f1982013-05-14 11:09:04 +09001440 if (min_pcnt) {
1441 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001442 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001443 }
1444
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001445 fstack = pstack__new(2);
1446 if (fstack == NULL)
1447 goto out;
1448
1449 ui_helpline__push(helpline);
1450
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001451 memset(options, 0, sizeof(options));
1452
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001453 perf_hpp__for_each_format(fmt)
1454 perf_hpp__reset_width(fmt, hists);
1455
Namhyung Kim5b591662014-07-31 14:47:38 +09001456 if (symbol_conf.col_width_list_str)
1457 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1458
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001459 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001460 const struct thread *thread = NULL;
1461 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001462 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001463 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001464 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001465 int scripts_comm = -2, scripts_symbol = -2,
1466 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001467
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001468 nr_options = 0;
1469
Jiri Olsadd00d482014-06-19 13:41:13 +02001470 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001471
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001472 if (browser->he_selection != NULL) {
1473 thread = hist_browser__selected_thread(browser);
1474 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1475 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001476 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001477 case K_TAB:
1478 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001479 if (nr_events == 1)
1480 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001481 /*
1482 * Exit the browser, let hists__browser_tree
1483 * go to the next or previous
1484 */
1485 goto out_free_stack;
1486 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001487 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001488 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001489 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001490 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001491 continue;
1492 }
1493
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001494 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001495 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001496 browser->selection->map->dso->annotate_warned)
1497 continue;
1498 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001499 case 'P':
1500 hist_browser__dump(browser);
1501 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001502 case 'd':
1503 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001504 case 'V':
1505 browser->show_dso = !browser->show_dso;
1506 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001507 case 't':
1508 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001509 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001510 if (ui_browser__input_window("Symbol to show",
1511 "Please enter the name of symbol you want to see",
1512 buf, "ENTER: OK, ESC: Cancel",
1513 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001514 hists->symbol_filter_str = *buf ? buf : NULL;
1515 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001516 hist_browser__reset(browser);
1517 }
1518 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001519 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001520 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001521 goto do_scripts;
1522 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001523 case 's':
1524 if (is_report_browser(hbt))
1525 goto do_data_switch;
1526 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001527 case 'i':
1528 /* env->arch is NULL for live-mode (i.e. perf top) */
1529 if (env->arch)
1530 tui__header_window(env);
1531 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001532 case 'F':
1533 symbol_conf.filter_relative ^= 1;
1534 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001535 case 'z':
1536 if (!is_report_browser(hbt)) {
1537 struct perf_top *top = hbt->arg;
1538
1539 top->zero = !top->zero;
1540 }
1541 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001542 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001543 case 'h':
1544 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001545 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001546 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001547 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001548 case K_ENTER:
1549 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001550 /* menu */
1551 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001552 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001553 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001554
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001555 if (pstack__empty(fstack)) {
1556 /*
1557 * Go back to the perf_evsel_menu__run or other user
1558 */
1559 if (left_exits)
1560 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001561 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001562 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001563 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001564 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001565 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001566 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001567 goto zoom_out_thread;
1568 continue;
1569 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001570 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001571 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001572 !ui_browser__dialog_yesno(&browser->b,
1573 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001574 continue;
1575 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001576 case 'q':
1577 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001578 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001579 default:
1580 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001581 }
1582
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001583 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001584 goto add_exit_option;
1585
Namhyung Kim55369fc2013-04-01 20:35:20 +09001586 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001587 bi = browser->he_selection->branch_info;
1588 if (browser->selection != NULL &&
1589 bi &&
1590 bi->from.sym != NULL &&
1591 !bi->from.map->dso->annotate_warned &&
1592 asprintf(&options[nr_options], "Annotate %s",
1593 bi->from.sym->name) > 0)
1594 annotate_f = nr_options++;
1595
1596 if (browser->selection != NULL &&
1597 bi &&
1598 bi->to.sym != NULL &&
1599 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001600 (bi->to.sym != bi->from.sym ||
1601 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001602 asprintf(&options[nr_options], "Annotate %s",
1603 bi->to.sym->name) > 0)
1604 annotate_t = nr_options++;
1605 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001606 if (browser->selection != NULL &&
1607 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001608 !browser->selection->map->dso->annotate_warned) {
1609 struct annotation *notes;
1610
1611 notes = symbol__annotation(browser->selection->sym);
1612
1613 if (notes->src &&
1614 asprintf(&options[nr_options], "Annotate %s",
1615 browser->selection->sym->name) > 0)
1616 annotate = nr_options++;
1617 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001618 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001619
1620 if (thread != NULL &&
1621 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001622 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001623 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001624 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001625 zoom_thread = nr_options++;
1626
1627 if (dso != NULL &&
1628 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001629 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001630 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1631 zoom_dso = nr_options++;
1632
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001633 if (browser->selection != NULL &&
1634 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001635 asprintf(&options[nr_options], "Browse map details") > 0)
1636 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001637
1638 /* perf script support */
1639 if (browser->he_selection) {
1640 struct symbol *sym;
1641
1642 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001643 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001644 scripts_comm = nr_options++;
1645
1646 sym = browser->he_selection->ms.sym;
1647 if (sym && sym->namelen &&
1648 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1649 sym->name) > 0)
1650 scripts_symbol = nr_options++;
1651 }
1652
1653 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1654 scripts_all = nr_options++;
1655
Feng Tang341487ab2013-02-03 14:38:20 +08001656 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1657 "Switch to another data file in PWD") > 0)
1658 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001659add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001660 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001661retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001662 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001663
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001664 if (choice == nr_options - 1)
1665 break;
1666
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001667 if (choice == -1) {
1668 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001669 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001670 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001671
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001672 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001673 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001674 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001675 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001676do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001677 if (!objdump_path && perf_session_env__lookup_objdump(env))
1678 continue;
1679
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001680 he = hist_browser__selected_entry(browser);
1681 if (he == NULL)
1682 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001683
1684 /*
1685 * we stash the branch_info symbol + map into the
1686 * the ms so we don't have to rewrite all the annotation
1687 * code to use branch_info.
1688 * in branch mode, the ms struct is not used
1689 */
1690 if (choice == annotate_f) {
1691 he->ms.sym = he->branch_info->from.sym;
1692 he->ms.map = he->branch_info->from.map;
1693 } else if (choice == annotate_t) {
1694 he->ms.sym = he->branch_info->to.sym;
1695 he->ms.map = he->branch_info->to.map;
1696 }
1697
Jiri Olsad7553302014-06-15 10:22:15 +02001698 notes = symbol__annotation(he->ms.sym);
1699 if (!notes->src)
1700 continue;
1701
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001702 /*
1703 * Don't let this be freed, say, by hists__decay_entry.
1704 */
1705 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001706 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001707 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001708 /*
1709 * offer option to annotate the other branch source or target
1710 * (if they exists) when returning from annotate
1711 */
1712 if ((err == 'q' || err == CTRL('c'))
1713 && annotate_t != -2 && annotate_f != -2)
1714 goto retry_popup_menu;
1715
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001716 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001717 if (err)
1718 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001719
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001720 } else if (choice == browse_map)
1721 map__browse(browser->selection->map);
1722 else if (choice == zoom_dso) {
1723zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001724 if (browser->hists->dso_filter) {
1725 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001726zoom_out_dso:
1727 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001728 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001729 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001730 } else {
1731 if (dso == NULL)
1732 continue;
1733 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1734 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001735 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001736 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001737 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001738 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001739 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001740 hist_browser__reset(browser);
1741 } else if (choice == zoom_thread) {
1742zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001743 if (browser->hists->thread_filter) {
1744 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001745zoom_out_thread:
1746 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001747 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001748 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001749 } else {
1750 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001751 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001752 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001753 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001754 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001755 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001756 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001757 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758 hist_browser__reset(browser);
1759 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001760 /* perf scripts support */
1761 else if (choice == scripts_all || choice == scripts_comm ||
1762 choice == scripts_symbol) {
1763do_scripts:
1764 memset(script_opt, 0, 64);
1765
1766 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001767 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001768
1769 if (choice == scripts_symbol)
1770 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1771
1772 script_browse(script_opt);
1773 }
Feng Tang341487ab2013-02-03 14:38:20 +08001774 /* Switch to another data file */
1775 else if (choice == switch_data) {
1776do_data_switch:
1777 if (!switch_data_file()) {
1778 key = K_SWITCH_INPUT_DATA;
1779 break;
1780 } else
1781 ui__warning("Won't switch the data files due to\n"
1782 "no valid data file get selected!\n");
1783 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001784 }
1785out_free_stack:
1786 pstack__delete(fstack);
1787out:
1788 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001789 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001790 return key;
1791}
1792
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001793struct perf_evsel_menu {
1794 struct ui_browser b;
1795 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001796 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001797 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001798 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001799};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001800
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001801static void perf_evsel_menu__write(struct ui_browser *browser,
1802 void *entry, int row)
1803{
1804 struct perf_evsel_menu *menu = container_of(browser,
1805 struct perf_evsel_menu, b);
1806 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001807 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001808 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001809 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001810 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001811 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001812 const char *warn = " ";
1813 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001814
1815 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1816 HE_COLORSET_NORMAL);
1817
Namhyung Kim759ff492013-03-05 14:53:26 +09001818 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001819 struct perf_evsel *pos;
1820
1821 ev_name = perf_evsel__group_name(evsel);
1822
1823 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001824 struct hists *pos_hists = evsel__hists(pos);
1825 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001826 }
1827 }
1828
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001829 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001830 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001831 unit, unit == ' ' ? "" : " ", ev_name);
1832 slsmg_printf("%s", bf);
1833
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001834 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001835 if (nr_events != 0) {
1836 menu->lost_events = true;
1837 if (!current_entry)
1838 ui_browser__set_color(browser, HE_COLORSET_TOP);
1839 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001840 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1841 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001842 warn = bf;
1843 }
1844
1845 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001846
1847 if (current_entry)
1848 menu->selection = evsel;
1849}
1850
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001851static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1852 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001853 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001854{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001855 struct perf_evlist *evlist = menu->b.priv;
1856 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001857 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001858 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001859 int key;
1860
1861 if (ui_browser__show(&menu->b, title,
1862 "ESC: exit, ENTER|->: Browse histograms") < 0)
1863 return -1;
1864
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001865 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001866 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001867
1868 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001869 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001870 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001871
1872 if (!menu->lost_events_warned && menu->lost_events) {
1873 ui_browser__warn_lost_events(&menu->b);
1874 menu->lost_events_warned = true;
1875 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001876 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001877 case K_RIGHT:
1878 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001879 if (!menu->selection)
1880 continue;
1881 pos = menu->selection;
1882browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001883 perf_evlist__set_selected(evlist, pos);
1884 /*
1885 * Give the calling tool a chance to populate the non
1886 * default evsel resorted hists tree.
1887 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001888 if (hbt)
1889 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001890 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001891 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001892 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001893 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001894 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001895 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001896 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001897 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001898 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001899 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001900 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001901 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001902 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001903 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001904 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001905 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001906 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001907 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001908 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001909 if (!ui_browser__dialog_yesno(&menu->b,
1910 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001911 continue;
1912 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001913 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001914 case 'q':
1915 case CTRL('c'):
1916 goto out;
1917 default:
1918 continue;
1919 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001920 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001921 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001922 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001923 if (!ui_browser__dialog_yesno(&menu->b,
1924 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001925 continue;
1926 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001927 case 'q':
1928 case CTRL('c'):
1929 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001930 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001931 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001932 }
1933 }
1934
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001935out:
1936 ui_browser__hide(&menu->b);
1937 return key;
1938}
1939
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001940static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001941 void *entry)
1942{
1943 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1944
1945 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1946 return true;
1947
1948 return false;
1949}
1950
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001951static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001952 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001953 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001954 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001955 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001956{
1957 struct perf_evsel *pos;
1958 struct perf_evsel_menu menu = {
1959 .b = {
1960 .entries = &evlist->entries,
1961 .refresh = ui_browser__list_head_refresh,
1962 .seek = ui_browser__list_head_seek,
1963 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001964 .filter = filter_group_entries,
1965 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001966 .priv = evlist,
1967 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001968 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001969 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001970 };
1971
1972 ui_helpline__push("Press ESC to exit");
1973
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001974 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001975 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001976 size_t line_len = strlen(ev_name) + 7;
1977
1978 if (menu.b.width < line_len)
1979 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001980 }
1981
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001982 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001983}
1984
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001985int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001986 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001987 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001988 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001989{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001990 int nr_entries = evlist->nr_entries;
1991
1992single_entry:
1993 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001994 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001995
1996 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001997 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001998 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001999 }
2000
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002001 if (symbol_conf.event_group) {
2002 struct perf_evsel *pos;
2003
2004 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002005 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002006 if (perf_evsel__is_group_leader(pos))
2007 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002008 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002009
2010 if (nr_entries == 1)
2011 goto single_entry;
2012 }
2013
2014 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002015 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002016}