blob: 2f34c6b6d5dc1a678539e33c410e19f5cd08cb52 [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;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030028 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030029 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020030 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090031 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090032 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090033 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030034};
35
Namhyung Kimf5951d52012-09-03 11:53:09 +090036extern void hist_browser__init_hpp(void);
37
Jiri Olsadd00d482014-06-19 13:41:13 +020038static int hists__browser_title(struct hists *hists, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090039static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030040
Namhyung Kimc3b78952014-04-22 15:56:17 +090041static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090042 float min_pcnt);
43
Namhyung Kim268397c2014-04-22 14:49:31 +090044static bool hist_browser__has_filter(struct hist_browser *hb)
45{
46 return hists__has_filter(hb->hists) || hb->min_pcnt;
47}
48
Namhyung Kimc3b78952014-04-22 15:56:17 +090049static u32 hist_browser__nr_entries(struct hist_browser *hb)
50{
51 u32 nr_entries;
52
53 if (hist_browser__has_filter(hb))
54 nr_entries = hb->nr_non_filtered_entries;
55 else
56 nr_entries = hb->hists->nr_entries;
57
58 return nr_entries + hb->nr_callchain_rows;
59}
60
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020061static void hist_browser__update_rows(struct hist_browser *hb)
62{
63 struct ui_browser *browser = &hb->b;
64 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
65
66 browser->rows = browser->height - header_offset;
67 /*
68 * Verify if we were at the last line and that line isn't
69 * visibe because we now show the header line(s).
70 */
71 index_row = browser->index - browser->top_idx;
72 if (index_row >= browser->rows)
73 browser->index -= index_row - browser->rows + 1;
74}
75
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030076static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030077{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030078 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
79
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030080 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030081 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
82 /*
83 * FIXME: Just keeping existing behaviour, but this really should be
84 * before updating browser->width, as it will invalidate the
85 * calculation above. Fix this and the fallout in another
86 * changeset.
87 */
88 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020089 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030090}
91
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030092static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
93{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020094 u16 header_offset = browser->show_headers ? 1 : 0;
95
96 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030097}
98
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030099static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300100{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900101 /*
102 * The hists__remove_entry_filter() already folds non-filtered
103 * entries so we can assume it has 0 callchain rows.
104 */
105 browser->nr_callchain_rows = 0;
106
Namhyung Kim268397c2014-04-22 14:49:31 +0900107 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900108 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300109 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300110 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300111}
112
113static char tree__folded_sign(bool unfolded)
114{
115 return unfolded ? '-' : '+';
116}
117
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300118static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300119{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300120 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300121}
122
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300123static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300124{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300125 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300126}
127
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300128static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300129{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300130 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300131}
132
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300133static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300134{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300135 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300136}
137
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300138static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300139{
140 int n = 0;
141 struct rb_node *nd;
142
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300143 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
145 struct callchain_list *chain;
146 char folded_sign = ' '; /* No children */
147
148 list_for_each_entry(chain, &child->val, list) {
149 ++n;
150 /* We need this because we may not have children */
151 folded_sign = callchain_list__folded(chain);
152 if (folded_sign == '+')
153 break;
154 }
155
156 if (folded_sign == '-') /* Have children and they're unfolded */
157 n += callchain_node__count_rows_rb_tree(child);
158 }
159
160 return n;
161}
162
163static int callchain_node__count_rows(struct callchain_node *node)
164{
165 struct callchain_list *chain;
166 bool unfolded = false;
167 int n = 0;
168
169 list_for_each_entry(chain, &node->val, list) {
170 ++n;
171 unfolded = chain->ms.unfolded;
172 }
173
174 if (unfolded)
175 n += callchain_node__count_rows_rb_tree(node);
176
177 return n;
178}
179
180static int callchain__count_rows(struct rb_root *chain)
181{
182 struct rb_node *nd;
183 int n = 0;
184
185 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
186 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
187 n += callchain_node__count_rows(node);
188 }
189
190 return n;
191}
192
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300193static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300194{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300195 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200196 return false;
197
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300198 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300199 return false;
200
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300201 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300202 return true;
203}
204
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300205static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300206{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300207 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300208
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300209 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300210 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
211 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300212 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300213
214 list_for_each_entry(chain, &child->val, list) {
215 if (first) {
216 first = false;
217 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300218 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300219 } else
220 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300221 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300222 }
223
224 callchain_node__init_have_children_rb_tree(child);
225 }
226}
227
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300228static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229{
230 struct callchain_list *chain;
231
Namhyung Kim82162b52014-08-13 15:02:41 +0900232 if (!list_empty(&node->val)) {
233 chain = list_entry(node->val.prev, struct callchain_list, list);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300234 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900235 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300236
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300237 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300238}
239
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300240static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300241{
242 struct rb_node *nd;
243
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300244 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300245 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
246 callchain_node__init_have_children(node);
247 }
248}
249
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300250static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300251{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300252 if (!he->init_have_children) {
253 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
254 callchain__init_have_children(&he->sorted_chain);
255 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300256 }
257}
258
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300259static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300260{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300261 if (map_symbol__toggle_fold(browser->selection)) {
262 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300263
264 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900265 browser->b.nr_entries -= he->nr_rows;
266 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300267
268 if (he->ms.unfolded)
269 he->nr_rows = callchain__count_rows(&he->sorted_chain);
270 else
271 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900272
273 browser->b.nr_entries += he->nr_rows;
274 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300275
276 return true;
277 }
278
279 /* If it doesn't have children, no toggling performed */
280 return false;
281}
282
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300283static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300284{
285 int n = 0;
286 struct rb_node *nd;
287
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300288 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300289 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
290 struct callchain_list *chain;
291 bool has_children = false;
292
293 list_for_each_entry(chain, &child->val, list) {
294 ++n;
295 map_symbol__set_folding(&chain->ms, unfold);
296 has_children = chain->ms.has_children;
297 }
298
299 if (has_children)
300 n += callchain_node__set_folding_rb_tree(child, unfold);
301 }
302
303 return n;
304}
305
306static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
307{
308 struct callchain_list *chain;
309 bool has_children = false;
310 int n = 0;
311
312 list_for_each_entry(chain, &node->val, list) {
313 ++n;
314 map_symbol__set_folding(&chain->ms, unfold);
315 has_children = chain->ms.has_children;
316 }
317
318 if (has_children)
319 n += callchain_node__set_folding_rb_tree(node, unfold);
320
321 return n;
322}
323
324static int callchain__set_folding(struct rb_root *chain, bool unfold)
325{
326 struct rb_node *nd;
327 int n = 0;
328
329 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
330 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
331 n += callchain_node__set_folding(node, unfold);
332 }
333
334 return n;
335}
336
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300337static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300338{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300339 hist_entry__init_have_children(he);
340 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300341
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300342 if (he->ms.has_children) {
343 int n = callchain__set_folding(&he->sorted_chain, unfold);
344 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300345 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300346 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300347}
348
Namhyung Kimc3b78952014-04-22 15:56:17 +0900349static void
350__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300351{
352 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900353 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300354
Namhyung Kimc3b78952014-04-22 15:56:17 +0900355 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900356 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900357 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300358 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
359 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900360 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300361 }
362}
363
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300364static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300365{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900366 browser->nr_callchain_rows = 0;
367 __hist_browser__set_folding(browser, unfold);
368
369 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300370 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300372}
373
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200374static void ui_browser__warn_lost_events(struct ui_browser *browser)
375{
376 ui_browser__warning(browser, 4,
377 "Events are being lost, check IO/CPU overload!\n\n"
378 "You may want to run 'perf' using a RT scheduler policy:\n\n"
379 " perf top -r 80\n\n"
380 "Or reduce the sampling frequency.");
381}
382
Jiri Olsadd00d482014-06-19 13:41:13 +0200383static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900384 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300386 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300387 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900388 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300389
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300390 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900391 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392
Jiri Olsadd00d482014-06-19 13:41:13 +0200393 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300395 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300396 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300397 return -1;
398
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300399 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300400 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300402 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900403 case K_TIMER: {
404 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900405 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900406
Namhyung Kimc3b78952014-04-22 15:56:17 +0900407 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900408 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900409
Namhyung Kimc3b78952014-04-22 15:56:17 +0900410 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900411 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200412
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300413 if (browser->hists->stats.nr_lost_warned !=
414 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
415 browser->hists->stats.nr_lost_warned =
416 browser->hists->stats.nr_events[PERF_RECORD_LOST];
417 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200418 }
419
Jiri Olsadd00d482014-06-19 13:41:13 +0200420 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300421 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300422 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900423 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300424 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300425 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300426 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300427 struct hist_entry, rb_node);
428 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300429 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 -0300430 seq++, browser->b.nr_entries,
431 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300432 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300433 browser->b.index,
434 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300435 h->row_offset, h->nr_rows);
436 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300437 break;
438 case 'C':
439 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300440 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300441 break;
442 case 'E':
443 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300444 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300445 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200446 case 'H':
447 browser->show_headers = !browser->show_headers;
448 hist_browser__update_rows(browser);
449 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200450 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300451 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300452 break;
453 /* fall thru */
454 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300455 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300456 }
457 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300458out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300459 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300460 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300461}
462
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300463static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300464 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300465{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300466 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300467
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300468 if (cl->ms.sym)
469 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
470 else
471 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
472
473 if (show_dso)
474 scnprintf(bf + printed, bfsize - printed, " %s",
475 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
476
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300477 return bf;
478}
479
480#define LEVEL_OFFSET_STEP 3
481
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300482static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300483 struct callchain_node *chain_node,
484 u64 total, int level,
485 unsigned short row,
486 off_t *row_offset,
487 bool *is_current_entry)
488{
489 struct rb_node *node;
490 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900491 u64 new_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300492
493 if (callchain_param.mode == CHAIN_GRAPH_REL)
494 new_total = chain_node->children_hit;
495 else
496 new_total = total;
497
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300498 node = rb_first(&chain_node->rb_root);
499 while (node) {
500 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
501 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100502 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300503 struct callchain_list *chain;
504 char folded_sign = ' ';
505 int first = true;
506 int extra_offset = 0;
507
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300508 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300509 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300510 const char *str;
511 int color;
512 bool was_first = first;
513
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300514 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300515 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300516 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300517 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300518
519 folded_sign = callchain_list__folded(chain);
520 if (*row_offset != 0) {
521 --*row_offset;
522 goto do_next;
523 }
524
525 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300526 str = callchain_list__sym_name(chain, bf, sizeof(bf),
527 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300528 if (was_first) {
529 double percent = cumul * 100.0 / new_total;
530
531 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
532 str = "Not enough memory!";
533 else
534 str = alloc_str;
535 }
536
537 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300538 width = browser->b.width - (offset + extra_offset + 2);
539 if (ui_browser__is_current_entry(&browser->b, row)) {
540 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300541 color = HE_COLORSET_SELECTED;
542 *is_current_entry = true;
543 }
544
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300545 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300546 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300547 slsmg_write_nstring(" ", offset + extra_offset);
548 slsmg_printf("%c ", folded_sign);
549 slsmg_write_nstring(str, width);
550 free(alloc_str);
551
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300552 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300553 goto out;
554do_next:
555 if (folded_sign == '+')
556 break;
557 }
558
559 if (folded_sign == '-') {
560 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300561 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300562 new_level, row, row_offset,
563 is_current_entry);
564 }
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300565 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300566 goto out;
567 node = next;
568 }
569out:
570 return row - first_row;
571}
572
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300573static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300574 struct callchain_node *node,
575 int level, unsigned short row,
576 off_t *row_offset,
577 bool *is_current_entry)
578{
579 struct callchain_list *chain;
580 int first_row = row,
581 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300582 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300583 char folded_sign = ' ';
584
585 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300586 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300587 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300588
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300589 folded_sign = callchain_list__folded(chain);
590
591 if (*row_offset != 0) {
592 --*row_offset;
593 continue;
594 }
595
596 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300597 if (ui_browser__is_current_entry(&browser->b, row)) {
598 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300599 color = HE_COLORSET_SELECTED;
600 *is_current_entry = true;
601 }
602
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300603 s = callchain_list__sym_name(chain, bf, sizeof(bf),
604 browser->show_dso);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300605 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300606 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607 slsmg_write_nstring(" ", offset);
608 slsmg_printf("%c ", folded_sign);
609 slsmg_write_nstring(s, width - 2);
610
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300611 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300612 goto out;
613 }
614
615 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300616 row += hist_browser__show_callchain_node_rb_tree(browser, node,
617 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300618 level + 1, row,
619 row_offset,
620 is_current_entry);
621out:
622 return row - first_row;
623}
624
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300625static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300626 struct rb_root *chain,
627 int level, unsigned short row,
628 off_t *row_offset,
629 bool *is_current_entry)
630{
631 struct rb_node *nd;
632 int first_row = row;
633
634 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
635 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
636
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300637 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300638 row, row_offset,
639 is_current_entry);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300640 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300641 break;
642 }
643
644 return row - first_row;
645}
646
Namhyung Kim89701462013-01-22 18:09:38 +0900647struct hpp_arg {
648 struct ui_browser *b;
649 char folded_sign;
650 bool current_entry;
651};
652
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900653static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
654{
655 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900656 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900657 va_list args;
658 double percent;
659
660 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900661 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900662 percent = va_arg(args, double);
663 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900664
Namhyung Kim89701462013-01-22 18:09:38 +0900665 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900666
Namhyung Kimd6751072014-07-31 14:47:36 +0900667 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900668 slsmg_printf("%s", hpp->buf);
669
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900670 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900671 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900672}
673
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900674#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900675static u64 __hpp_get_##_field(struct hist_entry *he) \
676{ \
677 return he->stat._field; \
678} \
679 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100680static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900681hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100682 struct perf_hpp *hpp, \
683 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900684{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900685 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
686 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900687}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900688
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900689#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
690static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
691{ \
692 return he->stat_acc->_field; \
693} \
694 \
695static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900696hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900697 struct perf_hpp *hpp, \
698 struct hist_entry *he) \
699{ \
700 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900701 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900702 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900703 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900704 slsmg_printf("%s", hpp->buf); \
705 \
706 return ret; \
707 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900708 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
709 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900710}
711
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900712__HPP_COLOR_PERCENT_FN(overhead, period)
713__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
714__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
715__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
716__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900717__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900718
719#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900720#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900721
722void hist_browser__init_hpp(void)
723{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900724 perf_hpp__format[PERF_HPP__OVERHEAD].color =
725 hist_browser__hpp_color_overhead;
726 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
727 hist_browser__hpp_color_overhead_sys;
728 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
729 hist_browser__hpp_color_overhead_us;
730 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
731 hist_browser__hpp_color_overhead_guest_sys;
732 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
733 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900734 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
735 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900736}
737
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300738static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300739 struct hist_entry *entry,
740 unsigned short row)
741{
742 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200743 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900744 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300745 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300746 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300747 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300748 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200749 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300750
751 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300752 browser->he_selection = entry;
753 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300754 }
755
756 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300757 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300758 folded_sign = hist_entry__folded(entry);
759 }
760
761 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900762 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900763 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900764 .folded_sign = folded_sign,
765 .current_entry = current_entry,
766 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900767 struct perf_hpp hpp = {
768 .buf = s,
769 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900770 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900771 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300772
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300773 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900774
Jiri Olsa12400052012-10-13 00:06:16 +0200775 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900776 if (perf_hpp__should_skip(fmt))
777 continue;
778
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900779 if (current_entry && browser->b.navkeypressed) {
780 ui_browser__set_color(&browser->b,
781 HE_COLORSET_SELECTED);
782 } else {
783 ui_browser__set_color(&browser->b,
784 HE_COLORSET_NORMAL);
785 }
786
787 if (first) {
788 if (symbol_conf.use_callchain) {
789 slsmg_printf("%c ", folded_sign);
790 width -= 2;
791 }
792 first = false;
793 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900794 slsmg_printf(" ");
795 width -= 2;
796 }
797
Jiri Olsa12400052012-10-13 00:06:16 +0200798 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100799 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900800 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100801 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900802 slsmg_printf("%s", s);
803 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300804 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200805
806 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300807 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200808 width += 1;
809
Namhyung Kim26d8b332014-03-03 16:16:20 +0900810 slsmg_write_nstring("", width);
811
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300812 ++row;
813 ++printed;
814 } else
815 --row_offset;
816
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300817 if (folded_sign == '-' && row != browser->b.rows) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300818 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300819 1, row, &row_offset,
820 &current_entry);
821 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300822 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300823 }
824
825 return printed;
826}
827
Jiri Olsa81a888f2014-06-14 15:44:52 +0200828static int advance_hpp_check(struct perf_hpp *hpp, int inc)
829{
830 advance_hpp(hpp, inc);
831 return hpp->size <= 0;
832}
833
834static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
835{
836 struct perf_hpp dummy_hpp = {
837 .buf = buf,
838 .size = size,
839 };
840 struct perf_hpp_fmt *fmt;
841 size_t ret = 0;
842
843 if (symbol_conf.use_callchain) {
844 ret = scnprintf(buf, size, " ");
845 if (advance_hpp_check(&dummy_hpp, ret))
846 return ret;
847 }
848
849 perf_hpp__for_each_format(fmt) {
850 if (perf_hpp__should_skip(fmt))
851 continue;
852
Jiri Olsa81a888f2014-06-14 15:44:52 +0200853 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
854 if (advance_hpp_check(&dummy_hpp, ret))
855 break;
856
857 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
858 if (advance_hpp_check(&dummy_hpp, ret))
859 break;
860 }
861
862 return ret;
863}
864
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200865static void hist_browser__show_headers(struct hist_browser *browser)
866{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200867 char headers[1024];
868
869 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200870 ui_browser__gotorc(&browser->b, 0, 0);
871 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200872 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200873}
874
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300875static void ui_browser__hists_init_top(struct ui_browser *browser)
876{
877 if (browser->top == NULL) {
878 struct hist_browser *hb;
879
880 hb = container_of(browser, struct hist_browser, b);
881 browser->top = rb_first(&hb->hists->entries);
882 }
883}
884
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300885static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300886{
887 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200888 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300889 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300890 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300891
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200892 if (hb->show_headers) {
893 hist_browser__show_headers(hb);
894 header_offset = 1;
895 }
896
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300897 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300898
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300899 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300900 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900901 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300902
903 if (h->filtered)
904 continue;
905
Namhyung Kim14135662013-10-31 10:17:39 +0900906 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900907 if (percent < hb->min_pcnt)
908 continue;
909
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300910 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300911 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300912 break;
913 }
914
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200915 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300916}
917
Namhyung Kim064f1982013-05-14 11:09:04 +0900918static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900919 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300920{
921 while (nd != NULL) {
922 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900923 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900924
Namhyung Kimc0f15272014-04-16 11:16:33 +0900925 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300926 return nd;
927
928 nd = rb_next(nd);
929 }
930
931 return NULL;
932}
933
Namhyung Kim064f1982013-05-14 11:09:04 +0900934static struct rb_node *hists__filter_prev_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
941 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300942 return nd;
943
944 nd = rb_prev(nd);
945 }
946
947 return NULL;
948}
949
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300950static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300951 off_t offset, int whence)
952{
953 struct hist_entry *h;
954 struct rb_node *nd;
955 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900956 struct hist_browser *hb;
957
958 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300959
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300960 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300961 return;
962
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300963 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300964
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300965 switch (whence) {
966 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900967 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900968 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300969 break;
970 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300971 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300972 goto do_offset;
973 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900974 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900975 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300976 first = false;
977 break;
978 default:
979 return;
980 }
981
982 /*
983 * Moves not relative to the first visible entry invalidates its
984 * row_offset:
985 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300986 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300987 h->row_offset = 0;
988
989 /*
990 * Here we have to check if nd is expanded (+), if it is we can't go
991 * the next top level hist_entry, instead we must compute an offset of
992 * what _not_ to show and not change the first visible entry.
993 *
994 * This offset increments when we are going from top to bottom and
995 * decreases when we're going from bottom to top.
996 *
997 * As we don't have backpointers to the top level in the callchains
998 * structure, we need to always print the whole hist_entry callchain,
999 * skipping the first ones that are before the first visible entry
1000 * and stop when we printed enough lines to fill the screen.
1001 */
1002do_offset:
1003 if (offset > 0) {
1004 do {
1005 h = rb_entry(nd, struct hist_entry, rb_node);
1006 if (h->ms.unfolded) {
1007 u16 remaining = h->nr_rows - h->row_offset;
1008 if (offset > remaining) {
1009 offset -= remaining;
1010 h->row_offset = 0;
1011 } else {
1012 h->row_offset += offset;
1013 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001014 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001015 break;
1016 }
1017 }
Namhyung Kim14135662013-10-31 10:17:39 +09001018 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001019 if (nd == NULL)
1020 break;
1021 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001022 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001023 } while (offset != 0);
1024 } else if (offset < 0) {
1025 while (1) {
1026 h = rb_entry(nd, struct hist_entry, rb_node);
1027 if (h->ms.unfolded) {
1028 if (first) {
1029 if (-offset > h->row_offset) {
1030 offset += h->row_offset;
1031 h->row_offset = 0;
1032 } else {
1033 h->row_offset += offset;
1034 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001035 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001036 break;
1037 }
1038 } else {
1039 if (-offset > h->nr_rows) {
1040 offset += h->nr_rows;
1041 h->row_offset = 0;
1042 } else {
1043 h->row_offset = h->nr_rows + offset;
1044 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001045 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001046 break;
1047 }
1048 }
1049 }
1050
Namhyung Kim14135662013-10-31 10:17:39 +09001051 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001052 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001053 if (nd == NULL)
1054 break;
1055 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001056 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001057 if (offset == 0) {
1058 /*
1059 * Last unfiltered hist_entry, check if it is
1060 * unfolded, if it is then we should have
1061 * row_offset at its last entry.
1062 */
1063 h = rb_entry(nd, struct hist_entry, rb_node);
1064 if (h->ms.unfolded)
1065 h->row_offset = h->nr_rows;
1066 break;
1067 }
1068 first = false;
1069 }
1070 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001071 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001072 h = rb_entry(nd, struct hist_entry, rb_node);
1073 h->row_offset = 0;
1074 }
1075}
1076
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001077static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
1078 struct callchain_node *chain_node,
1079 u64 total, int level,
1080 FILE *fp)
1081{
1082 struct rb_node *node;
1083 int offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +09001084 u64 new_total;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001085 int printed = 0;
1086
1087 if (callchain_param.mode == CHAIN_GRAPH_REL)
1088 new_total = chain_node->children_hit;
1089 else
1090 new_total = total;
1091
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001092 node = rb_first(&chain_node->rb_root);
1093 while (node) {
1094 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1095 struct rb_node *next = rb_next(node);
1096 u64 cumul = callchain_cumul_hits(child);
1097 struct callchain_list *chain;
1098 char folded_sign = ' ';
1099 int first = true;
1100 int extra_offset = 0;
1101
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001102 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001103 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001104 const char *str;
1105 bool was_first = first;
1106
1107 if (first)
1108 first = false;
1109 else
1110 extra_offset = LEVEL_OFFSET_STEP;
1111
1112 folded_sign = callchain_list__folded(chain);
1113
1114 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001115 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1116 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001117 if (was_first) {
1118 double percent = cumul * 100.0 / new_total;
1119
1120 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1121 str = "Not enough memory!";
1122 else
1123 str = alloc_str;
1124 }
1125
1126 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1127 free(alloc_str);
1128 if (folded_sign == '+')
1129 break;
1130 }
1131
1132 if (folded_sign == '-') {
1133 const int new_level = level + (extra_offset ? 2 : 1);
1134 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1135 new_level, fp);
1136 }
1137
1138 node = next;
1139 }
1140
1141 return printed;
1142}
1143
1144static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1145 struct callchain_node *node,
1146 int level, FILE *fp)
1147{
1148 struct callchain_list *chain;
1149 int offset = level * LEVEL_OFFSET_STEP;
1150 char folded_sign = ' ';
1151 int printed = 0;
1152
1153 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001154 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001155
1156 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001157 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001158 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1159 }
1160
1161 if (folded_sign == '-')
1162 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1163 browser->hists->stats.total_period,
1164 level + 1, fp);
1165 return printed;
1166}
1167
1168static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1169 struct rb_root *chain, int level, FILE *fp)
1170{
1171 struct rb_node *nd;
1172 int printed = 0;
1173
1174 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1175 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1176
1177 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1178 }
1179
1180 return printed;
1181}
1182
1183static int hist_browser__fprintf_entry(struct hist_browser *browser,
1184 struct hist_entry *he, FILE *fp)
1185{
1186 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001187 int printed = 0;
1188 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001189 struct perf_hpp hpp = {
1190 .buf = s,
1191 .size = sizeof(s),
1192 };
1193 struct perf_hpp_fmt *fmt;
1194 bool first = true;
1195 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001196
1197 if (symbol_conf.use_callchain)
1198 folded_sign = hist_entry__folded(he);
1199
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001200 if (symbol_conf.use_callchain)
1201 printed += fprintf(fp, "%c ", folded_sign);
1202
Namhyung Kim26d8b332014-03-03 16:16:20 +09001203 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001204 if (perf_hpp__should_skip(fmt))
1205 continue;
1206
Namhyung Kim26d8b332014-03-03 16:16:20 +09001207 if (!first) {
1208 ret = scnprintf(hpp.buf, hpp.size, " ");
1209 advance_hpp(&hpp, ret);
1210 } else
1211 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001212
Namhyung Kim26d8b332014-03-03 16:16:20 +09001213 ret = fmt->entry(fmt, &hpp, he);
1214 advance_hpp(&hpp, ret);
1215 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001216 printed += fprintf(fp, "%s\n", rtrim(s));
1217
1218 if (folded_sign == '-')
1219 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1220
1221 return printed;
1222}
1223
1224static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1225{
Namhyung Kim064f1982013-05-14 11:09:04 +09001226 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001227 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001228 int printed = 0;
1229
1230 while (nd) {
1231 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1232
1233 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001234 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001235 }
1236
1237 return printed;
1238}
1239
1240static int hist_browser__dump(struct hist_browser *browser)
1241{
1242 char filename[64];
1243 FILE *fp;
1244
1245 while (1) {
1246 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1247 if (access(filename, F_OK))
1248 break;
1249 /*
1250 * XXX: Just an arbitrary lazy upper limit
1251 */
1252 if (++browser->print_seq == 8192) {
1253 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1254 return -1;
1255 }
1256 }
1257
1258 fp = fopen(filename, "w");
1259 if (fp == NULL) {
1260 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001261 const char *err = strerror_r(errno, bf, sizeof(bf));
1262 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001263 return -1;
1264 }
1265
1266 ++browser->print_seq;
1267 hist_browser__fprintf(browser, fp);
1268 fclose(fp);
1269 ui_helpline__fpush("%s written!", filename);
1270
1271 return 0;
1272}
1273
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001274static struct hist_browser *hist_browser__new(struct hists *hists)
1275{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001276 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001277
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001278 if (browser) {
1279 browser->hists = hists;
1280 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001281 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001282 browser->b.seek = ui_browser__hists_seek;
1283 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001284 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001285 }
1286
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001287 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001288}
1289
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001290static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001291{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001292 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001293}
1294
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001295static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001296{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001297 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001298}
1299
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001300static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001301{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001302 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001303}
1304
Jiri Olsadd00d482014-06-19 13:41:13 +02001305static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001306{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001307 char unit;
1308 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001309 const struct dso *dso = hists->dso_filter;
1310 const struct thread *thread = hists->thread_filter;
1311 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1312 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001313 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001314 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001315 char buf[512];
1316 size_t buflen = sizeof(buf);
1317
Namhyung Kimf2148332014-01-14 11:52:48 +09001318 if (symbol_conf.filter_relative) {
1319 nr_samples = hists->stats.nr_non_filtered_samples;
1320 nr_events = hists->stats.total_non_filtered_period;
1321 }
1322
Namhyung Kim759ff492013-03-05 14:53:26 +09001323 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001324 struct perf_evsel *pos;
1325
1326 perf_evsel__group_desc(evsel, buf, buflen);
1327 ev_name = buf;
1328
1329 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001330 if (symbol_conf.filter_relative) {
1331 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1332 nr_events += pos->hists.stats.total_non_filtered_period;
1333 } else {
1334 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1335 nr_events += pos->hists.stats.total_period;
1336 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001337 }
1338 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001339
Ashay Ranecc686282012-04-05 21:01:01 -05001340 nr_samples = convert_unit(nr_samples, &unit);
1341 printed = scnprintf(bf, size,
1342 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1343 nr_samples, unit, ev_name, nr_events);
1344
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001345
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001346 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001347 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001348 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001349 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001350 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001351 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001352 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001353 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001354 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001355 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001356 ", DSO: %s", dso->short_name);
1357 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001358}
1359
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001360static inline void free_popup_options(char **options, int n)
1361{
1362 int i;
1363
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001364 for (i = 0; i < n; ++i)
1365 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001366}
1367
Feng Tangc77d8d72012-11-01 00:00:55 +08001368/* Check whether the browser is for 'top' or 'report' */
1369static inline bool is_report_browser(void *timer)
1370{
1371 return timer == NULL;
1372}
1373
Feng Tang341487ab2013-02-03 14:38:20 +08001374/*
1375 * Only runtime switching of perf data file will make "input_name" point
1376 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1377 * whether we need to call free() for current "input_name" during the switch.
1378 */
1379static bool is_input_name_malloced = false;
1380
1381static int switch_data_file(void)
1382{
1383 char *pwd, *options[32], *abs_path[32], *tmp;
1384 DIR *pwd_dir;
1385 int nr_options = 0, choice = -1, ret = -1;
1386 struct dirent *dent;
1387
1388 pwd = getenv("PWD");
1389 if (!pwd)
1390 return ret;
1391
1392 pwd_dir = opendir(pwd);
1393 if (!pwd_dir)
1394 return ret;
1395
1396 memset(options, 0, sizeof(options));
1397 memset(options, 0, sizeof(abs_path));
1398
1399 while ((dent = readdir(pwd_dir))) {
1400 char path[PATH_MAX];
1401 u64 magic;
1402 char *name = dent->d_name;
1403 FILE *file;
1404
1405 if (!(dent->d_type == DT_REG))
1406 continue;
1407
1408 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1409
1410 file = fopen(path, "r");
1411 if (!file)
1412 continue;
1413
1414 if (fread(&magic, 1, 8, file) < 8)
1415 goto close_file_and_continue;
1416
1417 if (is_perf_magic(magic)) {
1418 options[nr_options] = strdup(name);
1419 if (!options[nr_options])
1420 goto close_file_and_continue;
1421
1422 abs_path[nr_options] = strdup(path);
1423 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001424 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001425 ui__warning("Can't search all data files due to memory shortage.\n");
1426 fclose(file);
1427 break;
1428 }
1429
1430 nr_options++;
1431 }
1432
1433close_file_and_continue:
1434 fclose(file);
1435 if (nr_options >= 32) {
1436 ui__warning("Too many perf data files in PWD!\n"
1437 "Only the first 32 files will be listed.\n");
1438 break;
1439 }
1440 }
1441 closedir(pwd_dir);
1442
1443 if (nr_options) {
1444 choice = ui__popup_menu(nr_options, options);
1445 if (choice < nr_options && choice >= 0) {
1446 tmp = strdup(abs_path[choice]);
1447 if (tmp) {
1448 if (is_input_name_malloced)
1449 free((void *)input_name);
1450 input_name = tmp;
1451 is_input_name_malloced = true;
1452 ret = 0;
1453 } else
1454 ui__warning("Data switch failed due to memory shortage!\n");
1455 }
1456 }
1457
1458 free_popup_options(options, nr_options);
1459 free_popup_options(abs_path, nr_options);
1460 return ret;
1461}
1462
Namhyung Kim112f7612014-04-22 14:05:35 +09001463static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001464{
1465 u64 nr_entries = 0;
1466 struct rb_node *nd = rb_first(&hb->hists->entries);
1467
Namhyung Kim268397c2014-04-22 14:49:31 +09001468 if (hb->min_pcnt == 0) {
1469 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1470 return;
1471 }
1472
Namhyung Kim14135662013-10-31 10:17:39 +09001473 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001474 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001475 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001476 }
1477
Namhyung Kim112f7612014-04-22 14:05:35 +09001478 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001479}
Feng Tang341487ab2013-02-03 14:38:20 +08001480
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001481static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001482 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001483 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001484 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001485 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001486 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001487{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001488 struct hists *hists = &evsel->hists;
1489 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001490 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001491 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001492 char *options[16];
1493 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001494 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001495 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001496 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001497 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001498 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001499
Namhyung Kime8e684a2013-12-26 14:37:58 +09001500#define HIST_BROWSER_HELP_COMMON \
1501 "h/?/F1 Show this window\n" \
1502 "UP/DOWN/PGUP\n" \
1503 "PGDN/SPACE Navigate\n" \
1504 "q/ESC/CTRL+C Exit browser\n\n" \
1505 "For multiple event sessions:\n\n" \
1506 "TAB/UNTAB Switch events\n\n" \
1507 "For symbolic views (--sort has sym):\n\n" \
1508 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1509 "<- Zoom out\n" \
1510 "a Annotate current symbol\n" \
1511 "C Collapse all callchains\n" \
1512 "d Zoom into current DSO\n" \
1513 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001514 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001515 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001516
1517 /* help messages are sorted by lexical order of the hotkey */
1518 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001519 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001520 "P Print histograms to perf.hist.N\n"
1521 "r Run available scripts\n"
1522 "s Switch to another data file in PWD\n"
1523 "t Zoom into current Thread\n"
1524 "V Verbose (DSO names in callchains, etc)\n"
1525 "/ Filter symbol by name";
1526 const char top_help[] = HIST_BROWSER_HELP_COMMON
1527 "P Print histograms to perf.hist.N\n"
1528 "t Zoom into current Thread\n"
1529 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001530 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001531 "/ Filter symbol by name";
1532
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001533 if (browser == NULL)
1534 return -1;
1535
Namhyung Kim064f1982013-05-14 11:09:04 +09001536 if (min_pcnt) {
1537 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001538 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001539 }
1540
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001541 fstack = pstack__new(2);
1542 if (fstack == NULL)
1543 goto out;
1544
1545 ui_helpline__push(helpline);
1546
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001547 memset(options, 0, sizeof(options));
1548
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001549 perf_hpp__for_each_format(fmt)
1550 perf_hpp__reset_width(fmt, hists);
1551
Namhyung Kim5b591662014-07-31 14:47:38 +09001552 if (symbol_conf.col_width_list_str)
1553 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1554
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001555 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001556 const struct thread *thread = NULL;
1557 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001558 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001559 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001560 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001561 int scripts_comm = -2, scripts_symbol = -2,
1562 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001563
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001564 nr_options = 0;
1565
Jiri Olsadd00d482014-06-19 13:41:13 +02001566 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001567
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001568 if (browser->he_selection != NULL) {
1569 thread = hist_browser__selected_thread(browser);
1570 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1571 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001572 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001573 case K_TAB:
1574 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001575 if (nr_events == 1)
1576 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001577 /*
1578 * Exit the browser, let hists__browser_tree
1579 * go to the next or previous
1580 */
1581 goto out_free_stack;
1582 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001583 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001584 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001585 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001586 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001587 continue;
1588 }
1589
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001590 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001591 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001592 browser->selection->map->dso->annotate_warned)
1593 continue;
1594 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001595 case 'P':
1596 hist_browser__dump(browser);
1597 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001598 case 'd':
1599 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001600 case 'V':
1601 browser->show_dso = !browser->show_dso;
1602 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001603 case 't':
1604 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001605 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001606 if (ui_browser__input_window("Symbol to show",
1607 "Please enter the name of symbol you want to see",
1608 buf, "ENTER: OK, ESC: Cancel",
1609 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001610 hists->symbol_filter_str = *buf ? buf : NULL;
1611 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001612 hist_browser__reset(browser);
1613 }
1614 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001615 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001616 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001617 goto do_scripts;
1618 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001619 case 's':
1620 if (is_report_browser(hbt))
1621 goto do_data_switch;
1622 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001623 case 'i':
1624 /* env->arch is NULL for live-mode (i.e. perf top) */
1625 if (env->arch)
1626 tui__header_window(env);
1627 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001628 case 'F':
1629 symbol_conf.filter_relative ^= 1;
1630 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001631 case 'z':
1632 if (!is_report_browser(hbt)) {
1633 struct perf_top *top = hbt->arg;
1634
1635 top->zero = !top->zero;
1636 }
1637 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001638 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001639 case 'h':
1640 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001641 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001642 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001643 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001644 case K_ENTER:
1645 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001646 /* menu */
1647 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001648 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001649 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001650
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001651 if (pstack__empty(fstack)) {
1652 /*
1653 * Go back to the perf_evsel_menu__run or other user
1654 */
1655 if (left_exits)
1656 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001657 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001658 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001659 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001660 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001661 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001662 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001663 goto zoom_out_thread;
1664 continue;
1665 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001666 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001667 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001668 !ui_browser__dialog_yesno(&browser->b,
1669 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001670 continue;
1671 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001672 case 'q':
1673 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001674 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001675 default:
1676 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001677 }
1678
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001679 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001680 goto add_exit_option;
1681
Namhyung Kim55369fc2013-04-01 20:35:20 +09001682 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001683 bi = browser->he_selection->branch_info;
1684 if (browser->selection != NULL &&
1685 bi &&
1686 bi->from.sym != NULL &&
1687 !bi->from.map->dso->annotate_warned &&
1688 asprintf(&options[nr_options], "Annotate %s",
1689 bi->from.sym->name) > 0)
1690 annotate_f = nr_options++;
1691
1692 if (browser->selection != NULL &&
1693 bi &&
1694 bi->to.sym != NULL &&
1695 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001696 (bi->to.sym != bi->from.sym ||
1697 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001698 asprintf(&options[nr_options], "Annotate %s",
1699 bi->to.sym->name) > 0)
1700 annotate_t = nr_options++;
1701 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001702 if (browser->selection != NULL &&
1703 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001704 !browser->selection->map->dso->annotate_warned) {
1705 struct annotation *notes;
1706
1707 notes = symbol__annotation(browser->selection->sym);
1708
1709 if (notes->src &&
1710 asprintf(&options[nr_options], "Annotate %s",
1711 browser->selection->sym->name) > 0)
1712 annotate = nr_options++;
1713 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001714 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001715
1716 if (thread != NULL &&
1717 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001718 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001719 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001720 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001721 zoom_thread = nr_options++;
1722
1723 if (dso != NULL &&
1724 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001725 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001726 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1727 zoom_dso = nr_options++;
1728
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001729 if (browser->selection != NULL &&
1730 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001731 asprintf(&options[nr_options], "Browse map details") > 0)
1732 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001733
1734 /* perf script support */
1735 if (browser->he_selection) {
1736 struct symbol *sym;
1737
1738 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001739 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001740 scripts_comm = nr_options++;
1741
1742 sym = browser->he_selection->ms.sym;
1743 if (sym && sym->namelen &&
1744 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1745 sym->name) > 0)
1746 scripts_symbol = nr_options++;
1747 }
1748
1749 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1750 scripts_all = nr_options++;
1751
Feng Tang341487ab2013-02-03 14:38:20 +08001752 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1753 "Switch to another data file in PWD") > 0)
1754 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001755add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001756 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001757retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001758 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001759
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001760 if (choice == nr_options - 1)
1761 break;
1762
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001763 if (choice == -1) {
1764 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001765 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001766 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001767
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001768 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001770 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001771 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001772do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001773 if (!objdump_path && perf_session_env__lookup_objdump(env))
1774 continue;
1775
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001776 he = hist_browser__selected_entry(browser);
1777 if (he == NULL)
1778 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001779
1780 /*
1781 * we stash the branch_info symbol + map into the
1782 * the ms so we don't have to rewrite all the annotation
1783 * code to use branch_info.
1784 * in branch mode, the ms struct is not used
1785 */
1786 if (choice == annotate_f) {
1787 he->ms.sym = he->branch_info->from.sym;
1788 he->ms.map = he->branch_info->from.map;
1789 } else if (choice == annotate_t) {
1790 he->ms.sym = he->branch_info->to.sym;
1791 he->ms.map = he->branch_info->to.map;
1792 }
1793
Jiri Olsad7553302014-06-15 10:22:15 +02001794 notes = symbol__annotation(he->ms.sym);
1795 if (!notes->src)
1796 continue;
1797
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001798 /*
1799 * Don't let this be freed, say, by hists__decay_entry.
1800 */
1801 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001802 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001803 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001804 /*
1805 * offer option to annotate the other branch source or target
1806 * (if they exists) when returning from annotate
1807 */
1808 if ((err == 'q' || err == CTRL('c'))
1809 && annotate_t != -2 && annotate_f != -2)
1810 goto retry_popup_menu;
1811
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001812 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001813 if (err)
1814 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001815
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001816 } else if (choice == browse_map)
1817 map__browse(browser->selection->map);
1818 else if (choice == zoom_dso) {
1819zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001820 if (browser->hists->dso_filter) {
1821 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001822zoom_out_dso:
1823 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001824 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001825 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001826 } else {
1827 if (dso == NULL)
1828 continue;
1829 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1830 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001831 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001832 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001833 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001834 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001835 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001836 hist_browser__reset(browser);
1837 } else if (choice == zoom_thread) {
1838zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001839 if (browser->hists->thread_filter) {
1840 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001841zoom_out_thread:
1842 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001843 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001844 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001845 } else {
1846 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001847 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001848 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001849 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001850 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001851 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001852 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001853 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001854 hist_browser__reset(browser);
1855 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001856 /* perf scripts support */
1857 else if (choice == scripts_all || choice == scripts_comm ||
1858 choice == scripts_symbol) {
1859do_scripts:
1860 memset(script_opt, 0, 64);
1861
1862 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001863 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001864
1865 if (choice == scripts_symbol)
1866 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1867
1868 script_browse(script_opt);
1869 }
Feng Tang341487ab2013-02-03 14:38:20 +08001870 /* Switch to another data file */
1871 else if (choice == switch_data) {
1872do_data_switch:
1873 if (!switch_data_file()) {
1874 key = K_SWITCH_INPUT_DATA;
1875 break;
1876 } else
1877 ui__warning("Won't switch the data files due to\n"
1878 "no valid data file get selected!\n");
1879 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001880 }
1881out_free_stack:
1882 pstack__delete(fstack);
1883out:
1884 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001885 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001886 return key;
1887}
1888
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001889struct perf_evsel_menu {
1890 struct ui_browser b;
1891 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001892 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001893 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001894 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001895};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001896
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001897static void perf_evsel_menu__write(struct ui_browser *browser,
1898 void *entry, int row)
1899{
1900 struct perf_evsel_menu *menu = container_of(browser,
1901 struct perf_evsel_menu, b);
1902 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1903 bool current_entry = ui_browser__is_current_entry(browser, row);
1904 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001905 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001906 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001907 const char *warn = " ";
1908 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001909
1910 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1911 HE_COLORSET_NORMAL);
1912
Namhyung Kim759ff492013-03-05 14:53:26 +09001913 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001914 struct perf_evsel *pos;
1915
1916 ev_name = perf_evsel__group_name(evsel);
1917
1918 for_each_group_member(pos, evsel) {
1919 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1920 }
1921 }
1922
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001923 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001924 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001925 unit, unit == ' ' ? "" : " ", ev_name);
1926 slsmg_printf("%s", bf);
1927
1928 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1929 if (nr_events != 0) {
1930 menu->lost_events = true;
1931 if (!current_entry)
1932 ui_browser__set_color(browser, HE_COLORSET_TOP);
1933 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001934 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1935 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001936 warn = bf;
1937 }
1938
1939 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001940
1941 if (current_entry)
1942 menu->selection = evsel;
1943}
1944
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001945static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1946 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001947 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001948{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001949 struct perf_evlist *evlist = menu->b.priv;
1950 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001951 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001952 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001953 int key;
1954
1955 if (ui_browser__show(&menu->b, title,
1956 "ESC: exit, ENTER|->: Browse histograms") < 0)
1957 return -1;
1958
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001959 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001960 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001961
1962 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001963 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001964 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001965
1966 if (!menu->lost_events_warned && menu->lost_events) {
1967 ui_browser__warn_lost_events(&menu->b);
1968 menu->lost_events_warned = true;
1969 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001970 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001971 case K_RIGHT:
1972 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001973 if (!menu->selection)
1974 continue;
1975 pos = menu->selection;
1976browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001977 perf_evlist__set_selected(evlist, pos);
1978 /*
1979 * Give the calling tool a chance to populate the non
1980 * default evsel resorted hists tree.
1981 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001982 if (hbt)
1983 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001984 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001985 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001986 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001987 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001988 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001989 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001990 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001991 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001992 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001993 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001994 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001995 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001996 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001997 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001998 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001999 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002000 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002001 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002002 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002003 if (!ui_browser__dialog_yesno(&menu->b,
2004 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002005 continue;
2006 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08002007 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002008 case 'q':
2009 case CTRL('c'):
2010 goto out;
2011 default:
2012 continue;
2013 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002014 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002015 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002016 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002017 if (!ui_browser__dialog_yesno(&menu->b,
2018 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002019 continue;
2020 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002021 case 'q':
2022 case CTRL('c'):
2023 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002024 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002025 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002026 }
2027 }
2028
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002029out:
2030 ui_browser__hide(&menu->b);
2031 return key;
2032}
2033
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002034static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002035 void *entry)
2036{
2037 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2038
2039 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2040 return true;
2041
2042 return false;
2043}
2044
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002045static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002046 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002047 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002048 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002049 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002050{
2051 struct perf_evsel *pos;
2052 struct perf_evsel_menu menu = {
2053 .b = {
2054 .entries = &evlist->entries,
2055 .refresh = ui_browser__list_head_refresh,
2056 .seek = ui_browser__list_head_seek,
2057 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002058 .filter = filter_group_entries,
2059 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002060 .priv = evlist,
2061 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002062 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002063 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002064 };
2065
2066 ui_helpline__push("Press ESC to exit");
2067
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002068 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002069 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002070 size_t line_len = strlen(ev_name) + 7;
2071
2072 if (menu.b.width < line_len)
2073 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002074 }
2075
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002076 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002077}
2078
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002079int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002080 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002081 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002082 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002083{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002084 int nr_entries = evlist->nr_entries;
2085
2086single_entry:
2087 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002088 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002089
2090 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002091 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002092 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002093 }
2094
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002095 if (symbol_conf.event_group) {
2096 struct perf_evsel *pos;
2097
2098 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002099 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002100 if (perf_evsel__is_group_leader(pos))
2101 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002102 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002103
2104 if (nr_entries == 1)
2105 goto single_entry;
2106 }
2107
2108 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002109 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002110}