blob: 0972d4722297a5fd7c55da316b0bde4b83c612fa [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 Ranecc686282012-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 Ranecc686282012-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;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001427#define MAX_OPTIONS 16
1428 char *options[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001429 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001430 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001431 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001432 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001433 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001434 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001435
Namhyung Kime8e684a2013-12-26 14:37:58 +09001436#define HIST_BROWSER_HELP_COMMON \
1437 "h/?/F1 Show this window\n" \
1438 "UP/DOWN/PGUP\n" \
1439 "PGDN/SPACE Navigate\n" \
1440 "q/ESC/CTRL+C Exit browser\n\n" \
1441 "For multiple event sessions:\n\n" \
1442 "TAB/UNTAB Switch events\n\n" \
1443 "For symbolic views (--sort has sym):\n\n" \
1444 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1445 "<- Zoom out\n" \
1446 "a Annotate current symbol\n" \
1447 "C Collapse all callchains\n" \
1448 "d Zoom into current DSO\n" \
1449 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001450 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001451 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001452
1453 /* help messages are sorted by lexical order of the hotkey */
1454 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001455 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001456 "P Print histograms to perf.hist.N\n"
1457 "r Run available scripts\n"
1458 "s Switch to another data file in PWD\n"
1459 "t Zoom into current Thread\n"
1460 "V Verbose (DSO names in callchains, etc)\n"
1461 "/ Filter symbol by name";
1462 const char top_help[] = HIST_BROWSER_HELP_COMMON
1463 "P Print histograms to perf.hist.N\n"
1464 "t Zoom into current Thread\n"
1465 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001466 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001467 "/ Filter symbol by name";
1468
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001469 if (browser == NULL)
1470 return -1;
1471
Namhyung Kim064f1982013-05-14 11:09:04 +09001472 if (min_pcnt) {
1473 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001474 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001475 }
1476
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001477 fstack = pstack__new(2);
1478 if (fstack == NULL)
1479 goto out;
1480
1481 ui_helpline__push(helpline);
1482
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001483 memset(options, 0, sizeof(options));
1484
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001485 perf_hpp__for_each_format(fmt)
1486 perf_hpp__reset_width(fmt, hists);
1487
Namhyung Kim5b591662014-07-31 14:47:38 +09001488 if (symbol_conf.col_width_list_str)
1489 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1490
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001491 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001492 struct thread *thread = NULL;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001493 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001494 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001495 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001496 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001497 int scripts_comm = -2, scripts_symbol = -2,
1498 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001499
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001500 nr_options = 0;
1501
Jiri Olsadd00d482014-06-19 13:41:13 +02001502 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001503
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001504 if (browser->he_selection != NULL) {
1505 thread = hist_browser__selected_thread(browser);
1506 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1507 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001508 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001509 case K_TAB:
1510 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001511 if (nr_events == 1)
1512 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001513 /*
1514 * Exit the browser, let hists__browser_tree
1515 * go to the next or previous
1516 */
1517 goto out_free_stack;
1518 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001519 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001520 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001521 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001522 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001523 continue;
1524 }
1525
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001526 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001527 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001528 browser->selection->map->dso->annotate_warned)
1529 continue;
1530 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001531 case 'P':
1532 hist_browser__dump(browser);
1533 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001534 case 'd':
1535 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001536 case 'V':
1537 browser->show_dso = !browser->show_dso;
1538 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001539 case 't':
1540 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001541 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001542 if (ui_browser__input_window("Symbol to show",
1543 "Please enter the name of symbol you want to see",
1544 buf, "ENTER: OK, ESC: Cancel",
1545 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001546 hists->symbol_filter_str = *buf ? buf : NULL;
1547 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001548 hist_browser__reset(browser);
1549 }
1550 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001551 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001552 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001553 goto do_scripts;
1554 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001555 case 's':
1556 if (is_report_browser(hbt))
1557 goto do_data_switch;
1558 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001559 case 'i':
1560 /* env->arch is NULL for live-mode (i.e. perf top) */
1561 if (env->arch)
1562 tui__header_window(env);
1563 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001564 case 'F':
1565 symbol_conf.filter_relative ^= 1;
1566 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001567 case 'z':
1568 if (!is_report_browser(hbt)) {
1569 struct perf_top *top = hbt->arg;
1570
1571 top->zero = !top->zero;
1572 }
1573 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001574 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001575 case 'h':
1576 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001577 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001578 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001579 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001580 case K_ENTER:
1581 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001582 /* menu */
1583 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001584 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001585 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001586
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001587 if (pstack__empty(fstack)) {
1588 /*
1589 * Go back to the perf_evsel_menu__run or other user
1590 */
1591 if (left_exits)
1592 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001593 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001594 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001595 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001596 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001597 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001598 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001599 goto zoom_out_thread;
1600 continue;
1601 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001602 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001603 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001604 !ui_browser__dialog_yesno(&browser->b,
1605 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001606 continue;
1607 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001608 case 'q':
1609 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001610 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001611 default:
1612 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001613 }
1614
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001615 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001616 goto add_exit_option;
1617
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001618 if (browser->selection == NULL)
1619 goto skip_annotation;
1620
Namhyung Kim55369fc2013-04-01 20:35:20 +09001621 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001622 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001623
1624 if (bi == NULL)
1625 goto skip_annotation;
1626
1627 if (bi->from.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001628 !bi->from.map->dso->annotate_warned &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001629 asprintf(&options[nr_options], "Annotate %s", bi->from.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001630 annotate_f = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001631 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001632
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001633 if (bi->to.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001634 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001635 (bi->to.sym != bi->from.sym ||
1636 bi->to.map->dso != bi->from.map->dso) &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001637 asprintf(&options[nr_options], "Annotate %s", bi->to.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001638 annotate_t = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001639 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001640 } else {
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001641 if (browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001642 !browser->selection->map->dso->annotate_warned) {
1643 struct annotation *notes;
1644
1645 notes = symbol__annotation(browser->selection->sym);
1646
1647 if (notes->src &&
1648 asprintf(&options[nr_options], "Annotate %s",
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001649 browser->selection->sym->name) > 0) {
Jiri Olsad7553302014-06-15 10:22:15 +02001650 annotate = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001651 }
Jiri Olsad7553302014-06-15 10:22:15 +02001652 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001653 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001654skip_annotation:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001655 if (thread != NULL &&
1656 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001657 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001658 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001659 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001660 zoom_thread = nr_options++;
1661
1662 if (dso != NULL &&
1663 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001664 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001665 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1666 zoom_dso = nr_options++;
1667
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001668 if (browser->selection != NULL &&
1669 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001670 asprintf(&options[nr_options], "Browse map details") > 0)
1671 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001672
1673 /* perf script support */
1674 if (browser->he_selection) {
1675 struct symbol *sym;
1676
1677 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001678 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001679 scripts_comm = nr_options++;
1680
1681 sym = browser->he_selection->ms.sym;
1682 if (sym && sym->namelen &&
1683 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1684 sym->name) > 0)
1685 scripts_symbol = nr_options++;
1686 }
1687
1688 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1689 scripts_all = nr_options++;
1690
Feng Tang341487ab2013-02-03 14:38:20 +08001691 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1692 "Switch to another data file in PWD") > 0)
1693 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001694add_exit_option:
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001695 if (asprintf(&options[nr_options], "Exit") > 0)
1696 nr_options++;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001697retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001698 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001699
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001700 if (choice == nr_options - 1)
1701 break;
1702
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001703 if (choice == -1) {
1704 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001705 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001706 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001707
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001708 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001709 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001710 struct annotation *notes;
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001711 struct map_symbol ms;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001712 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001713do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001714 if (!objdump_path && perf_session_env__lookup_objdump(env))
1715 continue;
1716
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001717 he = hist_browser__selected_entry(browser);
1718 if (he == NULL)
1719 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001720
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001721 if (choice == annotate_f) {
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001722 ms.map = he->branch_info->from.map;
1723 ms.sym = he->branch_info->from.sym;
1724 } else if (choice == annotate_t) {
1725 ms.map = he->branch_info->to.map;
1726 ms.sym = he->branch_info->to.sym;
1727 } else {
1728 ms = *browser->selection;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001729 }
1730
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001731 notes = symbol__annotation(ms.sym);
Jiri Olsad7553302014-06-15 10:22:15 +02001732 if (!notes->src)
1733 continue;
1734
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001735 err = map_symbol__tui_annotate(&ms, evsel, hbt);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001736 /*
1737 * offer option to annotate the other branch source or target
1738 * (if they exists) when returning from annotate
1739 */
1740 if ((err == 'q' || err == CTRL('c'))
1741 && annotate_t != -2 && annotate_f != -2)
1742 goto retry_popup_menu;
1743
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001744 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001745 if (err)
1746 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001747
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001748 } else if (choice == browse_map)
1749 map__browse(browser->selection->map);
1750 else if (choice == zoom_dso) {
1751zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001752 if (browser->hists->dso_filter) {
1753 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001754zoom_out_dso:
1755 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001756 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001757 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758 } else {
1759 if (dso == NULL)
1760 continue;
1761 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1762 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001763 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001764 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001765 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001767 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001768 hist_browser__reset(browser);
1769 } else if (choice == zoom_thread) {
1770zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001771 if (browser->hists->thread_filter) {
1772 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001773zoom_out_thread:
1774 ui_helpline__pop();
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001775 thread__zput(browser->hists->thread_filter);
Jiri Olsaf2998422014-05-23 17:15:47 +02001776 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001777 } else {
1778 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001779 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001780 thread->tid);
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001781 browser->hists->thread_filter = thread__get(thread);
Jiri Olsaf2998422014-05-23 17:15:47 +02001782 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001783 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001784 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001785 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001786 hist_browser__reset(browser);
1787 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001788 /* perf scripts support */
1789 else if (choice == scripts_all || choice == scripts_comm ||
1790 choice == scripts_symbol) {
1791do_scripts:
1792 memset(script_opt, 0, 64);
1793
1794 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001795 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001796
1797 if (choice == scripts_symbol)
1798 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1799
1800 script_browse(script_opt);
1801 }
Feng Tang341487ab2013-02-03 14:38:20 +08001802 /* Switch to another data file */
1803 else if (choice == switch_data) {
1804do_data_switch:
1805 if (!switch_data_file()) {
1806 key = K_SWITCH_INPUT_DATA;
1807 break;
1808 } else
1809 ui__warning("Won't switch the data files due to\n"
1810 "no valid data file get selected!\n");
1811 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001812 }
1813out_free_stack:
1814 pstack__delete(fstack);
1815out:
1816 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001817 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001818 return key;
1819}
1820
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001821struct perf_evsel_menu {
1822 struct ui_browser b;
1823 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001824 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001825 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001826 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001827};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001828
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001829static void perf_evsel_menu__write(struct ui_browser *browser,
1830 void *entry, int row)
1831{
1832 struct perf_evsel_menu *menu = container_of(browser,
1833 struct perf_evsel_menu, b);
1834 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001835 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001836 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001837 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001838 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001839 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001840 const char *warn = " ";
1841 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001842
1843 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1844 HE_COLORSET_NORMAL);
1845
Namhyung Kim759ff492013-03-05 14:53:26 +09001846 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001847 struct perf_evsel *pos;
1848
1849 ev_name = perf_evsel__group_name(evsel);
1850
1851 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001852 struct hists *pos_hists = evsel__hists(pos);
1853 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001854 }
1855 }
1856
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001857 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001858 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001859 unit, unit == ' ' ? "" : " ", ev_name);
1860 slsmg_printf("%s", bf);
1861
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001862 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001863 if (nr_events != 0) {
1864 menu->lost_events = true;
1865 if (!current_entry)
1866 ui_browser__set_color(browser, HE_COLORSET_TOP);
1867 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001868 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1869 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001870 warn = bf;
1871 }
1872
1873 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001874
1875 if (current_entry)
1876 menu->selection = evsel;
1877}
1878
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001879static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1880 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001881 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001882{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001883 struct perf_evlist *evlist = menu->b.priv;
1884 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001885 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001886 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001887 int key;
1888
1889 if (ui_browser__show(&menu->b, title,
1890 "ESC: exit, ENTER|->: Browse histograms") < 0)
1891 return -1;
1892
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001893 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001894 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001895
1896 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001897 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001898 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001899
1900 if (!menu->lost_events_warned && menu->lost_events) {
1901 ui_browser__warn_lost_events(&menu->b);
1902 menu->lost_events_warned = true;
1903 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001904 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001905 case K_RIGHT:
1906 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001907 if (!menu->selection)
1908 continue;
1909 pos = menu->selection;
1910browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001911 perf_evlist__set_selected(evlist, pos);
1912 /*
1913 * Give the calling tool a chance to populate the non
1914 * default evsel resorted hists tree.
1915 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001916 if (hbt)
1917 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001918 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001919 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001920 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001921 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001922 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001923 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001924 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001925 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001926 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001927 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001928 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001929 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001930 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001931 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001932 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001933 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001934 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001935 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001936 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001937 if (!ui_browser__dialog_yesno(&menu->b,
1938 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001939 continue;
1940 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001941 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001942 case 'q':
1943 case CTRL('c'):
1944 goto out;
1945 default:
1946 continue;
1947 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001948 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001949 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001950 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001951 if (!ui_browser__dialog_yesno(&menu->b,
1952 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001953 continue;
1954 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001955 case 'q':
1956 case CTRL('c'):
1957 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001958 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001959 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001960 }
1961 }
1962
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001963out:
1964 ui_browser__hide(&menu->b);
1965 return key;
1966}
1967
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001968static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001969 void *entry)
1970{
1971 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1972
1973 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1974 return true;
1975
1976 return false;
1977}
1978
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001979static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001980 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001981 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001982 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001983 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001984{
1985 struct perf_evsel *pos;
1986 struct perf_evsel_menu menu = {
1987 .b = {
1988 .entries = &evlist->entries,
1989 .refresh = ui_browser__list_head_refresh,
1990 .seek = ui_browser__list_head_seek,
1991 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001992 .filter = filter_group_entries,
1993 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001994 .priv = evlist,
1995 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001996 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001997 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001998 };
1999
2000 ui_helpline__push("Press ESC to exit");
2001
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002002 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002003 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002004 size_t line_len = strlen(ev_name) + 7;
2005
2006 if (menu.b.width < line_len)
2007 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002008 }
2009
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002010 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002011}
2012
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002013int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002014 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002015 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002016 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002017{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002018 int nr_entries = evlist->nr_entries;
2019
2020single_entry:
2021 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002022 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002023
2024 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002025 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002026 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002027 }
2028
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002029 if (symbol_conf.event_group) {
2030 struct perf_evsel *pos;
2031
2032 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002033 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002034 if (perf_evsel__is_group_leader(pos))
2035 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002036 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002037
2038 if (nr_entries == 1)
2039 goto single_entry;
2040 }
2041
2042 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002043 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002044}