blob: c42adb6000914554bf0d109e02d9ad5cec801313 [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
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300427static int hist_browser__run(struct hist_browser *browser, const char *help)
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 Melo5f00b0f2015-06-19 17:30:20 -0300439 if (ui_browser__show(&browser->b, title, help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300440 return -1;
441
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300442 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300443 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300444
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300445 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900446 case K_TIMER: {
447 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900448 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900449
Namhyung Kimc3b78952014-04-22 15:56:17 +0900450 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900451 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900452
Namhyung Kimc3b78952014-04-22 15:56:17 +0900453 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900454 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200455
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300456 if (browser->hists->stats.nr_lost_warned !=
457 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
458 browser->hists->stats.nr_lost_warned =
459 browser->hists->stats.nr_events[PERF_RECORD_LOST];
460 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200461 }
462
Taeung Song1e378eb2014-10-07 16:13:15 +0900463 hists__browser_title(browser->hists,
464 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300465 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300466 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900467 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300468 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300469 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300470 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300471 struct hist_entry, rb_node);
472 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300473 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 -0300474 seq++, browser->b.nr_entries,
475 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300476 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300477 browser->b.index,
478 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300479 h->row_offset, h->nr_rows);
480 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300481 break;
482 case 'C':
483 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300484 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300485 break;
486 case 'E':
487 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300488 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300489 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200490 case 'H':
491 browser->show_headers = !browser->show_headers;
492 hist_browser__update_rows(browser);
493 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200494 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300495 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300496 break;
497 /* fall thru */
498 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300499 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300500 }
501 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300502out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300503 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300504 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300505}
506
Namhyung Kim39ee5332014-08-22 09:13:21 +0900507struct callchain_print_arg {
508 /* for hists browser */
509 off_t row_offset;
510 bool is_current_entry;
511
512 /* for file dump */
513 FILE *fp;
514 int printed;
515};
516
517typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
518 struct callchain_list *chain,
519 const char *str, int offset,
520 unsigned short row,
521 struct callchain_print_arg *arg);
522
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900523static void hist_browser__show_callchain_entry(struct hist_browser *browser,
524 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900525 const char *str, int offset,
526 unsigned short row,
527 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900528{
529 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900530 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300531 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900532
533 color = HE_COLORSET_NORMAL;
534 width = browser->b.width - (offset + 2);
535 if (ui_browser__is_current_entry(&browser->b, row)) {
536 browser->selection = &chain->ms;
537 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900538 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900539 }
540
541 ui_browser__set_color(&browser->b, color);
542 hist_browser__gotorc(browser, row, 0);
543 slsmg_write_nstring(" ", offset);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300544 slsmg_printf("%c", folded_sign);
545 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900546 slsmg_write_nstring(str, width);
547}
548
Namhyung Kim39ee5332014-08-22 09:13:21 +0900549static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
550 struct callchain_list *chain,
551 const char *str, int offset,
552 unsigned short row __maybe_unused,
553 struct callchain_print_arg *arg)
554{
555 char folded_sign = callchain_list__folded(chain);
556
557 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
558 folded_sign, str);
559}
560
561typedef bool (*check_output_full_fn)(struct hist_browser *browser,
562 unsigned short row);
563
564static bool hist_browser__check_output_full(struct hist_browser *browser,
565 unsigned short row)
566{
567 return browser->b.rows == row;
568}
569
570static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
571 unsigned short row __maybe_unused)
572{
573 return false;
574}
575
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300576#define LEVEL_OFFSET_STEP 3
577
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900578static int hist_browser__show_callchain(struct hist_browser *browser,
579 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900580 unsigned short row, u64 total,
581 print_callchain_entry_fn print,
582 struct callchain_print_arg *arg,
583 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300584{
585 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900586 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900587 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900588 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300589
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900590 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900591 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900592
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300593 while (node) {
594 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
595 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100596 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300597 struct callchain_list *chain;
598 char folded_sign = ' ';
599 int first = true;
600 int extra_offset = 0;
601
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300602 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300603 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300604 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300605 bool was_first = first;
606
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300607 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300608 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900609 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300610 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300611
612 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900613 if (arg->row_offset != 0) {
614 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300615 goto do_next;
616 }
617
618 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300619 str = callchain_list__sym_name(chain, bf, sizeof(bf),
620 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900621
Namhyung Kim4087d112014-11-24 17:13:26 +0900622 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900623 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300624
625 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
626 str = "Not enough memory!";
627 else
628 str = alloc_str;
629 }
630
Namhyung Kim39ee5332014-08-22 09:13:21 +0900631 print(browser, chain, str, offset + extra_offset, row, arg);
632
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300633 free(alloc_str);
634
Namhyung Kim39ee5332014-08-22 09:13:21 +0900635 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300636 goto out;
637do_next:
638 if (folded_sign == '+')
639 break;
640 }
641
642 if (folded_sign == '-') {
643 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900644
645 if (callchain_param.mode == CHAIN_GRAPH_REL)
646 new_total = child->children_hit;
647 else
648 new_total = total;
649
650 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900651 new_level, row, new_total,
652 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300653 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900654 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900655 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300656 node = next;
657 }
658out:
659 return row - first_row;
660}
661
Namhyung Kim89701462013-01-22 18:09:38 +0900662struct hpp_arg {
663 struct ui_browser *b;
664 char folded_sign;
665 bool current_entry;
666};
667
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900668static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
669{
670 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900671 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900672 va_list args;
673 double percent;
674
675 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900676 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900677 percent = va_arg(args, double);
678 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900679
Namhyung Kim89701462013-01-22 18:09:38 +0900680 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900681
Namhyung Kimd6751072014-07-31 14:47:36 +0900682 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900683 slsmg_printf("%s", hpp->buf);
684
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900685 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900686 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900687}
688
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900689#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900690static u64 __hpp_get_##_field(struct hist_entry *he) \
691{ \
692 return he->stat._field; \
693} \
694 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100695static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900696hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100697 struct perf_hpp *hpp, \
698 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900699{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900700 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
701 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900702}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900703
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900704#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
705static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
706{ \
707 return he->stat_acc->_field; \
708} \
709 \
710static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900711hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900712 struct perf_hpp *hpp, \
713 struct hist_entry *he) \
714{ \
715 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900716 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900717 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900718 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900719 slsmg_printf("%s", hpp->buf); \
720 \
721 return ret; \
722 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900723 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
724 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900725}
726
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900727__HPP_COLOR_PERCENT_FN(overhead, period)
728__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
729__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
730__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
731__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900732__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900733
734#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900735#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900736
737void hist_browser__init_hpp(void)
738{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900739 perf_hpp__format[PERF_HPP__OVERHEAD].color =
740 hist_browser__hpp_color_overhead;
741 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
742 hist_browser__hpp_color_overhead_sys;
743 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
744 hist_browser__hpp_color_overhead_us;
745 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
746 hist_browser__hpp_color_overhead_guest_sys;
747 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
748 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900749 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
750 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900751}
752
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300753static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300754 struct hist_entry *entry,
755 unsigned short row)
756{
757 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200758 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900759 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300760 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300761 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300762 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300763 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200764 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300765
766 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300767 browser->he_selection = entry;
768 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300769 }
770
771 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300772 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300773 folded_sign = hist_entry__folded(entry);
774 }
775
776 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900777 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900778 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900779 .folded_sign = folded_sign,
780 .current_entry = current_entry,
781 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900782 struct perf_hpp hpp = {
783 .buf = s,
784 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900785 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900786 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300787
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300788 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900789
Jiri Olsa12400052012-10-13 00:06:16 +0200790 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900791 if (perf_hpp__should_skip(fmt))
792 continue;
793
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900794 if (current_entry && browser->b.navkeypressed) {
795 ui_browser__set_color(&browser->b,
796 HE_COLORSET_SELECTED);
797 } else {
798 ui_browser__set_color(&browser->b,
799 HE_COLORSET_NORMAL);
800 }
801
802 if (first) {
803 if (symbol_conf.use_callchain) {
804 slsmg_printf("%c ", folded_sign);
805 width -= 2;
806 }
807 first = false;
808 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900809 slsmg_printf(" ");
810 width -= 2;
811 }
812
Jiri Olsa12400052012-10-13 00:06:16 +0200813 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100814 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900815 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100816 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900817 slsmg_printf("%s", s);
818 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300819 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200820
821 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300822 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200823 width += 1;
824
Namhyung Kim26d8b332014-03-03 16:16:20 +0900825 slsmg_write_nstring("", width);
826
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300827 ++row;
828 ++printed;
829 } else
830 --row_offset;
831
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300832 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900833 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900834 struct callchain_print_arg arg = {
835 .row_offset = row_offset,
836 .is_current_entry = current_entry,
837 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900838
Namhyung Kim4087d112014-11-24 17:13:26 +0900839 if (callchain_param.mode == CHAIN_GRAPH_REL) {
840 if (symbol_conf.cumulate_callchain)
841 total = entry->stat_acc->period;
842 else
843 total = entry->stat.period;
844 }
845
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900846 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900847 &entry->sorted_chain, 1, row, total,
848 hist_browser__show_callchain_entry, &arg,
849 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900850
Namhyung Kim39ee5332014-08-22 09:13:21 +0900851 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300852 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300853 }
854
855 return printed;
856}
857
Jiri Olsa81a888f2014-06-14 15:44:52 +0200858static int advance_hpp_check(struct perf_hpp *hpp, int inc)
859{
860 advance_hpp(hpp, inc);
861 return hpp->size <= 0;
862}
863
864static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
865{
866 struct perf_hpp dummy_hpp = {
867 .buf = buf,
868 .size = size,
869 };
870 struct perf_hpp_fmt *fmt;
871 size_t ret = 0;
872
873 if (symbol_conf.use_callchain) {
874 ret = scnprintf(buf, size, " ");
875 if (advance_hpp_check(&dummy_hpp, ret))
876 return ret;
877 }
878
879 perf_hpp__for_each_format(fmt) {
880 if (perf_hpp__should_skip(fmt))
881 continue;
882
Jiri Olsa81a888f2014-06-14 15:44:52 +0200883 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
884 if (advance_hpp_check(&dummy_hpp, ret))
885 break;
886
887 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
888 if (advance_hpp_check(&dummy_hpp, ret))
889 break;
890 }
891
892 return ret;
893}
894
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200895static void hist_browser__show_headers(struct hist_browser *browser)
896{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200897 char headers[1024];
898
899 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200900 ui_browser__gotorc(&browser->b, 0, 0);
901 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200902 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200903}
904
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300905static void ui_browser__hists_init_top(struct ui_browser *browser)
906{
907 if (browser->top == NULL) {
908 struct hist_browser *hb;
909
910 hb = container_of(browser, struct hist_browser, b);
911 browser->top = rb_first(&hb->hists->entries);
912 }
913}
914
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300915static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300916{
917 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200918 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300919 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300920 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300921
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200922 if (hb->show_headers) {
923 hist_browser__show_headers(hb);
924 header_offset = 1;
925 }
926
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300927 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300928
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300929 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300930 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900931 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300932
933 if (h->filtered)
934 continue;
935
Namhyung Kim14135662013-10-31 10:17:39 +0900936 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900937 if (percent < hb->min_pcnt)
938 continue;
939
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300940 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300941 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300942 break;
943 }
944
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200945 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300946}
947
Namhyung Kim064f1982013-05-14 11:09:04 +0900948static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900949 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300950{
951 while (nd != NULL) {
952 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900953 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900954
Namhyung Kimc0f15272014-04-16 11:16:33 +0900955 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300956 return nd;
957
958 nd = rb_next(nd);
959 }
960
961 return NULL;
962}
963
Namhyung Kim064f1982013-05-14 11:09:04 +0900964static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900965 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300966{
967 while (nd != NULL) {
968 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900969 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900970
971 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300972 return nd;
973
974 nd = rb_prev(nd);
975 }
976
977 return NULL;
978}
979
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300980static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300981 off_t offset, int whence)
982{
983 struct hist_entry *h;
984 struct rb_node *nd;
985 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900986 struct hist_browser *hb;
987
988 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300989
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300990 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300991 return;
992
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300993 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300994
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300995 switch (whence) {
996 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900997 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900998 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300999 break;
1000 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001001 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001002 goto do_offset;
1003 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001004 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001005 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001006 first = false;
1007 break;
1008 default:
1009 return;
1010 }
1011
1012 /*
1013 * Moves not relative to the first visible entry invalidates its
1014 * row_offset:
1015 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001016 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001017 h->row_offset = 0;
1018
1019 /*
1020 * Here we have to check if nd is expanded (+), if it is we can't go
1021 * the next top level hist_entry, instead we must compute an offset of
1022 * what _not_ to show and not change the first visible entry.
1023 *
1024 * This offset increments when we are going from top to bottom and
1025 * decreases when we're going from bottom to top.
1026 *
1027 * As we don't have backpointers to the top level in the callchains
1028 * structure, we need to always print the whole hist_entry callchain,
1029 * skipping the first ones that are before the first visible entry
1030 * and stop when we printed enough lines to fill the screen.
1031 */
1032do_offset:
1033 if (offset > 0) {
1034 do {
1035 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001036 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001037 u16 remaining = h->nr_rows - h->row_offset;
1038 if (offset > remaining) {
1039 offset -= remaining;
1040 h->row_offset = 0;
1041 } else {
1042 h->row_offset += offset;
1043 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001044 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001045 break;
1046 }
1047 }
Namhyung Kim14135662013-10-31 10:17:39 +09001048 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001049 if (nd == NULL)
1050 break;
1051 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001052 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001053 } while (offset != 0);
1054 } else if (offset < 0) {
1055 while (1) {
1056 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001057 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001058 if (first) {
1059 if (-offset > h->row_offset) {
1060 offset += h->row_offset;
1061 h->row_offset = 0;
1062 } else {
1063 h->row_offset += offset;
1064 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001065 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001066 break;
1067 }
1068 } else {
1069 if (-offset > h->nr_rows) {
1070 offset += h->nr_rows;
1071 h->row_offset = 0;
1072 } else {
1073 h->row_offset = h->nr_rows + offset;
1074 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001075 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001076 break;
1077 }
1078 }
1079 }
1080
Namhyung Kim14135662013-10-31 10:17:39 +09001081 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001082 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001083 if (nd == NULL)
1084 break;
1085 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001086 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001087 if (offset == 0) {
1088 /*
1089 * Last unfiltered hist_entry, check if it is
1090 * unfolded, if it is then we should have
1091 * row_offset at its last entry.
1092 */
1093 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001094 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001095 h->row_offset = h->nr_rows;
1096 break;
1097 }
1098 first = false;
1099 }
1100 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001101 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001102 h = rb_entry(nd, struct hist_entry, rb_node);
1103 h->row_offset = 0;
1104 }
1105}
1106
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001107static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001108 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001109{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001110 u64 total = hists__total_period(he->hists);
1111 struct callchain_print_arg arg = {
1112 .fp = fp,
1113 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001114
Namhyung Kim39ee5332014-08-22 09:13:21 +09001115 if (symbol_conf.cumulate_callchain)
1116 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001117
Namhyung Kim39ee5332014-08-22 09:13:21 +09001118 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1119 hist_browser__fprintf_callchain_entry, &arg,
1120 hist_browser__check_dump_full);
1121 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001122}
1123
1124static int hist_browser__fprintf_entry(struct hist_browser *browser,
1125 struct hist_entry *he, FILE *fp)
1126{
1127 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001128 int printed = 0;
1129 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001130 struct perf_hpp hpp = {
1131 .buf = s,
1132 .size = sizeof(s),
1133 };
1134 struct perf_hpp_fmt *fmt;
1135 bool first = true;
1136 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001137
1138 if (symbol_conf.use_callchain)
1139 folded_sign = hist_entry__folded(he);
1140
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001141 if (symbol_conf.use_callchain)
1142 printed += fprintf(fp, "%c ", folded_sign);
1143
Namhyung Kim26d8b332014-03-03 16:16:20 +09001144 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001145 if (perf_hpp__should_skip(fmt))
1146 continue;
1147
Namhyung Kim26d8b332014-03-03 16:16:20 +09001148 if (!first) {
1149 ret = scnprintf(hpp.buf, hpp.size, " ");
1150 advance_hpp(&hpp, ret);
1151 } else
1152 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001153
Namhyung Kim26d8b332014-03-03 16:16:20 +09001154 ret = fmt->entry(fmt, &hpp, he);
1155 advance_hpp(&hpp, ret);
1156 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001157 printed += fprintf(fp, "%s\n", rtrim(s));
1158
1159 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001160 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001161
1162 return printed;
1163}
1164
1165static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1166{
Namhyung Kim064f1982013-05-14 11:09:04 +09001167 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001168 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001169 int printed = 0;
1170
1171 while (nd) {
1172 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1173
1174 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001175 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001176 }
1177
1178 return printed;
1179}
1180
1181static int hist_browser__dump(struct hist_browser *browser)
1182{
1183 char filename[64];
1184 FILE *fp;
1185
1186 while (1) {
1187 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1188 if (access(filename, F_OK))
1189 break;
1190 /*
1191 * XXX: Just an arbitrary lazy upper limit
1192 */
1193 if (++browser->print_seq == 8192) {
1194 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1195 return -1;
1196 }
1197 }
1198
1199 fp = fopen(filename, "w");
1200 if (fp == NULL) {
1201 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001202 const char *err = strerror_r(errno, bf, sizeof(bf));
1203 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001204 return -1;
1205 }
1206
1207 ++browser->print_seq;
1208 hist_browser__fprintf(browser, fp);
1209 fclose(fp);
1210 ui_helpline__fpush("%s written!", filename);
1211
1212 return 0;
1213}
1214
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001215static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001216 struct hist_browser_timer *hbt,
1217 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001219 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001221 if (browser) {
1222 browser->hists = hists;
1223 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001224 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001225 browser->b.seek = ui_browser__hists_seek;
1226 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001227 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001228 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001229 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001230 }
1231
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001232 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001233}
1234
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001235static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001236{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001237 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001238}
1239
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001240static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001242 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001243}
1244
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001245static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001246{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001247 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001248}
1249
Taeung Song1e378eb2014-10-07 16:13:15 +09001250/* Check whether the browser is for 'top' or 'report' */
1251static inline bool is_report_browser(void *timer)
1252{
1253 return timer == NULL;
1254}
1255
1256static int hists__browser_title(struct hists *hists,
1257 struct hist_browser_timer *hbt,
1258 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001260 char unit;
1261 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001262 const struct dso *dso = hists->dso_filter;
1263 const struct thread *thread = hists->thread_filter;
1264 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1265 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001266 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001267 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001268 char buf[512];
1269 size_t buflen = sizeof(buf);
1270
Namhyung Kimf2148332014-01-14 11:52:48 +09001271 if (symbol_conf.filter_relative) {
1272 nr_samples = hists->stats.nr_non_filtered_samples;
1273 nr_events = hists->stats.total_non_filtered_period;
1274 }
1275
Namhyung Kim759ff492013-03-05 14:53:26 +09001276 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001277 struct perf_evsel *pos;
1278
1279 perf_evsel__group_desc(evsel, buf, buflen);
1280 ev_name = buf;
1281
1282 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001283 struct hists *pos_hists = evsel__hists(pos);
1284
Namhyung Kimf2148332014-01-14 11:52:48 +09001285 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001286 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1287 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001288 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001289 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1290 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001291 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001292 }
1293 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001294
Ashay Ranecc686282012-04-05 21:01:01 -05001295 nr_samples = convert_unit(nr_samples, &unit);
1296 printed = scnprintf(bf, size,
Tom Huynhe641f692014-12-02 11:37:22 -06001297 "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
Ashay Ranecc686282012-04-05 21:01:01 -05001298 nr_samples, unit, ev_name, nr_events);
1299
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001300
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001301 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001302 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001303 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001304 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001305 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001306 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001307 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001308 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001309 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001310 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001311 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001312 if (!is_report_browser(hbt)) {
1313 struct perf_top *top = hbt->arg;
1314
1315 if (top->zero)
1316 printed += scnprintf(bf + printed, size - printed, " [z]");
1317 }
1318
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001319 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001320}
1321
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001322static inline void free_popup_options(char **options, int n)
1323{
1324 int i;
1325
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001326 for (i = 0; i < n; ++i)
1327 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001328}
1329
Feng Tang341487ab2013-02-03 14:38:20 +08001330/*
1331 * Only runtime switching of perf data file will make "input_name" point
1332 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1333 * whether we need to call free() for current "input_name" during the switch.
1334 */
1335static bool is_input_name_malloced = false;
1336
1337static int switch_data_file(void)
1338{
1339 char *pwd, *options[32], *abs_path[32], *tmp;
1340 DIR *pwd_dir;
1341 int nr_options = 0, choice = -1, ret = -1;
1342 struct dirent *dent;
1343
1344 pwd = getenv("PWD");
1345 if (!pwd)
1346 return ret;
1347
1348 pwd_dir = opendir(pwd);
1349 if (!pwd_dir)
1350 return ret;
1351
1352 memset(options, 0, sizeof(options));
1353 memset(options, 0, sizeof(abs_path));
1354
1355 while ((dent = readdir(pwd_dir))) {
1356 char path[PATH_MAX];
1357 u64 magic;
1358 char *name = dent->d_name;
1359 FILE *file;
1360
1361 if (!(dent->d_type == DT_REG))
1362 continue;
1363
1364 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1365
1366 file = fopen(path, "r");
1367 if (!file)
1368 continue;
1369
1370 if (fread(&magic, 1, 8, file) < 8)
1371 goto close_file_and_continue;
1372
1373 if (is_perf_magic(magic)) {
1374 options[nr_options] = strdup(name);
1375 if (!options[nr_options])
1376 goto close_file_and_continue;
1377
1378 abs_path[nr_options] = strdup(path);
1379 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001380 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001381 ui__warning("Can't search all data files due to memory shortage.\n");
1382 fclose(file);
1383 break;
1384 }
1385
1386 nr_options++;
1387 }
1388
1389close_file_and_continue:
1390 fclose(file);
1391 if (nr_options >= 32) {
1392 ui__warning("Too many perf data files in PWD!\n"
1393 "Only the first 32 files will be listed.\n");
1394 break;
1395 }
1396 }
1397 closedir(pwd_dir);
1398
1399 if (nr_options) {
1400 choice = ui__popup_menu(nr_options, options);
1401 if (choice < nr_options && choice >= 0) {
1402 tmp = strdup(abs_path[choice]);
1403 if (tmp) {
1404 if (is_input_name_malloced)
1405 free((void *)input_name);
1406 input_name = tmp;
1407 is_input_name_malloced = true;
1408 ret = 0;
1409 } else
1410 ui__warning("Data switch failed due to memory shortage!\n");
1411 }
1412 }
1413
1414 free_popup_options(options, nr_options);
1415 free_popup_options(abs_path, nr_options);
1416 return ret;
1417}
1418
Namhyung Kimea7cd592015-04-22 16:18:19 +09001419struct popup_action {
1420 struct thread *thread;
1421 struct dso *dso;
1422 struct map_symbol ms;
1423
1424 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1425};
1426
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001427static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001428do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001429{
1430 struct perf_evsel *evsel;
1431 struct annotation *notes;
1432 struct hist_entry *he;
1433 int err;
1434
1435 if (!objdump_path && perf_session_env__lookup_objdump(browser->env))
1436 return 0;
1437
Namhyung Kimea7cd592015-04-22 16:18:19 +09001438 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001439 if (!notes->src)
1440 return 0;
1441
1442 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001443 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001444 he = hist_browser__selected_entry(browser);
1445 /*
1446 * offer option to annotate the other branch source or target
1447 * (if they exists) when returning from annotate
1448 */
1449 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1450 return 1;
1451
1452 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1453 if (err)
1454 ui_browser__handle_resize(&browser->b);
1455 return 0;
1456}
1457
1458static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001459add_annotate_opt(struct hist_browser *browser __maybe_unused,
1460 struct popup_action *act, char **optstr,
1461 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001462{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001463 if (sym == NULL || map->dso->annotate_warned)
1464 return 0;
1465
1466 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1467 return 0;
1468
1469 act->ms.map = map;
1470 act->ms.sym = sym;
1471 act->fn = do_annotate;
1472 return 1;
1473}
1474
1475static int
1476do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1477{
1478 struct thread *thread = act->thread;
1479
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001480 if (browser->hists->thread_filter) {
1481 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1482 perf_hpp__set_elide(HISTC_THREAD, false);
1483 thread__zput(browser->hists->thread_filter);
1484 ui_helpline__pop();
1485 } else {
1486 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1487 thread->comm_set ? thread__comm_str(thread) : "",
1488 thread->tid);
1489 browser->hists->thread_filter = thread__get(thread);
1490 perf_hpp__set_elide(HISTC_THREAD, false);
1491 pstack__push(browser->pstack, &browser->hists->thread_filter);
1492 }
1493
1494 hists__filter_by_thread(browser->hists);
1495 hist_browser__reset(browser);
1496 return 0;
1497}
1498
1499static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001500add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1501 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001502{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001503 if (thread == NULL)
1504 return 0;
1505
1506 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1507 browser->hists->thread_filter ? "out of" : "into",
1508 thread->comm_set ? thread__comm_str(thread) : "",
1509 thread->tid) < 0)
1510 return 0;
1511
1512 act->thread = thread;
1513 act->fn = do_zoom_thread;
1514 return 1;
1515}
1516
1517static int
1518do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1519{
1520 struct dso *dso = act->dso;
1521
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001522 if (browser->hists->dso_filter) {
1523 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1524 perf_hpp__set_elide(HISTC_DSO, false);
1525 browser->hists->dso_filter = NULL;
1526 ui_helpline__pop();
1527 } else {
1528 if (dso == NULL)
1529 return 0;
1530 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1531 dso->kernel ? "the Kernel" : dso->short_name);
1532 browser->hists->dso_filter = dso;
1533 perf_hpp__set_elide(HISTC_DSO, true);
1534 pstack__push(browser->pstack, &browser->hists->dso_filter);
1535 }
1536
1537 hists__filter_by_dso(browser->hists);
1538 hist_browser__reset(browser);
1539 return 0;
1540}
1541
1542static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001543add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1544 char **optstr, struct dso *dso)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001545{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001546 if (dso == NULL)
1547 return 0;
1548
1549 if (asprintf(optstr, "Zoom %s %s DSO",
1550 browser->hists->dso_filter ? "out of" : "into",
1551 dso->kernel ? "the Kernel" : dso->short_name) < 0)
1552 return 0;
1553
1554 act->dso = dso;
1555 act->fn = do_zoom_dso;
1556 return 1;
1557}
1558
1559static int
1560do_browse_map(struct hist_browser *browser __maybe_unused,
1561 struct popup_action *act)
1562{
1563 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001564 return 0;
1565}
1566
1567static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001568add_map_opt(struct hist_browser *browser __maybe_unused,
1569 struct popup_action *act, char **optstr, struct map *map)
1570{
1571 if (map == NULL)
1572 return 0;
1573
1574 if (asprintf(optstr, "Browse map details") < 0)
1575 return 0;
1576
1577 act->ms.map = map;
1578 act->fn = do_browse_map;
1579 return 1;
1580}
1581
1582static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001583do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001584 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001585{
1586 char script_opt[64];
1587 memset(script_opt, 0, sizeof(script_opt));
1588
Namhyung Kimea7cd592015-04-22 16:18:19 +09001589 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001590 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001591 thread__comm_str(act->thread));
1592 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001593 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001594 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001595 }
1596
1597 script_browse(script_opt);
1598 return 0;
1599}
1600
1601static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001602add_script_opt(struct hist_browser *browser __maybe_unused,
1603 struct popup_action *act, char **optstr,
1604 struct thread *thread, struct symbol *sym)
1605{
1606 if (thread) {
1607 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1608 thread__comm_str(thread)) < 0)
1609 return 0;
1610 } else if (sym) {
1611 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1612 sym->name) < 0)
1613 return 0;
1614 } else {
1615 if (asprintf(optstr, "Run scripts for all samples") < 0)
1616 return 0;
1617 }
1618
1619 act->thread = thread;
1620 act->ms.sym = sym;
1621 act->fn = do_run_script;
1622 return 1;
1623}
1624
1625static int
1626do_switch_data(struct hist_browser *browser __maybe_unused,
1627 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001628{
1629 if (switch_data_file()) {
1630 ui__warning("Won't switch the data files due to\n"
1631 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001632 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001633 }
1634
1635 return K_SWITCH_INPUT_DATA;
1636}
1637
Namhyung Kimea7cd592015-04-22 16:18:19 +09001638static int
1639add_switch_opt(struct hist_browser *browser,
1640 struct popup_action *act, char **optstr)
1641{
1642 if (!is_report_browser(browser->hbt))
1643 return 0;
1644
1645 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1646 return 0;
1647
1648 act->fn = do_switch_data;
1649 return 1;
1650}
1651
1652static int
1653do_exit_browser(struct hist_browser *browser __maybe_unused,
1654 struct popup_action *act __maybe_unused)
1655{
1656 return 0;
1657}
1658
1659static int
1660add_exit_opt(struct hist_browser *browser __maybe_unused,
1661 struct popup_action *act, char **optstr)
1662{
1663 if (asprintf(optstr, "Exit") < 0)
1664 return 0;
1665
1666 act->fn = do_exit_browser;
1667 return 1;
1668}
1669
Namhyung Kim112f7612014-04-22 14:05:35 +09001670static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001671{
1672 u64 nr_entries = 0;
1673 struct rb_node *nd = rb_first(&hb->hists->entries);
1674
Namhyung Kim268397c2014-04-22 14:49:31 +09001675 if (hb->min_pcnt == 0) {
1676 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1677 return;
1678 }
1679
Namhyung Kim14135662013-10-31 10:17:39 +09001680 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001681 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001682 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001683 }
1684
Namhyung Kim112f7612014-04-22 14:05:35 +09001685 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001686}
Feng Tang341487ab2013-02-03 14:38:20 +08001687
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001688static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001689 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001690 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001691 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001692 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001693 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001694{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001695 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001696 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001697 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001698#define MAX_OPTIONS 16
1699 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09001700 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001701 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001702 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001703 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001704 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001705 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001706
Namhyung Kime8e684a2013-12-26 14:37:58 +09001707#define HIST_BROWSER_HELP_COMMON \
1708 "h/?/F1 Show this window\n" \
1709 "UP/DOWN/PGUP\n" \
1710 "PGDN/SPACE Navigate\n" \
1711 "q/ESC/CTRL+C Exit browser\n\n" \
1712 "For multiple event sessions:\n\n" \
1713 "TAB/UNTAB Switch events\n\n" \
1714 "For symbolic views (--sort has sym):\n\n" \
1715 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1716 "<- Zoom out\n" \
1717 "a Annotate current symbol\n" \
1718 "C Collapse all callchains\n" \
1719 "d Zoom into current DSO\n" \
1720 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001721 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001722 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001723
1724 /* help messages are sorted by lexical order of the hotkey */
1725 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001726 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001727 "P Print histograms to perf.hist.N\n"
1728 "r Run available scripts\n"
1729 "s Switch to another data file in PWD\n"
1730 "t Zoom into current Thread\n"
1731 "V Verbose (DSO names in callchains, etc)\n"
1732 "/ Filter symbol by name";
1733 const char top_help[] = HIST_BROWSER_HELP_COMMON
1734 "P Print histograms to perf.hist.N\n"
1735 "t Zoom into current Thread\n"
1736 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001737 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001738 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001739 "/ Filter symbol by name";
1740
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001741 if (browser == NULL)
1742 return -1;
1743
Namhyung Kimed426912015-05-29 21:53:44 +09001744 /* reset abort key so that it can get Ctrl-C as a key */
1745 SLang_reset_tty();
1746 SLang_init_tty(0, 0, 0);
1747
Namhyung Kim064f1982013-05-14 11:09:04 +09001748 if (min_pcnt) {
1749 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001750 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001751 }
1752
Namhyung Kim01f00a12015-04-22 16:18:16 +09001753 browser->pstack = pstack__new(2);
1754 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001755 goto out;
1756
1757 ui_helpline__push(helpline);
1758
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001759 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09001760 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001761
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001762 perf_hpp__for_each_format(fmt)
1763 perf_hpp__reset_width(fmt, hists);
1764
Namhyung Kim5b591662014-07-31 14:47:38 +09001765 if (symbol_conf.col_width_list_str)
1766 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1767
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001768 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001769 struct thread *thread = NULL;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001770 struct dso *dso = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001771 int choice = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001772
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001773 nr_options = 0;
1774
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03001775 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001776
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001777 if (browser->he_selection != NULL) {
1778 thread = hist_browser__selected_thread(browser);
1779 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1780 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001781 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001782 case K_TAB:
1783 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001784 if (nr_events == 1)
1785 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001786 /*
1787 * Exit the browser, let hists__browser_tree
1788 * go to the next or previous
1789 */
1790 goto out_free_stack;
1791 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001792 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001793 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001794 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001795 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001796 continue;
1797 }
1798
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001799 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001800 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001801 browser->selection->map->dso->annotate_warned)
1802 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001803
Namhyung Kimea7cd592015-04-22 16:18:19 +09001804 actions->ms.map = browser->selection->map;
1805 actions->ms.sym = browser->selection->sym;
1806 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001807 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001808 case 'P':
1809 hist_browser__dump(browser);
1810 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001811 case 'd':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001812 actions->dso = dso;
1813 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001814 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001815 case 'V':
1816 browser->show_dso = !browser->show_dso;
1817 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001818 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001819 actions->thread = thread;
1820 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001821 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001822 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001823 if (ui_browser__input_window("Symbol to show",
1824 "Please enter the name of symbol you want to see",
1825 buf, "ENTER: OK, ESC: Cancel",
1826 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001827 hists->symbol_filter_str = *buf ? buf : NULL;
1828 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001829 hist_browser__reset(browser);
1830 }
1831 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001832 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001833 if (is_report_browser(hbt)) {
1834 actions->thread = NULL;
1835 actions->ms.sym = NULL;
1836 do_run_script(browser, actions);
1837 }
Feng Tangc77d8d72012-11-01 00:00:55 +08001838 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001839 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001840 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001841 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001842 if (key == K_SWITCH_INPUT_DATA)
1843 goto out_free_stack;
1844 }
Feng Tang341487ab2013-02-03 14:38:20 +08001845 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001846 case 'i':
1847 /* env->arch is NULL for live-mode (i.e. perf top) */
1848 if (env->arch)
1849 tui__header_window(env);
1850 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001851 case 'F':
1852 symbol_conf.filter_relative ^= 1;
1853 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001854 case 'z':
1855 if (!is_report_browser(hbt)) {
1856 struct perf_top *top = hbt->arg;
1857
1858 top->zero = !top->zero;
1859 }
1860 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001861 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001862 case 'h':
1863 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001864 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001865 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001866 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001867 case K_ENTER:
1868 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001869 /* menu */
1870 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001871 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001872 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001873
Namhyung Kim01f00a12015-04-22 16:18:16 +09001874 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001875 /*
1876 * Go back to the perf_evsel_menu__run or other user
1877 */
1878 if (left_exits)
1879 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001880 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001881 }
Namhyung Kim64221842015-04-24 10:15:33 +09001882 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001883 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001884 /*
1885 * No need to set actions->dso here since
1886 * it's just to remove the current filter.
1887 * Ditto for thread below.
1888 */
1889 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001890 }
Namhyung Kim64221842015-04-24 10:15:33 +09001891 if (top == &browser->hists->thread_filter)
1892 do_zoom_thread(browser, actions);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001893 continue;
1894 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001895 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001896 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001897 !ui_browser__dialog_yesno(&browser->b,
1898 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001899 continue;
1900 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001901 case 'q':
1902 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03001903 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001904 case 'f':
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03001905 if (!is_report_browser(hbt))
1906 goto out_free_stack;
1907 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001908 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03001909 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001910 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}