blob: 79a093a7d221da9401a276180393da98eff7e063 [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;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +090028 struct hist_browser_timer *hbt;
Namhyung Kim01f00a12015-04-22 16:18:16 +090029 struct pstack *pstack;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +090030 struct perf_session_env *env;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030031 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030032 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020033 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090034 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090035 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090036 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030037};
38
Namhyung Kimf5951d52012-09-03 11:53:09 +090039extern void hist_browser__init_hpp(void);
40
Taeung Song1e378eb2014-10-07 16:13:15 +090041static int hists__browser_title(struct hists *hists,
42 struct hist_browser_timer *hbt,
43 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090044static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030045
Namhyung Kimc3b78952014-04-22 15:56:17 +090046static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090047 float min_pcnt);
48
Namhyung Kim268397c2014-04-22 14:49:31 +090049static bool hist_browser__has_filter(struct hist_browser *hb)
50{
51 return hists__has_filter(hb->hists) || hb->min_pcnt;
52}
53
He Kuang4fabf3d2015-03-12 15:21:49 +080054static int hist_browser__get_folding(struct hist_browser *browser)
55{
56 struct rb_node *nd;
57 struct hists *hists = browser->hists;
58 int unfolded_rows = 0;
59
60 for (nd = rb_first(&hists->entries);
61 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
62 nd = rb_next(nd)) {
63 struct hist_entry *he =
64 rb_entry(nd, struct hist_entry, rb_node);
65
Namhyung Kim3698dab2015-05-05 23:55:46 +090066 if (he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080067 unfolded_rows += he->nr_rows;
68 }
69 return unfolded_rows;
70}
71
Namhyung Kimc3b78952014-04-22 15:56:17 +090072static u32 hist_browser__nr_entries(struct hist_browser *hb)
73{
74 u32 nr_entries;
75
76 if (hist_browser__has_filter(hb))
77 nr_entries = hb->nr_non_filtered_entries;
78 else
79 nr_entries = hb->hists->nr_entries;
80
He Kuang4fabf3d2015-03-12 15:21:49 +080081 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090082 return nr_entries + hb->nr_callchain_rows;
83}
84
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020085static void hist_browser__update_rows(struct hist_browser *hb)
86{
87 struct ui_browser *browser = &hb->b;
88 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
89
90 browser->rows = browser->height - header_offset;
91 /*
92 * Verify if we were at the last line and that line isn't
93 * visibe because we now show the header line(s).
94 */
95 index_row = browser->index - browser->top_idx;
96 if (index_row >= browser->rows)
97 browser->index -= index_row - browser->rows + 1;
98}
99
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300100static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300102 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
103
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300104 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300105 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
106 /*
107 * FIXME: Just keeping existing behaviour, but this really should be
108 * before updating browser->width, as it will invalidate the
109 * calculation above. Fix this and the fallout in another
110 * changeset.
111 */
112 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200113 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300114}
115
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300116static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
117{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200118 u16 header_offset = browser->show_headers ? 1 : 0;
119
120 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300121}
122
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300123static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300124{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900125 /*
126 * The hists__remove_entry_filter() already folds non-filtered
127 * entries so we can assume it has 0 callchain rows.
128 */
129 browser->nr_callchain_rows = 0;
130
Namhyung Kim268397c2014-04-22 14:49:31 +0900131 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900132 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300133 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300134 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300135}
136
137static char tree__folded_sign(bool unfolded)
138{
139 return unfolded ? '-' : '+';
140}
141
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300142static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900144 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145}
146
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900149 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300150}
151
Namhyung Kim3698dab2015-05-05 23:55:46 +0900152static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300153{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900154 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300155}
156
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300157static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300158{
159 int n = 0;
160 struct rb_node *nd;
161
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300162 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300163 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
164 struct callchain_list *chain;
165 char folded_sign = ' '; /* No children */
166
167 list_for_each_entry(chain, &child->val, list) {
168 ++n;
169 /* We need this because we may not have children */
170 folded_sign = callchain_list__folded(chain);
171 if (folded_sign == '+')
172 break;
173 }
174
175 if (folded_sign == '-') /* Have children and they're unfolded */
176 n += callchain_node__count_rows_rb_tree(child);
177 }
178
179 return n;
180}
181
182static int callchain_node__count_rows(struct callchain_node *node)
183{
184 struct callchain_list *chain;
185 bool unfolded = false;
186 int n = 0;
187
188 list_for_each_entry(chain, &node->val, list) {
189 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900190 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300191 }
192
193 if (unfolded)
194 n += callchain_node__count_rows_rb_tree(node);
195
196 return n;
197}
198
199static int callchain__count_rows(struct rb_root *chain)
200{
201 struct rb_node *nd;
202 int n = 0;
203
204 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
205 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
206 n += callchain_node__count_rows(node);
207 }
208
209 return n;
210}
211
Namhyung Kim3698dab2015-05-05 23:55:46 +0900212static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300213{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900214 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200215 return false;
216
Namhyung Kim3698dab2015-05-05 23:55:46 +0900217 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300218 return false;
219
Namhyung Kim3698dab2015-05-05 23:55:46 +0900220 he->unfolded = !he->unfolded;
221 return true;
222}
223
224static bool callchain_list__toggle_fold(struct callchain_list *cl)
225{
226 if (!cl)
227 return false;
228
229 if (!cl->has_children)
230 return false;
231
232 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300233 return true;
234}
235
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300236static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300237{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300238 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300239
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300240 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300241 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
242 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300243 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300244
245 list_for_each_entry(chain, &child->val, list) {
246 if (first) {
247 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900248 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300249 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300250 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900251 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300252 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300253 }
254
255 callchain_node__init_have_children_rb_tree(child);
256 }
257}
258
Namhyung Kima7444af2014-11-24 17:13:27 +0900259static void callchain_node__init_have_children(struct callchain_node *node,
260 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300261{
262 struct callchain_list *chain;
263
Namhyung Kima7444af2014-11-24 17:13:27 +0900264 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900265 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900266
Namhyung Kim82162b52014-08-13 15:02:41 +0900267 if (!list_empty(&node->val)) {
268 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900269 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900270 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300271
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300272 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300273}
274
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300275static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300276{
Namhyung Kima7444af2014-11-24 17:13:27 +0900277 struct rb_node *nd = rb_first(root);
278 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300279
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300280 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300281 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900282 callchain_node__init_have_children(node, has_sibling);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300283 }
284}
285
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300286static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300287{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300288 if (!he->init_have_children) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900289 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300290 callchain__init_have_children(&he->sorted_chain);
291 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300292 }
293}
294
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300295static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300296{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900297 struct hist_entry *he = browser->he_selection;
298 struct map_symbol *ms = browser->selection;
299 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
300 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300301
Namhyung Kim3698dab2015-05-05 23:55:46 +0900302 if (ms == &he->ms)
303 has_children = hist_entry__toggle_fold(he);
304 else
305 has_children = callchain_list__toggle_fold(cl);
306
307 if (has_children) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300308 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900309 browser->b.nr_entries -= he->nr_rows;
310 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300311
Namhyung Kim3698dab2015-05-05 23:55:46 +0900312 if (he->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300313 he->nr_rows = callchain__count_rows(&he->sorted_chain);
314 else
315 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900316
317 browser->b.nr_entries += he->nr_rows;
318 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300319
320 return true;
321 }
322
323 /* If it doesn't have children, no toggling performed */
324 return false;
325}
326
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300327static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300328{
329 int n = 0;
330 struct rb_node *nd;
331
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300332 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300333 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
334 struct callchain_list *chain;
335 bool has_children = false;
336
337 list_for_each_entry(chain, &child->val, list) {
338 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900339 callchain_list__set_folding(chain, unfold);
340 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300341 }
342
343 if (has_children)
344 n += callchain_node__set_folding_rb_tree(child, unfold);
345 }
346
347 return n;
348}
349
350static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
351{
352 struct callchain_list *chain;
353 bool has_children = false;
354 int n = 0;
355
356 list_for_each_entry(chain, &node->val, list) {
357 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900358 callchain_list__set_folding(chain, unfold);
359 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300360 }
361
362 if (has_children)
363 n += callchain_node__set_folding_rb_tree(node, unfold);
364
365 return n;
366}
367
368static int callchain__set_folding(struct rb_root *chain, bool unfold)
369{
370 struct rb_node *nd;
371 int n = 0;
372
373 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
374 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
375 n += callchain_node__set_folding(node, unfold);
376 }
377
378 return n;
379}
380
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300381static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300382{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300383 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900384 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300385
Namhyung Kim3698dab2015-05-05 23:55:46 +0900386 if (he->has_children) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300387 int n = callchain__set_folding(&he->sorted_chain, unfold);
388 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300389 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300390 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300391}
392
Namhyung Kimc3b78952014-04-22 15:56:17 +0900393static void
394__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300395{
396 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900397 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300398
Namhyung Kimc3b78952014-04-22 15:56:17 +0900399 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900400 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900401 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300402 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
403 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900404 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300405 }
406}
407
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300408static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300409{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900410 browser->nr_callchain_rows = 0;
411 __hist_browser__set_folding(browser, unfold);
412
413 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300414 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300415 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300416}
417
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200418static void ui_browser__warn_lost_events(struct ui_browser *browser)
419{
420 ui_browser__warning(browser, 4,
421 "Events are being lost, check IO/CPU overload!\n\n"
422 "You may want to run 'perf' using a RT scheduler policy:\n\n"
423 " perf top -r 80\n\n"
424 "Or reduce the sampling frequency.");
425}
426
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900427static int hist_browser__run(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300429 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300430 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900431 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900432 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300433
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300434 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900435 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300436
Taeung Song1e378eb2014-10-07 16:13:15 +0900437 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300438
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300439 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300440 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300441 return -1;
442
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300443 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300444 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300445
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300446 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900447 case K_TIMER: {
448 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900449 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900450
Namhyung Kimc3b78952014-04-22 15:56:17 +0900451 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900452 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900453
Namhyung Kimc3b78952014-04-22 15:56:17 +0900454 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900455 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200456
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300457 if (browser->hists->stats.nr_lost_warned !=
458 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
459 browser->hists->stats.nr_lost_warned =
460 browser->hists->stats.nr_events[PERF_RECORD_LOST];
461 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200462 }
463
Taeung Song1e378eb2014-10-07 16:13:15 +0900464 hists__browser_title(browser->hists,
465 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300466 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300467 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900468 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300469 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300470 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300471 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300472 struct hist_entry, rb_node);
473 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300474 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 -0300475 seq++, browser->b.nr_entries,
476 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300477 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300478 browser->b.index,
479 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300480 h->row_offset, h->nr_rows);
481 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300482 break;
483 case 'C':
484 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300485 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300486 break;
487 case 'E':
488 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300489 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300490 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200491 case 'H':
492 browser->show_headers = !browser->show_headers;
493 hist_browser__update_rows(browser);
494 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200495 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300496 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300497 break;
498 /* fall thru */
499 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300500 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300501 }
502 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300503out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300504 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300505 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300506}
507
Namhyung Kim39ee5332014-08-22 09:13:21 +0900508struct callchain_print_arg {
509 /* for hists browser */
510 off_t row_offset;
511 bool is_current_entry;
512
513 /* for file dump */
514 FILE *fp;
515 int printed;
516};
517
518typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
519 struct callchain_list *chain,
520 const char *str, int offset,
521 unsigned short row,
522 struct callchain_print_arg *arg);
523
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900524static void hist_browser__show_callchain_entry(struct hist_browser *browser,
525 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900526 const char *str, int offset,
527 unsigned short row,
528 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900529{
530 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900531 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300532 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900533
534 color = HE_COLORSET_NORMAL;
535 width = browser->b.width - (offset + 2);
536 if (ui_browser__is_current_entry(&browser->b, row)) {
537 browser->selection = &chain->ms;
538 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900539 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900540 }
541
542 ui_browser__set_color(&browser->b, color);
543 hist_browser__gotorc(browser, row, 0);
544 slsmg_write_nstring(" ", offset);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300545 slsmg_printf("%c", folded_sign);
546 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900547 slsmg_write_nstring(str, width);
548}
549
Namhyung Kim39ee5332014-08-22 09:13:21 +0900550static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
551 struct callchain_list *chain,
552 const char *str, int offset,
553 unsigned short row __maybe_unused,
554 struct callchain_print_arg *arg)
555{
556 char folded_sign = callchain_list__folded(chain);
557
558 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
559 folded_sign, str);
560}
561
562typedef bool (*check_output_full_fn)(struct hist_browser *browser,
563 unsigned short row);
564
565static bool hist_browser__check_output_full(struct hist_browser *browser,
566 unsigned short row)
567{
568 return browser->b.rows == row;
569}
570
571static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
572 unsigned short row __maybe_unused)
573{
574 return false;
575}
576
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300577#define LEVEL_OFFSET_STEP 3
578
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900579static int hist_browser__show_callchain(struct hist_browser *browser,
580 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900581 unsigned short row, u64 total,
582 print_callchain_entry_fn print,
583 struct callchain_print_arg *arg,
584 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300585{
586 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900587 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900588 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900589 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900591 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900592 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900593
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300594 while (node) {
595 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
596 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100597 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300598 struct callchain_list *chain;
599 char folded_sign = ' ';
600 int first = true;
601 int extra_offset = 0;
602
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300603 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300604 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300605 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300606 bool was_first = first;
607
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300608 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300609 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900610 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300611 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300612
613 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900614 if (arg->row_offset != 0) {
615 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300616 goto do_next;
617 }
618
619 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300620 str = callchain_list__sym_name(chain, bf, sizeof(bf),
621 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900622
Namhyung Kim4087d112014-11-24 17:13:26 +0900623 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900624 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300625
626 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
627 str = "Not enough memory!";
628 else
629 str = alloc_str;
630 }
631
Namhyung Kim39ee5332014-08-22 09:13:21 +0900632 print(browser, chain, str, offset + extra_offset, row, arg);
633
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300634 free(alloc_str);
635
Namhyung Kim39ee5332014-08-22 09:13:21 +0900636 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300637 goto out;
638do_next:
639 if (folded_sign == '+')
640 break;
641 }
642
643 if (folded_sign == '-') {
644 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900645
646 if (callchain_param.mode == CHAIN_GRAPH_REL)
647 new_total = child->children_hit;
648 else
649 new_total = total;
650
651 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900652 new_level, row, new_total,
653 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300654 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900655 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900656 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300657 node = next;
658 }
659out:
660 return row - first_row;
661}
662
Namhyung Kim89701462013-01-22 18:09:38 +0900663struct hpp_arg {
664 struct ui_browser *b;
665 char folded_sign;
666 bool current_entry;
667};
668
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900669static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
670{
671 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900672 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900673 va_list args;
674 double percent;
675
676 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900677 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900678 percent = va_arg(args, double);
679 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900680
Namhyung Kim89701462013-01-22 18:09:38 +0900681 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900682
Namhyung Kimd6751072014-07-31 14:47:36 +0900683 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900684 slsmg_printf("%s", hpp->buf);
685
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900686 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900687 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900688}
689
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900690#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900691static u64 __hpp_get_##_field(struct hist_entry *he) \
692{ \
693 return he->stat._field; \
694} \
695 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100696static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900697hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100698 struct perf_hpp *hpp, \
699 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900700{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900701 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
702 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900703}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900704
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900705#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
706static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
707{ \
708 return he->stat_acc->_field; \
709} \
710 \
711static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900712hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900713 struct perf_hpp *hpp, \
714 struct hist_entry *he) \
715{ \
716 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900717 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900718 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900719 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900720 slsmg_printf("%s", hpp->buf); \
721 \
722 return ret; \
723 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900724 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
725 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900726}
727
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900728__HPP_COLOR_PERCENT_FN(overhead, period)
729__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
730__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
731__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
732__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900733__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900734
735#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900736#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900737
738void hist_browser__init_hpp(void)
739{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900740 perf_hpp__format[PERF_HPP__OVERHEAD].color =
741 hist_browser__hpp_color_overhead;
742 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
743 hist_browser__hpp_color_overhead_sys;
744 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
745 hist_browser__hpp_color_overhead_us;
746 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
747 hist_browser__hpp_color_overhead_guest_sys;
748 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
749 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900750 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
751 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900752}
753
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300754static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300755 struct hist_entry *entry,
756 unsigned short row)
757{
758 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200759 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900760 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300761 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300762 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300763 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300764 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200765 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300766
767 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300768 browser->he_selection = entry;
769 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300770 }
771
772 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300773 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300774 folded_sign = hist_entry__folded(entry);
775 }
776
777 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900778 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900779 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900780 .folded_sign = folded_sign,
781 .current_entry = current_entry,
782 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900783 struct perf_hpp hpp = {
784 .buf = s,
785 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900786 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900787 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300788
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300789 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900790
Jiri Olsa12400052012-10-13 00:06:16 +0200791 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900792 if (perf_hpp__should_skip(fmt))
793 continue;
794
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900795 if (current_entry && browser->b.navkeypressed) {
796 ui_browser__set_color(&browser->b,
797 HE_COLORSET_SELECTED);
798 } else {
799 ui_browser__set_color(&browser->b,
800 HE_COLORSET_NORMAL);
801 }
802
803 if (first) {
804 if (symbol_conf.use_callchain) {
805 slsmg_printf("%c ", folded_sign);
806 width -= 2;
807 }
808 first = false;
809 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900810 slsmg_printf(" ");
811 width -= 2;
812 }
813
Jiri Olsa12400052012-10-13 00:06:16 +0200814 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100815 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900816 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100817 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900818 slsmg_printf("%s", s);
819 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300820 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200821
822 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300823 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200824 width += 1;
825
Namhyung Kim26d8b332014-03-03 16:16:20 +0900826 slsmg_write_nstring("", width);
827
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300828 ++row;
829 ++printed;
830 } else
831 --row_offset;
832
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300833 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900834 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900835 struct callchain_print_arg arg = {
836 .row_offset = row_offset,
837 .is_current_entry = current_entry,
838 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900839
Namhyung Kim4087d112014-11-24 17:13:26 +0900840 if (callchain_param.mode == CHAIN_GRAPH_REL) {
841 if (symbol_conf.cumulate_callchain)
842 total = entry->stat_acc->period;
843 else
844 total = entry->stat.period;
845 }
846
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900847 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900848 &entry->sorted_chain, 1, row, total,
849 hist_browser__show_callchain_entry, &arg,
850 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900851
Namhyung Kim39ee5332014-08-22 09:13:21 +0900852 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300853 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300854 }
855
856 return printed;
857}
858
Jiri Olsa81a888f2014-06-14 15:44:52 +0200859static int advance_hpp_check(struct perf_hpp *hpp, int inc)
860{
861 advance_hpp(hpp, inc);
862 return hpp->size <= 0;
863}
864
865static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
866{
867 struct perf_hpp dummy_hpp = {
868 .buf = buf,
869 .size = size,
870 };
871 struct perf_hpp_fmt *fmt;
872 size_t ret = 0;
873
874 if (symbol_conf.use_callchain) {
875 ret = scnprintf(buf, size, " ");
876 if (advance_hpp_check(&dummy_hpp, ret))
877 return ret;
878 }
879
880 perf_hpp__for_each_format(fmt) {
881 if (perf_hpp__should_skip(fmt))
882 continue;
883
Jiri Olsa81a888f2014-06-14 15:44:52 +0200884 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
885 if (advance_hpp_check(&dummy_hpp, ret))
886 break;
887
888 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
889 if (advance_hpp_check(&dummy_hpp, ret))
890 break;
891 }
892
893 return ret;
894}
895
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200896static void hist_browser__show_headers(struct hist_browser *browser)
897{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200898 char headers[1024];
899
900 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200901 ui_browser__gotorc(&browser->b, 0, 0);
902 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200903 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200904}
905
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300906static void ui_browser__hists_init_top(struct ui_browser *browser)
907{
908 if (browser->top == NULL) {
909 struct hist_browser *hb;
910
911 hb = container_of(browser, struct hist_browser, b);
912 browser->top = rb_first(&hb->hists->entries);
913 }
914}
915
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300916static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300917{
918 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200919 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300920 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300921 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300922
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200923 if (hb->show_headers) {
924 hist_browser__show_headers(hb);
925 header_offset = 1;
926 }
927
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300928 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300929
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300930 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300931 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900932 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300933
934 if (h->filtered)
935 continue;
936
Namhyung Kim14135662013-10-31 10:17:39 +0900937 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900938 if (percent < hb->min_pcnt)
939 continue;
940
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300941 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300942 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300943 break;
944 }
945
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200946 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300947}
948
Namhyung Kim064f1982013-05-14 11:09:04 +0900949static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900950 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300951{
952 while (nd != NULL) {
953 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900954 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900955
Namhyung Kimc0f15272014-04-16 11:16:33 +0900956 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300957 return nd;
958
959 nd = rb_next(nd);
960 }
961
962 return NULL;
963}
964
Namhyung Kim064f1982013-05-14 11:09:04 +0900965static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900966 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300967{
968 while (nd != NULL) {
969 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900970 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900971
972 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300973 return nd;
974
975 nd = rb_prev(nd);
976 }
977
978 return NULL;
979}
980
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300981static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300982 off_t offset, int whence)
983{
984 struct hist_entry *h;
985 struct rb_node *nd;
986 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900987 struct hist_browser *hb;
988
989 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300990
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300991 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300992 return;
993
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300994 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300995
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300996 switch (whence) {
997 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900998 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900999 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001000 break;
1001 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001002 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001003 goto do_offset;
1004 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001005 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001006 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001007 first = false;
1008 break;
1009 default:
1010 return;
1011 }
1012
1013 /*
1014 * Moves not relative to the first visible entry invalidates its
1015 * row_offset:
1016 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001017 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001018 h->row_offset = 0;
1019
1020 /*
1021 * Here we have to check if nd is expanded (+), if it is we can't go
1022 * the next top level hist_entry, instead we must compute an offset of
1023 * what _not_ to show and not change the first visible entry.
1024 *
1025 * This offset increments when we are going from top to bottom and
1026 * decreases when we're going from bottom to top.
1027 *
1028 * As we don't have backpointers to the top level in the callchains
1029 * structure, we need to always print the whole hist_entry callchain,
1030 * skipping the first ones that are before the first visible entry
1031 * and stop when we printed enough lines to fill the screen.
1032 */
1033do_offset:
1034 if (offset > 0) {
1035 do {
1036 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001037 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001038 u16 remaining = h->nr_rows - h->row_offset;
1039 if (offset > remaining) {
1040 offset -= remaining;
1041 h->row_offset = 0;
1042 } else {
1043 h->row_offset += offset;
1044 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001045 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001046 break;
1047 }
1048 }
Namhyung Kim14135662013-10-31 10:17:39 +09001049 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001050 if (nd == NULL)
1051 break;
1052 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001053 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001054 } while (offset != 0);
1055 } else if (offset < 0) {
1056 while (1) {
1057 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001058 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001059 if (first) {
1060 if (-offset > h->row_offset) {
1061 offset += h->row_offset;
1062 h->row_offset = 0;
1063 } else {
1064 h->row_offset += offset;
1065 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001066 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001067 break;
1068 }
1069 } else {
1070 if (-offset > h->nr_rows) {
1071 offset += h->nr_rows;
1072 h->row_offset = 0;
1073 } else {
1074 h->row_offset = h->nr_rows + offset;
1075 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001076 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001077 break;
1078 }
1079 }
1080 }
1081
Namhyung Kim14135662013-10-31 10:17:39 +09001082 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001083 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001084 if (nd == NULL)
1085 break;
1086 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001087 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001088 if (offset == 0) {
1089 /*
1090 * Last unfiltered hist_entry, check if it is
1091 * unfolded, if it is then we should have
1092 * row_offset at its last entry.
1093 */
1094 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001095 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001096 h->row_offset = h->nr_rows;
1097 break;
1098 }
1099 first = false;
1100 }
1101 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001102 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001103 h = rb_entry(nd, struct hist_entry, rb_node);
1104 h->row_offset = 0;
1105 }
1106}
1107
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001108static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001109 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001110{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001111 u64 total = hists__total_period(he->hists);
1112 struct callchain_print_arg arg = {
1113 .fp = fp,
1114 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001115
Namhyung Kim39ee5332014-08-22 09:13:21 +09001116 if (symbol_conf.cumulate_callchain)
1117 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001118
Namhyung Kim39ee5332014-08-22 09:13:21 +09001119 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1120 hist_browser__fprintf_callchain_entry, &arg,
1121 hist_browser__check_dump_full);
1122 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001123}
1124
1125static int hist_browser__fprintf_entry(struct hist_browser *browser,
1126 struct hist_entry *he, FILE *fp)
1127{
1128 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001129 int printed = 0;
1130 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001131 struct perf_hpp hpp = {
1132 .buf = s,
1133 .size = sizeof(s),
1134 };
1135 struct perf_hpp_fmt *fmt;
1136 bool first = true;
1137 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001138
1139 if (symbol_conf.use_callchain)
1140 folded_sign = hist_entry__folded(he);
1141
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001142 if (symbol_conf.use_callchain)
1143 printed += fprintf(fp, "%c ", folded_sign);
1144
Namhyung Kim26d8b332014-03-03 16:16:20 +09001145 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001146 if (perf_hpp__should_skip(fmt))
1147 continue;
1148
Namhyung Kim26d8b332014-03-03 16:16:20 +09001149 if (!first) {
1150 ret = scnprintf(hpp.buf, hpp.size, " ");
1151 advance_hpp(&hpp, ret);
1152 } else
1153 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001154
Namhyung Kim26d8b332014-03-03 16:16:20 +09001155 ret = fmt->entry(fmt, &hpp, he);
1156 advance_hpp(&hpp, ret);
1157 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001158 printed += fprintf(fp, "%s\n", rtrim(s));
1159
1160 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001161 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001162
1163 return printed;
1164}
1165
1166static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1167{
Namhyung Kim064f1982013-05-14 11:09:04 +09001168 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001169 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001170 int printed = 0;
1171
1172 while (nd) {
1173 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1174
1175 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001176 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001177 }
1178
1179 return printed;
1180}
1181
1182static int hist_browser__dump(struct hist_browser *browser)
1183{
1184 char filename[64];
1185 FILE *fp;
1186
1187 while (1) {
1188 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1189 if (access(filename, F_OK))
1190 break;
1191 /*
1192 * XXX: Just an arbitrary lazy upper limit
1193 */
1194 if (++browser->print_seq == 8192) {
1195 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1196 return -1;
1197 }
1198 }
1199
1200 fp = fopen(filename, "w");
1201 if (fp == NULL) {
1202 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001203 const char *err = strerror_r(errno, bf, sizeof(bf));
1204 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001205 return -1;
1206 }
1207
1208 ++browser->print_seq;
1209 hist_browser__fprintf(browser, fp);
1210 fclose(fp);
1211 ui_helpline__fpush("%s written!", filename);
1212
1213 return 0;
1214}
1215
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001216static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001217 struct hist_browser_timer *hbt,
1218 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001220 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001222 if (browser) {
1223 browser->hists = hists;
1224 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001225 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001226 browser->b.seek = ui_browser__hists_seek;
1227 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001228 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001229 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001230 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001231 }
1232
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001233 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001234}
1235
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001236static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001237{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001238 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001239}
1240
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001241static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001242{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001243 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001244}
1245
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001246static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001247{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001248 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001249}
1250
Taeung Song1e378eb2014-10-07 16:13:15 +09001251/* Check whether the browser is for 'top' or 'report' */
1252static inline bool is_report_browser(void *timer)
1253{
1254 return timer == NULL;
1255}
1256
1257static int hists__browser_title(struct hists *hists,
1258 struct hist_browser_timer *hbt,
1259 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001260{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001261 char unit;
1262 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001263 const struct dso *dso = hists->dso_filter;
1264 const struct thread *thread = hists->thread_filter;
1265 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1266 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001267 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001268 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001269 char buf[512];
1270 size_t buflen = sizeof(buf);
1271
Namhyung Kimf2148332014-01-14 11:52:48 +09001272 if (symbol_conf.filter_relative) {
1273 nr_samples = hists->stats.nr_non_filtered_samples;
1274 nr_events = hists->stats.total_non_filtered_period;
1275 }
1276
Namhyung Kim759ff492013-03-05 14:53:26 +09001277 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001278 struct perf_evsel *pos;
1279
1280 perf_evsel__group_desc(evsel, buf, buflen);
1281 ev_name = buf;
1282
1283 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001284 struct hists *pos_hists = evsel__hists(pos);
1285
Namhyung Kimf2148332014-01-14 11:52:48 +09001286 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001287 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1288 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001289 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001290 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1291 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001292 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001293 }
1294 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001295
Ashay Ranecc686282012-04-05 21:01:01 -05001296 nr_samples = convert_unit(nr_samples, &unit);
1297 printed = scnprintf(bf, size,
Tom Huynhe641f692014-12-02 11:37:22 -06001298 "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
Ashay Ranecc686282012-04-05 21:01:01 -05001299 nr_samples, unit, ev_name, nr_events);
1300
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001301
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001302 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001303 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001304 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001305 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001306 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001307 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001308 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001309 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001310 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001311 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001312 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001313 if (!is_report_browser(hbt)) {
1314 struct perf_top *top = hbt->arg;
1315
1316 if (top->zero)
1317 printed += scnprintf(bf + printed, size - printed, " [z]");
1318 }
1319
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001320 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001321}
1322
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001323static inline void free_popup_options(char **options, int n)
1324{
1325 int i;
1326
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001327 for (i = 0; i < n; ++i)
1328 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001329}
1330
Feng Tang341487ab2013-02-03 14:38:20 +08001331/*
1332 * Only runtime switching of perf data file will make "input_name" point
1333 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1334 * whether we need to call free() for current "input_name" during the switch.
1335 */
1336static bool is_input_name_malloced = false;
1337
1338static int switch_data_file(void)
1339{
1340 char *pwd, *options[32], *abs_path[32], *tmp;
1341 DIR *pwd_dir;
1342 int nr_options = 0, choice = -1, ret = -1;
1343 struct dirent *dent;
1344
1345 pwd = getenv("PWD");
1346 if (!pwd)
1347 return ret;
1348
1349 pwd_dir = opendir(pwd);
1350 if (!pwd_dir)
1351 return ret;
1352
1353 memset(options, 0, sizeof(options));
1354 memset(options, 0, sizeof(abs_path));
1355
1356 while ((dent = readdir(pwd_dir))) {
1357 char path[PATH_MAX];
1358 u64 magic;
1359 char *name = dent->d_name;
1360 FILE *file;
1361
1362 if (!(dent->d_type == DT_REG))
1363 continue;
1364
1365 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1366
1367 file = fopen(path, "r");
1368 if (!file)
1369 continue;
1370
1371 if (fread(&magic, 1, 8, file) < 8)
1372 goto close_file_and_continue;
1373
1374 if (is_perf_magic(magic)) {
1375 options[nr_options] = strdup(name);
1376 if (!options[nr_options])
1377 goto close_file_and_continue;
1378
1379 abs_path[nr_options] = strdup(path);
1380 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001381 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001382 ui__warning("Can't search all data files due to memory shortage.\n");
1383 fclose(file);
1384 break;
1385 }
1386
1387 nr_options++;
1388 }
1389
1390close_file_and_continue:
1391 fclose(file);
1392 if (nr_options >= 32) {
1393 ui__warning("Too many perf data files in PWD!\n"
1394 "Only the first 32 files will be listed.\n");
1395 break;
1396 }
1397 }
1398 closedir(pwd_dir);
1399
1400 if (nr_options) {
1401 choice = ui__popup_menu(nr_options, options);
1402 if (choice < nr_options && choice >= 0) {
1403 tmp = strdup(abs_path[choice]);
1404 if (tmp) {
1405 if (is_input_name_malloced)
1406 free((void *)input_name);
1407 input_name = tmp;
1408 is_input_name_malloced = true;
1409 ret = 0;
1410 } else
1411 ui__warning("Data switch failed due to memory shortage!\n");
1412 }
1413 }
1414
1415 free_popup_options(options, nr_options);
1416 free_popup_options(abs_path, nr_options);
1417 return ret;
1418}
1419
Namhyung Kimea7cd592015-04-22 16:18:19 +09001420struct popup_action {
1421 struct thread *thread;
1422 struct dso *dso;
1423 struct map_symbol ms;
1424
1425 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1426};
1427
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001428static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001429do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001430{
1431 struct perf_evsel *evsel;
1432 struct annotation *notes;
1433 struct hist_entry *he;
1434 int err;
1435
1436 if (!objdump_path && perf_session_env__lookup_objdump(browser->env))
1437 return 0;
1438
Namhyung Kimea7cd592015-04-22 16:18:19 +09001439 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001440 if (!notes->src)
1441 return 0;
1442
1443 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001444 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001445 he = hist_browser__selected_entry(browser);
1446 /*
1447 * offer option to annotate the other branch source or target
1448 * (if they exists) when returning from annotate
1449 */
1450 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1451 return 1;
1452
1453 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1454 if (err)
1455 ui_browser__handle_resize(&browser->b);
1456 return 0;
1457}
1458
1459static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001460add_annotate_opt(struct hist_browser *browser __maybe_unused,
1461 struct popup_action *act, char **optstr,
1462 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001463{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001464 if (sym == NULL || map->dso->annotate_warned)
1465 return 0;
1466
1467 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1468 return 0;
1469
1470 act->ms.map = map;
1471 act->ms.sym = sym;
1472 act->fn = do_annotate;
1473 return 1;
1474}
1475
1476static int
1477do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1478{
1479 struct thread *thread = act->thread;
1480
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001481 if (browser->hists->thread_filter) {
1482 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1483 perf_hpp__set_elide(HISTC_THREAD, false);
1484 thread__zput(browser->hists->thread_filter);
1485 ui_helpline__pop();
1486 } else {
1487 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1488 thread->comm_set ? thread__comm_str(thread) : "",
1489 thread->tid);
1490 browser->hists->thread_filter = thread__get(thread);
1491 perf_hpp__set_elide(HISTC_THREAD, false);
1492 pstack__push(browser->pstack, &browser->hists->thread_filter);
1493 }
1494
1495 hists__filter_by_thread(browser->hists);
1496 hist_browser__reset(browser);
1497 return 0;
1498}
1499
1500static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001501add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1502 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001503{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001504 if (thread == NULL)
1505 return 0;
1506
1507 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1508 browser->hists->thread_filter ? "out of" : "into",
1509 thread->comm_set ? thread__comm_str(thread) : "",
1510 thread->tid) < 0)
1511 return 0;
1512
1513 act->thread = thread;
1514 act->fn = do_zoom_thread;
1515 return 1;
1516}
1517
1518static int
1519do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1520{
1521 struct dso *dso = act->dso;
1522
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001523 if (browser->hists->dso_filter) {
1524 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1525 perf_hpp__set_elide(HISTC_DSO, false);
1526 browser->hists->dso_filter = NULL;
1527 ui_helpline__pop();
1528 } else {
1529 if (dso == NULL)
1530 return 0;
1531 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1532 dso->kernel ? "the Kernel" : dso->short_name);
1533 browser->hists->dso_filter = dso;
1534 perf_hpp__set_elide(HISTC_DSO, true);
1535 pstack__push(browser->pstack, &browser->hists->dso_filter);
1536 }
1537
1538 hists__filter_by_dso(browser->hists);
1539 hist_browser__reset(browser);
1540 return 0;
1541}
1542
1543static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001544add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1545 char **optstr, struct dso *dso)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001546{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001547 if (dso == NULL)
1548 return 0;
1549
1550 if (asprintf(optstr, "Zoom %s %s DSO",
1551 browser->hists->dso_filter ? "out of" : "into",
1552 dso->kernel ? "the Kernel" : dso->short_name) < 0)
1553 return 0;
1554
1555 act->dso = dso;
1556 act->fn = do_zoom_dso;
1557 return 1;
1558}
1559
1560static int
1561do_browse_map(struct hist_browser *browser __maybe_unused,
1562 struct popup_action *act)
1563{
1564 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001565 return 0;
1566}
1567
1568static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001569add_map_opt(struct hist_browser *browser __maybe_unused,
1570 struct popup_action *act, char **optstr, struct map *map)
1571{
1572 if (map == NULL)
1573 return 0;
1574
1575 if (asprintf(optstr, "Browse map details") < 0)
1576 return 0;
1577
1578 act->ms.map = map;
1579 act->fn = do_browse_map;
1580 return 1;
1581}
1582
1583static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001584do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001585 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001586{
1587 char script_opt[64];
1588 memset(script_opt, 0, sizeof(script_opt));
1589
Namhyung Kimea7cd592015-04-22 16:18:19 +09001590 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001591 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001592 thread__comm_str(act->thread));
1593 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001594 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001595 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001596 }
1597
1598 script_browse(script_opt);
1599 return 0;
1600}
1601
1602static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001603add_script_opt(struct hist_browser *browser __maybe_unused,
1604 struct popup_action *act, char **optstr,
1605 struct thread *thread, struct symbol *sym)
1606{
1607 if (thread) {
1608 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1609 thread__comm_str(thread)) < 0)
1610 return 0;
1611 } else if (sym) {
1612 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1613 sym->name) < 0)
1614 return 0;
1615 } else {
1616 if (asprintf(optstr, "Run scripts for all samples") < 0)
1617 return 0;
1618 }
1619
1620 act->thread = thread;
1621 act->ms.sym = sym;
1622 act->fn = do_run_script;
1623 return 1;
1624}
1625
1626static int
1627do_switch_data(struct hist_browser *browser __maybe_unused,
1628 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001629{
1630 if (switch_data_file()) {
1631 ui__warning("Won't switch the data files due to\n"
1632 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001633 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001634 }
1635
1636 return K_SWITCH_INPUT_DATA;
1637}
1638
Namhyung Kimea7cd592015-04-22 16:18:19 +09001639static int
1640add_switch_opt(struct hist_browser *browser,
1641 struct popup_action *act, char **optstr)
1642{
1643 if (!is_report_browser(browser->hbt))
1644 return 0;
1645
1646 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1647 return 0;
1648
1649 act->fn = do_switch_data;
1650 return 1;
1651}
1652
1653static int
1654do_exit_browser(struct hist_browser *browser __maybe_unused,
1655 struct popup_action *act __maybe_unused)
1656{
1657 return 0;
1658}
1659
1660static int
1661add_exit_opt(struct hist_browser *browser __maybe_unused,
1662 struct popup_action *act, char **optstr)
1663{
1664 if (asprintf(optstr, "Exit") < 0)
1665 return 0;
1666
1667 act->fn = do_exit_browser;
1668 return 1;
1669}
1670
Namhyung Kim112f7612014-04-22 14:05:35 +09001671static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001672{
1673 u64 nr_entries = 0;
1674 struct rb_node *nd = rb_first(&hb->hists->entries);
1675
Namhyung Kim268397c2014-04-22 14:49:31 +09001676 if (hb->min_pcnt == 0) {
1677 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1678 return;
1679 }
1680
Namhyung Kim14135662013-10-31 10:17:39 +09001681 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001682 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001683 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001684 }
1685
Namhyung Kim112f7612014-04-22 14:05:35 +09001686 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001687}
Feng Tang341487ab2013-02-03 14:38:20 +08001688
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001689static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001690 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001691 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001692 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001693 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001694 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001695{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001696 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001697 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001698 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001699#define MAX_OPTIONS 16
1700 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09001701 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001702 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001703 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001704 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001705 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001706 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001707
Namhyung Kime8e684a2013-12-26 14:37:58 +09001708#define HIST_BROWSER_HELP_COMMON \
1709 "h/?/F1 Show this window\n" \
1710 "UP/DOWN/PGUP\n" \
1711 "PGDN/SPACE Navigate\n" \
1712 "q/ESC/CTRL+C Exit browser\n\n" \
1713 "For multiple event sessions:\n\n" \
1714 "TAB/UNTAB Switch events\n\n" \
1715 "For symbolic views (--sort has sym):\n\n" \
1716 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1717 "<- Zoom out\n" \
1718 "a Annotate current symbol\n" \
1719 "C Collapse all callchains\n" \
1720 "d Zoom into current DSO\n" \
1721 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001722 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001723 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001724
1725 /* help messages are sorted by lexical order of the hotkey */
1726 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001727 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001728 "P Print histograms to perf.hist.N\n"
1729 "r Run available scripts\n"
1730 "s Switch to another data file in PWD\n"
1731 "t Zoom into current Thread\n"
1732 "V Verbose (DSO names in callchains, etc)\n"
1733 "/ Filter symbol by name";
1734 const char top_help[] = HIST_BROWSER_HELP_COMMON
1735 "P Print histograms to perf.hist.N\n"
1736 "t Zoom into current Thread\n"
1737 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001738 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001739 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001740 "/ Filter symbol by name";
1741
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001742 if (browser == NULL)
1743 return -1;
1744
Namhyung Kimed426912015-05-29 21:53:44 +09001745 /* reset abort key so that it can get Ctrl-C as a key */
1746 SLang_reset_tty();
1747 SLang_init_tty(0, 0, 0);
1748
Namhyung Kim064f1982013-05-14 11:09:04 +09001749 if (min_pcnt) {
1750 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001751 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001752 }
1753
Namhyung Kim01f00a12015-04-22 16:18:16 +09001754 browser->pstack = pstack__new(2);
1755 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001756 goto out;
1757
1758 ui_helpline__push(helpline);
1759
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001760 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09001761 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001762
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001763 perf_hpp__for_each_format(fmt)
1764 perf_hpp__reset_width(fmt, hists);
1765
Namhyung Kim5b591662014-07-31 14:47:38 +09001766 if (symbol_conf.col_width_list_str)
1767 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1768
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001770 struct thread *thread = NULL;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001771 struct dso *dso = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001772 int choice = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001773
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001774 nr_options = 0;
1775
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001776 key = hist_browser__run(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001777
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001778 if (browser->he_selection != NULL) {
1779 thread = hist_browser__selected_thread(browser);
1780 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1781 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001782 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001783 case K_TAB:
1784 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001785 if (nr_events == 1)
1786 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001787 /*
1788 * Exit the browser, let hists__browser_tree
1789 * go to the next or previous
1790 */
1791 goto out_free_stack;
1792 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001793 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001794 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001795 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001796 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001797 continue;
1798 }
1799
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001800 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001801 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001802 browser->selection->map->dso->annotate_warned)
1803 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001804
Namhyung Kimea7cd592015-04-22 16:18:19 +09001805 actions->ms.map = browser->selection->map;
1806 actions->ms.sym = browser->selection->sym;
1807 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001808 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001809 case 'P':
1810 hist_browser__dump(browser);
1811 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001812 case 'd':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001813 actions->dso = dso;
1814 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001815 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001816 case 'V':
1817 browser->show_dso = !browser->show_dso;
1818 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001819 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001820 actions->thread = thread;
1821 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001822 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001823 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001824 if (ui_browser__input_window("Symbol to show",
1825 "Please enter the name of symbol you want to see",
1826 buf, "ENTER: OK, ESC: Cancel",
1827 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001828 hists->symbol_filter_str = *buf ? buf : NULL;
1829 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001830 hist_browser__reset(browser);
1831 }
1832 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001833 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001834 if (is_report_browser(hbt)) {
1835 actions->thread = NULL;
1836 actions->ms.sym = NULL;
1837 do_run_script(browser, actions);
1838 }
Feng Tangc77d8d72012-11-01 00:00:55 +08001839 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001840 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001841 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001842 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001843 if (key == K_SWITCH_INPUT_DATA)
1844 goto out_free_stack;
1845 }
Feng Tang341487ab2013-02-03 14:38:20 +08001846 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001847 case 'i':
1848 /* env->arch is NULL for live-mode (i.e. perf top) */
1849 if (env->arch)
1850 tui__header_window(env);
1851 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001852 case 'F':
1853 symbol_conf.filter_relative ^= 1;
1854 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001855 case 'z':
1856 if (!is_report_browser(hbt)) {
1857 struct perf_top *top = hbt->arg;
1858
1859 top->zero = !top->zero;
1860 }
1861 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001862 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001863 case 'h':
1864 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001865 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001866 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001867 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001868 case K_ENTER:
1869 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001870 /* menu */
1871 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001872 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001873 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001874
Namhyung Kim01f00a12015-04-22 16:18:16 +09001875 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001876 /*
1877 * Go back to the perf_evsel_menu__run or other user
1878 */
1879 if (left_exits)
1880 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001881 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001882 }
Namhyung Kim64221842015-04-24 10:15:33 +09001883 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001884 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001885 /*
1886 * No need to set actions->dso here since
1887 * it's just to remove the current filter.
1888 * Ditto for thread below.
1889 */
1890 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001891 }
Namhyung Kim64221842015-04-24 10:15:33 +09001892 if (top == &browser->hists->thread_filter)
1893 do_zoom_thread(browser, actions);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001894 continue;
1895 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001896 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001897 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001898 !ui_browser__dialog_yesno(&browser->b,
1899 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001900 continue;
1901 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001902 case 'q':
1903 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03001904 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001905 case 'f':
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03001906 if (is_report_browser(hbt))
1907 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001908 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001909 default:
1910 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001911 }
1912
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001913 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001914 goto add_exit_option;
1915
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001916 if (browser->selection == NULL)
1917 goto skip_annotation;
1918
Namhyung Kim55369fc2013-04-01 20:35:20 +09001919 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001920 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001921
1922 if (bi == NULL)
1923 goto skip_annotation;
1924
Namhyung Kimea7cd592015-04-22 16:18:19 +09001925 nr_options += add_annotate_opt(browser,
1926 &actions[nr_options],
1927 &options[nr_options],
1928 bi->from.map,
1929 bi->from.sym);
1930 if (bi->to.sym != bi->from.sym)
1931 nr_options += add_annotate_opt(browser,
1932 &actions[nr_options],
1933 &options[nr_options],
1934 bi->to.map,
1935 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001936 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001937 nr_options += add_annotate_opt(browser,
1938 &actions[nr_options],
1939 &options[nr_options],
1940 browser->selection->map,
1941 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001942 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001943skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09001944 nr_options += add_thread_opt(browser, &actions[nr_options],
1945 &options[nr_options], thread);
1946 nr_options += add_dso_opt(browser, &actions[nr_options],
1947 &options[nr_options], dso);
1948 nr_options += add_map_opt(browser, &actions[nr_options],
1949 &options[nr_options],
1950 browser->selection->map);
Feng Tangcdbab7c2012-10-30 11:56:06 +08001951
1952 /* perf script support */
1953 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001954 nr_options += add_script_opt(browser,
1955 &actions[nr_options],
1956 &options[nr_options],
1957 thread, NULL);
1958 nr_options += add_script_opt(browser,
1959 &actions[nr_options],
1960 &options[nr_options],
1961 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08001962 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09001963 nr_options += add_script_opt(browser, &actions[nr_options],
1964 &options[nr_options], NULL, NULL);
1965 nr_options += add_switch_opt(browser, &actions[nr_options],
1966 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001967add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09001968 nr_options += add_exit_opt(browser, &actions[nr_options],
1969 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001970
Namhyung Kimea7cd592015-04-22 16:18:19 +09001971 do {
1972 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001973
Namhyung Kimea7cd592015-04-22 16:18:19 +09001974 choice = ui__popup_menu(nr_options, options);
1975 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08001976 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001977
1978 act = &actions[choice];
1979 key = act->fn(browser, act);
1980 } while (key == 1);
1981
1982 if (key == K_SWITCH_INPUT_DATA)
1983 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001984 }
1985out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09001986 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001987out:
1988 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001989 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001990 return key;
1991}
1992
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001993struct perf_evsel_menu {
1994 struct ui_browser b;
1995 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001996 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001997 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001998 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001999};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002000
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002001static void perf_evsel_menu__write(struct ui_browser *browser,
2002 void *entry, int row)
2003{
2004 struct perf_evsel_menu *menu = container_of(browser,
2005 struct perf_evsel_menu, b);
2006 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002007 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002008 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002009 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002010 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002011 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002012 const char *warn = " ";
2013 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002014
2015 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2016 HE_COLORSET_NORMAL);
2017
Namhyung Kim759ff492013-03-05 14:53:26 +09002018 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002019 struct perf_evsel *pos;
2020
2021 ev_name = perf_evsel__group_name(evsel);
2022
2023 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002024 struct hists *pos_hists = evsel__hists(pos);
2025 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002026 }
2027 }
2028
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002029 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002030 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002031 unit, unit == ' ' ? "" : " ", ev_name);
2032 slsmg_printf("%s", bf);
2033
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002034 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002035 if (nr_events != 0) {
2036 menu->lost_events = true;
2037 if (!current_entry)
2038 ui_browser__set_color(browser, HE_COLORSET_TOP);
2039 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002040 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2041 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002042 warn = bf;
2043 }
2044
2045 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002046
2047 if (current_entry)
2048 menu->selection = evsel;
2049}
2050
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002051static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2052 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002053 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002054{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002055 struct perf_evlist *evlist = menu->b.priv;
2056 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002057 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002058 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002059 int key;
2060
2061 if (ui_browser__show(&menu->b, title,
2062 "ESC: exit, ENTER|->: Browse histograms") < 0)
2063 return -1;
2064
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002065 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002066 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002067
2068 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002069 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002070 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002071
2072 if (!menu->lost_events_warned && menu->lost_events) {
2073 ui_browser__warn_lost_events(&menu->b);
2074 menu->lost_events_warned = true;
2075 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002076 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002077 case K_RIGHT:
2078 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002079 if (!menu->selection)
2080 continue;
2081 pos = menu->selection;
2082browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002083 perf_evlist__set_selected(evlist, pos);
2084 /*
2085 * Give the calling tool a chance to populate the non
2086 * default evsel resorted hists tree.
2087 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002088 if (hbt)
2089 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002090 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002091 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002092 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002093 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002094 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002095 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002096 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002097 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002098 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002099 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002100 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002101 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002102 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002103 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002104 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002105 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002106 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002107 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002108 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002109 if (!ui_browser__dialog_yesno(&menu->b,
2110 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002111 continue;
2112 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08002113 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002114 case 'q':
2115 case CTRL('c'):
2116 goto out;
2117 default:
2118 continue;
2119 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002120 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002121 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002122 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002123 if (!ui_browser__dialog_yesno(&menu->b,
2124 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002125 continue;
2126 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002127 case 'q':
2128 case CTRL('c'):
2129 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002130 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002131 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002132 }
2133 }
2134
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002135out:
2136 ui_browser__hide(&menu->b);
2137 return key;
2138}
2139
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002140static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002141 void *entry)
2142{
2143 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2144
2145 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2146 return true;
2147
2148 return false;
2149}
2150
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002151static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002152 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002153 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002154 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002155 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002156{
2157 struct perf_evsel *pos;
2158 struct perf_evsel_menu menu = {
2159 .b = {
2160 .entries = &evlist->entries,
2161 .refresh = ui_browser__list_head_refresh,
2162 .seek = ui_browser__list_head_seek,
2163 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002164 .filter = filter_group_entries,
2165 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002166 .priv = evlist,
2167 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002168 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002169 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002170 };
2171
2172 ui_helpline__push("Press ESC to exit");
2173
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002174 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002175 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002176 size_t line_len = strlen(ev_name) + 7;
2177
2178 if (menu.b.width < line_len)
2179 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002180 }
2181
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002182 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002183}
2184
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002185int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002186 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002187 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002188 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002189{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002190 int nr_entries = evlist->nr_entries;
2191
2192single_entry:
2193 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002194 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002195
2196 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002197 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002198 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002199 }
2200
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002201 if (symbol_conf.event_group) {
2202 struct perf_evsel *pos;
2203
2204 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002205 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002206 if (perf_evsel__is_group_leader(pos))
2207 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002208 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002209
2210 if (nr_entries == 1)
2211 goto single_entry;
2212 }
2213
2214 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002215 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002216}