blob: 45704d6383e489a2c2367bd12e868abdb8760e05 [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 Kim112f7612014-04-22 14:05:35 +09001405static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001406{
1407 u64 nr_entries = 0;
1408 struct rb_node *nd = rb_first(&hb->hists->entries);
1409
Namhyung Kim268397c2014-04-22 14:49:31 +09001410 if (hb->min_pcnt == 0) {
1411 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1412 return;
1413 }
1414
Namhyung Kim14135662013-10-31 10:17:39 +09001415 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001416 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001417 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001418 }
1419
Namhyung Kim112f7612014-04-22 14:05:35 +09001420 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001421}
Feng Tang341487ab2013-02-03 14:38:20 +08001422
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001423static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001424 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001425 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001426 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001427 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001428 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001429{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001430 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001431 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001432 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001433#define MAX_OPTIONS 16
1434 char *options[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001435 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001436 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001437 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001438 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001439 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001440 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001441
Namhyung Kime8e684a2013-12-26 14:37:58 +09001442#define HIST_BROWSER_HELP_COMMON \
1443 "h/?/F1 Show this window\n" \
1444 "UP/DOWN/PGUP\n" \
1445 "PGDN/SPACE Navigate\n" \
1446 "q/ESC/CTRL+C Exit browser\n\n" \
1447 "For multiple event sessions:\n\n" \
1448 "TAB/UNTAB Switch events\n\n" \
1449 "For symbolic views (--sort has sym):\n\n" \
1450 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1451 "<- Zoom out\n" \
1452 "a Annotate current symbol\n" \
1453 "C Collapse all callchains\n" \
1454 "d Zoom into current DSO\n" \
1455 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001456 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001457 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001458
1459 /* help messages are sorted by lexical order of the hotkey */
1460 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001461 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001462 "P Print histograms to perf.hist.N\n"
1463 "r Run available scripts\n"
1464 "s Switch to another data file in PWD\n"
1465 "t Zoom into current Thread\n"
1466 "V Verbose (DSO names in callchains, etc)\n"
1467 "/ Filter symbol by name";
1468 const char top_help[] = HIST_BROWSER_HELP_COMMON
1469 "P Print histograms to perf.hist.N\n"
1470 "t Zoom into current Thread\n"
1471 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001472 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001473 "/ Filter symbol by name";
1474
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001475 if (browser == NULL)
1476 return -1;
1477
Namhyung Kim064f1982013-05-14 11:09:04 +09001478 if (min_pcnt) {
1479 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001480 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001481 }
1482
Namhyung Kim01f00a12015-04-22 16:18:16 +09001483 browser->pstack = pstack__new(2);
1484 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001485 goto out;
1486
1487 ui_helpline__push(helpline);
1488
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001489 memset(options, 0, sizeof(options));
1490
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001491 perf_hpp__for_each_format(fmt)
1492 perf_hpp__reset_width(fmt, hists);
1493
Namhyung Kim5b591662014-07-31 14:47:38 +09001494 if (symbol_conf.col_width_list_str)
1495 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1496
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001497 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001498 struct thread *thread = NULL;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001499 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001500 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001501 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001502 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001503 int scripts_comm = -2, scripts_symbol = -2,
1504 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001505
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001506 nr_options = 0;
1507
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001508 key = hist_browser__run(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001509
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001510 if (browser->he_selection != NULL) {
1511 thread = hist_browser__selected_thread(browser);
1512 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1513 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001514 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001515 case K_TAB:
1516 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001517 if (nr_events == 1)
1518 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001519 /*
1520 * Exit the browser, let hists__browser_tree
1521 * go to the next or previous
1522 */
1523 goto out_free_stack;
1524 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001525 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001526 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001527 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001528 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001529 continue;
1530 }
1531
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001532 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001533 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001534 browser->selection->map->dso->annotate_warned)
1535 continue;
1536 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001537 case 'P':
1538 hist_browser__dump(browser);
1539 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001540 case 'd':
1541 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001542 case 'V':
1543 browser->show_dso = !browser->show_dso;
1544 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001545 case 't':
1546 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001547 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001548 if (ui_browser__input_window("Symbol to show",
1549 "Please enter the name of symbol you want to see",
1550 buf, "ENTER: OK, ESC: Cancel",
1551 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001552 hists->symbol_filter_str = *buf ? buf : NULL;
1553 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001554 hist_browser__reset(browser);
1555 }
1556 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001557 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001558 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001559 goto do_scripts;
1560 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001561 case 's':
1562 if (is_report_browser(hbt))
1563 goto do_data_switch;
1564 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001565 case 'i':
1566 /* env->arch is NULL for live-mode (i.e. perf top) */
1567 if (env->arch)
1568 tui__header_window(env);
1569 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001570 case 'F':
1571 symbol_conf.filter_relative ^= 1;
1572 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001573 case 'z':
1574 if (!is_report_browser(hbt)) {
1575 struct perf_top *top = hbt->arg;
1576
1577 top->zero = !top->zero;
1578 }
1579 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001580 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001581 case 'h':
1582 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001583 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001584 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001585 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001586 case K_ENTER:
1587 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001588 /* menu */
1589 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001590 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001591 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001592
Namhyung Kim01f00a12015-04-22 16:18:16 +09001593 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001594 /*
1595 * Go back to the perf_evsel_menu__run or other user
1596 */
1597 if (left_exits)
1598 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001599 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001600 }
Namhyung Kim01f00a12015-04-22 16:18:16 +09001601 top = pstack__pop(browser->pstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001602 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001603 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001604 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001605 goto zoom_out_thread;
1606 continue;
1607 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001608 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001609 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001610 !ui_browser__dialog_yesno(&browser->b,
1611 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001612 continue;
1613 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001614 case 'q':
1615 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001616 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001617 default:
1618 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001619 }
1620
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001621 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001622 goto add_exit_option;
1623
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001624 if (browser->selection == NULL)
1625 goto skip_annotation;
1626
Namhyung Kim55369fc2013-04-01 20:35:20 +09001627 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001628 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001629
1630 if (bi == NULL)
1631 goto skip_annotation;
1632
1633 if (bi->from.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001634 !bi->from.map->dso->annotate_warned &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001635 asprintf(&options[nr_options], "Annotate %s", bi->from.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001636 annotate_f = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001637 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001638
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001639 if (bi->to.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001640 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001641 (bi->to.sym != bi->from.sym ||
1642 bi->to.map->dso != bi->from.map->dso) &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001643 asprintf(&options[nr_options], "Annotate %s", bi->to.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001644 annotate_t = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001645 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001646 } else {
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001647 if (browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001648 !browser->selection->map->dso->annotate_warned) {
1649 struct annotation *notes;
1650
1651 notes = symbol__annotation(browser->selection->sym);
1652
1653 if (notes->src &&
1654 asprintf(&options[nr_options], "Annotate %s",
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001655 browser->selection->sym->name) > 0) {
Jiri Olsad7553302014-06-15 10:22:15 +02001656 annotate = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001657 }
Jiri Olsad7553302014-06-15 10:22:15 +02001658 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001659 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001660skip_annotation:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001661 if (thread != NULL &&
1662 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001663 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001664 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001665 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001666 zoom_thread = nr_options++;
1667
1668 if (dso != NULL &&
1669 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001670 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001671 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1672 zoom_dso = nr_options++;
1673
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001674 if (browser->selection != NULL &&
1675 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001676 asprintf(&options[nr_options], "Browse map details") > 0)
1677 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001678
1679 /* perf script support */
1680 if (browser->he_selection) {
1681 struct symbol *sym;
1682
1683 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001684 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001685 scripts_comm = nr_options++;
1686
1687 sym = browser->he_selection->ms.sym;
1688 if (sym && sym->namelen &&
1689 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1690 sym->name) > 0)
1691 scripts_symbol = nr_options++;
1692 }
1693
1694 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1695 scripts_all = nr_options++;
1696
Feng Tang341487ab2013-02-03 14:38:20 +08001697 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1698 "Switch to another data file in PWD") > 0)
1699 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001700add_exit_option:
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001701 if (asprintf(&options[nr_options], "Exit") > 0)
1702 nr_options++;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001703retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001704 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001705
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001706 if (choice == nr_options - 1)
1707 break;
1708
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001709 if (choice == -1) {
1710 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001711 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001712 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001713
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001714 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001715 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001716 struct annotation *notes;
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001717 struct map_symbol ms;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001718 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001719do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001720 if (!objdump_path && perf_session_env__lookup_objdump(env))
1721 continue;
1722
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001723 he = hist_browser__selected_entry(browser);
1724 if (he == NULL)
1725 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001726
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001727 if (choice == annotate_f) {
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001728 ms.map = he->branch_info->from.map;
1729 ms.sym = he->branch_info->from.sym;
1730 } else if (choice == annotate_t) {
1731 ms.map = he->branch_info->to.map;
1732 ms.sym = he->branch_info->to.sym;
1733 } else {
1734 ms = *browser->selection;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001735 }
1736
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001737 notes = symbol__annotation(ms.sym);
Jiri Olsad7553302014-06-15 10:22:15 +02001738 if (!notes->src)
1739 continue;
1740
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001741 err = map_symbol__tui_annotate(&ms, evsel, hbt);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001742 /*
1743 * offer option to annotate the other branch source or target
1744 * (if they exists) when returning from annotate
1745 */
1746 if ((err == 'q' || err == CTRL('c'))
1747 && annotate_t != -2 && annotate_f != -2)
1748 goto retry_popup_menu;
1749
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001750 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001751 if (err)
1752 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001753
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001754 } else if (choice == browse_map)
1755 map__browse(browser->selection->map);
1756 else if (choice == zoom_dso) {
1757zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001758 if (browser->hists->dso_filter) {
Namhyung Kim01f00a12015-04-22 16:18:16 +09001759 pstack__remove(browser->pstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001760zoom_out_dso:
1761 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001762 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001763 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001764 } else {
1765 if (dso == NULL)
1766 continue;
1767 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1768 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001769 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001770 perf_hpp__set_elide(HISTC_DSO, true);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001771 pstack__push(browser->pstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001772 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001773 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001774 hist_browser__reset(browser);
1775 } else if (choice == zoom_thread) {
1776zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001777 if (browser->hists->thread_filter) {
Namhyung Kim01f00a12015-04-22 16:18:16 +09001778 pstack__remove(browser->pstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001779zoom_out_thread:
1780 ui_helpline__pop();
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001781 thread__zput(browser->hists->thread_filter);
Jiri Olsaf2998422014-05-23 17:15:47 +02001782 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001783 } else {
1784 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001785 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001786 thread->tid);
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001787 browser->hists->thread_filter = thread__get(thread);
Jiri Olsaf2998422014-05-23 17:15:47 +02001788 perf_hpp__set_elide(HISTC_THREAD, false);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001789 pstack__push(browser->pstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001790 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001791 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001792 hist_browser__reset(browser);
1793 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001794 /* perf scripts support */
1795 else if (choice == scripts_all || choice == scripts_comm ||
1796 choice == scripts_symbol) {
1797do_scripts:
1798 memset(script_opt, 0, 64);
1799
1800 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001801 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001802
1803 if (choice == scripts_symbol)
1804 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1805
1806 script_browse(script_opt);
1807 }
Feng Tang341487ab2013-02-03 14:38:20 +08001808 /* Switch to another data file */
1809 else if (choice == switch_data) {
1810do_data_switch:
1811 if (!switch_data_file()) {
1812 key = K_SWITCH_INPUT_DATA;
1813 break;
1814 } else
1815 ui__warning("Won't switch the data files due to\n"
1816 "no valid data file get selected!\n");
1817 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001818 }
1819out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09001820 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001821out:
1822 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001823 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001824 return key;
1825}
1826
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001827struct perf_evsel_menu {
1828 struct ui_browser b;
1829 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001830 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001831 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001832 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001833};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001834
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001835static void perf_evsel_menu__write(struct ui_browser *browser,
1836 void *entry, int row)
1837{
1838 struct perf_evsel_menu *menu = container_of(browser,
1839 struct perf_evsel_menu, b);
1840 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001841 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001842 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001843 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001844 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001845 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001846 const char *warn = " ";
1847 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001848
1849 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1850 HE_COLORSET_NORMAL);
1851
Namhyung Kim759ff492013-03-05 14:53:26 +09001852 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001853 struct perf_evsel *pos;
1854
1855 ev_name = perf_evsel__group_name(evsel);
1856
1857 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001858 struct hists *pos_hists = evsel__hists(pos);
1859 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001860 }
1861 }
1862
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001863 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001864 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001865 unit, unit == ' ' ? "" : " ", ev_name);
1866 slsmg_printf("%s", bf);
1867
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001868 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001869 if (nr_events != 0) {
1870 menu->lost_events = true;
1871 if (!current_entry)
1872 ui_browser__set_color(browser, HE_COLORSET_TOP);
1873 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001874 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1875 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001876 warn = bf;
1877 }
1878
1879 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001880
1881 if (current_entry)
1882 menu->selection = evsel;
1883}
1884
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001885static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1886 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001887 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001888{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001889 struct perf_evlist *evlist = menu->b.priv;
1890 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001891 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001892 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001893 int key;
1894
1895 if (ui_browser__show(&menu->b, title,
1896 "ESC: exit, ENTER|->: Browse histograms") < 0)
1897 return -1;
1898
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001899 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001900 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001901
1902 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001903 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001904 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001905
1906 if (!menu->lost_events_warned && menu->lost_events) {
1907 ui_browser__warn_lost_events(&menu->b);
1908 menu->lost_events_warned = true;
1909 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001910 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001911 case K_RIGHT:
1912 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001913 if (!menu->selection)
1914 continue;
1915 pos = menu->selection;
1916browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001917 perf_evlist__set_selected(evlist, pos);
1918 /*
1919 * Give the calling tool a chance to populate the non
1920 * default evsel resorted hists tree.
1921 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001922 if (hbt)
1923 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001924 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001925 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001926 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001927 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001928 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001929 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001930 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001931 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001932 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001933 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001934 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001935 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001936 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001937 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001938 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001939 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001940 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001941 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001942 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001943 if (!ui_browser__dialog_yesno(&menu->b,
1944 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001945 continue;
1946 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001947 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001948 case 'q':
1949 case CTRL('c'):
1950 goto out;
1951 default:
1952 continue;
1953 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001954 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001955 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001956 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001957 if (!ui_browser__dialog_yesno(&menu->b,
1958 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001959 continue;
1960 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001961 case 'q':
1962 case CTRL('c'):
1963 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001964 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001965 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001966 }
1967 }
1968
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001969out:
1970 ui_browser__hide(&menu->b);
1971 return key;
1972}
1973
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001974static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001975 void *entry)
1976{
1977 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1978
1979 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1980 return true;
1981
1982 return false;
1983}
1984
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001985static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001986 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001987 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001988 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001989 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001990{
1991 struct perf_evsel *pos;
1992 struct perf_evsel_menu menu = {
1993 .b = {
1994 .entries = &evlist->entries,
1995 .refresh = ui_browser__list_head_refresh,
1996 .seek = ui_browser__list_head_seek,
1997 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001998 .filter = filter_group_entries,
1999 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002000 .priv = evlist,
2001 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002002 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002003 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002004 };
2005
2006 ui_helpline__push("Press ESC to exit");
2007
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002008 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002009 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002010 size_t line_len = strlen(ev_name) + 7;
2011
2012 if (menu.b.width < line_len)
2013 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002014 }
2015
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002016 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002017}
2018
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002019int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002020 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002021 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002022 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002023{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002024 int nr_entries = evlist->nr_entries;
2025
2026single_entry:
2027 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002028 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002029
2030 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002031 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002032 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002033 }
2034
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002035 if (symbol_conf.event_group) {
2036 struct perf_evsel *pos;
2037
2038 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002039 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002040 if (perf_evsel__is_group_leader(pos))
2041 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002042 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002043
2044 if (nr_entries == 1)
2045 goto single_entry;
2046 }
2047
2048 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002049 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002050}