blob: f69371b7f49bed0f0a2efaaa2aedc04d0f4efcd7 [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include "../libslang.h"
3#include <stdlib.h>
4#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <linux/rbtree.h>
6
Namhyung Kimaca7a942012-04-04 00:14:26 -07007#include "../../util/evsel.h"
8#include "../../util/evlist.h"
9#include "../../util/hist.h"
10#include "../../util/pstack.h"
11#include "../../util/sort.h"
12#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090013#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090014#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030015
16#include "../browser.h"
17#include "../helpline.h"
18#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020019#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030020#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020021#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030023struct hist_browser {
24 struct ui_browser b;
25 struct hists *hists;
26 struct hist_entry *he_selection;
27 struct map_symbol *selection;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030028 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030029 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020030 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090031 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090032 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090033 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030034};
35
Namhyung Kimf5951d52012-09-03 11:53:09 +090036extern void hist_browser__init_hpp(void);
37
Taeung Song1e378eb2014-10-07 16:13:15 +090038static int hists__browser_title(struct hists *hists,
39 struct hist_browser_timer *hbt,
40 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090041static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030042
Namhyung Kimc3b78952014-04-22 15:56:17 +090043static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090044 float min_pcnt);
45
Namhyung Kim268397c2014-04-22 14:49:31 +090046static bool hist_browser__has_filter(struct hist_browser *hb)
47{
48 return hists__has_filter(hb->hists) || hb->min_pcnt;
49}
50
He Kuang4fabf3d2015-03-12 15:21:49 +080051static int hist_browser__get_folding(struct hist_browser *browser)
52{
53 struct rb_node *nd;
54 struct hists *hists = browser->hists;
55 int unfolded_rows = 0;
56
57 for (nd = rb_first(&hists->entries);
58 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
59 nd = rb_next(nd)) {
60 struct hist_entry *he =
61 rb_entry(nd, struct hist_entry, rb_node);
62
63 if (he->ms.unfolded)
64 unfolded_rows += he->nr_rows;
65 }
66 return unfolded_rows;
67}
68
Namhyung Kimc3b78952014-04-22 15:56:17 +090069static u32 hist_browser__nr_entries(struct hist_browser *hb)
70{
71 u32 nr_entries;
72
73 if (hist_browser__has_filter(hb))
74 nr_entries = hb->nr_non_filtered_entries;
75 else
76 nr_entries = hb->hists->nr_entries;
77
He Kuang4fabf3d2015-03-12 15:21:49 +080078 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090079 return nr_entries + hb->nr_callchain_rows;
80}
81
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020082static void hist_browser__update_rows(struct hist_browser *hb)
83{
84 struct ui_browser *browser = &hb->b;
85 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
86
87 browser->rows = browser->height - header_offset;
88 /*
89 * Verify if we were at the last line and that line isn't
90 * visibe because we now show the header line(s).
91 */
92 index_row = browser->index - browser->top_idx;
93 if (index_row >= browser->rows)
94 browser->index -= index_row - browser->rows + 1;
95}
96
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030097static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030098{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030099 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
100
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300102 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
103 /*
104 * FIXME: Just keeping existing behaviour, but this really should be
105 * before updating browser->width, as it will invalidate the
106 * calculation above. Fix this and the fallout in another
107 * changeset.
108 */
109 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200110 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300111}
112
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300113static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
114{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200115 u16 header_offset = browser->show_headers ? 1 : 0;
116
117 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300118}
119
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300120static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300121{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900122 /*
123 * The hists__remove_entry_filter() already folds non-filtered
124 * entries so we can assume it has 0 callchain rows.
125 */
126 browser->nr_callchain_rows = 0;
127
Namhyung Kim268397c2014-04-22 14:49:31 +0900128 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900129 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300130 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300131 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300132}
133
134static char tree__folded_sign(bool unfolded)
135{
136 return unfolded ? '-' : '+';
137}
138
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300139static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300140{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300141 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300142}
143
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300144static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300146 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300147}
148
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300149static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300150{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300151 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300152}
153
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300154static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300155{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300156 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300157}
158
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300159static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300160{
161 int n = 0;
162 struct rb_node *nd;
163
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300164 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300165 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
166 struct callchain_list *chain;
167 char folded_sign = ' '; /* No children */
168
169 list_for_each_entry(chain, &child->val, list) {
170 ++n;
171 /* We need this because we may not have children */
172 folded_sign = callchain_list__folded(chain);
173 if (folded_sign == '+')
174 break;
175 }
176
177 if (folded_sign == '-') /* Have children and they're unfolded */
178 n += callchain_node__count_rows_rb_tree(child);
179 }
180
181 return n;
182}
183
184static int callchain_node__count_rows(struct callchain_node *node)
185{
186 struct callchain_list *chain;
187 bool unfolded = false;
188 int n = 0;
189
190 list_for_each_entry(chain, &node->val, list) {
191 ++n;
192 unfolded = chain->ms.unfolded;
193 }
194
195 if (unfolded)
196 n += callchain_node__count_rows_rb_tree(node);
197
198 return n;
199}
200
201static int callchain__count_rows(struct rb_root *chain)
202{
203 struct rb_node *nd;
204 int n = 0;
205
206 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
207 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
208 n += callchain_node__count_rows(node);
209 }
210
211 return n;
212}
213
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300214static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300215{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300216 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200217 return false;
218
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300219 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300220 return false;
221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300222 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300223 return true;
224}
225
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300226static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300227{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300228 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300230 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300231 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
232 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300233 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300234
235 list_for_each_entry(chain, &child->val, list) {
236 if (first) {
237 first = false;
238 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300239 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300240 } else
241 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300242 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300243 }
244
245 callchain_node__init_have_children_rb_tree(child);
246 }
247}
248
Namhyung Kima7444af2014-11-24 17:13:27 +0900249static void callchain_node__init_have_children(struct callchain_node *node,
250 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300251{
252 struct callchain_list *chain;
253
Namhyung Kima7444af2014-11-24 17:13:27 +0900254 chain = list_entry(node->val.next, struct callchain_list, list);
255 chain->ms.has_children = has_sibling;
256
Namhyung Kim82162b52014-08-13 15:02:41 +0900257 if (!list_empty(&node->val)) {
258 chain = list_entry(node->val.prev, struct callchain_list, list);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300259 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900260 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300261
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300262 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300263}
264
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300265static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300266{
Namhyung Kima7444af2014-11-24 17:13:27 +0900267 struct rb_node *nd = rb_first(root);
268 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300269
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300270 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300271 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900272 callchain_node__init_have_children(node, has_sibling);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300273 }
274}
275
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300276static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300277{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300278 if (!he->init_have_children) {
279 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
280 callchain__init_have_children(&he->sorted_chain);
281 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300282 }
283}
284
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300285static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300286{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300287 if (map_symbol__toggle_fold(browser->selection)) {
288 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300289
290 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900291 browser->b.nr_entries -= he->nr_rows;
292 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300293
294 if (he->ms.unfolded)
295 he->nr_rows = callchain__count_rows(&he->sorted_chain);
296 else
297 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900298
299 browser->b.nr_entries += he->nr_rows;
300 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300301
302 return true;
303 }
304
305 /* If it doesn't have children, no toggling performed */
306 return false;
307}
308
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300309static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300310{
311 int n = 0;
312 struct rb_node *nd;
313
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300314 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300315 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
316 struct callchain_list *chain;
317 bool has_children = false;
318
319 list_for_each_entry(chain, &child->val, list) {
320 ++n;
321 map_symbol__set_folding(&chain->ms, unfold);
322 has_children = chain->ms.has_children;
323 }
324
325 if (has_children)
326 n += callchain_node__set_folding_rb_tree(child, unfold);
327 }
328
329 return n;
330}
331
332static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
333{
334 struct callchain_list *chain;
335 bool has_children = false;
336 int n = 0;
337
338 list_for_each_entry(chain, &node->val, list) {
339 ++n;
340 map_symbol__set_folding(&chain->ms, unfold);
341 has_children = chain->ms.has_children;
342 }
343
344 if (has_children)
345 n += callchain_node__set_folding_rb_tree(node, unfold);
346
347 return n;
348}
349
350static int callchain__set_folding(struct rb_root *chain, bool unfold)
351{
352 struct rb_node *nd;
353 int n = 0;
354
355 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
356 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
357 n += callchain_node__set_folding(node, unfold);
358 }
359
360 return n;
361}
362
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300363static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300364{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300365 hist_entry__init_have_children(he);
366 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300367
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368 if (he->ms.has_children) {
369 int n = callchain__set_folding(&he->sorted_chain, unfold);
370 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300371 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300372 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300373}
374
Namhyung Kimc3b78952014-04-22 15:56:17 +0900375static void
376__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300377{
378 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900379 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300380
Namhyung Kimc3b78952014-04-22 15:56:17 +0900381 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900382 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900383 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300384 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
385 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900386 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300387 }
388}
389
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300390static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300391{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900392 browser->nr_callchain_rows = 0;
393 __hist_browser__set_folding(browser, unfold);
394
395 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300396 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300397 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300398}
399
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200400static void ui_browser__warn_lost_events(struct ui_browser *browser)
401{
402 ui_browser__warning(browser, 4,
403 "Events are being lost, check IO/CPU overload!\n\n"
404 "You may want to run 'perf' using a RT scheduler policy:\n\n"
405 " perf top -r 80\n\n"
406 "Or reduce the sampling frequency.");
407}
408
Jiri Olsadd00d482014-06-19 13:41:13 +0200409static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900410 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300411{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300412 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300413 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900414 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300415
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300416 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900417 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300418
Taeung Song1e378eb2014-10-07 16:13:15 +0900419 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300420
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300421 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300422 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300423 return -1;
424
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300425 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300426 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300427
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300428 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900429 case K_TIMER: {
430 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900431 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900432
Namhyung Kimc3b78952014-04-22 15:56:17 +0900433 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900434 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900435
Namhyung Kimc3b78952014-04-22 15:56:17 +0900436 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900437 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200438
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300439 if (browser->hists->stats.nr_lost_warned !=
440 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
441 browser->hists->stats.nr_lost_warned =
442 browser->hists->stats.nr_events[PERF_RECORD_LOST];
443 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200444 }
445
Taeung Song1e378eb2014-10-07 16:13:15 +0900446 hists__browser_title(browser->hists,
447 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300448 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300449 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900450 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300451 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300452 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300453 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300454 struct hist_entry, rb_node);
455 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300456 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 -0300457 seq++, browser->b.nr_entries,
458 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300459 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300460 browser->b.index,
461 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300462 h->row_offset, h->nr_rows);
463 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300464 break;
465 case 'C':
466 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300467 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300468 break;
469 case 'E':
470 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300471 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300472 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200473 case 'H':
474 browser->show_headers = !browser->show_headers;
475 hist_browser__update_rows(browser);
476 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200477 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300478 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300479 break;
480 /* fall thru */
481 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300482 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300483 }
484 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300485out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300486 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300487 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300488}
489
Namhyung Kim39ee5332014-08-22 09:13:21 +0900490struct callchain_print_arg {
491 /* for hists browser */
492 off_t row_offset;
493 bool is_current_entry;
494
495 /* for file dump */
496 FILE *fp;
497 int printed;
498};
499
500typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
501 struct callchain_list *chain,
502 const char *str, int offset,
503 unsigned short row,
504 struct callchain_print_arg *arg);
505
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900506static void hist_browser__show_callchain_entry(struct hist_browser *browser,
507 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900508 const char *str, int offset,
509 unsigned short row,
510 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900511{
512 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900513 char folded_sign = callchain_list__folded(chain);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900514
515 color = HE_COLORSET_NORMAL;
516 width = browser->b.width - (offset + 2);
517 if (ui_browser__is_current_entry(&browser->b, row)) {
518 browser->selection = &chain->ms;
519 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900520 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900521 }
522
523 ui_browser__set_color(&browser->b, color);
524 hist_browser__gotorc(browser, row, 0);
525 slsmg_write_nstring(" ", offset);
526 slsmg_printf("%c ", folded_sign);
527 slsmg_write_nstring(str, width);
528}
529
Namhyung Kim39ee5332014-08-22 09:13:21 +0900530static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
531 struct callchain_list *chain,
532 const char *str, int offset,
533 unsigned short row __maybe_unused,
534 struct callchain_print_arg *arg)
535{
536 char folded_sign = callchain_list__folded(chain);
537
538 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
539 folded_sign, str);
540}
541
542typedef bool (*check_output_full_fn)(struct hist_browser *browser,
543 unsigned short row);
544
545static bool hist_browser__check_output_full(struct hist_browser *browser,
546 unsigned short row)
547{
548 return browser->b.rows == row;
549}
550
551static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
552 unsigned short row __maybe_unused)
553{
554 return false;
555}
556
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300557#define LEVEL_OFFSET_STEP 3
558
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900559static int hist_browser__show_callchain(struct hist_browser *browser,
560 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900561 unsigned short row, u64 total,
562 print_callchain_entry_fn print,
563 struct callchain_print_arg *arg,
564 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300565{
566 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900567 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900568 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900569 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300570
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900571 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900572 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900573
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300574 while (node) {
575 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
576 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100577 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300578 struct callchain_list *chain;
579 char folded_sign = ' ';
580 int first = true;
581 int extra_offset = 0;
582
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300583 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300584 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300585 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300586 bool was_first = first;
587
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300588 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300589 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900590 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300591 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592
593 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900594 if (arg->row_offset != 0) {
595 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300596 goto do_next;
597 }
598
599 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300600 str = callchain_list__sym_name(chain, bf, sizeof(bf),
601 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900602
Namhyung Kim4087d112014-11-24 17:13:26 +0900603 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900604 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300605
606 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
607 str = "Not enough memory!";
608 else
609 str = alloc_str;
610 }
611
Namhyung Kim39ee5332014-08-22 09:13:21 +0900612 print(browser, chain, str, offset + extra_offset, row, arg);
613
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300614 free(alloc_str);
615
Namhyung Kim39ee5332014-08-22 09:13:21 +0900616 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300617 goto out;
618do_next:
619 if (folded_sign == '+')
620 break;
621 }
622
623 if (folded_sign == '-') {
624 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900625
626 if (callchain_param.mode == CHAIN_GRAPH_REL)
627 new_total = child->children_hit;
628 else
629 new_total = total;
630
631 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900632 new_level, row, new_total,
633 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300634 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900635 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900636 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300637 node = next;
638 }
639out:
640 return row - first_row;
641}
642
Namhyung Kim89701462013-01-22 18:09:38 +0900643struct hpp_arg {
644 struct ui_browser *b;
645 char folded_sign;
646 bool current_entry;
647};
648
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900649static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
650{
651 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900652 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900653 va_list args;
654 double percent;
655
656 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900657 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900658 percent = va_arg(args, double);
659 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900660
Namhyung Kim89701462013-01-22 18:09:38 +0900661 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900662
Namhyung Kimd6751072014-07-31 14:47:36 +0900663 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900664 slsmg_printf("%s", hpp->buf);
665
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900666 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900667 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900668}
669
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900670#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900671static u64 __hpp_get_##_field(struct hist_entry *he) \
672{ \
673 return he->stat._field; \
674} \
675 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100676static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900677hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100678 struct perf_hpp *hpp, \
679 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900680{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900681 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
682 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900683}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900684
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900685#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
686static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
687{ \
688 return he->stat_acc->_field; \
689} \
690 \
691static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900692hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900693 struct perf_hpp *hpp, \
694 struct hist_entry *he) \
695{ \
696 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900697 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900698 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900699 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900700 slsmg_printf("%s", hpp->buf); \
701 \
702 return ret; \
703 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900704 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
705 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900706}
707
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900708__HPP_COLOR_PERCENT_FN(overhead, period)
709__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
710__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
711__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
712__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900713__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900714
715#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900716#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900717
718void hist_browser__init_hpp(void)
719{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900720 perf_hpp__format[PERF_HPP__OVERHEAD].color =
721 hist_browser__hpp_color_overhead;
722 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
723 hist_browser__hpp_color_overhead_sys;
724 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
725 hist_browser__hpp_color_overhead_us;
726 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
727 hist_browser__hpp_color_overhead_guest_sys;
728 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
729 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900730 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
731 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900732}
733
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300734static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300735 struct hist_entry *entry,
736 unsigned short row)
737{
738 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200739 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900740 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300741 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300742 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300743 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300744 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200745 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300746
747 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300748 browser->he_selection = entry;
749 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300750 }
751
752 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300753 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300754 folded_sign = hist_entry__folded(entry);
755 }
756
757 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900758 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900759 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900760 .folded_sign = folded_sign,
761 .current_entry = current_entry,
762 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900763 struct perf_hpp hpp = {
764 .buf = s,
765 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900766 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900767 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300768
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300769 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900770
Jiri Olsa12400052012-10-13 00:06:16 +0200771 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900772 if (perf_hpp__should_skip(fmt))
773 continue;
774
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900775 if (current_entry && browser->b.navkeypressed) {
776 ui_browser__set_color(&browser->b,
777 HE_COLORSET_SELECTED);
778 } else {
779 ui_browser__set_color(&browser->b,
780 HE_COLORSET_NORMAL);
781 }
782
783 if (first) {
784 if (symbol_conf.use_callchain) {
785 slsmg_printf("%c ", folded_sign);
786 width -= 2;
787 }
788 first = false;
789 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900790 slsmg_printf(" ");
791 width -= 2;
792 }
793
Jiri Olsa12400052012-10-13 00:06:16 +0200794 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100795 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900796 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100797 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900798 slsmg_printf("%s", s);
799 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300800 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200801
802 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300803 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200804 width += 1;
805
Namhyung Kim26d8b332014-03-03 16:16:20 +0900806 slsmg_write_nstring("", width);
807
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300808 ++row;
809 ++printed;
810 } else
811 --row_offset;
812
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300813 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900814 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900815 struct callchain_print_arg arg = {
816 .row_offset = row_offset,
817 .is_current_entry = current_entry,
818 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900819
Namhyung Kim4087d112014-11-24 17:13:26 +0900820 if (callchain_param.mode == CHAIN_GRAPH_REL) {
821 if (symbol_conf.cumulate_callchain)
822 total = entry->stat_acc->period;
823 else
824 total = entry->stat.period;
825 }
826
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900827 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900828 &entry->sorted_chain, 1, row, total,
829 hist_browser__show_callchain_entry, &arg,
830 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900831
Namhyung Kim39ee5332014-08-22 09:13:21 +0900832 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300833 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300834 }
835
836 return printed;
837}
838
Jiri Olsa81a888f2014-06-14 15:44:52 +0200839static int advance_hpp_check(struct perf_hpp *hpp, int inc)
840{
841 advance_hpp(hpp, inc);
842 return hpp->size <= 0;
843}
844
845static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
846{
847 struct perf_hpp dummy_hpp = {
848 .buf = buf,
849 .size = size,
850 };
851 struct perf_hpp_fmt *fmt;
852 size_t ret = 0;
853
854 if (symbol_conf.use_callchain) {
855 ret = scnprintf(buf, size, " ");
856 if (advance_hpp_check(&dummy_hpp, ret))
857 return ret;
858 }
859
860 perf_hpp__for_each_format(fmt) {
861 if (perf_hpp__should_skip(fmt))
862 continue;
863
Jiri Olsa81a888f2014-06-14 15:44:52 +0200864 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
865 if (advance_hpp_check(&dummy_hpp, ret))
866 break;
867
868 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
869 if (advance_hpp_check(&dummy_hpp, ret))
870 break;
871 }
872
873 return ret;
874}
875
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200876static void hist_browser__show_headers(struct hist_browser *browser)
877{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200878 char headers[1024];
879
880 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200881 ui_browser__gotorc(&browser->b, 0, 0);
882 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200883 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200884}
885
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300886static void ui_browser__hists_init_top(struct ui_browser *browser)
887{
888 if (browser->top == NULL) {
889 struct hist_browser *hb;
890
891 hb = container_of(browser, struct hist_browser, b);
892 browser->top = rb_first(&hb->hists->entries);
893 }
894}
895
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300896static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300897{
898 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200899 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300900 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300901 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300902
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200903 if (hb->show_headers) {
904 hist_browser__show_headers(hb);
905 header_offset = 1;
906 }
907
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300908 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300909
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300910 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300911 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900912 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300913
914 if (h->filtered)
915 continue;
916
Namhyung Kim14135662013-10-31 10:17:39 +0900917 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900918 if (percent < hb->min_pcnt)
919 continue;
920
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300921 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300922 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300923 break;
924 }
925
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200926 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300927}
928
Namhyung Kim064f1982013-05-14 11:09:04 +0900929static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900930 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300931{
932 while (nd != NULL) {
933 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900934 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900935
Namhyung Kimc0f15272014-04-16 11:16:33 +0900936 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300937 return nd;
938
939 nd = rb_next(nd);
940 }
941
942 return NULL;
943}
944
Namhyung Kim064f1982013-05-14 11:09:04 +0900945static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900946 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300947{
948 while (nd != NULL) {
949 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900950 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900951
952 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300953 return nd;
954
955 nd = rb_prev(nd);
956 }
957
958 return NULL;
959}
960
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300961static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300962 off_t offset, int whence)
963{
964 struct hist_entry *h;
965 struct rb_node *nd;
966 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900967 struct hist_browser *hb;
968
969 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300970
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300971 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300972 return;
973
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300974 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300975
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300976 switch (whence) {
977 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900978 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900979 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300980 break;
981 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300982 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300983 goto do_offset;
984 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900985 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900986 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300987 first = false;
988 break;
989 default:
990 return;
991 }
992
993 /*
994 * Moves not relative to the first visible entry invalidates its
995 * row_offset:
996 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300997 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300998 h->row_offset = 0;
999
1000 /*
1001 * Here we have to check if nd is expanded (+), if it is we can't go
1002 * the next top level hist_entry, instead we must compute an offset of
1003 * what _not_ to show and not change the first visible entry.
1004 *
1005 * This offset increments when we are going from top to bottom and
1006 * decreases when we're going from bottom to top.
1007 *
1008 * As we don't have backpointers to the top level in the callchains
1009 * structure, we need to always print the whole hist_entry callchain,
1010 * skipping the first ones that are before the first visible entry
1011 * and stop when we printed enough lines to fill the screen.
1012 */
1013do_offset:
1014 if (offset > 0) {
1015 do {
1016 h = rb_entry(nd, struct hist_entry, rb_node);
1017 if (h->ms.unfolded) {
1018 u16 remaining = h->nr_rows - h->row_offset;
1019 if (offset > remaining) {
1020 offset -= remaining;
1021 h->row_offset = 0;
1022 } else {
1023 h->row_offset += offset;
1024 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001025 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001026 break;
1027 }
1028 }
Namhyung Kim14135662013-10-31 10:17:39 +09001029 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001030 if (nd == NULL)
1031 break;
1032 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001033 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001034 } while (offset != 0);
1035 } else if (offset < 0) {
1036 while (1) {
1037 h = rb_entry(nd, struct hist_entry, rb_node);
1038 if (h->ms.unfolded) {
1039 if (first) {
1040 if (-offset > h->row_offset) {
1041 offset += h->row_offset;
1042 h->row_offset = 0;
1043 } else {
1044 h->row_offset += offset;
1045 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001046 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001047 break;
1048 }
1049 } else {
1050 if (-offset > h->nr_rows) {
1051 offset += h->nr_rows;
1052 h->row_offset = 0;
1053 } else {
1054 h->row_offset = h->nr_rows + offset;
1055 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001056 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001057 break;
1058 }
1059 }
1060 }
1061
Namhyung Kim14135662013-10-31 10:17:39 +09001062 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001063 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001064 if (nd == NULL)
1065 break;
1066 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001067 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001068 if (offset == 0) {
1069 /*
1070 * Last unfiltered hist_entry, check if it is
1071 * unfolded, if it is then we should have
1072 * row_offset at its last entry.
1073 */
1074 h = rb_entry(nd, struct hist_entry, rb_node);
1075 if (h->ms.unfolded)
1076 h->row_offset = h->nr_rows;
1077 break;
1078 }
1079 first = false;
1080 }
1081 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001082 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001083 h = rb_entry(nd, struct hist_entry, rb_node);
1084 h->row_offset = 0;
1085 }
1086}
1087
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001088static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001089 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001090{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001091 u64 total = hists__total_period(he->hists);
1092 struct callchain_print_arg arg = {
1093 .fp = fp,
1094 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001095
Namhyung Kim39ee5332014-08-22 09:13:21 +09001096 if (symbol_conf.cumulate_callchain)
1097 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001098
Namhyung Kim39ee5332014-08-22 09:13:21 +09001099 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1100 hist_browser__fprintf_callchain_entry, &arg,
1101 hist_browser__check_dump_full);
1102 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001103}
1104
1105static int hist_browser__fprintf_entry(struct hist_browser *browser,
1106 struct hist_entry *he, FILE *fp)
1107{
1108 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001109 int printed = 0;
1110 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001111 struct perf_hpp hpp = {
1112 .buf = s,
1113 .size = sizeof(s),
1114 };
1115 struct perf_hpp_fmt *fmt;
1116 bool first = true;
1117 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001118
1119 if (symbol_conf.use_callchain)
1120 folded_sign = hist_entry__folded(he);
1121
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001122 if (symbol_conf.use_callchain)
1123 printed += fprintf(fp, "%c ", folded_sign);
1124
Namhyung Kim26d8b332014-03-03 16:16:20 +09001125 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001126 if (perf_hpp__should_skip(fmt))
1127 continue;
1128
Namhyung Kim26d8b332014-03-03 16:16:20 +09001129 if (!first) {
1130 ret = scnprintf(hpp.buf, hpp.size, " ");
1131 advance_hpp(&hpp, ret);
1132 } else
1133 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001134
Namhyung Kim26d8b332014-03-03 16:16:20 +09001135 ret = fmt->entry(fmt, &hpp, he);
1136 advance_hpp(&hpp, ret);
1137 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001138 printed += fprintf(fp, "%s\n", rtrim(s));
1139
1140 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001141 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001142
1143 return printed;
1144}
1145
1146static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1147{
Namhyung Kim064f1982013-05-14 11:09:04 +09001148 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001149 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001150 int printed = 0;
1151
1152 while (nd) {
1153 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1154
1155 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001156 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001157 }
1158
1159 return printed;
1160}
1161
1162static int hist_browser__dump(struct hist_browser *browser)
1163{
1164 char filename[64];
1165 FILE *fp;
1166
1167 while (1) {
1168 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1169 if (access(filename, F_OK))
1170 break;
1171 /*
1172 * XXX: Just an arbitrary lazy upper limit
1173 */
1174 if (++browser->print_seq == 8192) {
1175 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1176 return -1;
1177 }
1178 }
1179
1180 fp = fopen(filename, "w");
1181 if (fp == NULL) {
1182 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001183 const char *err = strerror_r(errno, bf, sizeof(bf));
1184 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001185 return -1;
1186 }
1187
1188 ++browser->print_seq;
1189 hist_browser__fprintf(browser, fp);
1190 fclose(fp);
1191 ui_helpline__fpush("%s written!", filename);
1192
1193 return 0;
1194}
1195
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196static struct hist_browser *hist_browser__new(struct hists *hists)
1197{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001198 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001200 if (browser) {
1201 browser->hists = hists;
1202 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001203 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001204 browser->b.seek = ui_browser__hists_seek;
1205 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001206 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207 }
1208
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001209 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001210}
1211
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001212static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001213{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001214 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215}
1216
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001217static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001219 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220}
1221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001222static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001223{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001224 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001225}
1226
Taeung Song1e378eb2014-10-07 16:13:15 +09001227/* Check whether the browser is for 'top' or 'report' */
1228static inline bool is_report_browser(void *timer)
1229{
1230 return timer == NULL;
1231}
1232
1233static int hists__browser_title(struct hists *hists,
1234 struct hist_browser_timer *hbt,
1235 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001236{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001237 char unit;
1238 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001239 const struct dso *dso = hists->dso_filter;
1240 const struct thread *thread = hists->thread_filter;
1241 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1242 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001243 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001244 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001245 char buf[512];
1246 size_t buflen = sizeof(buf);
1247
Namhyung Kimf2148332014-01-14 11:52:48 +09001248 if (symbol_conf.filter_relative) {
1249 nr_samples = hists->stats.nr_non_filtered_samples;
1250 nr_events = hists->stats.total_non_filtered_period;
1251 }
1252
Namhyung Kim759ff492013-03-05 14:53:26 +09001253 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001254 struct perf_evsel *pos;
1255
1256 perf_evsel__group_desc(evsel, buf, buflen);
1257 ev_name = buf;
1258
1259 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001260 struct hists *pos_hists = evsel__hists(pos);
1261
Namhyung Kimf2148332014-01-14 11:52:48 +09001262 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001263 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1264 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001265 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001266 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1267 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001268 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001269 }
1270 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001271
Ashay Ranecc6862802012-04-05 21:01:01 -05001272 nr_samples = convert_unit(nr_samples, &unit);
1273 printed = scnprintf(bf, size,
Tom Huynhe641f692014-12-02 11:37:22 -06001274 "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
Ashay Ranecc6862802012-04-05 21:01:01 -05001275 nr_samples, unit, ev_name, nr_events);
1276
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001277
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001278 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001279 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001280 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001281 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001282 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001283 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001284 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001285 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001286 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001287 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001288 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001289 if (!is_report_browser(hbt)) {
1290 struct perf_top *top = hbt->arg;
1291
1292 if (top->zero)
1293 printed += scnprintf(bf + printed, size - printed, " [z]");
1294 }
1295
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001296 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001297}
1298
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001299static inline void free_popup_options(char **options, int n)
1300{
1301 int i;
1302
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001303 for (i = 0; i < n; ++i)
1304 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001305}
1306
Feng Tang341487ab2013-02-03 14:38:20 +08001307/*
1308 * Only runtime switching of perf data file will make "input_name" point
1309 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1310 * whether we need to call free() for current "input_name" during the switch.
1311 */
1312static bool is_input_name_malloced = false;
1313
1314static int switch_data_file(void)
1315{
1316 char *pwd, *options[32], *abs_path[32], *tmp;
1317 DIR *pwd_dir;
1318 int nr_options = 0, choice = -1, ret = -1;
1319 struct dirent *dent;
1320
1321 pwd = getenv("PWD");
1322 if (!pwd)
1323 return ret;
1324
1325 pwd_dir = opendir(pwd);
1326 if (!pwd_dir)
1327 return ret;
1328
1329 memset(options, 0, sizeof(options));
1330 memset(options, 0, sizeof(abs_path));
1331
1332 while ((dent = readdir(pwd_dir))) {
1333 char path[PATH_MAX];
1334 u64 magic;
1335 char *name = dent->d_name;
1336 FILE *file;
1337
1338 if (!(dent->d_type == DT_REG))
1339 continue;
1340
1341 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1342
1343 file = fopen(path, "r");
1344 if (!file)
1345 continue;
1346
1347 if (fread(&magic, 1, 8, file) < 8)
1348 goto close_file_and_continue;
1349
1350 if (is_perf_magic(magic)) {
1351 options[nr_options] = strdup(name);
1352 if (!options[nr_options])
1353 goto close_file_and_continue;
1354
1355 abs_path[nr_options] = strdup(path);
1356 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001357 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001358 ui__warning("Can't search all data files due to memory shortage.\n");
1359 fclose(file);
1360 break;
1361 }
1362
1363 nr_options++;
1364 }
1365
1366close_file_and_continue:
1367 fclose(file);
1368 if (nr_options >= 32) {
1369 ui__warning("Too many perf data files in PWD!\n"
1370 "Only the first 32 files will be listed.\n");
1371 break;
1372 }
1373 }
1374 closedir(pwd_dir);
1375
1376 if (nr_options) {
1377 choice = ui__popup_menu(nr_options, options);
1378 if (choice < nr_options && choice >= 0) {
1379 tmp = strdup(abs_path[choice]);
1380 if (tmp) {
1381 if (is_input_name_malloced)
1382 free((void *)input_name);
1383 input_name = tmp;
1384 is_input_name_malloced = true;
1385 ret = 0;
1386 } else
1387 ui__warning("Data switch failed due to memory shortage!\n");
1388 }
1389 }
1390
1391 free_popup_options(options, nr_options);
1392 free_popup_options(abs_path, nr_options);
1393 return ret;
1394}
1395
Namhyung Kim112f7612014-04-22 14:05:35 +09001396static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001397{
1398 u64 nr_entries = 0;
1399 struct rb_node *nd = rb_first(&hb->hists->entries);
1400
Namhyung Kim268397c2014-04-22 14:49:31 +09001401 if (hb->min_pcnt == 0) {
1402 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1403 return;
1404 }
1405
Namhyung Kim14135662013-10-31 10:17:39 +09001406 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001407 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001408 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001409 }
1410
Namhyung Kim112f7612014-04-22 14:05:35 +09001411 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001412}
Feng Tang341487ab2013-02-03 14:38:20 +08001413
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001414static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001415 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001416 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001417 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001418 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001419 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001420{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001421 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001422 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001423 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001424 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001425 char *options[16];
1426 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001427 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001428 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001429 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001430 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001431 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001432
Namhyung Kime8e684a2013-12-26 14:37:58 +09001433#define HIST_BROWSER_HELP_COMMON \
1434 "h/?/F1 Show this window\n" \
1435 "UP/DOWN/PGUP\n" \
1436 "PGDN/SPACE Navigate\n" \
1437 "q/ESC/CTRL+C Exit browser\n\n" \
1438 "For multiple event sessions:\n\n" \
1439 "TAB/UNTAB Switch events\n\n" \
1440 "For symbolic views (--sort has sym):\n\n" \
1441 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1442 "<- Zoom out\n" \
1443 "a Annotate current symbol\n" \
1444 "C Collapse all callchains\n" \
1445 "d Zoom into current DSO\n" \
1446 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001447 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001448 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001449
1450 /* help messages are sorted by lexical order of the hotkey */
1451 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001452 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001453 "P Print histograms to perf.hist.N\n"
1454 "r Run available scripts\n"
1455 "s Switch to another data file in PWD\n"
1456 "t Zoom into current Thread\n"
1457 "V Verbose (DSO names in callchains, etc)\n"
1458 "/ Filter symbol by name";
1459 const char top_help[] = HIST_BROWSER_HELP_COMMON
1460 "P Print histograms to perf.hist.N\n"
1461 "t Zoom into current Thread\n"
1462 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001463 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001464 "/ Filter symbol by name";
1465
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001466 if (browser == NULL)
1467 return -1;
1468
Namhyung Kim064f1982013-05-14 11:09:04 +09001469 if (min_pcnt) {
1470 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001471 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001472 }
1473
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001474 fstack = pstack__new(2);
1475 if (fstack == NULL)
1476 goto out;
1477
1478 ui_helpline__push(helpline);
1479
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001480 memset(options, 0, sizeof(options));
1481
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001482 perf_hpp__for_each_format(fmt)
1483 perf_hpp__reset_width(fmt, hists);
1484
Namhyung Kim5b591662014-07-31 14:47:38 +09001485 if (symbol_conf.col_width_list_str)
1486 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1487
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001488 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001489 struct thread *thread = NULL;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001490 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001491 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001492 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001493 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001494 int scripts_comm = -2, scripts_symbol = -2,
1495 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001496
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001497 nr_options = 0;
1498
Jiri Olsadd00d482014-06-19 13:41:13 +02001499 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001500
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001501 if (browser->he_selection != NULL) {
1502 thread = hist_browser__selected_thread(browser);
1503 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1504 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001505 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001506 case K_TAB:
1507 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001508 if (nr_events == 1)
1509 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001510 /*
1511 * Exit the browser, let hists__browser_tree
1512 * go to the next or previous
1513 */
1514 goto out_free_stack;
1515 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001516 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001517 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001518 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001519 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001520 continue;
1521 }
1522
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001523 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001524 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001525 browser->selection->map->dso->annotate_warned)
1526 continue;
1527 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001528 case 'P':
1529 hist_browser__dump(browser);
1530 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001531 case 'd':
1532 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001533 case 'V':
1534 browser->show_dso = !browser->show_dso;
1535 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001536 case 't':
1537 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001538 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001539 if (ui_browser__input_window("Symbol to show",
1540 "Please enter the name of symbol you want to see",
1541 buf, "ENTER: OK, ESC: Cancel",
1542 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001543 hists->symbol_filter_str = *buf ? buf : NULL;
1544 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001545 hist_browser__reset(browser);
1546 }
1547 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001548 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001549 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001550 goto do_scripts;
1551 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001552 case 's':
1553 if (is_report_browser(hbt))
1554 goto do_data_switch;
1555 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001556 case 'i':
1557 /* env->arch is NULL for live-mode (i.e. perf top) */
1558 if (env->arch)
1559 tui__header_window(env);
1560 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001561 case 'F':
1562 symbol_conf.filter_relative ^= 1;
1563 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001564 case 'z':
1565 if (!is_report_browser(hbt)) {
1566 struct perf_top *top = hbt->arg;
1567
1568 top->zero = !top->zero;
1569 }
1570 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001571 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001572 case 'h':
1573 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001574 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001575 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001576 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001577 case K_ENTER:
1578 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001579 /* menu */
1580 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001581 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001582 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001583
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001584 if (pstack__empty(fstack)) {
1585 /*
1586 * Go back to the perf_evsel_menu__run or other user
1587 */
1588 if (left_exits)
1589 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001590 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001591 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001592 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001593 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001594 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001595 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001596 goto zoom_out_thread;
1597 continue;
1598 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001599 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001600 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001601 !ui_browser__dialog_yesno(&browser->b,
1602 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001603 continue;
1604 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001605 case 'q':
1606 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001607 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001608 default:
1609 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001610 }
1611
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001612 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001613 goto add_exit_option;
1614
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001615 if (browser->selection == NULL)
1616 goto skip_annotation;
1617
Namhyung Kim55369fc2013-04-01 20:35:20 +09001618 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001619 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001620
1621 if (bi == NULL)
1622 goto skip_annotation;
1623
1624 if (bi->from.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001625 !bi->from.map->dso->annotate_warned &&
1626 asprintf(&options[nr_options], "Annotate %s",
1627 bi->from.sym->name) > 0)
1628 annotate_f = nr_options++;
1629
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001630 if (bi->to.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001631 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001632 (bi->to.sym != bi->from.sym ||
1633 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001634 asprintf(&options[nr_options], "Annotate %s",
1635 bi->to.sym->name) > 0)
1636 annotate_t = nr_options++;
1637 } else {
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001638 if (browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001639 !browser->selection->map->dso->annotate_warned) {
1640 struct annotation *notes;
1641
1642 notes = symbol__annotation(browser->selection->sym);
1643
1644 if (notes->src &&
1645 asprintf(&options[nr_options], "Annotate %s",
1646 browser->selection->sym->name) > 0)
1647 annotate = nr_options++;
1648 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001649 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001650skip_annotation:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001651 if (thread != NULL &&
1652 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001653 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001654 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001655 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001656 zoom_thread = nr_options++;
1657
1658 if (dso != NULL &&
1659 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001660 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001661 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1662 zoom_dso = nr_options++;
1663
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001664 if (browser->selection != NULL &&
1665 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001666 asprintf(&options[nr_options], "Browse map details") > 0)
1667 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001668
1669 /* perf script support */
1670 if (browser->he_selection) {
1671 struct symbol *sym;
1672
1673 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001674 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001675 scripts_comm = nr_options++;
1676
1677 sym = browser->he_selection->ms.sym;
1678 if (sym && sym->namelen &&
1679 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1680 sym->name) > 0)
1681 scripts_symbol = nr_options++;
1682 }
1683
1684 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1685 scripts_all = nr_options++;
1686
Feng Tang341487ab2013-02-03 14:38:20 +08001687 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1688 "Switch to another data file in PWD") > 0)
1689 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001690add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001691 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001692retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001693 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001694
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001695 if (choice == nr_options - 1)
1696 break;
1697
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001698 if (choice == -1) {
1699 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001700 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001701 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001702
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001703 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001704 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001705 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001706 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001707do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001708 if (!objdump_path && perf_session_env__lookup_objdump(env))
1709 continue;
1710
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001711 he = hist_browser__selected_entry(browser);
1712 if (he == NULL)
1713 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001714
1715 /*
1716 * we stash the branch_info symbol + map into the
1717 * the ms so we don't have to rewrite all the annotation
1718 * code to use branch_info.
1719 * in branch mode, the ms struct is not used
1720 */
1721 if (choice == annotate_f) {
1722 he->ms.sym = he->branch_info->from.sym;
1723 he->ms.map = he->branch_info->from.map;
1724 } else if (choice == annotate_t) {
1725 he->ms.sym = he->branch_info->to.sym;
1726 he->ms.map = he->branch_info->to.map;
1727 }
1728
Jiri Olsad7553302014-06-15 10:22:15 +02001729 notes = symbol__annotation(he->ms.sym);
1730 if (!notes->src)
1731 continue;
1732
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001733 /*
1734 * Don't let this be freed, say, by hists__decay_entry.
1735 */
1736 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001737 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001738 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001739 /*
1740 * offer option to annotate the other branch source or target
1741 * (if they exists) when returning from annotate
1742 */
1743 if ((err == 'q' || err == CTRL('c'))
1744 && annotate_t != -2 && annotate_f != -2)
1745 goto retry_popup_menu;
1746
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001747 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001748 if (err)
1749 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001750
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001751 } else if (choice == browse_map)
1752 map__browse(browser->selection->map);
1753 else if (choice == zoom_dso) {
1754zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001755 if (browser->hists->dso_filter) {
1756 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757zoom_out_dso:
1758 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001759 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001760 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761 } else {
1762 if (dso == NULL)
1763 continue;
1764 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1765 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001766 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001767 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001768 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001770 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001771 hist_browser__reset(browser);
1772 } else if (choice == zoom_thread) {
1773zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001774 if (browser->hists->thread_filter) {
1775 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001776zoom_out_thread:
1777 ui_helpline__pop();
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001778 thread__zput(browser->hists->thread_filter);
Jiri Olsaf2998422014-05-23 17:15:47 +02001779 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001780 } else {
1781 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001782 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001783 thread->tid);
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001784 browser->hists->thread_filter = thread__get(thread);
Jiri Olsaf2998422014-05-23 17:15:47 +02001785 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001786 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001787 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001788 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001789 hist_browser__reset(browser);
1790 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001791 /* perf scripts support */
1792 else if (choice == scripts_all || choice == scripts_comm ||
1793 choice == scripts_symbol) {
1794do_scripts:
1795 memset(script_opt, 0, 64);
1796
1797 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001798 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001799
1800 if (choice == scripts_symbol)
1801 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1802
1803 script_browse(script_opt);
1804 }
Feng Tang341487ab2013-02-03 14:38:20 +08001805 /* Switch to another data file */
1806 else if (choice == switch_data) {
1807do_data_switch:
1808 if (!switch_data_file()) {
1809 key = K_SWITCH_INPUT_DATA;
1810 break;
1811 } else
1812 ui__warning("Won't switch the data files due to\n"
1813 "no valid data file get selected!\n");
1814 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001815 }
1816out_free_stack:
1817 pstack__delete(fstack);
1818out:
1819 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001820 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001821 return key;
1822}
1823
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001824struct perf_evsel_menu {
1825 struct ui_browser b;
1826 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001827 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001828 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001829 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001830};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001831
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001832static void perf_evsel_menu__write(struct ui_browser *browser,
1833 void *entry, int row)
1834{
1835 struct perf_evsel_menu *menu = container_of(browser,
1836 struct perf_evsel_menu, b);
1837 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001838 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001839 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001840 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001841 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001842 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001843 const char *warn = " ";
1844 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001845
1846 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1847 HE_COLORSET_NORMAL);
1848
Namhyung Kim759ff492013-03-05 14:53:26 +09001849 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001850 struct perf_evsel *pos;
1851
1852 ev_name = perf_evsel__group_name(evsel);
1853
1854 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001855 struct hists *pos_hists = evsel__hists(pos);
1856 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001857 }
1858 }
1859
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001860 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001861 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001862 unit, unit == ' ' ? "" : " ", ev_name);
1863 slsmg_printf("%s", bf);
1864
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001865 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001866 if (nr_events != 0) {
1867 menu->lost_events = true;
1868 if (!current_entry)
1869 ui_browser__set_color(browser, HE_COLORSET_TOP);
1870 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001871 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1872 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001873 warn = bf;
1874 }
1875
1876 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001877
1878 if (current_entry)
1879 menu->selection = evsel;
1880}
1881
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001882static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1883 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001884 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001885{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001886 struct perf_evlist *evlist = menu->b.priv;
1887 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001888 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001889 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001890 int key;
1891
1892 if (ui_browser__show(&menu->b, title,
1893 "ESC: exit, ENTER|->: Browse histograms") < 0)
1894 return -1;
1895
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001896 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001897 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001898
1899 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001900 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001901 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001902
1903 if (!menu->lost_events_warned && menu->lost_events) {
1904 ui_browser__warn_lost_events(&menu->b);
1905 menu->lost_events_warned = true;
1906 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001907 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001908 case K_RIGHT:
1909 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001910 if (!menu->selection)
1911 continue;
1912 pos = menu->selection;
1913browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001914 perf_evlist__set_selected(evlist, pos);
1915 /*
1916 * Give the calling tool a chance to populate the non
1917 * default evsel resorted hists tree.
1918 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001919 if (hbt)
1920 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001921 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001922 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001923 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001924 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001925 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001926 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001927 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001928 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001929 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001930 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001931 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001932 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001933 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001934 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001935 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001936 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001937 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001938 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001939 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001940 if (!ui_browser__dialog_yesno(&menu->b,
1941 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001942 continue;
1943 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001944 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001945 case 'q':
1946 case CTRL('c'):
1947 goto out;
1948 default:
1949 continue;
1950 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001951 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001952 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001953 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001954 if (!ui_browser__dialog_yesno(&menu->b,
1955 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001956 continue;
1957 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001958 case 'q':
1959 case CTRL('c'):
1960 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001961 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001962 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001963 }
1964 }
1965
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001966out:
1967 ui_browser__hide(&menu->b);
1968 return key;
1969}
1970
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001971static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001972 void *entry)
1973{
1974 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1975
1976 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1977 return true;
1978
1979 return false;
1980}
1981
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001982static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001983 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001984 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001985 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001986 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001987{
1988 struct perf_evsel *pos;
1989 struct perf_evsel_menu menu = {
1990 .b = {
1991 .entries = &evlist->entries,
1992 .refresh = ui_browser__list_head_refresh,
1993 .seek = ui_browser__list_head_seek,
1994 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001995 .filter = filter_group_entries,
1996 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001997 .priv = evlist,
1998 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001999 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002000 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002001 };
2002
2003 ui_helpline__push("Press ESC to exit");
2004
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002005 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002006 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002007 size_t line_len = strlen(ev_name) + 7;
2008
2009 if (menu.b.width < line_len)
2010 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002011 }
2012
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002013 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002014}
2015
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002016int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002017 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002018 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002019 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002020{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002021 int nr_entries = evlist->nr_entries;
2022
2023single_entry:
2024 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002025 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002026
2027 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002028 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002029 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002030 }
2031
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002032 if (symbol_conf.event_group) {
2033 struct perf_evsel *pos;
2034
2035 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002036 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002037 if (perf_evsel__is_group_leader(pos))
2038 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002039 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002040
2041 if (nr_entries == 1)
2042 goto single_entry;
2043 }
2044
2045 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002046 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002047}