blob: 7d88a1cdf04b35a615e49841bc4d429e9be61db7 [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 Kimbc7cad42015-04-22 16:18:18 +09001405static int
1406do_annotate(struct hist_browser *browser, struct map_symbol *ms)
1407{
1408 struct perf_evsel *evsel;
1409 struct annotation *notes;
1410 struct hist_entry *he;
1411 int err;
1412
1413 if (!objdump_path && perf_session_env__lookup_objdump(browser->env))
1414 return 0;
1415
1416 notes = symbol__annotation(ms->sym);
1417 if (!notes->src)
1418 return 0;
1419
1420 evsel = hists_to_evsel(browser->hists);
1421 err = map_symbol__tui_annotate(ms, evsel, browser->hbt);
1422 he = hist_browser__selected_entry(browser);
1423 /*
1424 * offer option to annotate the other branch source or target
1425 * (if they exists) when returning from annotate
1426 */
1427 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1428 return 1;
1429
1430 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1431 if (err)
1432 ui_browser__handle_resize(&browser->b);
1433 return 0;
1434}
1435
1436static int
1437do_zoom_thread(struct hist_browser *browser, struct thread *thread)
1438{
1439 if (browser->hists->thread_filter) {
1440 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1441 perf_hpp__set_elide(HISTC_THREAD, false);
1442 thread__zput(browser->hists->thread_filter);
1443 ui_helpline__pop();
1444 } else {
1445 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1446 thread->comm_set ? thread__comm_str(thread) : "",
1447 thread->tid);
1448 browser->hists->thread_filter = thread__get(thread);
1449 perf_hpp__set_elide(HISTC_THREAD, false);
1450 pstack__push(browser->pstack, &browser->hists->thread_filter);
1451 }
1452
1453 hists__filter_by_thread(browser->hists);
1454 hist_browser__reset(browser);
1455 return 0;
1456}
1457
1458static int
1459do_zoom_dso(struct hist_browser *browser, struct dso *dso)
1460{
1461 if (browser->hists->dso_filter) {
1462 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1463 perf_hpp__set_elide(HISTC_DSO, false);
1464 browser->hists->dso_filter = NULL;
1465 ui_helpline__pop();
1466 } else {
1467 if (dso == NULL)
1468 return 0;
1469 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1470 dso->kernel ? "the Kernel" : dso->short_name);
1471 browser->hists->dso_filter = dso;
1472 perf_hpp__set_elide(HISTC_DSO, true);
1473 pstack__push(browser->pstack, &browser->hists->dso_filter);
1474 }
1475
1476 hists__filter_by_dso(browser->hists);
1477 hist_browser__reset(browser);
1478 return 0;
1479}
1480
1481static int
1482do_browse_map(struct hist_browser *browser __maybe_unused, struct map *map)
1483{
1484 map__browse(map);
1485 return 0;
1486}
1487
1488static int
1489do_run_script(struct hist_browser *browser __maybe_unused,
1490 struct thread *thread, struct symbol *sym)
1491{
1492 char script_opt[64];
1493 memset(script_opt, 0, sizeof(script_opt));
1494
1495 if (thread) {
1496 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
1497 thread__comm_str(thread));
1498 } else if (sym) {
1499 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
1500 sym->name);
1501 }
1502
1503 script_browse(script_opt);
1504 return 0;
1505}
1506
1507static int
1508do_switch_data(struct hist_browser *browser __maybe_unused, int key)
1509{
1510 if (switch_data_file()) {
1511 ui__warning("Won't switch the data files due to\n"
1512 "no valid data file get selected!\n");
1513 return key;
1514 }
1515
1516 return K_SWITCH_INPUT_DATA;
1517}
1518
Namhyung Kim112f7612014-04-22 14:05:35 +09001519static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001520{
1521 u64 nr_entries = 0;
1522 struct rb_node *nd = rb_first(&hb->hists->entries);
1523
Namhyung Kim268397c2014-04-22 14:49:31 +09001524 if (hb->min_pcnt == 0) {
1525 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1526 return;
1527 }
1528
Namhyung Kim14135662013-10-31 10:17:39 +09001529 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001530 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001531 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001532 }
1533
Namhyung Kim112f7612014-04-22 14:05:35 +09001534 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001535}
Feng Tang341487ab2013-02-03 14:38:20 +08001536
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001537static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001538 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001539 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001540 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001541 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001542 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001543{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001544 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001545 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001546 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001547#define MAX_OPTIONS 16
1548 char *options[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001549 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001550 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001551 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001552 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001553 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001554
Namhyung Kime8e684a2013-12-26 14:37:58 +09001555#define HIST_BROWSER_HELP_COMMON \
1556 "h/?/F1 Show this window\n" \
1557 "UP/DOWN/PGUP\n" \
1558 "PGDN/SPACE Navigate\n" \
1559 "q/ESC/CTRL+C Exit browser\n\n" \
1560 "For multiple event sessions:\n\n" \
1561 "TAB/UNTAB Switch events\n\n" \
1562 "For symbolic views (--sort has sym):\n\n" \
1563 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1564 "<- Zoom out\n" \
1565 "a Annotate current symbol\n" \
1566 "C Collapse all callchains\n" \
1567 "d Zoom into current DSO\n" \
1568 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001569 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001570 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001571
1572 /* help messages are sorted by lexical order of the hotkey */
1573 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001574 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001575 "P Print histograms to perf.hist.N\n"
1576 "r Run available scripts\n"
1577 "s Switch to another data file in PWD\n"
1578 "t Zoom into current Thread\n"
1579 "V Verbose (DSO names in callchains, etc)\n"
1580 "/ Filter symbol by name";
1581 const char top_help[] = HIST_BROWSER_HELP_COMMON
1582 "P Print histograms to perf.hist.N\n"
1583 "t Zoom into current Thread\n"
1584 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001585 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001586 "/ Filter symbol by name";
1587
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001588 if (browser == NULL)
1589 return -1;
1590
Namhyung Kim064f1982013-05-14 11:09:04 +09001591 if (min_pcnt) {
1592 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001593 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001594 }
1595
Namhyung Kim01f00a12015-04-22 16:18:16 +09001596 browser->pstack = pstack__new(2);
1597 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001598 goto out;
1599
1600 ui_helpline__push(helpline);
1601
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001602 memset(options, 0, sizeof(options));
1603
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001604 perf_hpp__for_each_format(fmt)
1605 perf_hpp__reset_width(fmt, hists);
1606
Namhyung Kim5b591662014-07-31 14:47:38 +09001607 if (symbol_conf.col_width_list_str)
1608 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1609
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001610 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001611 struct thread *thread = NULL;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001612 struct dso *dso = NULL;
1613 struct map_symbol ms;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001614 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001615 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001616 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001617 int scripts_comm = -2, scripts_symbol = -2,
1618 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001619
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001620 nr_options = 0;
1621
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001622 key = hist_browser__run(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001623
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001624 if (browser->he_selection != NULL) {
1625 thread = hist_browser__selected_thread(browser);
1626 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1627 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001628 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001629 case K_TAB:
1630 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001631 if (nr_events == 1)
1632 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001633 /*
1634 * Exit the browser, let hists__browser_tree
1635 * go to the next or previous
1636 */
1637 goto out_free_stack;
1638 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001639 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001640 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001641 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001642 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001643 continue;
1644 }
1645
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001646 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001647 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001648 browser->selection->map->dso->annotate_warned)
1649 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001650
1651 ms.map = browser->selection->map;
1652 ms.sym = browser->selection->sym;
1653
1654 do_annotate(browser, &ms);
1655 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001656 case 'P':
1657 hist_browser__dump(browser);
1658 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001659 case 'd':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001660 do_zoom_dso(browser, dso);
1661 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001662 case 'V':
1663 browser->show_dso = !browser->show_dso;
1664 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001665 case 't':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001666 do_zoom_thread(browser, thread);
1667 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001668 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001669 if (ui_browser__input_window("Symbol to show",
1670 "Please enter the name of symbol you want to see",
1671 buf, "ENTER: OK, ESC: Cancel",
1672 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001673 hists->symbol_filter_str = *buf ? buf : NULL;
1674 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001675 hist_browser__reset(browser);
1676 }
1677 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001678 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001679 if (is_report_browser(hbt))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001680 do_run_script(browser, NULL, NULL);
Feng Tangc77d8d72012-11-01 00:00:55 +08001681 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001682 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001683 if (is_report_browser(hbt)) {
1684 key = do_switch_data(browser, key);
1685 if (key == K_SWITCH_INPUT_DATA)
1686 goto out_free_stack;
1687 }
Feng Tang341487ab2013-02-03 14:38:20 +08001688 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001689 case 'i':
1690 /* env->arch is NULL for live-mode (i.e. perf top) */
1691 if (env->arch)
1692 tui__header_window(env);
1693 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001694 case 'F':
1695 symbol_conf.filter_relative ^= 1;
1696 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001697 case 'z':
1698 if (!is_report_browser(hbt)) {
1699 struct perf_top *top = hbt->arg;
1700
1701 top->zero = !top->zero;
1702 }
1703 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001704 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001705 case 'h':
1706 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001707 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001708 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001709 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001710 case K_ENTER:
1711 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001712 /* menu */
1713 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001714 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001715 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001716
Namhyung Kim01f00a12015-04-22 16:18:16 +09001717 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001718 /*
1719 * Go back to the perf_evsel_menu__run or other user
1720 */
1721 if (left_exits)
1722 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001723 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001724 }
Namhyung Kim01f00a12015-04-22 16:18:16 +09001725 top = pstack__pop(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001726 if (top == &browser->hists->dso_filter) {
1727 perf_hpp__set_elide(HISTC_DSO, false);
1728 browser->hists->dso_filter = NULL;
1729 hists__filter_by_dso(browser->hists);
1730 }
1731 if (top == &browser->hists->thread_filter) {
1732 perf_hpp__set_elide(HISTC_THREAD, false);
1733 thread__zput(browser->hists->thread_filter);
1734 hists__filter_by_thread(browser->hists);
1735 }
1736 ui_helpline__pop();
1737 hist_browser__reset(browser);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001738 continue;
1739 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001740 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001741 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001742 !ui_browser__dialog_yesno(&browser->b,
1743 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001744 continue;
1745 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001746 case 'q':
1747 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001748 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001749 default:
1750 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001751 }
1752
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001753 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001754 goto add_exit_option;
1755
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001756 if (browser->selection == NULL)
1757 goto skip_annotation;
1758
Namhyung Kim55369fc2013-04-01 20:35:20 +09001759 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001760 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001761
1762 if (bi == NULL)
1763 goto skip_annotation;
1764
1765 if (bi->from.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001766 !bi->from.map->dso->annotate_warned &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001767 asprintf(&options[nr_options], "Annotate %s", bi->from.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001768 annotate_f = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001769 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001770
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001771 if (bi->to.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001772 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001773 (bi->to.sym != bi->from.sym ||
1774 bi->to.map->dso != bi->from.map->dso) &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001775 asprintf(&options[nr_options], "Annotate %s", bi->to.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001776 annotate_t = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001777 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001778 } else {
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001779 if (browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001780 !browser->selection->map->dso->annotate_warned) {
1781 struct annotation *notes;
1782
1783 notes = symbol__annotation(browser->selection->sym);
1784
1785 if (notes->src &&
1786 asprintf(&options[nr_options], "Annotate %s",
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001787 browser->selection->sym->name) > 0) {
Jiri Olsad7553302014-06-15 10:22:15 +02001788 annotate = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001789 }
Jiri Olsad7553302014-06-15 10:22:15 +02001790 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001791 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001792skip_annotation:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001793 if (thread != NULL &&
1794 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001795 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001796 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001797 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001798 zoom_thread = nr_options++;
1799
1800 if (dso != NULL &&
1801 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001802 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001803 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1804 zoom_dso = nr_options++;
1805
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001806 if (browser->selection != NULL &&
1807 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001808 asprintf(&options[nr_options], "Browse map details") > 0)
1809 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001810
1811 /* perf script support */
1812 if (browser->he_selection) {
1813 struct symbol *sym;
1814
1815 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001816 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001817 scripts_comm = nr_options++;
1818
1819 sym = browser->he_selection->ms.sym;
1820 if (sym && sym->namelen &&
1821 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1822 sym->name) > 0)
1823 scripts_symbol = nr_options++;
1824 }
1825
1826 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1827 scripts_all = nr_options++;
1828
Feng Tang341487ab2013-02-03 14:38:20 +08001829 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1830 "Switch to another data file in PWD") > 0)
1831 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001832add_exit_option:
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001833 if (asprintf(&options[nr_options], "Exit") > 0)
1834 nr_options++;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001835retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001836 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001837
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001838 if (choice == nr_options - 1)
1839 break;
1840
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001841 if (choice == -1) {
1842 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001843 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001844 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001845
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001846 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001847 struct hist_entry *he;
Namhyung Kim68d80752012-11-02 14:50:06 +09001848
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001849 he = hist_browser__selected_entry(browser);
1850 if (he == NULL)
1851 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001852
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001853 if (choice == annotate_f) {
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001854 ms.map = he->branch_info->from.map;
1855 ms.sym = he->branch_info->from.sym;
1856 } else if (choice == annotate_t) {
1857 ms.map = he->branch_info->to.map;
1858 ms.sym = he->branch_info->to.sym;
1859 } else {
1860 ms = *browser->selection;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001861 }
1862
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001863 if (do_annotate(browser, &ms) == 1)
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001864 goto retry_popup_menu;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001865 } else if (choice == browse_map) {
1866 do_browse_map(browser, browser->selection->map);
1867 } else if (choice == zoom_dso) {
1868 do_zoom_dso(browser, dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001869 } else if (choice == zoom_thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001870 do_zoom_thread(browser, thread);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001871 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001872 /* perf scripts support */
1873 else if (choice == scripts_all || choice == scripts_comm ||
1874 choice == scripts_symbol) {
Feng Tangcdbab7c2012-10-30 11:56:06 +08001875 if (choice == scripts_comm)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001876 do_run_script(browser, browser->he_selection->thread, NULL);
Feng Tangcdbab7c2012-10-30 11:56:06 +08001877 if (choice == scripts_symbol)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001878 do_run_script(browser, NULL, browser->he_selection->ms.sym);
1879 if (choice == scripts_all)
1880 do_run_script(browser, NULL, NULL);
Feng Tangcdbab7c2012-10-30 11:56:06 +08001881 }
Feng Tang341487ab2013-02-03 14:38:20 +08001882 /* Switch to another data file */
1883 else if (choice == switch_data) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001884 key = do_switch_data(browser, key);
1885 if (key == K_SWITCH_INPUT_DATA)
Feng Tang341487ab2013-02-03 14:38:20 +08001886 break;
Feng Tang341487ab2013-02-03 14:38:20 +08001887 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001888 }
1889out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09001890 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001891out:
1892 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001893 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001894 return key;
1895}
1896
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001897struct perf_evsel_menu {
1898 struct ui_browser b;
1899 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001900 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001901 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001902 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001903};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001904
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001905static void perf_evsel_menu__write(struct ui_browser *browser,
1906 void *entry, int row)
1907{
1908 struct perf_evsel_menu *menu = container_of(browser,
1909 struct perf_evsel_menu, b);
1910 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001911 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001912 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001913 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001914 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001915 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001916 const char *warn = " ";
1917 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001918
1919 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1920 HE_COLORSET_NORMAL);
1921
Namhyung Kim759ff492013-03-05 14:53:26 +09001922 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001923 struct perf_evsel *pos;
1924
1925 ev_name = perf_evsel__group_name(evsel);
1926
1927 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001928 struct hists *pos_hists = evsel__hists(pos);
1929 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001930 }
1931 }
1932
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001933 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001934 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001935 unit, unit == ' ' ? "" : " ", ev_name);
1936 slsmg_printf("%s", bf);
1937
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001938 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001939 if (nr_events != 0) {
1940 menu->lost_events = true;
1941 if (!current_entry)
1942 ui_browser__set_color(browser, HE_COLORSET_TOP);
1943 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001944 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1945 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001946 warn = bf;
1947 }
1948
1949 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001950
1951 if (current_entry)
1952 menu->selection = evsel;
1953}
1954
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001955static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1956 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001957 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001958{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001959 struct perf_evlist *evlist = menu->b.priv;
1960 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001961 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001962 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001963 int key;
1964
1965 if (ui_browser__show(&menu->b, title,
1966 "ESC: exit, ENTER|->: Browse histograms") < 0)
1967 return -1;
1968
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001969 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001970 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001971
1972 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001973 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001974 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001975
1976 if (!menu->lost_events_warned && menu->lost_events) {
1977 ui_browser__warn_lost_events(&menu->b);
1978 menu->lost_events_warned = true;
1979 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001980 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001981 case K_RIGHT:
1982 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001983 if (!menu->selection)
1984 continue;
1985 pos = menu->selection;
1986browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001987 perf_evlist__set_selected(evlist, pos);
1988 /*
1989 * Give the calling tool a chance to populate the non
1990 * default evsel resorted hists tree.
1991 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001992 if (hbt)
1993 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001994 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001995 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001996 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001997 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001998 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001999 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002000 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002001 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002002 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002003 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002004 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002005 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002006 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002007 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002008 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002009 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002010 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002011 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002012 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002013 if (!ui_browser__dialog_yesno(&menu->b,
2014 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002015 continue;
2016 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08002017 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002018 case 'q':
2019 case CTRL('c'):
2020 goto out;
2021 default:
2022 continue;
2023 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002024 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002025 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002026 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002027 if (!ui_browser__dialog_yesno(&menu->b,
2028 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002029 continue;
2030 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002031 case 'q':
2032 case CTRL('c'):
2033 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002034 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002035 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002036 }
2037 }
2038
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002039out:
2040 ui_browser__hide(&menu->b);
2041 return key;
2042}
2043
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002044static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002045 void *entry)
2046{
2047 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2048
2049 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2050 return true;
2051
2052 return false;
2053}
2054
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002055static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002056 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002057 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002058 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002059 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002060{
2061 struct perf_evsel *pos;
2062 struct perf_evsel_menu menu = {
2063 .b = {
2064 .entries = &evlist->entries,
2065 .refresh = ui_browser__list_head_refresh,
2066 .seek = ui_browser__list_head_seek,
2067 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002068 .filter = filter_group_entries,
2069 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002070 .priv = evlist,
2071 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002072 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002073 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002074 };
2075
2076 ui_helpline__push("Press ESC to exit");
2077
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002078 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002079 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002080 size_t line_len = strlen(ev_name) + 7;
2081
2082 if (menu.b.width < line_len)
2083 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002084 }
2085
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002086 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002087}
2088
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002089int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002090 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002091 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002092 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002093{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002094 int nr_entries = evlist->nr_entries;
2095
2096single_entry:
2097 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002098 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002099
2100 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002101 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002102 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002103 }
2104
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002105 if (symbol_conf.event_group) {
2106 struct perf_evsel *pos;
2107
2108 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002109 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002110 if (perf_evsel__is_group_leader(pos))
2111 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002112 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002113
2114 if (nr_entries == 1)
2115 goto single_entry;
2116 }
2117
2118 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002119 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002120}