blob: 4892480e8298d880692ceb2f42f431cb25e652f5 [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;
491 u64 new_total, remaining;
492
493 if (callchain_param.mode == CHAIN_GRAPH_REL)
494 new_total = chain_node->children_hit;
495 else
496 new_total = total;
497
498 remaining = new_total;
499 node = rb_first(&chain_node->rb_root);
500 while (node) {
501 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
502 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100503 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300504 struct callchain_list *chain;
505 char folded_sign = ' ';
506 int first = true;
507 int extra_offset = 0;
508
509 remaining -= cumul;
510
511 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300512 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300513 const char *str;
514 int color;
515 bool was_first = first;
516
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300517 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300518 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300519 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300520 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300521
522 folded_sign = callchain_list__folded(chain);
523 if (*row_offset != 0) {
524 --*row_offset;
525 goto do_next;
526 }
527
528 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300529 str = callchain_list__sym_name(chain, bf, sizeof(bf),
530 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300531 if (was_first) {
532 double percent = cumul * 100.0 / new_total;
533
534 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
535 str = "Not enough memory!";
536 else
537 str = alloc_str;
538 }
539
540 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300541 width = browser->b.width - (offset + extra_offset + 2);
542 if (ui_browser__is_current_entry(&browser->b, row)) {
543 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300544 color = HE_COLORSET_SELECTED;
545 *is_current_entry = true;
546 }
547
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300548 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300549 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300550 slsmg_write_nstring(" ", offset + extra_offset);
551 slsmg_printf("%c ", folded_sign);
552 slsmg_write_nstring(str, width);
553 free(alloc_str);
554
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300555 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300556 goto out;
557do_next:
558 if (folded_sign == '+')
559 break;
560 }
561
562 if (folded_sign == '-') {
563 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300564 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300565 new_level, row, row_offset,
566 is_current_entry);
567 }
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300568 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300569 goto out;
570 node = next;
571 }
572out:
573 return row - first_row;
574}
575
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300576static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300577 struct callchain_node *node,
578 int level, unsigned short row,
579 off_t *row_offset,
580 bool *is_current_entry)
581{
582 struct callchain_list *chain;
583 int first_row = row,
584 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300585 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300586 char folded_sign = ' ';
587
588 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300589 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300591
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592 folded_sign = callchain_list__folded(chain);
593
594 if (*row_offset != 0) {
595 --*row_offset;
596 continue;
597 }
598
599 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300600 if (ui_browser__is_current_entry(&browser->b, row)) {
601 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300602 color = HE_COLORSET_SELECTED;
603 *is_current_entry = true;
604 }
605
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300606 s = callchain_list__sym_name(chain, bf, sizeof(bf),
607 browser->show_dso);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300608 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300609 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300610 slsmg_write_nstring(" ", offset);
611 slsmg_printf("%c ", folded_sign);
612 slsmg_write_nstring(s, width - 2);
613
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300614 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300615 goto out;
616 }
617
618 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300619 row += hist_browser__show_callchain_node_rb_tree(browser, node,
620 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300621 level + 1, row,
622 row_offset,
623 is_current_entry);
624out:
625 return row - first_row;
626}
627
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300628static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300629 struct rb_root *chain,
630 int level, unsigned short row,
631 off_t *row_offset,
632 bool *is_current_entry)
633{
634 struct rb_node *nd;
635 int first_row = row;
636
637 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
638 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
639
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300640 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300641 row, row_offset,
642 is_current_entry);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300643 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300644 break;
645 }
646
647 return row - first_row;
648}
649
Namhyung Kim89701462013-01-22 18:09:38 +0900650struct hpp_arg {
651 struct ui_browser *b;
652 char folded_sign;
653 bool current_entry;
654};
655
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900656static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
657{
658 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900659 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900660 va_list args;
661 double percent;
662
663 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900664 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900665 percent = va_arg(args, double);
666 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900667
Namhyung Kim89701462013-01-22 18:09:38 +0900668 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900669
Namhyung Kimd6751072014-07-31 14:47:36 +0900670 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900671 slsmg_printf("%s", hpp->buf);
672
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900673 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900674 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900675}
676
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900677#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900678static u64 __hpp_get_##_field(struct hist_entry *he) \
679{ \
680 return he->stat._field; \
681} \
682 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100683static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900684hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100685 struct perf_hpp *hpp, \
686 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900687{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900688 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
689 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900690}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900691
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900692#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
693static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
694{ \
695 return he->stat_acc->_field; \
696} \
697 \
698static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900699hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900700 struct perf_hpp *hpp, \
701 struct hist_entry *he) \
702{ \
703 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900704 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900705 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900706 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900707 slsmg_printf("%s", hpp->buf); \
708 \
709 return ret; \
710 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900711 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
712 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900713}
714
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900715__HPP_COLOR_PERCENT_FN(overhead, period)
716__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
717__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
718__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
719__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900720__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900721
722#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900723#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900724
725void hist_browser__init_hpp(void)
726{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900727 perf_hpp__format[PERF_HPP__OVERHEAD].color =
728 hist_browser__hpp_color_overhead;
729 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
730 hist_browser__hpp_color_overhead_sys;
731 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
732 hist_browser__hpp_color_overhead_us;
733 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
734 hist_browser__hpp_color_overhead_guest_sys;
735 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
736 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900737 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
738 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900739}
740
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300741static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300742 struct hist_entry *entry,
743 unsigned short row)
744{
745 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200746 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900747 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300748 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300749 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300750 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300751 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200752 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300753
754 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300755 browser->he_selection = entry;
756 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300757 }
758
759 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300760 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300761 folded_sign = hist_entry__folded(entry);
762 }
763
764 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900765 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900766 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900767 .folded_sign = folded_sign,
768 .current_entry = current_entry,
769 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900770 struct perf_hpp hpp = {
771 .buf = s,
772 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900773 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900774 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300775
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300776 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900777
Jiri Olsa12400052012-10-13 00:06:16 +0200778 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900779 if (perf_hpp__should_skip(fmt))
780 continue;
781
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900782 if (current_entry && browser->b.navkeypressed) {
783 ui_browser__set_color(&browser->b,
784 HE_COLORSET_SELECTED);
785 } else {
786 ui_browser__set_color(&browser->b,
787 HE_COLORSET_NORMAL);
788 }
789
790 if (first) {
791 if (symbol_conf.use_callchain) {
792 slsmg_printf("%c ", folded_sign);
793 width -= 2;
794 }
795 first = false;
796 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900797 slsmg_printf(" ");
798 width -= 2;
799 }
800
Jiri Olsa12400052012-10-13 00:06:16 +0200801 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100802 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900803 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100804 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900805 slsmg_printf("%s", s);
806 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300807 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200808
809 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300810 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200811 width += 1;
812
Namhyung Kim26d8b332014-03-03 16:16:20 +0900813 slsmg_write_nstring("", width);
814
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300815 ++row;
816 ++printed;
817 } else
818 --row_offset;
819
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300820 if (folded_sign == '-' && row != browser->b.rows) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300821 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300822 1, row, &row_offset,
823 &current_entry);
824 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300825 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300826 }
827
828 return printed;
829}
830
Jiri Olsa81a888f2014-06-14 15:44:52 +0200831static int advance_hpp_check(struct perf_hpp *hpp, int inc)
832{
833 advance_hpp(hpp, inc);
834 return hpp->size <= 0;
835}
836
837static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
838{
839 struct perf_hpp dummy_hpp = {
840 .buf = buf,
841 .size = size,
842 };
843 struct perf_hpp_fmt *fmt;
844 size_t ret = 0;
845
846 if (symbol_conf.use_callchain) {
847 ret = scnprintf(buf, size, " ");
848 if (advance_hpp_check(&dummy_hpp, ret))
849 return ret;
850 }
851
852 perf_hpp__for_each_format(fmt) {
853 if (perf_hpp__should_skip(fmt))
854 continue;
855
Jiri Olsa81a888f2014-06-14 15:44:52 +0200856 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
857 if (advance_hpp_check(&dummy_hpp, ret))
858 break;
859
860 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
861 if (advance_hpp_check(&dummy_hpp, ret))
862 break;
863 }
864
865 return ret;
866}
867
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200868static void hist_browser__show_headers(struct hist_browser *browser)
869{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200870 char headers[1024];
871
872 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200873 ui_browser__gotorc(&browser->b, 0, 0);
874 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200875 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200876}
877
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300878static void ui_browser__hists_init_top(struct ui_browser *browser)
879{
880 if (browser->top == NULL) {
881 struct hist_browser *hb;
882
883 hb = container_of(browser, struct hist_browser, b);
884 browser->top = rb_first(&hb->hists->entries);
885 }
886}
887
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300888static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300889{
890 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200891 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300892 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300893 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300894
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200895 if (hb->show_headers) {
896 hist_browser__show_headers(hb);
897 header_offset = 1;
898 }
899
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300900 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300901
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300902 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300903 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900904 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300905
906 if (h->filtered)
907 continue;
908
Namhyung Kim14135662013-10-31 10:17:39 +0900909 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900910 if (percent < hb->min_pcnt)
911 continue;
912
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300913 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300914 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300915 break;
916 }
917
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200918 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300919}
920
Namhyung Kim064f1982013-05-14 11:09:04 +0900921static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900922 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300923{
924 while (nd != NULL) {
925 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900926 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900927
Namhyung Kimc0f15272014-04-16 11:16:33 +0900928 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300929 return nd;
930
931 nd = rb_next(nd);
932 }
933
934 return NULL;
935}
936
Namhyung Kim064f1982013-05-14 11:09:04 +0900937static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900938 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300939{
940 while (nd != NULL) {
941 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900942 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900943
944 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300945 return nd;
946
947 nd = rb_prev(nd);
948 }
949
950 return NULL;
951}
952
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300953static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300954 off_t offset, int whence)
955{
956 struct hist_entry *h;
957 struct rb_node *nd;
958 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900959 struct hist_browser *hb;
960
961 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300962
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300963 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300964 return;
965
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300966 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300967
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300968 switch (whence) {
969 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900970 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900971 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300972 break;
973 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300974 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300975 goto do_offset;
976 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900977 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900978 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300979 first = false;
980 break;
981 default:
982 return;
983 }
984
985 /*
986 * Moves not relative to the first visible entry invalidates its
987 * row_offset:
988 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300989 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300990 h->row_offset = 0;
991
992 /*
993 * Here we have to check if nd is expanded (+), if it is we can't go
994 * the next top level hist_entry, instead we must compute an offset of
995 * what _not_ to show and not change the first visible entry.
996 *
997 * This offset increments when we are going from top to bottom and
998 * decreases when we're going from bottom to top.
999 *
1000 * As we don't have backpointers to the top level in the callchains
1001 * structure, we need to always print the whole hist_entry callchain,
1002 * skipping the first ones that are before the first visible entry
1003 * and stop when we printed enough lines to fill the screen.
1004 */
1005do_offset:
1006 if (offset > 0) {
1007 do {
1008 h = rb_entry(nd, struct hist_entry, rb_node);
1009 if (h->ms.unfolded) {
1010 u16 remaining = h->nr_rows - h->row_offset;
1011 if (offset > remaining) {
1012 offset -= remaining;
1013 h->row_offset = 0;
1014 } else {
1015 h->row_offset += offset;
1016 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001017 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001018 break;
1019 }
1020 }
Namhyung Kim14135662013-10-31 10:17:39 +09001021 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001022 if (nd == NULL)
1023 break;
1024 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001025 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001026 } while (offset != 0);
1027 } else if (offset < 0) {
1028 while (1) {
1029 h = rb_entry(nd, struct hist_entry, rb_node);
1030 if (h->ms.unfolded) {
1031 if (first) {
1032 if (-offset > h->row_offset) {
1033 offset += h->row_offset;
1034 h->row_offset = 0;
1035 } else {
1036 h->row_offset += offset;
1037 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001038 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001039 break;
1040 }
1041 } else {
1042 if (-offset > h->nr_rows) {
1043 offset += h->nr_rows;
1044 h->row_offset = 0;
1045 } else {
1046 h->row_offset = h->nr_rows + offset;
1047 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001048 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001049 break;
1050 }
1051 }
1052 }
1053
Namhyung Kim14135662013-10-31 10:17:39 +09001054 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001055 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001056 if (nd == NULL)
1057 break;
1058 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001059 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001060 if (offset == 0) {
1061 /*
1062 * Last unfiltered hist_entry, check if it is
1063 * unfolded, if it is then we should have
1064 * row_offset at its last entry.
1065 */
1066 h = rb_entry(nd, struct hist_entry, rb_node);
1067 if (h->ms.unfolded)
1068 h->row_offset = h->nr_rows;
1069 break;
1070 }
1071 first = false;
1072 }
1073 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001074 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001075 h = rb_entry(nd, struct hist_entry, rb_node);
1076 h->row_offset = 0;
1077 }
1078}
1079
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001080static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
1081 struct callchain_node *chain_node,
1082 u64 total, int level,
1083 FILE *fp)
1084{
1085 struct rb_node *node;
1086 int offset = level * LEVEL_OFFSET_STEP;
1087 u64 new_total, remaining;
1088 int printed = 0;
1089
1090 if (callchain_param.mode == CHAIN_GRAPH_REL)
1091 new_total = chain_node->children_hit;
1092 else
1093 new_total = total;
1094
1095 remaining = new_total;
1096 node = rb_first(&chain_node->rb_root);
1097 while (node) {
1098 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1099 struct rb_node *next = rb_next(node);
1100 u64 cumul = callchain_cumul_hits(child);
1101 struct callchain_list *chain;
1102 char folded_sign = ' ';
1103 int first = true;
1104 int extra_offset = 0;
1105
1106 remaining -= cumul;
1107
1108 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001109 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001110 const char *str;
1111 bool was_first = first;
1112
1113 if (first)
1114 first = false;
1115 else
1116 extra_offset = LEVEL_OFFSET_STEP;
1117
1118 folded_sign = callchain_list__folded(chain);
1119
1120 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001121 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1122 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001123 if (was_first) {
1124 double percent = cumul * 100.0 / new_total;
1125
1126 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1127 str = "Not enough memory!";
1128 else
1129 str = alloc_str;
1130 }
1131
1132 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1133 free(alloc_str);
1134 if (folded_sign == '+')
1135 break;
1136 }
1137
1138 if (folded_sign == '-') {
1139 const int new_level = level + (extra_offset ? 2 : 1);
1140 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1141 new_level, fp);
1142 }
1143
1144 node = next;
1145 }
1146
1147 return printed;
1148}
1149
1150static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1151 struct callchain_node *node,
1152 int level, FILE *fp)
1153{
1154 struct callchain_list *chain;
1155 int offset = level * LEVEL_OFFSET_STEP;
1156 char folded_sign = ' ';
1157 int printed = 0;
1158
1159 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001160 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001161
1162 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001163 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001164 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1165 }
1166
1167 if (folded_sign == '-')
1168 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1169 browser->hists->stats.total_period,
1170 level + 1, fp);
1171 return printed;
1172}
1173
1174static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1175 struct rb_root *chain, int level, FILE *fp)
1176{
1177 struct rb_node *nd;
1178 int printed = 0;
1179
1180 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1181 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1182
1183 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1184 }
1185
1186 return printed;
1187}
1188
1189static int hist_browser__fprintf_entry(struct hist_browser *browser,
1190 struct hist_entry *he, FILE *fp)
1191{
1192 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001193 int printed = 0;
1194 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001195 struct perf_hpp hpp = {
1196 .buf = s,
1197 .size = sizeof(s),
1198 };
1199 struct perf_hpp_fmt *fmt;
1200 bool first = true;
1201 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001202
1203 if (symbol_conf.use_callchain)
1204 folded_sign = hist_entry__folded(he);
1205
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001206 if (symbol_conf.use_callchain)
1207 printed += fprintf(fp, "%c ", folded_sign);
1208
Namhyung Kim26d8b332014-03-03 16:16:20 +09001209 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001210 if (perf_hpp__should_skip(fmt))
1211 continue;
1212
Namhyung Kim26d8b332014-03-03 16:16:20 +09001213 if (!first) {
1214 ret = scnprintf(hpp.buf, hpp.size, " ");
1215 advance_hpp(&hpp, ret);
1216 } else
1217 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001218
Namhyung Kim26d8b332014-03-03 16:16:20 +09001219 ret = fmt->entry(fmt, &hpp, he);
1220 advance_hpp(&hpp, ret);
1221 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001222 printed += fprintf(fp, "%s\n", rtrim(s));
1223
1224 if (folded_sign == '-')
1225 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1226
1227 return printed;
1228}
1229
1230static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1231{
Namhyung Kim064f1982013-05-14 11:09:04 +09001232 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001233 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001234 int printed = 0;
1235
1236 while (nd) {
1237 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1238
1239 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001240 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001241 }
1242
1243 return printed;
1244}
1245
1246static int hist_browser__dump(struct hist_browser *browser)
1247{
1248 char filename[64];
1249 FILE *fp;
1250
1251 while (1) {
1252 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1253 if (access(filename, F_OK))
1254 break;
1255 /*
1256 * XXX: Just an arbitrary lazy upper limit
1257 */
1258 if (++browser->print_seq == 8192) {
1259 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1260 return -1;
1261 }
1262 }
1263
1264 fp = fopen(filename, "w");
1265 if (fp == NULL) {
1266 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001267 const char *err = strerror_r(errno, bf, sizeof(bf));
1268 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001269 return -1;
1270 }
1271
1272 ++browser->print_seq;
1273 hist_browser__fprintf(browser, fp);
1274 fclose(fp);
1275 ui_helpline__fpush("%s written!", filename);
1276
1277 return 0;
1278}
1279
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001280static struct hist_browser *hist_browser__new(struct hists *hists)
1281{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001282 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001283
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001284 if (browser) {
1285 browser->hists = hists;
1286 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001287 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001288 browser->b.seek = ui_browser__hists_seek;
1289 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001290 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001291 }
1292
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001293 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001294}
1295
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001296static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001297{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001298 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001299}
1300
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001301static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001302{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001303 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001304}
1305
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001306static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001307{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001308 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001309}
1310
Jiri Olsadd00d482014-06-19 13:41:13 +02001311static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001312{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001313 char unit;
1314 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001315 const struct dso *dso = hists->dso_filter;
1316 const struct thread *thread = hists->thread_filter;
1317 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1318 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001319 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001320 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001321 char buf[512];
1322 size_t buflen = sizeof(buf);
1323
Namhyung Kimf2148332014-01-14 11:52:48 +09001324 if (symbol_conf.filter_relative) {
1325 nr_samples = hists->stats.nr_non_filtered_samples;
1326 nr_events = hists->stats.total_non_filtered_period;
1327 }
1328
Namhyung Kim759ff492013-03-05 14:53:26 +09001329 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001330 struct perf_evsel *pos;
1331
1332 perf_evsel__group_desc(evsel, buf, buflen);
1333 ev_name = buf;
1334
1335 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001336 if (symbol_conf.filter_relative) {
1337 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1338 nr_events += pos->hists.stats.total_non_filtered_period;
1339 } else {
1340 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1341 nr_events += pos->hists.stats.total_period;
1342 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001343 }
1344 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001345
Ashay Ranecc6862802012-04-05 21:01:01 -05001346 nr_samples = convert_unit(nr_samples, &unit);
1347 printed = scnprintf(bf, size,
1348 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1349 nr_samples, unit, ev_name, nr_events);
1350
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001351
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001352 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001353 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001354 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001355 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001356 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001357 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001358 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001359 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001360 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001361 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001362 ", DSO: %s", dso->short_name);
1363 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001364}
1365
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001366static inline void free_popup_options(char **options, int n)
1367{
1368 int i;
1369
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001370 for (i = 0; i < n; ++i)
1371 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001372}
1373
Feng Tangc77d8d72012-11-01 00:00:55 +08001374/* Check whether the browser is for 'top' or 'report' */
1375static inline bool is_report_browser(void *timer)
1376{
1377 return timer == NULL;
1378}
1379
Feng Tang341487ab2013-02-03 14:38:20 +08001380/*
1381 * Only runtime switching of perf data file will make "input_name" point
1382 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1383 * whether we need to call free() for current "input_name" during the switch.
1384 */
1385static bool is_input_name_malloced = false;
1386
1387static int switch_data_file(void)
1388{
1389 char *pwd, *options[32], *abs_path[32], *tmp;
1390 DIR *pwd_dir;
1391 int nr_options = 0, choice = -1, ret = -1;
1392 struct dirent *dent;
1393
1394 pwd = getenv("PWD");
1395 if (!pwd)
1396 return ret;
1397
1398 pwd_dir = opendir(pwd);
1399 if (!pwd_dir)
1400 return ret;
1401
1402 memset(options, 0, sizeof(options));
1403 memset(options, 0, sizeof(abs_path));
1404
1405 while ((dent = readdir(pwd_dir))) {
1406 char path[PATH_MAX];
1407 u64 magic;
1408 char *name = dent->d_name;
1409 FILE *file;
1410
1411 if (!(dent->d_type == DT_REG))
1412 continue;
1413
1414 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1415
1416 file = fopen(path, "r");
1417 if (!file)
1418 continue;
1419
1420 if (fread(&magic, 1, 8, file) < 8)
1421 goto close_file_and_continue;
1422
1423 if (is_perf_magic(magic)) {
1424 options[nr_options] = strdup(name);
1425 if (!options[nr_options])
1426 goto close_file_and_continue;
1427
1428 abs_path[nr_options] = strdup(path);
1429 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001430 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001431 ui__warning("Can't search all data files due to memory shortage.\n");
1432 fclose(file);
1433 break;
1434 }
1435
1436 nr_options++;
1437 }
1438
1439close_file_and_continue:
1440 fclose(file);
1441 if (nr_options >= 32) {
1442 ui__warning("Too many perf data files in PWD!\n"
1443 "Only the first 32 files will be listed.\n");
1444 break;
1445 }
1446 }
1447 closedir(pwd_dir);
1448
1449 if (nr_options) {
1450 choice = ui__popup_menu(nr_options, options);
1451 if (choice < nr_options && choice >= 0) {
1452 tmp = strdup(abs_path[choice]);
1453 if (tmp) {
1454 if (is_input_name_malloced)
1455 free((void *)input_name);
1456 input_name = tmp;
1457 is_input_name_malloced = true;
1458 ret = 0;
1459 } else
1460 ui__warning("Data switch failed due to memory shortage!\n");
1461 }
1462 }
1463
1464 free_popup_options(options, nr_options);
1465 free_popup_options(abs_path, nr_options);
1466 return ret;
1467}
1468
Namhyung Kim112f7612014-04-22 14:05:35 +09001469static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001470{
1471 u64 nr_entries = 0;
1472 struct rb_node *nd = rb_first(&hb->hists->entries);
1473
Namhyung Kim268397c2014-04-22 14:49:31 +09001474 if (hb->min_pcnt == 0) {
1475 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1476 return;
1477 }
1478
Namhyung Kim14135662013-10-31 10:17:39 +09001479 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001480 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001481 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001482 }
1483
Namhyung Kim112f7612014-04-22 14:05:35 +09001484 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001485}
Feng Tang341487ab2013-02-03 14:38:20 +08001486
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001487static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001488 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001489 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001490 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001491 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001492 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001493{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001494 struct hists *hists = &evsel->hists;
1495 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001496 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001497 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001498 char *options[16];
1499 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001500 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001501 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001502 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001503 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001504 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001505
Namhyung Kime8e684a2013-12-26 14:37:58 +09001506#define HIST_BROWSER_HELP_COMMON \
1507 "h/?/F1 Show this window\n" \
1508 "UP/DOWN/PGUP\n" \
1509 "PGDN/SPACE Navigate\n" \
1510 "q/ESC/CTRL+C Exit browser\n\n" \
1511 "For multiple event sessions:\n\n" \
1512 "TAB/UNTAB Switch events\n\n" \
1513 "For symbolic views (--sort has sym):\n\n" \
1514 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1515 "<- Zoom out\n" \
1516 "a Annotate current symbol\n" \
1517 "C Collapse all callchains\n" \
1518 "d Zoom into current DSO\n" \
1519 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001520 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001521 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001522
1523 /* help messages are sorted by lexical order of the hotkey */
1524 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001525 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001526 "P Print histograms to perf.hist.N\n"
1527 "r Run available scripts\n"
1528 "s Switch to another data file in PWD\n"
1529 "t Zoom into current Thread\n"
1530 "V Verbose (DSO names in callchains, etc)\n"
1531 "/ Filter symbol by name";
1532 const char top_help[] = HIST_BROWSER_HELP_COMMON
1533 "P Print histograms to perf.hist.N\n"
1534 "t Zoom into current Thread\n"
1535 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001536 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001537 "/ Filter symbol by name";
1538
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001539 if (browser == NULL)
1540 return -1;
1541
Namhyung Kim064f1982013-05-14 11:09:04 +09001542 if (min_pcnt) {
1543 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001544 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001545 }
1546
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001547 fstack = pstack__new(2);
1548 if (fstack == NULL)
1549 goto out;
1550
1551 ui_helpline__push(helpline);
1552
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001553 memset(options, 0, sizeof(options));
1554
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001555 perf_hpp__for_each_format(fmt)
1556 perf_hpp__reset_width(fmt, hists);
1557
Namhyung Kim5b591662014-07-31 14:47:38 +09001558 if (symbol_conf.col_width_list_str)
1559 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1560
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001561 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001562 const struct thread *thread = NULL;
1563 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001564 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001565 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001566 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001567 int scripts_comm = -2, scripts_symbol = -2,
1568 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001569
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001570 nr_options = 0;
1571
Jiri Olsadd00d482014-06-19 13:41:13 +02001572 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001573
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001574 if (browser->he_selection != NULL) {
1575 thread = hist_browser__selected_thread(browser);
1576 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1577 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001578 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001579 case K_TAB:
1580 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001581 if (nr_events == 1)
1582 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001583 /*
1584 * Exit the browser, let hists__browser_tree
1585 * go to the next or previous
1586 */
1587 goto out_free_stack;
1588 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001589 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001590 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001591 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001592 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001593 continue;
1594 }
1595
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001596 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001597 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001598 browser->selection->map->dso->annotate_warned)
1599 continue;
1600 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001601 case 'P':
1602 hist_browser__dump(browser);
1603 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001604 case 'd':
1605 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001606 case 'V':
1607 browser->show_dso = !browser->show_dso;
1608 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001609 case 't':
1610 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001611 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001612 if (ui_browser__input_window("Symbol to show",
1613 "Please enter the name of symbol you want to see",
1614 buf, "ENTER: OK, ESC: Cancel",
1615 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001616 hists->symbol_filter_str = *buf ? buf : NULL;
1617 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001618 hist_browser__reset(browser);
1619 }
1620 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001621 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001622 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001623 goto do_scripts;
1624 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001625 case 's':
1626 if (is_report_browser(hbt))
1627 goto do_data_switch;
1628 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001629 case 'i':
1630 /* env->arch is NULL for live-mode (i.e. perf top) */
1631 if (env->arch)
1632 tui__header_window(env);
1633 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001634 case 'F':
1635 symbol_conf.filter_relative ^= 1;
1636 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001637 case 'z':
1638 if (!is_report_browser(hbt)) {
1639 struct perf_top *top = hbt->arg;
1640
1641 top->zero = !top->zero;
1642 }
1643 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001644 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001645 case 'h':
1646 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001647 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001648 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001649 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001650 case K_ENTER:
1651 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001652 /* menu */
1653 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001654 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001655 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001656
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001657 if (pstack__empty(fstack)) {
1658 /*
1659 * Go back to the perf_evsel_menu__run or other user
1660 */
1661 if (left_exits)
1662 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001663 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001664 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001665 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001666 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001667 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001668 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001669 goto zoom_out_thread;
1670 continue;
1671 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001672 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001673 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001674 !ui_browser__dialog_yesno(&browser->b,
1675 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001676 continue;
1677 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001678 case 'q':
1679 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001680 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001681 default:
1682 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001683 }
1684
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001685 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001686 goto add_exit_option;
1687
Namhyung Kim55369fc2013-04-01 20:35:20 +09001688 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001689 bi = browser->he_selection->branch_info;
1690 if (browser->selection != NULL &&
1691 bi &&
1692 bi->from.sym != NULL &&
1693 !bi->from.map->dso->annotate_warned &&
1694 asprintf(&options[nr_options], "Annotate %s",
1695 bi->from.sym->name) > 0)
1696 annotate_f = nr_options++;
1697
1698 if (browser->selection != NULL &&
1699 bi &&
1700 bi->to.sym != NULL &&
1701 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001702 (bi->to.sym != bi->from.sym ||
1703 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001704 asprintf(&options[nr_options], "Annotate %s",
1705 bi->to.sym->name) > 0)
1706 annotate_t = nr_options++;
1707 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001708 if (browser->selection != NULL &&
1709 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001710 !browser->selection->map->dso->annotate_warned) {
1711 struct annotation *notes;
1712
1713 notes = symbol__annotation(browser->selection->sym);
1714
1715 if (notes->src &&
1716 asprintf(&options[nr_options], "Annotate %s",
1717 browser->selection->sym->name) > 0)
1718 annotate = nr_options++;
1719 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001720 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001721
1722 if (thread != NULL &&
1723 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001724 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001725 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001726 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001727 zoom_thread = nr_options++;
1728
1729 if (dso != NULL &&
1730 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001731 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001732 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1733 zoom_dso = nr_options++;
1734
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001735 if (browser->selection != NULL &&
1736 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001737 asprintf(&options[nr_options], "Browse map details") > 0)
1738 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001739
1740 /* perf script support */
1741 if (browser->he_selection) {
1742 struct symbol *sym;
1743
1744 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001745 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001746 scripts_comm = nr_options++;
1747
1748 sym = browser->he_selection->ms.sym;
1749 if (sym && sym->namelen &&
1750 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1751 sym->name) > 0)
1752 scripts_symbol = nr_options++;
1753 }
1754
1755 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1756 scripts_all = nr_options++;
1757
Feng Tang341487ab2013-02-03 14:38:20 +08001758 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1759 "Switch to another data file in PWD") > 0)
1760 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001761add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001762 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001763retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001764 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001765
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766 if (choice == nr_options - 1)
1767 break;
1768
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001769 if (choice == -1) {
1770 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001771 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001772 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001773
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001774 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001775 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001776 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001777 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001778do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001779 if (!objdump_path && perf_session_env__lookup_objdump(env))
1780 continue;
1781
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001782 he = hist_browser__selected_entry(browser);
1783 if (he == NULL)
1784 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001785
1786 /*
1787 * we stash the branch_info symbol + map into the
1788 * the ms so we don't have to rewrite all the annotation
1789 * code to use branch_info.
1790 * in branch mode, the ms struct is not used
1791 */
1792 if (choice == annotate_f) {
1793 he->ms.sym = he->branch_info->from.sym;
1794 he->ms.map = he->branch_info->from.map;
1795 } else if (choice == annotate_t) {
1796 he->ms.sym = he->branch_info->to.sym;
1797 he->ms.map = he->branch_info->to.map;
1798 }
1799
Jiri Olsad7553302014-06-15 10:22:15 +02001800 notes = symbol__annotation(he->ms.sym);
1801 if (!notes->src)
1802 continue;
1803
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001804 /*
1805 * Don't let this be freed, say, by hists__decay_entry.
1806 */
1807 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001808 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001809 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001810 /*
1811 * offer option to annotate the other branch source or target
1812 * (if they exists) when returning from annotate
1813 */
1814 if ((err == 'q' || err == CTRL('c'))
1815 && annotate_t != -2 && annotate_f != -2)
1816 goto retry_popup_menu;
1817
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001818 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001819 if (err)
1820 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001821
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001822 } else if (choice == browse_map)
1823 map__browse(browser->selection->map);
1824 else if (choice == zoom_dso) {
1825zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001826 if (browser->hists->dso_filter) {
1827 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001828zoom_out_dso:
1829 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001830 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001831 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001832 } else {
1833 if (dso == NULL)
1834 continue;
1835 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1836 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001837 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001838 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001839 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001840 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001841 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001842 hist_browser__reset(browser);
1843 } else if (choice == zoom_thread) {
1844zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001845 if (browser->hists->thread_filter) {
1846 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001847zoom_out_thread:
1848 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001849 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001850 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001851 } else {
1852 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001853 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001854 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001855 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001856 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001857 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001858 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001859 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001860 hist_browser__reset(browser);
1861 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001862 /* perf scripts support */
1863 else if (choice == scripts_all || choice == scripts_comm ||
1864 choice == scripts_symbol) {
1865do_scripts:
1866 memset(script_opt, 0, 64);
1867
1868 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001869 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001870
1871 if (choice == scripts_symbol)
1872 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1873
1874 script_browse(script_opt);
1875 }
Feng Tang341487ab2013-02-03 14:38:20 +08001876 /* Switch to another data file */
1877 else if (choice == switch_data) {
1878do_data_switch:
1879 if (!switch_data_file()) {
1880 key = K_SWITCH_INPUT_DATA;
1881 break;
1882 } else
1883 ui__warning("Won't switch the data files due to\n"
1884 "no valid data file get selected!\n");
1885 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001886 }
1887out_free_stack:
1888 pstack__delete(fstack);
1889out:
1890 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001891 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001892 return key;
1893}
1894
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001895struct perf_evsel_menu {
1896 struct ui_browser b;
1897 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001898 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001899 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001900 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001901};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001902
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001903static void perf_evsel_menu__write(struct ui_browser *browser,
1904 void *entry, int row)
1905{
1906 struct perf_evsel_menu *menu = container_of(browser,
1907 struct perf_evsel_menu, b);
1908 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1909 bool current_entry = ui_browser__is_current_entry(browser, row);
1910 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001911 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001912 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001913 const char *warn = " ";
1914 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001915
1916 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1917 HE_COLORSET_NORMAL);
1918
Namhyung Kim759ff492013-03-05 14:53:26 +09001919 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001920 struct perf_evsel *pos;
1921
1922 ev_name = perf_evsel__group_name(evsel);
1923
1924 for_each_group_member(pos, evsel) {
1925 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1926 }
1927 }
1928
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001929 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001930 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001931 unit, unit == ' ' ? "" : " ", ev_name);
1932 slsmg_printf("%s", bf);
1933
1934 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1935 if (nr_events != 0) {
1936 menu->lost_events = true;
1937 if (!current_entry)
1938 ui_browser__set_color(browser, HE_COLORSET_TOP);
1939 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001940 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1941 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001942 warn = bf;
1943 }
1944
1945 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001946
1947 if (current_entry)
1948 menu->selection = evsel;
1949}
1950
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001951static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1952 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001953 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001954{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001955 struct perf_evlist *evlist = menu->b.priv;
1956 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001957 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001958 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001959 int key;
1960
1961 if (ui_browser__show(&menu->b, title,
1962 "ESC: exit, ENTER|->: Browse histograms") < 0)
1963 return -1;
1964
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001965 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001966 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001967
1968 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001969 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001970 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001971
1972 if (!menu->lost_events_warned && menu->lost_events) {
1973 ui_browser__warn_lost_events(&menu->b);
1974 menu->lost_events_warned = true;
1975 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001976 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001977 case K_RIGHT:
1978 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001979 if (!menu->selection)
1980 continue;
1981 pos = menu->selection;
1982browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001983 perf_evlist__set_selected(evlist, pos);
1984 /*
1985 * Give the calling tool a chance to populate the non
1986 * default evsel resorted hists tree.
1987 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001988 if (hbt)
1989 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001990 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001991 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001992 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001993 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001994 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001995 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001996 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001997 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001998 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001999 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002000 pos = perf_evsel__next(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_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002003 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002004 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002005 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002006 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002007 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002008 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002009 if (!ui_browser__dialog_yesno(&menu->b,
2010 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002011 continue;
2012 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08002013 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002014 case 'q':
2015 case CTRL('c'):
2016 goto out;
2017 default:
2018 continue;
2019 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002020 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002021 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002022 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002023 if (!ui_browser__dialog_yesno(&menu->b,
2024 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002025 continue;
2026 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002027 case 'q':
2028 case CTRL('c'):
2029 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002030 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002031 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002032 }
2033 }
2034
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002035out:
2036 ui_browser__hide(&menu->b);
2037 return key;
2038}
2039
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002040static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002041 void *entry)
2042{
2043 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2044
2045 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2046 return true;
2047
2048 return false;
2049}
2050
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002051static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002052 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002053 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002054 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002055 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002056{
2057 struct perf_evsel *pos;
2058 struct perf_evsel_menu menu = {
2059 .b = {
2060 .entries = &evlist->entries,
2061 .refresh = ui_browser__list_head_refresh,
2062 .seek = ui_browser__list_head_seek,
2063 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002064 .filter = filter_group_entries,
2065 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002066 .priv = evlist,
2067 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002068 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002069 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002070 };
2071
2072 ui_helpline__push("Press ESC to exit");
2073
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002074 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002075 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002076 size_t line_len = strlen(ev_name) + 7;
2077
2078 if (menu.b.width < line_len)
2079 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002080 }
2081
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002082 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002083}
2084
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002085int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002086 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002087 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002088 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002089{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002090 int nr_entries = evlist->nr_entries;
2091
2092single_entry:
2093 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002094 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002095
2096 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002097 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002098 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002099 }
2100
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002101 if (symbol_conf.event_group) {
2102 struct perf_evsel *pos;
2103
2104 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002105 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002106 if (perf_evsel__is_group_leader(pos))
2107 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002108 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002109
2110 if (nr_entries == 1)
2111 goto single_entry;
2112 }
2113
2114 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002115 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002116}