blob: 995b7a8596b1420e9764f08f18326d319f2a0a31 [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);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300514 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900515
516 color = HE_COLORSET_NORMAL;
517 width = browser->b.width - (offset + 2);
518 if (ui_browser__is_current_entry(&browser->b, row)) {
519 browser->selection = &chain->ms;
520 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900521 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900522 }
523
524 ui_browser__set_color(&browser->b, color);
525 hist_browser__gotorc(browser, row, 0);
526 slsmg_write_nstring(" ", offset);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300527 slsmg_printf("%c", folded_sign);
528 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900529 slsmg_write_nstring(str, width);
530}
531
Namhyung Kim39ee5332014-08-22 09:13:21 +0900532static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
533 struct callchain_list *chain,
534 const char *str, int offset,
535 unsigned short row __maybe_unused,
536 struct callchain_print_arg *arg)
537{
538 char folded_sign = callchain_list__folded(chain);
539
540 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
541 folded_sign, str);
542}
543
544typedef bool (*check_output_full_fn)(struct hist_browser *browser,
545 unsigned short row);
546
547static bool hist_browser__check_output_full(struct hist_browser *browser,
548 unsigned short row)
549{
550 return browser->b.rows == row;
551}
552
553static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
554 unsigned short row __maybe_unused)
555{
556 return false;
557}
558
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300559#define LEVEL_OFFSET_STEP 3
560
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900561static int hist_browser__show_callchain(struct hist_browser *browser,
562 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900563 unsigned short row, u64 total,
564 print_callchain_entry_fn print,
565 struct callchain_print_arg *arg,
566 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300567{
568 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900569 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900570 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900571 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300572
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900573 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900574 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900575
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300576 while (node) {
577 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
578 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100579 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300580 struct callchain_list *chain;
581 char folded_sign = ' ';
582 int first = true;
583 int extra_offset = 0;
584
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300585 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300586 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300587 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300588 bool was_first = first;
589
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300590 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300591 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900592 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300593 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300594
595 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900596 if (arg->row_offset != 0) {
597 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300598 goto do_next;
599 }
600
601 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300602 str = callchain_list__sym_name(chain, bf, sizeof(bf),
603 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900604
Namhyung Kim4087d112014-11-24 17:13:26 +0900605 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900606 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607
608 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
609 str = "Not enough memory!";
610 else
611 str = alloc_str;
612 }
613
Namhyung Kim39ee5332014-08-22 09:13:21 +0900614 print(browser, chain, str, offset + extra_offset, row, arg);
615
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300616 free(alloc_str);
617
Namhyung Kim39ee5332014-08-22 09:13:21 +0900618 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300619 goto out;
620do_next:
621 if (folded_sign == '+')
622 break;
623 }
624
625 if (folded_sign == '-') {
626 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900627
628 if (callchain_param.mode == CHAIN_GRAPH_REL)
629 new_total = child->children_hit;
630 else
631 new_total = total;
632
633 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900634 new_level, row, new_total,
635 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300636 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900637 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900638 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300639 node = next;
640 }
641out:
642 return row - first_row;
643}
644
Namhyung Kim89701462013-01-22 18:09:38 +0900645struct hpp_arg {
646 struct ui_browser *b;
647 char folded_sign;
648 bool current_entry;
649};
650
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900651static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
652{
653 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900654 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900655 va_list args;
656 double percent;
657
658 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900659 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900660 percent = va_arg(args, double);
661 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900662
Namhyung Kim89701462013-01-22 18:09:38 +0900663 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900664
Namhyung Kimd6751072014-07-31 14:47:36 +0900665 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900666 slsmg_printf("%s", hpp->buf);
667
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900668 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900669 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900670}
671
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900672#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900673static u64 __hpp_get_##_field(struct hist_entry *he) \
674{ \
675 return he->stat._field; \
676} \
677 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100678static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900679hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100680 struct perf_hpp *hpp, \
681 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900682{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900683 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
684 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900685}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900686
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900687#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
688static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
689{ \
690 return he->stat_acc->_field; \
691} \
692 \
693static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900694hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900695 struct perf_hpp *hpp, \
696 struct hist_entry *he) \
697{ \
698 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900699 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900700 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900701 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900702 slsmg_printf("%s", hpp->buf); \
703 \
704 return ret; \
705 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900706 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
707 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900708}
709
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900710__HPP_COLOR_PERCENT_FN(overhead, period)
711__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
712__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
713__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
714__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900715__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900716
717#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900718#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900719
720void hist_browser__init_hpp(void)
721{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900722 perf_hpp__format[PERF_HPP__OVERHEAD].color =
723 hist_browser__hpp_color_overhead;
724 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
725 hist_browser__hpp_color_overhead_sys;
726 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
727 hist_browser__hpp_color_overhead_us;
728 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
729 hist_browser__hpp_color_overhead_guest_sys;
730 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
731 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900732 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
733 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900734}
735
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300736static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300737 struct hist_entry *entry,
738 unsigned short row)
739{
740 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200741 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900742 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300743 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300744 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300745 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300746 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200747 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300748
749 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300750 browser->he_selection = entry;
751 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300752 }
753
754 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300755 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300756 folded_sign = hist_entry__folded(entry);
757 }
758
759 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900760 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900761 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900762 .folded_sign = folded_sign,
763 .current_entry = current_entry,
764 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900765 struct perf_hpp hpp = {
766 .buf = s,
767 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900768 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900769 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300770
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300771 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900772
Jiri Olsa12400052012-10-13 00:06:16 +0200773 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900774 if (perf_hpp__should_skip(fmt))
775 continue;
776
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900777 if (current_entry && browser->b.navkeypressed) {
778 ui_browser__set_color(&browser->b,
779 HE_COLORSET_SELECTED);
780 } else {
781 ui_browser__set_color(&browser->b,
782 HE_COLORSET_NORMAL);
783 }
784
785 if (first) {
786 if (symbol_conf.use_callchain) {
787 slsmg_printf("%c ", folded_sign);
788 width -= 2;
789 }
790 first = false;
791 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900792 slsmg_printf(" ");
793 width -= 2;
794 }
795
Jiri Olsa12400052012-10-13 00:06:16 +0200796 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100797 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900798 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100799 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900800 slsmg_printf("%s", s);
801 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300802 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200803
804 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300805 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200806 width += 1;
807
Namhyung Kim26d8b332014-03-03 16:16:20 +0900808 slsmg_write_nstring("", width);
809
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300810 ++row;
811 ++printed;
812 } else
813 --row_offset;
814
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300815 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900816 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900817 struct callchain_print_arg arg = {
818 .row_offset = row_offset,
819 .is_current_entry = current_entry,
820 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900821
Namhyung Kim4087d112014-11-24 17:13:26 +0900822 if (callchain_param.mode == CHAIN_GRAPH_REL) {
823 if (symbol_conf.cumulate_callchain)
824 total = entry->stat_acc->period;
825 else
826 total = entry->stat.period;
827 }
828
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900829 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900830 &entry->sorted_chain, 1, row, total,
831 hist_browser__show_callchain_entry, &arg,
832 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900833
Namhyung Kim39ee5332014-08-22 09:13:21 +0900834 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300835 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300836 }
837
838 return printed;
839}
840
Jiri Olsa81a888f2014-06-14 15:44:52 +0200841static int advance_hpp_check(struct perf_hpp *hpp, int inc)
842{
843 advance_hpp(hpp, inc);
844 return hpp->size <= 0;
845}
846
847static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
848{
849 struct perf_hpp dummy_hpp = {
850 .buf = buf,
851 .size = size,
852 };
853 struct perf_hpp_fmt *fmt;
854 size_t ret = 0;
855
856 if (symbol_conf.use_callchain) {
857 ret = scnprintf(buf, size, " ");
858 if (advance_hpp_check(&dummy_hpp, ret))
859 return ret;
860 }
861
862 perf_hpp__for_each_format(fmt) {
863 if (perf_hpp__should_skip(fmt))
864 continue;
865
Jiri Olsa81a888f2014-06-14 15:44:52 +0200866 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
867 if (advance_hpp_check(&dummy_hpp, ret))
868 break;
869
870 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
871 if (advance_hpp_check(&dummy_hpp, ret))
872 break;
873 }
874
875 return ret;
876}
877
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200878static void hist_browser__show_headers(struct hist_browser *browser)
879{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200880 char headers[1024];
881
882 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200883 ui_browser__gotorc(&browser->b, 0, 0);
884 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200885 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200886}
887
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300888static void ui_browser__hists_init_top(struct ui_browser *browser)
889{
890 if (browser->top == NULL) {
891 struct hist_browser *hb;
892
893 hb = container_of(browser, struct hist_browser, b);
894 browser->top = rb_first(&hb->hists->entries);
895 }
896}
897
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300898static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300899{
900 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200901 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300902 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300903 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200905 if (hb->show_headers) {
906 hist_browser__show_headers(hb);
907 header_offset = 1;
908 }
909
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300910 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300911
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300912 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300913 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900914 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300915
916 if (h->filtered)
917 continue;
918
Namhyung Kim14135662013-10-31 10:17:39 +0900919 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900920 if (percent < hb->min_pcnt)
921 continue;
922
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300923 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300924 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300925 break;
926 }
927
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200928 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300929}
930
Namhyung Kim064f1982013-05-14 11:09:04 +0900931static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900932 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300933{
934 while (nd != NULL) {
935 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900936 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900937
Namhyung Kimc0f15272014-04-16 11:16:33 +0900938 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300939 return nd;
940
941 nd = rb_next(nd);
942 }
943
944 return NULL;
945}
946
Namhyung Kim064f1982013-05-14 11:09:04 +0900947static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900948 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300949{
950 while (nd != NULL) {
951 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900952 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900953
954 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300955 return nd;
956
957 nd = rb_prev(nd);
958 }
959
960 return NULL;
961}
962
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300963static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300964 off_t offset, int whence)
965{
966 struct hist_entry *h;
967 struct rb_node *nd;
968 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900969 struct hist_browser *hb;
970
971 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300972
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300973 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300974 return;
975
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300976 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300977
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300978 switch (whence) {
979 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900980 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900981 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300982 break;
983 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300984 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300985 goto do_offset;
986 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900987 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900988 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300989 first = false;
990 break;
991 default:
992 return;
993 }
994
995 /*
996 * Moves not relative to the first visible entry invalidates its
997 * row_offset:
998 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300999 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001000 h->row_offset = 0;
1001
1002 /*
1003 * Here we have to check if nd is expanded (+), if it is we can't go
1004 * the next top level hist_entry, instead we must compute an offset of
1005 * what _not_ to show and not change the first visible entry.
1006 *
1007 * This offset increments when we are going from top to bottom and
1008 * decreases when we're going from bottom to top.
1009 *
1010 * As we don't have backpointers to the top level in the callchains
1011 * structure, we need to always print the whole hist_entry callchain,
1012 * skipping the first ones that are before the first visible entry
1013 * and stop when we printed enough lines to fill the screen.
1014 */
1015do_offset:
1016 if (offset > 0) {
1017 do {
1018 h = rb_entry(nd, struct hist_entry, rb_node);
1019 if (h->ms.unfolded) {
1020 u16 remaining = h->nr_rows - h->row_offset;
1021 if (offset > remaining) {
1022 offset -= remaining;
1023 h->row_offset = 0;
1024 } else {
1025 h->row_offset += offset;
1026 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001027 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001028 break;
1029 }
1030 }
Namhyung Kim14135662013-10-31 10:17:39 +09001031 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001032 if (nd == NULL)
1033 break;
1034 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001035 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001036 } while (offset != 0);
1037 } else if (offset < 0) {
1038 while (1) {
1039 h = rb_entry(nd, struct hist_entry, rb_node);
1040 if (h->ms.unfolded) {
1041 if (first) {
1042 if (-offset > h->row_offset) {
1043 offset += h->row_offset;
1044 h->row_offset = 0;
1045 } else {
1046 h->row_offset += offset;
1047 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001048 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001049 break;
1050 }
1051 } else {
1052 if (-offset > h->nr_rows) {
1053 offset += h->nr_rows;
1054 h->row_offset = 0;
1055 } else {
1056 h->row_offset = h->nr_rows + offset;
1057 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001058 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001059 break;
1060 }
1061 }
1062 }
1063
Namhyung Kim14135662013-10-31 10:17:39 +09001064 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001065 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001066 if (nd == NULL)
1067 break;
1068 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001069 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001070 if (offset == 0) {
1071 /*
1072 * Last unfiltered hist_entry, check if it is
1073 * unfolded, if it is then we should have
1074 * row_offset at its last entry.
1075 */
1076 h = rb_entry(nd, struct hist_entry, rb_node);
1077 if (h->ms.unfolded)
1078 h->row_offset = h->nr_rows;
1079 break;
1080 }
1081 first = false;
1082 }
1083 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001084 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001085 h = rb_entry(nd, struct hist_entry, rb_node);
1086 h->row_offset = 0;
1087 }
1088}
1089
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001090static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001091 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001092{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001093 u64 total = hists__total_period(he->hists);
1094 struct callchain_print_arg arg = {
1095 .fp = fp,
1096 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001097
Namhyung Kim39ee5332014-08-22 09:13:21 +09001098 if (symbol_conf.cumulate_callchain)
1099 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001100
Namhyung Kim39ee5332014-08-22 09:13:21 +09001101 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1102 hist_browser__fprintf_callchain_entry, &arg,
1103 hist_browser__check_dump_full);
1104 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001105}
1106
1107static int hist_browser__fprintf_entry(struct hist_browser *browser,
1108 struct hist_entry *he, FILE *fp)
1109{
1110 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001111 int printed = 0;
1112 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001113 struct perf_hpp hpp = {
1114 .buf = s,
1115 .size = sizeof(s),
1116 };
1117 struct perf_hpp_fmt *fmt;
1118 bool first = true;
1119 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001120
1121 if (symbol_conf.use_callchain)
1122 folded_sign = hist_entry__folded(he);
1123
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001124 if (symbol_conf.use_callchain)
1125 printed += fprintf(fp, "%c ", folded_sign);
1126
Namhyung Kim26d8b332014-03-03 16:16:20 +09001127 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001128 if (perf_hpp__should_skip(fmt))
1129 continue;
1130
Namhyung Kim26d8b332014-03-03 16:16:20 +09001131 if (!first) {
1132 ret = scnprintf(hpp.buf, hpp.size, " ");
1133 advance_hpp(&hpp, ret);
1134 } else
1135 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001136
Namhyung Kim26d8b332014-03-03 16:16:20 +09001137 ret = fmt->entry(fmt, &hpp, he);
1138 advance_hpp(&hpp, ret);
1139 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001140 printed += fprintf(fp, "%s\n", rtrim(s));
1141
1142 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001143 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001144
1145 return printed;
1146}
1147
1148static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1149{
Namhyung Kim064f1982013-05-14 11:09:04 +09001150 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001151 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001152 int printed = 0;
1153
1154 while (nd) {
1155 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1156
1157 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001158 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001159 }
1160
1161 return printed;
1162}
1163
1164static int hist_browser__dump(struct hist_browser *browser)
1165{
1166 char filename[64];
1167 FILE *fp;
1168
1169 while (1) {
1170 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1171 if (access(filename, F_OK))
1172 break;
1173 /*
1174 * XXX: Just an arbitrary lazy upper limit
1175 */
1176 if (++browser->print_seq == 8192) {
1177 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1178 return -1;
1179 }
1180 }
1181
1182 fp = fopen(filename, "w");
1183 if (fp == NULL) {
1184 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001185 const char *err = strerror_r(errno, bf, sizeof(bf));
1186 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001187 return -1;
1188 }
1189
1190 ++browser->print_seq;
1191 hist_browser__fprintf(browser, fp);
1192 fclose(fp);
1193 ui_helpline__fpush("%s written!", filename);
1194
1195 return 0;
1196}
1197
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198static struct hist_browser *hist_browser__new(struct hists *hists)
1199{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001200 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001202 if (browser) {
1203 browser->hists = hists;
1204 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001205 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001206 browser->b.seek = ui_browser__hists_seek;
1207 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001208 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001209 }
1210
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001211 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001212}
1213
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001214static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001216 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001217}
1218
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001219static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001221 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001222}
1223
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001224static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001225{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001226 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001227}
1228
Taeung Song1e378eb2014-10-07 16:13:15 +09001229/* Check whether the browser is for 'top' or 'report' */
1230static inline bool is_report_browser(void *timer)
1231{
1232 return timer == NULL;
1233}
1234
1235static int hists__browser_title(struct hists *hists,
1236 struct hist_browser_timer *hbt,
1237 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001238{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001239 char unit;
1240 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001241 const struct dso *dso = hists->dso_filter;
1242 const struct thread *thread = hists->thread_filter;
1243 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1244 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001245 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001246 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001247 char buf[512];
1248 size_t buflen = sizeof(buf);
1249
Namhyung Kimf2148332014-01-14 11:52:48 +09001250 if (symbol_conf.filter_relative) {
1251 nr_samples = hists->stats.nr_non_filtered_samples;
1252 nr_events = hists->stats.total_non_filtered_period;
1253 }
1254
Namhyung Kim759ff492013-03-05 14:53:26 +09001255 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001256 struct perf_evsel *pos;
1257
1258 perf_evsel__group_desc(evsel, buf, buflen);
1259 ev_name = buf;
1260
1261 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001262 struct hists *pos_hists = evsel__hists(pos);
1263
Namhyung Kimf2148332014-01-14 11:52:48 +09001264 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001265 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1266 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001267 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001268 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1269 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001270 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001271 }
1272 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001273
Ashay Ranecc6862802012-04-05 21:01:01 -05001274 nr_samples = convert_unit(nr_samples, &unit);
1275 printed = scnprintf(bf, size,
Tom Huynhe641f692014-12-02 11:37:22 -06001276 "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
Ashay Ranecc6862802012-04-05 21:01:01 -05001277 nr_samples, unit, ev_name, nr_events);
1278
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001279
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001280 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001281 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001282 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001283 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001284 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001285 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001286 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001287 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001288 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001289 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001290 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001291 if (!is_report_browser(hbt)) {
1292 struct perf_top *top = hbt->arg;
1293
1294 if (top->zero)
1295 printed += scnprintf(bf + printed, size - printed, " [z]");
1296 }
1297
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001298 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001299}
1300
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001301static inline void free_popup_options(char **options, int n)
1302{
1303 int i;
1304
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001305 for (i = 0; i < n; ++i)
1306 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001307}
1308
Feng Tang341487ab2013-02-03 14:38:20 +08001309/*
1310 * Only runtime switching of perf data file will make "input_name" point
1311 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1312 * whether we need to call free() for current "input_name" during the switch.
1313 */
1314static bool is_input_name_malloced = false;
1315
1316static int switch_data_file(void)
1317{
1318 char *pwd, *options[32], *abs_path[32], *tmp;
1319 DIR *pwd_dir;
1320 int nr_options = 0, choice = -1, ret = -1;
1321 struct dirent *dent;
1322
1323 pwd = getenv("PWD");
1324 if (!pwd)
1325 return ret;
1326
1327 pwd_dir = opendir(pwd);
1328 if (!pwd_dir)
1329 return ret;
1330
1331 memset(options, 0, sizeof(options));
1332 memset(options, 0, sizeof(abs_path));
1333
1334 while ((dent = readdir(pwd_dir))) {
1335 char path[PATH_MAX];
1336 u64 magic;
1337 char *name = dent->d_name;
1338 FILE *file;
1339
1340 if (!(dent->d_type == DT_REG))
1341 continue;
1342
1343 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1344
1345 file = fopen(path, "r");
1346 if (!file)
1347 continue;
1348
1349 if (fread(&magic, 1, 8, file) < 8)
1350 goto close_file_and_continue;
1351
1352 if (is_perf_magic(magic)) {
1353 options[nr_options] = strdup(name);
1354 if (!options[nr_options])
1355 goto close_file_and_continue;
1356
1357 abs_path[nr_options] = strdup(path);
1358 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001359 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001360 ui__warning("Can't search all data files due to memory shortage.\n");
1361 fclose(file);
1362 break;
1363 }
1364
1365 nr_options++;
1366 }
1367
1368close_file_and_continue:
1369 fclose(file);
1370 if (nr_options >= 32) {
1371 ui__warning("Too many perf data files in PWD!\n"
1372 "Only the first 32 files will be listed.\n");
1373 break;
1374 }
1375 }
1376 closedir(pwd_dir);
1377
1378 if (nr_options) {
1379 choice = ui__popup_menu(nr_options, options);
1380 if (choice < nr_options && choice >= 0) {
1381 tmp = strdup(abs_path[choice]);
1382 if (tmp) {
1383 if (is_input_name_malloced)
1384 free((void *)input_name);
1385 input_name = tmp;
1386 is_input_name_malloced = true;
1387 ret = 0;
1388 } else
1389 ui__warning("Data switch failed due to memory shortage!\n");
1390 }
1391 }
1392
1393 free_popup_options(options, nr_options);
1394 free_popup_options(abs_path, nr_options);
1395 return ret;
1396}
1397
Namhyung Kim112f7612014-04-22 14:05:35 +09001398static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001399{
1400 u64 nr_entries = 0;
1401 struct rb_node *nd = rb_first(&hb->hists->entries);
1402
Namhyung Kim268397c2014-04-22 14:49:31 +09001403 if (hb->min_pcnt == 0) {
1404 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1405 return;
1406 }
1407
Namhyung Kim14135662013-10-31 10:17:39 +09001408 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001409 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001410 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001411 }
1412
Namhyung Kim112f7612014-04-22 14:05:35 +09001413 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001414}
Feng Tang341487ab2013-02-03 14:38:20 +08001415
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001416static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001417 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001418 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001419 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001420 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001421 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001422{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001423 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001424 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001425 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001426 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001427 char *options[16];
1428 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001429 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001430 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001431 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001432 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001433 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001434
Namhyung Kime8e684a2013-12-26 14:37:58 +09001435#define HIST_BROWSER_HELP_COMMON \
1436 "h/?/F1 Show this window\n" \
1437 "UP/DOWN/PGUP\n" \
1438 "PGDN/SPACE Navigate\n" \
1439 "q/ESC/CTRL+C Exit browser\n\n" \
1440 "For multiple event sessions:\n\n" \
1441 "TAB/UNTAB Switch events\n\n" \
1442 "For symbolic views (--sort has sym):\n\n" \
1443 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1444 "<- Zoom out\n" \
1445 "a Annotate current symbol\n" \
1446 "C Collapse all callchains\n" \
1447 "d Zoom into current DSO\n" \
1448 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001449 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001450 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001451
1452 /* help messages are sorted by lexical order of the hotkey */
1453 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001454 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001455 "P Print histograms to perf.hist.N\n"
1456 "r Run available scripts\n"
1457 "s Switch to another data file in PWD\n"
1458 "t Zoom into current Thread\n"
1459 "V Verbose (DSO names in callchains, etc)\n"
1460 "/ Filter symbol by name";
1461 const char top_help[] = HIST_BROWSER_HELP_COMMON
1462 "P Print histograms to perf.hist.N\n"
1463 "t Zoom into current Thread\n"
1464 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001465 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001466 "/ Filter symbol by name";
1467
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001468 if (browser == NULL)
1469 return -1;
1470
Namhyung Kim064f1982013-05-14 11:09:04 +09001471 if (min_pcnt) {
1472 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001473 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001474 }
1475
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001476 fstack = pstack__new(2);
1477 if (fstack == NULL)
1478 goto out;
1479
1480 ui_helpline__push(helpline);
1481
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001482 memset(options, 0, sizeof(options));
1483
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001484 perf_hpp__for_each_format(fmt)
1485 perf_hpp__reset_width(fmt, hists);
1486
Namhyung Kim5b591662014-07-31 14:47:38 +09001487 if (symbol_conf.col_width_list_str)
1488 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1489
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001490 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001491 struct thread *thread = NULL;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001492 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001493 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001494 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001495 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001496 int scripts_comm = -2, scripts_symbol = -2,
1497 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001498
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001499 nr_options = 0;
1500
Jiri Olsadd00d482014-06-19 13:41:13 +02001501 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001502
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001503 if (browser->he_selection != NULL) {
1504 thread = hist_browser__selected_thread(browser);
1505 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1506 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001507 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001508 case K_TAB:
1509 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001510 if (nr_events == 1)
1511 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001512 /*
1513 * Exit the browser, let hists__browser_tree
1514 * go to the next or previous
1515 */
1516 goto out_free_stack;
1517 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001518 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001519 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001520 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001521 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001522 continue;
1523 }
1524
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001525 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001526 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001527 browser->selection->map->dso->annotate_warned)
1528 continue;
1529 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001530 case 'P':
1531 hist_browser__dump(browser);
1532 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001533 case 'd':
1534 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001535 case 'V':
1536 browser->show_dso = !browser->show_dso;
1537 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001538 case 't':
1539 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001540 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001541 if (ui_browser__input_window("Symbol to show",
1542 "Please enter the name of symbol you want to see",
1543 buf, "ENTER: OK, ESC: Cancel",
1544 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001545 hists->symbol_filter_str = *buf ? buf : NULL;
1546 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001547 hist_browser__reset(browser);
1548 }
1549 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001550 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001551 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001552 goto do_scripts;
1553 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001554 case 's':
1555 if (is_report_browser(hbt))
1556 goto do_data_switch;
1557 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001558 case 'i':
1559 /* env->arch is NULL for live-mode (i.e. perf top) */
1560 if (env->arch)
1561 tui__header_window(env);
1562 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001563 case 'F':
1564 symbol_conf.filter_relative ^= 1;
1565 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001566 case 'z':
1567 if (!is_report_browser(hbt)) {
1568 struct perf_top *top = hbt->arg;
1569
1570 top->zero = !top->zero;
1571 }
1572 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001573 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001574 case 'h':
1575 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001576 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001577 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001578 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001579 case K_ENTER:
1580 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001581 /* menu */
1582 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001583 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001584 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001585
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001586 if (pstack__empty(fstack)) {
1587 /*
1588 * Go back to the perf_evsel_menu__run or other user
1589 */
1590 if (left_exits)
1591 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001592 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001593 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001594 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001595 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001596 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001597 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001598 goto zoom_out_thread;
1599 continue;
1600 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001601 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001602 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001603 !ui_browser__dialog_yesno(&browser->b,
1604 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001605 continue;
1606 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001607 case 'q':
1608 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001609 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001610 default:
1611 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001612 }
1613
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001614 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001615 goto add_exit_option;
1616
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001617 if (browser->selection == NULL)
1618 goto skip_annotation;
1619
Namhyung Kim55369fc2013-04-01 20:35:20 +09001620 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001621 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001622
1623 if (bi == NULL)
1624 goto skip_annotation;
1625
1626 if (bi->from.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001627 !bi->from.map->dso->annotate_warned &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001628 asprintf(&options[nr_options], "Annotate %s", bi->from.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001629 annotate_f = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001630 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001631
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001632 if (bi->to.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001633 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001634 (bi->to.sym != bi->from.sym ||
1635 bi->to.map->dso != bi->from.map->dso) &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001636 asprintf(&options[nr_options], "Annotate %s", bi->to.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001637 annotate_t = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001638 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001639 } else {
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001640 if (browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001641 !browser->selection->map->dso->annotate_warned) {
1642 struct annotation *notes;
1643
1644 notes = symbol__annotation(browser->selection->sym);
1645
1646 if (notes->src &&
1647 asprintf(&options[nr_options], "Annotate %s",
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001648 browser->selection->sym->name) > 0) {
Jiri Olsad7553302014-06-15 10:22:15 +02001649 annotate = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001650 }
Jiri Olsad7553302014-06-15 10:22:15 +02001651 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001652 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001653skip_annotation:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001654 if (thread != NULL &&
1655 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001656 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001657 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001658 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001659 zoom_thread = nr_options++;
1660
1661 if (dso != NULL &&
1662 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001663 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001664 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1665 zoom_dso = nr_options++;
1666
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001667 if (browser->selection != NULL &&
1668 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001669 asprintf(&options[nr_options], "Browse map details") > 0)
1670 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001671
1672 /* perf script support */
1673 if (browser->he_selection) {
1674 struct symbol *sym;
1675
1676 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001677 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001678 scripts_comm = nr_options++;
1679
1680 sym = browser->he_selection->ms.sym;
1681 if (sym && sym->namelen &&
1682 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1683 sym->name) > 0)
1684 scripts_symbol = nr_options++;
1685 }
1686
1687 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1688 scripts_all = nr_options++;
1689
Feng Tang341487ab2013-02-03 14:38:20 +08001690 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1691 "Switch to another data file in PWD") > 0)
1692 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001693add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001694 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001695retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001696 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001697
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001698 if (choice == nr_options - 1)
1699 break;
1700
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001701 if (choice == -1) {
1702 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001703 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001704 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001705
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001706 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001707 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001708 struct annotation *notes;
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001709 struct map_symbol ms;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001710 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001711do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001712 if (!objdump_path && perf_session_env__lookup_objdump(env))
1713 continue;
1714
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001715 he = hist_browser__selected_entry(browser);
1716 if (he == NULL)
1717 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001718
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001719 if (choice == annotate_f) {
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001720 ms.map = he->branch_info->from.map;
1721 ms.sym = he->branch_info->from.sym;
1722 } else if (choice == annotate_t) {
1723 ms.map = he->branch_info->to.map;
1724 ms.sym = he->branch_info->to.sym;
1725 } else {
1726 ms = *browser->selection;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001727 }
1728
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001729 notes = symbol__annotation(ms.sym);
Jiri Olsad7553302014-06-15 10:22:15 +02001730 if (!notes->src)
1731 continue;
1732
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001733 err = map_symbol__tui_annotate(&ms, evsel, hbt);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001734 /*
1735 * offer option to annotate the other branch source or target
1736 * (if they exists) when returning from annotate
1737 */
1738 if ((err == 'q' || err == CTRL('c'))
1739 && annotate_t != -2 && annotate_f != -2)
1740 goto retry_popup_menu;
1741
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001742 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001743 if (err)
1744 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001745
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001746 } else if (choice == browse_map)
1747 map__browse(browser->selection->map);
1748 else if (choice == zoom_dso) {
1749zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001750 if (browser->hists->dso_filter) {
1751 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001752zoom_out_dso:
1753 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001754 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001755 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001756 } else {
1757 if (dso == NULL)
1758 continue;
1759 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1760 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001761 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001762 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001763 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001764 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001765 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766 hist_browser__reset(browser);
1767 } else if (choice == zoom_thread) {
1768zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001769 if (browser->hists->thread_filter) {
1770 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001771zoom_out_thread:
1772 ui_helpline__pop();
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001773 thread__zput(browser->hists->thread_filter);
Jiri Olsaf2998422014-05-23 17:15:47 +02001774 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001775 } else {
1776 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001777 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001778 thread->tid);
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001779 browser->hists->thread_filter = thread__get(thread);
Jiri Olsaf2998422014-05-23 17:15:47 +02001780 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001781 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001782 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001783 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001784 hist_browser__reset(browser);
1785 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001786 /* perf scripts support */
1787 else if (choice == scripts_all || choice == scripts_comm ||
1788 choice == scripts_symbol) {
1789do_scripts:
1790 memset(script_opt, 0, 64);
1791
1792 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001793 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001794
1795 if (choice == scripts_symbol)
1796 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1797
1798 script_browse(script_opt);
1799 }
Feng Tang341487ab2013-02-03 14:38:20 +08001800 /* Switch to another data file */
1801 else if (choice == switch_data) {
1802do_data_switch:
1803 if (!switch_data_file()) {
1804 key = K_SWITCH_INPUT_DATA;
1805 break;
1806 } else
1807 ui__warning("Won't switch the data files due to\n"
1808 "no valid data file get selected!\n");
1809 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001810 }
1811out_free_stack:
1812 pstack__delete(fstack);
1813out:
1814 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001815 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001816 return key;
1817}
1818
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001819struct perf_evsel_menu {
1820 struct ui_browser b;
1821 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001822 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001823 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001824 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001825};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001826
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001827static void perf_evsel_menu__write(struct ui_browser *browser,
1828 void *entry, int row)
1829{
1830 struct perf_evsel_menu *menu = container_of(browser,
1831 struct perf_evsel_menu, b);
1832 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001833 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001834 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001835 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001836 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001837 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001838 const char *warn = " ";
1839 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001840
1841 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1842 HE_COLORSET_NORMAL);
1843
Namhyung Kim759ff492013-03-05 14:53:26 +09001844 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001845 struct perf_evsel *pos;
1846
1847 ev_name = perf_evsel__group_name(evsel);
1848
1849 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001850 struct hists *pos_hists = evsel__hists(pos);
1851 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001852 }
1853 }
1854
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001855 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001856 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001857 unit, unit == ' ' ? "" : " ", ev_name);
1858 slsmg_printf("%s", bf);
1859
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001860 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001861 if (nr_events != 0) {
1862 menu->lost_events = true;
1863 if (!current_entry)
1864 ui_browser__set_color(browser, HE_COLORSET_TOP);
1865 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001866 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1867 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001868 warn = bf;
1869 }
1870
1871 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001872
1873 if (current_entry)
1874 menu->selection = evsel;
1875}
1876
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001877static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1878 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001879 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001880{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001881 struct perf_evlist *evlist = menu->b.priv;
1882 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001883 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001884 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001885 int key;
1886
1887 if (ui_browser__show(&menu->b, title,
1888 "ESC: exit, ENTER|->: Browse histograms") < 0)
1889 return -1;
1890
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001891 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001892 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001893
1894 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001895 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001896 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001897
1898 if (!menu->lost_events_warned && menu->lost_events) {
1899 ui_browser__warn_lost_events(&menu->b);
1900 menu->lost_events_warned = true;
1901 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001902 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001903 case K_RIGHT:
1904 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001905 if (!menu->selection)
1906 continue;
1907 pos = menu->selection;
1908browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001909 perf_evlist__set_selected(evlist, pos);
1910 /*
1911 * Give the calling tool a chance to populate the non
1912 * default evsel resorted hists tree.
1913 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001914 if (hbt)
1915 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001916 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001917 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001918 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001919 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001920 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001921 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001922 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001923 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001924 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001925 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001926 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001927 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001928 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001929 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001930 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001931 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001932 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001933 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001934 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001935 if (!ui_browser__dialog_yesno(&menu->b,
1936 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001937 continue;
1938 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001939 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001940 case 'q':
1941 case CTRL('c'):
1942 goto out;
1943 default:
1944 continue;
1945 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001946 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001947 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001948 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001949 if (!ui_browser__dialog_yesno(&menu->b,
1950 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001951 continue;
1952 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001953 case 'q':
1954 case CTRL('c'):
1955 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001956 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001957 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001958 }
1959 }
1960
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001961out:
1962 ui_browser__hide(&menu->b);
1963 return key;
1964}
1965
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001966static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001967 void *entry)
1968{
1969 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1970
1971 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1972 return true;
1973
1974 return false;
1975}
1976
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001977static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001978 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001979 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001980 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001981 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001982{
1983 struct perf_evsel *pos;
1984 struct perf_evsel_menu menu = {
1985 .b = {
1986 .entries = &evlist->entries,
1987 .refresh = ui_browser__list_head_refresh,
1988 .seek = ui_browser__list_head_seek,
1989 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001990 .filter = filter_group_entries,
1991 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001992 .priv = evlist,
1993 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001994 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001995 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001996 };
1997
1998 ui_helpline__push("Press ESC to exit");
1999
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002000 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002001 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002002 size_t line_len = strlen(ev_name) + 7;
2003
2004 if (menu.b.width < line_len)
2005 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002006 }
2007
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002008 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002009}
2010
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002011int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002012 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002013 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002014 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002015{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002016 int nr_entries = evlist->nr_entries;
2017
2018single_entry:
2019 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002020 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002021
2022 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002023 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002024 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002025 }
2026
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002027 if (symbol_conf.event_group) {
2028 struct perf_evsel *pos;
2029
2030 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002031 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002032 if (perf_evsel__is_group_leader(pos))
2033 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002034 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002035
2036 if (nr_entries == 1)
2037 goto single_entry;
2038 }
2039
2040 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002041 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002042}