blob: 9bd7b38de64c60fcafd943fb44a0f6c663b99a6b [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
66 if (he->ms.unfolded)
67 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 map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300144 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145}
146
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300149 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300150}
151
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300152static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300153{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300154 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300155}
156
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300157static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300158{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300159 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300160}
161
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300162static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300163{
164 int n = 0;
165 struct rb_node *nd;
166
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300167 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300168 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
169 struct callchain_list *chain;
170 char folded_sign = ' '; /* No children */
171
172 list_for_each_entry(chain, &child->val, list) {
173 ++n;
174 /* We need this because we may not have children */
175 folded_sign = callchain_list__folded(chain);
176 if (folded_sign == '+')
177 break;
178 }
179
180 if (folded_sign == '-') /* Have children and they're unfolded */
181 n += callchain_node__count_rows_rb_tree(child);
182 }
183
184 return n;
185}
186
187static int callchain_node__count_rows(struct callchain_node *node)
188{
189 struct callchain_list *chain;
190 bool unfolded = false;
191 int n = 0;
192
193 list_for_each_entry(chain, &node->val, list) {
194 ++n;
195 unfolded = chain->ms.unfolded;
196 }
197
198 if (unfolded)
199 n += callchain_node__count_rows_rb_tree(node);
200
201 return n;
202}
203
204static int callchain__count_rows(struct rb_root *chain)
205{
206 struct rb_node *nd;
207 int n = 0;
208
209 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
210 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
211 n += callchain_node__count_rows(node);
212 }
213
214 return n;
215}
216
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300217static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300218{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300219 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200220 return false;
221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300222 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300223 return false;
224
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300225 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300226 return true;
227}
228
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300229static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300230{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300231 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300232
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300233 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300234 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
235 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300236 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300237
238 list_for_each_entry(chain, &child->val, list) {
239 if (first) {
240 first = false;
241 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300242 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300243 } else
244 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300245 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300246 }
247
248 callchain_node__init_have_children_rb_tree(child);
249 }
250}
251
Namhyung Kima7444af2014-11-24 17:13:27 +0900252static void callchain_node__init_have_children(struct callchain_node *node,
253 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300254{
255 struct callchain_list *chain;
256
Namhyung Kima7444af2014-11-24 17:13:27 +0900257 chain = list_entry(node->val.next, struct callchain_list, list);
258 chain->ms.has_children = has_sibling;
259
Namhyung Kim82162b52014-08-13 15:02:41 +0900260 if (!list_empty(&node->val)) {
261 chain = list_entry(node->val.prev, struct callchain_list, list);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300262 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900263 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300264
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300265 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300266}
267
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300268static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300269{
Namhyung Kima7444af2014-11-24 17:13:27 +0900270 struct rb_node *nd = rb_first(root);
271 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300272
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300273 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300274 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900275 callchain_node__init_have_children(node, has_sibling);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300276 }
277}
278
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300279static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300280{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300281 if (!he->init_have_children) {
282 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
283 callchain__init_have_children(&he->sorted_chain);
284 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300285 }
286}
287
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300288static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300289{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300290 if (map_symbol__toggle_fold(browser->selection)) {
291 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300292
293 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900294 browser->b.nr_entries -= he->nr_rows;
295 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300296
297 if (he->ms.unfolded)
298 he->nr_rows = callchain__count_rows(&he->sorted_chain);
299 else
300 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900301
302 browser->b.nr_entries += he->nr_rows;
303 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300304
305 return true;
306 }
307
308 /* If it doesn't have children, no toggling performed */
309 return false;
310}
311
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300312static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300313{
314 int n = 0;
315 struct rb_node *nd;
316
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300317 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300318 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
319 struct callchain_list *chain;
320 bool has_children = false;
321
322 list_for_each_entry(chain, &child->val, list) {
323 ++n;
324 map_symbol__set_folding(&chain->ms, unfold);
325 has_children = chain->ms.has_children;
326 }
327
328 if (has_children)
329 n += callchain_node__set_folding_rb_tree(child, unfold);
330 }
331
332 return n;
333}
334
335static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
336{
337 struct callchain_list *chain;
338 bool has_children = false;
339 int n = 0;
340
341 list_for_each_entry(chain, &node->val, list) {
342 ++n;
343 map_symbol__set_folding(&chain->ms, unfold);
344 has_children = chain->ms.has_children;
345 }
346
347 if (has_children)
348 n += callchain_node__set_folding_rb_tree(node, unfold);
349
350 return n;
351}
352
353static int callchain__set_folding(struct rb_root *chain, bool unfold)
354{
355 struct rb_node *nd;
356 int n = 0;
357
358 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
359 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
360 n += callchain_node__set_folding(node, unfold);
361 }
362
363 return n;
364}
365
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300367{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368 hist_entry__init_have_children(he);
369 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300370
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371 if (he->ms.has_children) {
372 int n = callchain__set_folding(&he->sorted_chain, unfold);
373 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300374 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300375 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300376}
377
Namhyung Kimc3b78952014-04-22 15:56:17 +0900378static void
379__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300380{
381 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900382 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300383
Namhyung Kimc3b78952014-04-22 15:56:17 +0900384 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900385 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900386 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300387 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
388 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900389 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300390 }
391}
392
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300393static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300394{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900395 browser->nr_callchain_rows = 0;
396 __hist_browser__set_folding(browser, unfold);
397
398 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300399 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300400 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300401}
402
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200403static void ui_browser__warn_lost_events(struct ui_browser *browser)
404{
405 ui_browser__warning(browser, 4,
406 "Events are being lost, check IO/CPU overload!\n\n"
407 "You may want to run 'perf' using a RT scheduler policy:\n\n"
408 " perf top -r 80\n\n"
409 "Or reduce the sampling frequency.");
410}
411
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900412static int hist_browser__run(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300413{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300414 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300415 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900416 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900417 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300418
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300419 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900420 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300421
Taeung Song1e378eb2014-10-07 16:13:15 +0900422 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300423
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300424 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300425 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300426 return -1;
427
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300429 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300430
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300431 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900432 case K_TIMER: {
433 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900434 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900435
Namhyung Kimc3b78952014-04-22 15:56:17 +0900436 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900437 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900438
Namhyung Kimc3b78952014-04-22 15:56:17 +0900439 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900440 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200441
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300442 if (browser->hists->stats.nr_lost_warned !=
443 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
444 browser->hists->stats.nr_lost_warned =
445 browser->hists->stats.nr_events[PERF_RECORD_LOST];
446 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200447 }
448
Taeung Song1e378eb2014-10-07 16:13:15 +0900449 hists__browser_title(browser->hists,
450 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300451 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300452 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900453 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300454 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300455 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300456 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300457 struct hist_entry, rb_node);
458 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300459 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 -0300460 seq++, browser->b.nr_entries,
461 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300462 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300463 browser->b.index,
464 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300465 h->row_offset, h->nr_rows);
466 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300467 break;
468 case 'C':
469 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300470 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300471 break;
472 case 'E':
473 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300474 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300475 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200476 case 'H':
477 browser->show_headers = !browser->show_headers;
478 hist_browser__update_rows(browser);
479 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200480 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300481 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300482 break;
483 /* fall thru */
484 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300485 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300486 }
487 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300488out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300489 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300490 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300491}
492
Namhyung Kim39ee5332014-08-22 09:13:21 +0900493struct callchain_print_arg {
494 /* for hists browser */
495 off_t row_offset;
496 bool is_current_entry;
497
498 /* for file dump */
499 FILE *fp;
500 int printed;
501};
502
503typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
504 struct callchain_list *chain,
505 const char *str, int offset,
506 unsigned short row,
507 struct callchain_print_arg *arg);
508
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900509static void hist_browser__show_callchain_entry(struct hist_browser *browser,
510 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900511 const char *str, int offset,
512 unsigned short row,
513 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900514{
515 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900516 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300517 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900518
519 color = HE_COLORSET_NORMAL;
520 width = browser->b.width - (offset + 2);
521 if (ui_browser__is_current_entry(&browser->b, row)) {
522 browser->selection = &chain->ms;
523 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900524 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900525 }
526
527 ui_browser__set_color(&browser->b, color);
528 hist_browser__gotorc(browser, row, 0);
529 slsmg_write_nstring(" ", offset);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300530 slsmg_printf("%c", folded_sign);
531 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900532 slsmg_write_nstring(str, width);
533}
534
Namhyung Kim39ee5332014-08-22 09:13:21 +0900535static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
536 struct callchain_list *chain,
537 const char *str, int offset,
538 unsigned short row __maybe_unused,
539 struct callchain_print_arg *arg)
540{
541 char folded_sign = callchain_list__folded(chain);
542
543 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
544 folded_sign, str);
545}
546
547typedef bool (*check_output_full_fn)(struct hist_browser *browser,
548 unsigned short row);
549
550static bool hist_browser__check_output_full(struct hist_browser *browser,
551 unsigned short row)
552{
553 return browser->b.rows == row;
554}
555
556static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
557 unsigned short row __maybe_unused)
558{
559 return false;
560}
561
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300562#define LEVEL_OFFSET_STEP 3
563
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900564static int hist_browser__show_callchain(struct hist_browser *browser,
565 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900566 unsigned short row, u64 total,
567 print_callchain_entry_fn print,
568 struct callchain_print_arg *arg,
569 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300570{
571 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900572 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900573 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900574 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300575
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900576 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900577 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900578
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300579 while (node) {
580 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
581 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100582 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300583 struct callchain_list *chain;
584 char folded_sign = ' ';
585 int first = true;
586 int extra_offset = 0;
587
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300588 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300589 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300591 bool was_first = first;
592
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300593 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300594 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900595 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300596 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300597
598 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900599 if (arg->row_offset != 0) {
600 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300601 goto do_next;
602 }
603
604 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300605 str = callchain_list__sym_name(chain, bf, sizeof(bf),
606 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900607
Namhyung Kim4087d112014-11-24 17:13:26 +0900608 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900609 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300610
611 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
612 str = "Not enough memory!";
613 else
614 str = alloc_str;
615 }
616
Namhyung Kim39ee5332014-08-22 09:13:21 +0900617 print(browser, chain, str, offset + extra_offset, row, arg);
618
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300619 free(alloc_str);
620
Namhyung Kim39ee5332014-08-22 09:13:21 +0900621 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300622 goto out;
623do_next:
624 if (folded_sign == '+')
625 break;
626 }
627
628 if (folded_sign == '-') {
629 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900630
631 if (callchain_param.mode == CHAIN_GRAPH_REL)
632 new_total = child->children_hit;
633 else
634 new_total = total;
635
636 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900637 new_level, row, new_total,
638 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300639 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900640 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900641 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300642 node = next;
643 }
644out:
645 return row - first_row;
646}
647
Namhyung Kim89701462013-01-22 18:09:38 +0900648struct hpp_arg {
649 struct ui_browser *b;
650 char folded_sign;
651 bool current_entry;
652};
653
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900654static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
655{
656 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900657 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900658 va_list args;
659 double percent;
660
661 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900662 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900663 percent = va_arg(args, double);
664 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900665
Namhyung Kim89701462013-01-22 18:09:38 +0900666 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900667
Namhyung Kimd6751072014-07-31 14:47:36 +0900668 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900669 slsmg_printf("%s", hpp->buf);
670
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900671 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900672 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900673}
674
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900675#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900676static u64 __hpp_get_##_field(struct hist_entry *he) \
677{ \
678 return he->stat._field; \
679} \
680 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100681static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900682hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100683 struct perf_hpp *hpp, \
684 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900685{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900686 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
687 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900688}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900689
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900690#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
691static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
692{ \
693 return he->stat_acc->_field; \
694} \
695 \
696static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900697hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900698 struct perf_hpp *hpp, \
699 struct hist_entry *he) \
700{ \
701 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900702 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900703 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900704 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900705 slsmg_printf("%s", hpp->buf); \
706 \
707 return ret; \
708 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900709 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
710 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900711}
712
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900713__HPP_COLOR_PERCENT_FN(overhead, period)
714__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
715__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
716__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
717__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900718__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900719
720#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900721#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900722
723void hist_browser__init_hpp(void)
724{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900725 perf_hpp__format[PERF_HPP__OVERHEAD].color =
726 hist_browser__hpp_color_overhead;
727 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
728 hist_browser__hpp_color_overhead_sys;
729 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
730 hist_browser__hpp_color_overhead_us;
731 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
732 hist_browser__hpp_color_overhead_guest_sys;
733 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
734 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900735 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
736 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900737}
738
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300739static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300740 struct hist_entry *entry,
741 unsigned short row)
742{
743 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200744 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900745 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300746 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300747 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300748 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300749 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200750 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300751
752 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300753 browser->he_selection = entry;
754 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300755 }
756
757 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300758 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300759 folded_sign = hist_entry__folded(entry);
760 }
761
762 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900763 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900764 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900765 .folded_sign = folded_sign,
766 .current_entry = current_entry,
767 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900768 struct perf_hpp hpp = {
769 .buf = s,
770 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900771 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900772 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300773
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300774 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900775
Jiri Olsa12400052012-10-13 00:06:16 +0200776 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900777 if (perf_hpp__should_skip(fmt))
778 continue;
779
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900780 if (current_entry && browser->b.navkeypressed) {
781 ui_browser__set_color(&browser->b,
782 HE_COLORSET_SELECTED);
783 } else {
784 ui_browser__set_color(&browser->b,
785 HE_COLORSET_NORMAL);
786 }
787
788 if (first) {
789 if (symbol_conf.use_callchain) {
790 slsmg_printf("%c ", folded_sign);
791 width -= 2;
792 }
793 first = false;
794 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900795 slsmg_printf(" ");
796 width -= 2;
797 }
798
Jiri Olsa12400052012-10-13 00:06:16 +0200799 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100800 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900801 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100802 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900803 slsmg_printf("%s", s);
804 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300805 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200806
807 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300808 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200809 width += 1;
810
Namhyung Kim26d8b332014-03-03 16:16:20 +0900811 slsmg_write_nstring("", width);
812
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300813 ++row;
814 ++printed;
815 } else
816 --row_offset;
817
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300818 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900819 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900820 struct callchain_print_arg arg = {
821 .row_offset = row_offset,
822 .is_current_entry = current_entry,
823 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900824
Namhyung Kim4087d112014-11-24 17:13:26 +0900825 if (callchain_param.mode == CHAIN_GRAPH_REL) {
826 if (symbol_conf.cumulate_callchain)
827 total = entry->stat_acc->period;
828 else
829 total = entry->stat.period;
830 }
831
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900832 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900833 &entry->sorted_chain, 1, row, total,
834 hist_browser__show_callchain_entry, &arg,
835 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900836
Namhyung Kim39ee5332014-08-22 09:13:21 +0900837 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300838 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300839 }
840
841 return printed;
842}
843
Jiri Olsa81a888f2014-06-14 15:44:52 +0200844static int advance_hpp_check(struct perf_hpp *hpp, int inc)
845{
846 advance_hpp(hpp, inc);
847 return hpp->size <= 0;
848}
849
850static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
851{
852 struct perf_hpp dummy_hpp = {
853 .buf = buf,
854 .size = size,
855 };
856 struct perf_hpp_fmt *fmt;
857 size_t ret = 0;
858
859 if (symbol_conf.use_callchain) {
860 ret = scnprintf(buf, size, " ");
861 if (advance_hpp_check(&dummy_hpp, ret))
862 return ret;
863 }
864
865 perf_hpp__for_each_format(fmt) {
866 if (perf_hpp__should_skip(fmt))
867 continue;
868
Jiri Olsa81a888f2014-06-14 15:44:52 +0200869 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
870 if (advance_hpp_check(&dummy_hpp, ret))
871 break;
872
873 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
874 if (advance_hpp_check(&dummy_hpp, ret))
875 break;
876 }
877
878 return ret;
879}
880
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200881static void hist_browser__show_headers(struct hist_browser *browser)
882{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200883 char headers[1024];
884
885 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200886 ui_browser__gotorc(&browser->b, 0, 0);
887 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200888 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200889}
890
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300891static void ui_browser__hists_init_top(struct ui_browser *browser)
892{
893 if (browser->top == NULL) {
894 struct hist_browser *hb;
895
896 hb = container_of(browser, struct hist_browser, b);
897 browser->top = rb_first(&hb->hists->entries);
898 }
899}
900
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300901static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300902{
903 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200904 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300905 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300906 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300907
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200908 if (hb->show_headers) {
909 hist_browser__show_headers(hb);
910 header_offset = 1;
911 }
912
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300913 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300914
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300915 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300916 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900917 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300918
919 if (h->filtered)
920 continue;
921
Namhyung Kim14135662013-10-31 10:17:39 +0900922 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900923 if (percent < hb->min_pcnt)
924 continue;
925
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300926 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300927 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300928 break;
929 }
930
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200931 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300932}
933
Namhyung Kim064f1982013-05-14 11:09:04 +0900934static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900935 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300936{
937 while (nd != NULL) {
938 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900939 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900940
Namhyung Kimc0f15272014-04-16 11:16:33 +0900941 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300942 return nd;
943
944 nd = rb_next(nd);
945 }
946
947 return NULL;
948}
949
Namhyung Kim064f1982013-05-14 11:09:04 +0900950static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900951 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300952{
953 while (nd != NULL) {
954 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900955 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900956
957 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300958 return nd;
959
960 nd = rb_prev(nd);
961 }
962
963 return NULL;
964}
965
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300966static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300967 off_t offset, int whence)
968{
969 struct hist_entry *h;
970 struct rb_node *nd;
971 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900972 struct hist_browser *hb;
973
974 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300975
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300976 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300977 return;
978
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300979 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300980
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300981 switch (whence) {
982 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900983 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900984 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300985 break;
986 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300987 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300988 goto do_offset;
989 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900990 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900991 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300992 first = false;
993 break;
994 default:
995 return;
996 }
997
998 /*
999 * Moves not relative to the first visible entry invalidates its
1000 * row_offset:
1001 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001002 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001003 h->row_offset = 0;
1004
1005 /*
1006 * Here we have to check if nd is expanded (+), if it is we can't go
1007 * the next top level hist_entry, instead we must compute an offset of
1008 * what _not_ to show and not change the first visible entry.
1009 *
1010 * This offset increments when we are going from top to bottom and
1011 * decreases when we're going from bottom to top.
1012 *
1013 * As we don't have backpointers to the top level in the callchains
1014 * structure, we need to always print the whole hist_entry callchain,
1015 * skipping the first ones that are before the first visible entry
1016 * and stop when we printed enough lines to fill the screen.
1017 */
1018do_offset:
1019 if (offset > 0) {
1020 do {
1021 h = rb_entry(nd, struct hist_entry, rb_node);
1022 if (h->ms.unfolded) {
1023 u16 remaining = h->nr_rows - h->row_offset;
1024 if (offset > remaining) {
1025 offset -= remaining;
1026 h->row_offset = 0;
1027 } else {
1028 h->row_offset += offset;
1029 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001030 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001031 break;
1032 }
1033 }
Namhyung Kim14135662013-10-31 10:17:39 +09001034 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001035 if (nd == NULL)
1036 break;
1037 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001038 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001039 } while (offset != 0);
1040 } else if (offset < 0) {
1041 while (1) {
1042 h = rb_entry(nd, struct hist_entry, rb_node);
1043 if (h->ms.unfolded) {
1044 if (first) {
1045 if (-offset > h->row_offset) {
1046 offset += h->row_offset;
1047 h->row_offset = 0;
1048 } else {
1049 h->row_offset += offset;
1050 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001051 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001052 break;
1053 }
1054 } else {
1055 if (-offset > h->nr_rows) {
1056 offset += h->nr_rows;
1057 h->row_offset = 0;
1058 } else {
1059 h->row_offset = h->nr_rows + offset;
1060 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001061 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001062 break;
1063 }
1064 }
1065 }
1066
Namhyung Kim14135662013-10-31 10:17:39 +09001067 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001068 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001069 if (nd == NULL)
1070 break;
1071 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001072 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001073 if (offset == 0) {
1074 /*
1075 * Last unfiltered hist_entry, check if it is
1076 * unfolded, if it is then we should have
1077 * row_offset at its last entry.
1078 */
1079 h = rb_entry(nd, struct hist_entry, rb_node);
1080 if (h->ms.unfolded)
1081 h->row_offset = h->nr_rows;
1082 break;
1083 }
1084 first = false;
1085 }
1086 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001087 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001088 h = rb_entry(nd, struct hist_entry, rb_node);
1089 h->row_offset = 0;
1090 }
1091}
1092
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001093static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001094 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001095{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001096 u64 total = hists__total_period(he->hists);
1097 struct callchain_print_arg arg = {
1098 .fp = fp,
1099 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001100
Namhyung Kim39ee5332014-08-22 09:13:21 +09001101 if (symbol_conf.cumulate_callchain)
1102 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001103
Namhyung Kim39ee5332014-08-22 09:13:21 +09001104 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1105 hist_browser__fprintf_callchain_entry, &arg,
1106 hist_browser__check_dump_full);
1107 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001108}
1109
1110static int hist_browser__fprintf_entry(struct hist_browser *browser,
1111 struct hist_entry *he, FILE *fp)
1112{
1113 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001114 int printed = 0;
1115 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001116 struct perf_hpp hpp = {
1117 .buf = s,
1118 .size = sizeof(s),
1119 };
1120 struct perf_hpp_fmt *fmt;
1121 bool first = true;
1122 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001123
1124 if (symbol_conf.use_callchain)
1125 folded_sign = hist_entry__folded(he);
1126
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001127 if (symbol_conf.use_callchain)
1128 printed += fprintf(fp, "%c ", folded_sign);
1129
Namhyung Kim26d8b332014-03-03 16:16:20 +09001130 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001131 if (perf_hpp__should_skip(fmt))
1132 continue;
1133
Namhyung Kim26d8b332014-03-03 16:16:20 +09001134 if (!first) {
1135 ret = scnprintf(hpp.buf, hpp.size, " ");
1136 advance_hpp(&hpp, ret);
1137 } else
1138 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001139
Namhyung Kim26d8b332014-03-03 16:16:20 +09001140 ret = fmt->entry(fmt, &hpp, he);
1141 advance_hpp(&hpp, ret);
1142 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001143 printed += fprintf(fp, "%s\n", rtrim(s));
1144
1145 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001146 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001147
1148 return printed;
1149}
1150
1151static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1152{
Namhyung Kim064f1982013-05-14 11:09:04 +09001153 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001154 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001155 int printed = 0;
1156
1157 while (nd) {
1158 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1159
1160 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001161 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001162 }
1163
1164 return printed;
1165}
1166
1167static int hist_browser__dump(struct hist_browser *browser)
1168{
1169 char filename[64];
1170 FILE *fp;
1171
1172 while (1) {
1173 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1174 if (access(filename, F_OK))
1175 break;
1176 /*
1177 * XXX: Just an arbitrary lazy upper limit
1178 */
1179 if (++browser->print_seq == 8192) {
1180 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1181 return -1;
1182 }
1183 }
1184
1185 fp = fopen(filename, "w");
1186 if (fp == NULL) {
1187 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001188 const char *err = strerror_r(errno, bf, sizeof(bf));
1189 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001190 return -1;
1191 }
1192
1193 ++browser->print_seq;
1194 hist_browser__fprintf(browser, fp);
1195 fclose(fp);
1196 ui_helpline__fpush("%s written!", filename);
1197
1198 return 0;
1199}
1200
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001201static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001202 struct hist_browser_timer *hbt,
1203 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001205 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001207 if (browser) {
1208 browser->hists = hists;
1209 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001210 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001211 browser->b.seek = ui_browser__hists_seek;
1212 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001213 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001214 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001215 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001216 }
1217
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001218 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219}
1220
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001221static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001222{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001223 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001224}
1225
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001226static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001227{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001228 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001229}
1230
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001231static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001232{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001233 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001234}
1235
Taeung Song1e378eb2014-10-07 16:13:15 +09001236/* Check whether the browser is for 'top' or 'report' */
1237static inline bool is_report_browser(void *timer)
1238{
1239 return timer == NULL;
1240}
1241
1242static int hists__browser_title(struct hists *hists,
1243 struct hist_browser_timer *hbt,
1244 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001245{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001246 char unit;
1247 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001248 const struct dso *dso = hists->dso_filter;
1249 const struct thread *thread = hists->thread_filter;
1250 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1251 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001252 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001253 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001254 char buf[512];
1255 size_t buflen = sizeof(buf);
1256
Namhyung Kimf2148332014-01-14 11:52:48 +09001257 if (symbol_conf.filter_relative) {
1258 nr_samples = hists->stats.nr_non_filtered_samples;
1259 nr_events = hists->stats.total_non_filtered_period;
1260 }
1261
Namhyung Kim759ff492013-03-05 14:53:26 +09001262 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001263 struct perf_evsel *pos;
1264
1265 perf_evsel__group_desc(evsel, buf, buflen);
1266 ev_name = buf;
1267
1268 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001269 struct hists *pos_hists = evsel__hists(pos);
1270
Namhyung Kimf2148332014-01-14 11:52:48 +09001271 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001272 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1273 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001274 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001275 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1276 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001277 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001278 }
1279 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001280
Ashay Ranecc686282012-04-05 21:01:01 -05001281 nr_samples = convert_unit(nr_samples, &unit);
1282 printed = scnprintf(bf, size,
Tom Huynhe641f692014-12-02 11:37:22 -06001283 "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
Ashay Ranecc686282012-04-05 21:01:01 -05001284 nr_samples, unit, ev_name, nr_events);
1285
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001286
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001287 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001288 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001289 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001290 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001291 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001292 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001293 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001294 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001295 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001296 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001297 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001298 if (!is_report_browser(hbt)) {
1299 struct perf_top *top = hbt->arg;
1300
1301 if (top->zero)
1302 printed += scnprintf(bf + printed, size - printed, " [z]");
1303 }
1304
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001305 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001306}
1307
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001308static inline void free_popup_options(char **options, int n)
1309{
1310 int i;
1311
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001312 for (i = 0; i < n; ++i)
1313 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001314}
1315
Feng Tang341487ab2013-02-03 14:38:20 +08001316/*
1317 * Only runtime switching of perf data file will make "input_name" point
1318 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1319 * whether we need to call free() for current "input_name" during the switch.
1320 */
1321static bool is_input_name_malloced = false;
1322
1323static int switch_data_file(void)
1324{
1325 char *pwd, *options[32], *abs_path[32], *tmp;
1326 DIR *pwd_dir;
1327 int nr_options = 0, choice = -1, ret = -1;
1328 struct dirent *dent;
1329
1330 pwd = getenv("PWD");
1331 if (!pwd)
1332 return ret;
1333
1334 pwd_dir = opendir(pwd);
1335 if (!pwd_dir)
1336 return ret;
1337
1338 memset(options, 0, sizeof(options));
1339 memset(options, 0, sizeof(abs_path));
1340
1341 while ((dent = readdir(pwd_dir))) {
1342 char path[PATH_MAX];
1343 u64 magic;
1344 char *name = dent->d_name;
1345 FILE *file;
1346
1347 if (!(dent->d_type == DT_REG))
1348 continue;
1349
1350 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1351
1352 file = fopen(path, "r");
1353 if (!file)
1354 continue;
1355
1356 if (fread(&magic, 1, 8, file) < 8)
1357 goto close_file_and_continue;
1358
1359 if (is_perf_magic(magic)) {
1360 options[nr_options] = strdup(name);
1361 if (!options[nr_options])
1362 goto close_file_and_continue;
1363
1364 abs_path[nr_options] = strdup(path);
1365 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001366 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001367 ui__warning("Can't search all data files due to memory shortage.\n");
1368 fclose(file);
1369 break;
1370 }
1371
1372 nr_options++;
1373 }
1374
1375close_file_and_continue:
1376 fclose(file);
1377 if (nr_options >= 32) {
1378 ui__warning("Too many perf data files in PWD!\n"
1379 "Only the first 32 files will be listed.\n");
1380 break;
1381 }
1382 }
1383 closedir(pwd_dir);
1384
1385 if (nr_options) {
1386 choice = ui__popup_menu(nr_options, options);
1387 if (choice < nr_options && choice >= 0) {
1388 tmp = strdup(abs_path[choice]);
1389 if (tmp) {
1390 if (is_input_name_malloced)
1391 free((void *)input_name);
1392 input_name = tmp;
1393 is_input_name_malloced = true;
1394 ret = 0;
1395 } else
1396 ui__warning("Data switch failed due to memory shortage!\n");
1397 }
1398 }
1399
1400 free_popup_options(options, nr_options);
1401 free_popup_options(abs_path, nr_options);
1402 return ret;
1403}
1404
Namhyung Kimea7cd592015-04-22 16:18:19 +09001405struct popup_action {
1406 struct thread *thread;
1407 struct dso *dso;
1408 struct map_symbol ms;
1409
1410 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1411};
1412
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001413static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001414do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001415{
1416 struct perf_evsel *evsel;
1417 struct annotation *notes;
1418 struct hist_entry *he;
1419 int err;
1420
1421 if (!objdump_path && perf_session_env__lookup_objdump(browser->env))
1422 return 0;
1423
Namhyung Kimea7cd592015-04-22 16:18:19 +09001424 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001425 if (!notes->src)
1426 return 0;
1427
1428 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001429 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001430 he = hist_browser__selected_entry(browser);
1431 /*
1432 * offer option to annotate the other branch source or target
1433 * (if they exists) when returning from annotate
1434 */
1435 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1436 return 1;
1437
1438 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1439 if (err)
1440 ui_browser__handle_resize(&browser->b);
1441 return 0;
1442}
1443
1444static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001445add_annotate_opt(struct hist_browser *browser __maybe_unused,
1446 struct popup_action *act, char **optstr,
1447 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001448{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001449 if (sym == NULL || map->dso->annotate_warned)
1450 return 0;
1451
1452 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1453 return 0;
1454
1455 act->ms.map = map;
1456 act->ms.sym = sym;
1457 act->fn = do_annotate;
1458 return 1;
1459}
1460
1461static int
1462do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1463{
1464 struct thread *thread = act->thread;
1465
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001466 if (browser->hists->thread_filter) {
1467 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1468 perf_hpp__set_elide(HISTC_THREAD, false);
1469 thread__zput(browser->hists->thread_filter);
1470 ui_helpline__pop();
1471 } else {
1472 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1473 thread->comm_set ? thread__comm_str(thread) : "",
1474 thread->tid);
1475 browser->hists->thread_filter = thread__get(thread);
1476 perf_hpp__set_elide(HISTC_THREAD, false);
1477 pstack__push(browser->pstack, &browser->hists->thread_filter);
1478 }
1479
1480 hists__filter_by_thread(browser->hists);
1481 hist_browser__reset(browser);
1482 return 0;
1483}
1484
1485static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001486add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1487 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001488{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001489 if (thread == NULL)
1490 return 0;
1491
1492 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1493 browser->hists->thread_filter ? "out of" : "into",
1494 thread->comm_set ? thread__comm_str(thread) : "",
1495 thread->tid) < 0)
1496 return 0;
1497
1498 act->thread = thread;
1499 act->fn = do_zoom_thread;
1500 return 1;
1501}
1502
1503static int
1504do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1505{
1506 struct dso *dso = act->dso;
1507
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001508 if (browser->hists->dso_filter) {
1509 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1510 perf_hpp__set_elide(HISTC_DSO, false);
1511 browser->hists->dso_filter = NULL;
1512 ui_helpline__pop();
1513 } else {
1514 if (dso == NULL)
1515 return 0;
1516 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1517 dso->kernel ? "the Kernel" : dso->short_name);
1518 browser->hists->dso_filter = dso;
1519 perf_hpp__set_elide(HISTC_DSO, true);
1520 pstack__push(browser->pstack, &browser->hists->dso_filter);
1521 }
1522
1523 hists__filter_by_dso(browser->hists);
1524 hist_browser__reset(browser);
1525 return 0;
1526}
1527
1528static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001529add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1530 char **optstr, struct dso *dso)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001531{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001532 if (dso == NULL)
1533 return 0;
1534
1535 if (asprintf(optstr, "Zoom %s %s DSO",
1536 browser->hists->dso_filter ? "out of" : "into",
1537 dso->kernel ? "the Kernel" : dso->short_name) < 0)
1538 return 0;
1539
1540 act->dso = dso;
1541 act->fn = do_zoom_dso;
1542 return 1;
1543}
1544
1545static int
1546do_browse_map(struct hist_browser *browser __maybe_unused,
1547 struct popup_action *act)
1548{
1549 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001550 return 0;
1551}
1552
1553static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001554add_map_opt(struct hist_browser *browser __maybe_unused,
1555 struct popup_action *act, char **optstr, struct map *map)
1556{
1557 if (map == NULL)
1558 return 0;
1559
1560 if (asprintf(optstr, "Browse map details") < 0)
1561 return 0;
1562
1563 act->ms.map = map;
1564 act->fn = do_browse_map;
1565 return 1;
1566}
1567
1568static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001569do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001570 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001571{
1572 char script_opt[64];
1573 memset(script_opt, 0, sizeof(script_opt));
1574
Namhyung Kimea7cd592015-04-22 16:18:19 +09001575 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001576 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001577 thread__comm_str(act->thread));
1578 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001579 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001580 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001581 }
1582
1583 script_browse(script_opt);
1584 return 0;
1585}
1586
1587static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001588add_script_opt(struct hist_browser *browser __maybe_unused,
1589 struct popup_action *act, char **optstr,
1590 struct thread *thread, struct symbol *sym)
1591{
1592 if (thread) {
1593 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1594 thread__comm_str(thread)) < 0)
1595 return 0;
1596 } else if (sym) {
1597 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1598 sym->name) < 0)
1599 return 0;
1600 } else {
1601 if (asprintf(optstr, "Run scripts for all samples") < 0)
1602 return 0;
1603 }
1604
1605 act->thread = thread;
1606 act->ms.sym = sym;
1607 act->fn = do_run_script;
1608 return 1;
1609}
1610
1611static int
1612do_switch_data(struct hist_browser *browser __maybe_unused,
1613 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001614{
1615 if (switch_data_file()) {
1616 ui__warning("Won't switch the data files due to\n"
1617 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001618 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001619 }
1620
1621 return K_SWITCH_INPUT_DATA;
1622}
1623
Namhyung Kimea7cd592015-04-22 16:18:19 +09001624static int
1625add_switch_opt(struct hist_browser *browser,
1626 struct popup_action *act, char **optstr)
1627{
1628 if (!is_report_browser(browser->hbt))
1629 return 0;
1630
1631 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1632 return 0;
1633
1634 act->fn = do_switch_data;
1635 return 1;
1636}
1637
1638static int
1639do_exit_browser(struct hist_browser *browser __maybe_unused,
1640 struct popup_action *act __maybe_unused)
1641{
1642 return 0;
1643}
1644
1645static int
1646add_exit_opt(struct hist_browser *browser __maybe_unused,
1647 struct popup_action *act, char **optstr)
1648{
1649 if (asprintf(optstr, "Exit") < 0)
1650 return 0;
1651
1652 act->fn = do_exit_browser;
1653 return 1;
1654}
1655
Namhyung Kim112f7612014-04-22 14:05:35 +09001656static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001657{
1658 u64 nr_entries = 0;
1659 struct rb_node *nd = rb_first(&hb->hists->entries);
1660
Namhyung Kim268397c2014-04-22 14:49:31 +09001661 if (hb->min_pcnt == 0) {
1662 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1663 return;
1664 }
1665
Namhyung Kim14135662013-10-31 10:17:39 +09001666 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001667 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001668 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001669 }
1670
Namhyung Kim112f7612014-04-22 14:05:35 +09001671 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001672}
Feng Tang341487ab2013-02-03 14:38:20 +08001673
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001674static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001675 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001676 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001677 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001678 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001679 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001680{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001681 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001682 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001683 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001684#define MAX_OPTIONS 16
1685 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09001686 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001687 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001688 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001689 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001690 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001691 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001692
Namhyung Kime8e684a2013-12-26 14:37:58 +09001693#define HIST_BROWSER_HELP_COMMON \
1694 "h/?/F1 Show this window\n" \
1695 "UP/DOWN/PGUP\n" \
1696 "PGDN/SPACE Navigate\n" \
1697 "q/ESC/CTRL+C Exit browser\n\n" \
1698 "For multiple event sessions:\n\n" \
1699 "TAB/UNTAB Switch events\n\n" \
1700 "For symbolic views (--sort has sym):\n\n" \
1701 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1702 "<- Zoom out\n" \
1703 "a Annotate current symbol\n" \
1704 "C Collapse all callchains\n" \
1705 "d Zoom into current DSO\n" \
1706 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001707 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001708 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001709
1710 /* help messages are sorted by lexical order of the hotkey */
1711 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001712 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001713 "P Print histograms to perf.hist.N\n"
1714 "r Run available scripts\n"
1715 "s Switch to another data file in PWD\n"
1716 "t Zoom into current Thread\n"
1717 "V Verbose (DSO names in callchains, etc)\n"
1718 "/ Filter symbol by name";
1719 const char top_help[] = HIST_BROWSER_HELP_COMMON
1720 "P Print histograms to perf.hist.N\n"
1721 "t Zoom into current Thread\n"
1722 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001723 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001724 "/ Filter symbol by name";
1725
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001726 if (browser == NULL)
1727 return -1;
1728
Namhyung Kim064f1982013-05-14 11:09:04 +09001729 if (min_pcnt) {
1730 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001731 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001732 }
1733
Namhyung Kim01f00a12015-04-22 16:18:16 +09001734 browser->pstack = pstack__new(2);
1735 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001736 goto out;
1737
1738 ui_helpline__push(helpline);
1739
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001740 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09001741 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001742
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001743 perf_hpp__for_each_format(fmt)
1744 perf_hpp__reset_width(fmt, hists);
1745
Namhyung Kim5b591662014-07-31 14:47:38 +09001746 if (symbol_conf.col_width_list_str)
1747 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1748
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001749 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001750 struct thread *thread = NULL;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001751 struct dso *dso = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001752 int choice = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001753
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001754 nr_options = 0;
1755
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001756 key = hist_browser__run(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001758 if (browser->he_selection != NULL) {
1759 thread = hist_browser__selected_thread(browser);
1760 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1761 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001762 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001763 case K_TAB:
1764 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001765 if (nr_events == 1)
1766 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001767 /*
1768 * Exit the browser, let hists__browser_tree
1769 * go to the next or previous
1770 */
1771 goto out_free_stack;
1772 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001773 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001774 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001775 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001776 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001777 continue;
1778 }
1779
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001780 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001781 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001782 browser->selection->map->dso->annotate_warned)
1783 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001784
Namhyung Kimea7cd592015-04-22 16:18:19 +09001785 actions->ms.map = browser->selection->map;
1786 actions->ms.sym = browser->selection->sym;
1787 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001788 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001789 case 'P':
1790 hist_browser__dump(browser);
1791 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001792 case 'd':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001793 actions->dso = dso;
1794 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001795 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001796 case 'V':
1797 browser->show_dso = !browser->show_dso;
1798 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001799 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001800 actions->thread = thread;
1801 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001802 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001803 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001804 if (ui_browser__input_window("Symbol to show",
1805 "Please enter the name of symbol you want to see",
1806 buf, "ENTER: OK, ESC: Cancel",
1807 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001808 hists->symbol_filter_str = *buf ? buf : NULL;
1809 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001810 hist_browser__reset(browser);
1811 }
1812 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001813 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001814 if (is_report_browser(hbt)) {
1815 actions->thread = NULL;
1816 actions->ms.sym = NULL;
1817 do_run_script(browser, actions);
1818 }
Feng Tangc77d8d72012-11-01 00:00:55 +08001819 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001820 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001821 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001822 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001823 if (key == K_SWITCH_INPUT_DATA)
1824 goto out_free_stack;
1825 }
Feng Tang341487ab2013-02-03 14:38:20 +08001826 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001827 case 'i':
1828 /* env->arch is NULL for live-mode (i.e. perf top) */
1829 if (env->arch)
1830 tui__header_window(env);
1831 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001832 case 'F':
1833 symbol_conf.filter_relative ^= 1;
1834 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001835 case 'z':
1836 if (!is_report_browser(hbt)) {
1837 struct perf_top *top = hbt->arg;
1838
1839 top->zero = !top->zero;
1840 }
1841 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001842 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001843 case 'h':
1844 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001845 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001846 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001847 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001848 case K_ENTER:
1849 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001850 /* menu */
1851 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001852 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001853 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001854
Namhyung Kim01f00a12015-04-22 16:18:16 +09001855 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001856 /*
1857 * Go back to the perf_evsel_menu__run or other user
1858 */
1859 if (left_exits)
1860 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001861 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001862 }
Namhyung Kim01f00a12015-04-22 16:18:16 +09001863 top = pstack__pop(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001864 if (top == &browser->hists->dso_filter) {
1865 perf_hpp__set_elide(HISTC_DSO, false);
1866 browser->hists->dso_filter = NULL;
1867 hists__filter_by_dso(browser->hists);
1868 }
1869 if (top == &browser->hists->thread_filter) {
1870 perf_hpp__set_elide(HISTC_THREAD, false);
1871 thread__zput(browser->hists->thread_filter);
1872 hists__filter_by_thread(browser->hists);
1873 }
1874 ui_helpline__pop();
1875 hist_browser__reset(browser);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001876 continue;
1877 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001878 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001879 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001880 !ui_browser__dialog_yesno(&browser->b,
1881 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001882 continue;
1883 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001884 case 'q':
1885 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001886 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001887 default:
1888 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001889 }
1890
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001891 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001892 goto add_exit_option;
1893
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001894 if (browser->selection == NULL)
1895 goto skip_annotation;
1896
Namhyung Kim55369fc2013-04-01 20:35:20 +09001897 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001898 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001899
1900 if (bi == NULL)
1901 goto skip_annotation;
1902
Namhyung Kimea7cd592015-04-22 16:18:19 +09001903 nr_options += add_annotate_opt(browser,
1904 &actions[nr_options],
1905 &options[nr_options],
1906 bi->from.map,
1907 bi->from.sym);
1908 if (bi->to.sym != bi->from.sym)
1909 nr_options += add_annotate_opt(browser,
1910 &actions[nr_options],
1911 &options[nr_options],
1912 bi->to.map,
1913 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001914 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001915 nr_options += add_annotate_opt(browser,
1916 &actions[nr_options],
1917 &options[nr_options],
1918 browser->selection->map,
1919 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001920 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001921skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09001922 nr_options += add_thread_opt(browser, &actions[nr_options],
1923 &options[nr_options], thread);
1924 nr_options += add_dso_opt(browser, &actions[nr_options],
1925 &options[nr_options], dso);
1926 nr_options += add_map_opt(browser, &actions[nr_options],
1927 &options[nr_options],
1928 browser->selection->map);
Feng Tangcdbab7c2012-10-30 11:56:06 +08001929
1930 /* perf script support */
1931 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001932 nr_options += add_script_opt(browser,
1933 &actions[nr_options],
1934 &options[nr_options],
1935 thread, NULL);
1936 nr_options += add_script_opt(browser,
1937 &actions[nr_options],
1938 &options[nr_options],
1939 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08001940 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09001941 nr_options += add_script_opt(browser, &actions[nr_options],
1942 &options[nr_options], NULL, NULL);
1943 nr_options += add_switch_opt(browser, &actions[nr_options],
1944 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001945add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09001946 nr_options += add_exit_opt(browser, &actions[nr_options],
1947 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001948
Namhyung Kimea7cd592015-04-22 16:18:19 +09001949 do {
1950 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001951
Namhyung Kimea7cd592015-04-22 16:18:19 +09001952 choice = ui__popup_menu(nr_options, options);
1953 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08001954 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001955
1956 act = &actions[choice];
1957 key = act->fn(browser, act);
1958 } while (key == 1);
1959
1960 if (key == K_SWITCH_INPUT_DATA)
1961 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001962 }
1963out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09001964 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001965out:
1966 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001967 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001968 return key;
1969}
1970
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001971struct perf_evsel_menu {
1972 struct ui_browser b;
1973 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001974 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001975 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001976 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001977};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001978
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001979static void perf_evsel_menu__write(struct ui_browser *browser,
1980 void *entry, int row)
1981{
1982 struct perf_evsel_menu *menu = container_of(browser,
1983 struct perf_evsel_menu, b);
1984 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001985 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001986 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001987 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001988 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001989 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001990 const char *warn = " ";
1991 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001992
1993 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1994 HE_COLORSET_NORMAL);
1995
Namhyung Kim759ff492013-03-05 14:53:26 +09001996 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001997 struct perf_evsel *pos;
1998
1999 ev_name = perf_evsel__group_name(evsel);
2000
2001 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002002 struct hists *pos_hists = evsel__hists(pos);
2003 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002004 }
2005 }
2006
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002007 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002008 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002009 unit, unit == ' ' ? "" : " ", ev_name);
2010 slsmg_printf("%s", bf);
2011
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002012 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002013 if (nr_events != 0) {
2014 menu->lost_events = true;
2015 if (!current_entry)
2016 ui_browser__set_color(browser, HE_COLORSET_TOP);
2017 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002018 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2019 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002020 warn = bf;
2021 }
2022
2023 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002024
2025 if (current_entry)
2026 menu->selection = evsel;
2027}
2028
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002029static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2030 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002031 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002032{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002033 struct perf_evlist *evlist = menu->b.priv;
2034 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002035 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002036 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002037 int key;
2038
2039 if (ui_browser__show(&menu->b, title,
2040 "ESC: exit, ENTER|->: Browse histograms") < 0)
2041 return -1;
2042
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002043 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002044 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002045
2046 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002047 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002048 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002049
2050 if (!menu->lost_events_warned && menu->lost_events) {
2051 ui_browser__warn_lost_events(&menu->b);
2052 menu->lost_events_warned = true;
2053 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002054 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002055 case K_RIGHT:
2056 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002057 if (!menu->selection)
2058 continue;
2059 pos = menu->selection;
2060browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002061 perf_evlist__set_selected(evlist, pos);
2062 /*
2063 * Give the calling tool a chance to populate the non
2064 * default evsel resorted hists tree.
2065 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002066 if (hbt)
2067 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002068 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002069 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002070 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002071 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002072 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002073 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002074 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002075 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002076 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002077 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002078 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002079 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002080 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002081 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002082 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002083 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002084 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002085 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002086 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002087 if (!ui_browser__dialog_yesno(&menu->b,
2088 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002089 continue;
2090 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08002091 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002092 case 'q':
2093 case CTRL('c'):
2094 goto out;
2095 default:
2096 continue;
2097 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002098 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002099 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002100 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002101 if (!ui_browser__dialog_yesno(&menu->b,
2102 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002103 continue;
2104 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002105 case 'q':
2106 case CTRL('c'):
2107 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002108 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002109 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002110 }
2111 }
2112
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002113out:
2114 ui_browser__hide(&menu->b);
2115 return key;
2116}
2117
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002118static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002119 void *entry)
2120{
2121 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2122
2123 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2124 return true;
2125
2126 return false;
2127}
2128
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002129static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002130 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002131 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002132 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002133 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002134{
2135 struct perf_evsel *pos;
2136 struct perf_evsel_menu menu = {
2137 .b = {
2138 .entries = &evlist->entries,
2139 .refresh = ui_browser__list_head_refresh,
2140 .seek = ui_browser__list_head_seek,
2141 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002142 .filter = filter_group_entries,
2143 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002144 .priv = evlist,
2145 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002146 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002147 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002148 };
2149
2150 ui_helpline__push("Press ESC to exit");
2151
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002152 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002153 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002154 size_t line_len = strlen(ev_name) + 7;
2155
2156 if (menu.b.width < line_len)
2157 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002158 }
2159
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002160 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002161}
2162
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002163int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002164 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002165 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002166 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002167{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002168 int nr_entries = evlist->nr_entries;
2169
2170single_entry:
2171 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002172 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002173
2174 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002175 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002176 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002177 }
2178
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002179 if (symbol_conf.event_group) {
2180 struct perf_evsel *pos;
2181
2182 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002183 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002184 if (perf_evsel__is_group_leader(pos))
2185 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002186 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002187
2188 if (nr_entries == 1)
2189 goto single_entry;
2190 }
2191
2192 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002193 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002194}