blob: d42d8a8f3810270ccb078dbbfafc65827abd58fd [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
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900480static void hist_browser__show_callchain_entry(struct hist_browser *browser,
481 struct callchain_list *chain,
482 unsigned short row, int offset,
483 char folded_sign, const char *str,
484 bool *is_current_entry)
485{
486 int color, width;
487
488 color = HE_COLORSET_NORMAL;
489 width = browser->b.width - (offset + 2);
490 if (ui_browser__is_current_entry(&browser->b, row)) {
491 browser->selection = &chain->ms;
492 color = HE_COLORSET_SELECTED;
493 *is_current_entry = true;
494 }
495
496 ui_browser__set_color(&browser->b, color);
497 hist_browser__gotorc(browser, row, 0);
498 slsmg_write_nstring(" ", offset);
499 slsmg_printf("%c ", folded_sign);
500 slsmg_write_nstring(str, width);
501}
502
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300503#define LEVEL_OFFSET_STEP 3
504
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300505static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300506 struct callchain_node *chain_node,
507 u64 total, int level,
508 unsigned short row,
509 off_t *row_offset,
510 bool *is_current_entry)
511{
512 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900513 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900514 u64 new_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300515
516 if (callchain_param.mode == CHAIN_GRAPH_REL)
517 new_total = chain_node->children_hit;
518 else
519 new_total = total;
520
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300521 node = rb_first(&chain_node->rb_root);
522 while (node) {
523 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
524 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100525 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300526 struct callchain_list *chain;
527 char folded_sign = ' ';
528 int first = true;
529 int extra_offset = 0;
530
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300531 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300532 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300533 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300534 bool was_first = first;
535
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300536 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300537 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300538 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300539 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300540
541 folded_sign = callchain_list__folded(chain);
542 if (*row_offset != 0) {
543 --*row_offset;
544 goto do_next;
545 }
546
547 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300548 str = callchain_list__sym_name(chain, bf, sizeof(bf),
549 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300550 if (was_first) {
551 double percent = cumul * 100.0 / new_total;
552
553 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
554 str = "Not enough memory!";
555 else
556 str = alloc_str;
557 }
558
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900559 hist_browser__show_callchain_entry(browser, chain, row,
560 offset + extra_offset,
561 folded_sign, str,
562 is_current_entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300563 free(alloc_str);
564
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300565 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300566 goto out;
567do_next:
568 if (folded_sign == '+')
569 break;
570 }
571
572 if (folded_sign == '-') {
573 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300574 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300575 new_level, row, row_offset,
576 is_current_entry);
577 }
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300578 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300579 goto out;
580 node = next;
581 }
582out:
583 return row - first_row;
584}
585
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300586static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300587 struct callchain_node *node,
588 int level, unsigned short row,
589 off_t *row_offset,
590 bool *is_current_entry)
591{
592 struct callchain_list *chain;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900593 int first_row = row;
594 int offset = level * LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300595 char folded_sign = ' ';
596
597 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300598 char bf[1024], *s;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300599
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300600 folded_sign = callchain_list__folded(chain);
601
602 if (*row_offset != 0) {
603 --*row_offset;
604 continue;
605 }
606
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300607 s = callchain_list__sym_name(chain, bf, sizeof(bf),
608 browser->show_dso);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900609 hist_browser__show_callchain_entry(browser, chain, row,
610 offset, folded_sign, s,
611 is_current_entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300612
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300613 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300614 goto out;
615 }
616
617 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300618 row += hist_browser__show_callchain_node_rb_tree(browser, node,
619 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300620 level + 1, row,
621 row_offset,
622 is_current_entry);
623out:
624 return row - first_row;
625}
626
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300627static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300628 struct rb_root *chain,
629 int level, unsigned short row,
630 off_t *row_offset,
631 bool *is_current_entry)
632{
633 struct rb_node *nd;
634 int first_row = row;
635
636 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
637 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
638
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300639 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300640 row, row_offset,
641 is_current_entry);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300642 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300643 break;
644 }
645
646 return row - first_row;
647}
648
Namhyung Kim89701462013-01-22 18:09:38 +0900649struct hpp_arg {
650 struct ui_browser *b;
651 char folded_sign;
652 bool current_entry;
653};
654
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900655static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
656{
657 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900658 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900659 va_list args;
660 double percent;
661
662 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900663 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900664 percent = va_arg(args, double);
665 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900666
Namhyung Kim89701462013-01-22 18:09:38 +0900667 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900668
Namhyung Kimd6751072014-07-31 14:47:36 +0900669 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900670 slsmg_printf("%s", hpp->buf);
671
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900672 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900673 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900674}
675
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900676#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900677static u64 __hpp_get_##_field(struct hist_entry *he) \
678{ \
679 return he->stat._field; \
680} \
681 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100682static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900683hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100684 struct perf_hpp *hpp, \
685 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900686{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900687 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
688 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900689}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900690
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900691#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
692static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
693{ \
694 return he->stat_acc->_field; \
695} \
696 \
697static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900698hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900699 struct perf_hpp *hpp, \
700 struct hist_entry *he) \
701{ \
702 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900703 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900704 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900705 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900706 slsmg_printf("%s", hpp->buf); \
707 \
708 return ret; \
709 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900710 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
711 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900712}
713
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900714__HPP_COLOR_PERCENT_FN(overhead, period)
715__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
716__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
717__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
718__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900719__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900720
721#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900722#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900723
724void hist_browser__init_hpp(void)
725{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900726 perf_hpp__format[PERF_HPP__OVERHEAD].color =
727 hist_browser__hpp_color_overhead;
728 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
729 hist_browser__hpp_color_overhead_sys;
730 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
731 hist_browser__hpp_color_overhead_us;
732 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
733 hist_browser__hpp_color_overhead_guest_sys;
734 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
735 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900736 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
737 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900738}
739
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300740static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300741 struct hist_entry *entry,
742 unsigned short row)
743{
744 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200745 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900746 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300747 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300748 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300749 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300750 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200751 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300752
753 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300754 browser->he_selection = entry;
755 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300756 }
757
758 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300759 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300760 folded_sign = hist_entry__folded(entry);
761 }
762
763 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900764 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900765 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900766 .folded_sign = folded_sign,
767 .current_entry = current_entry,
768 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900769 struct perf_hpp hpp = {
770 .buf = s,
771 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900772 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900773 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300774
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300775 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900776
Jiri Olsa12400052012-10-13 00:06:16 +0200777 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900778 if (perf_hpp__should_skip(fmt))
779 continue;
780
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900781 if (current_entry && browser->b.navkeypressed) {
782 ui_browser__set_color(&browser->b,
783 HE_COLORSET_SELECTED);
784 } else {
785 ui_browser__set_color(&browser->b,
786 HE_COLORSET_NORMAL);
787 }
788
789 if (first) {
790 if (symbol_conf.use_callchain) {
791 slsmg_printf("%c ", folded_sign);
792 width -= 2;
793 }
794 first = false;
795 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900796 slsmg_printf(" ");
797 width -= 2;
798 }
799
Jiri Olsa12400052012-10-13 00:06:16 +0200800 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100801 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900802 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100803 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900804 slsmg_printf("%s", s);
805 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300806 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200807
808 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300809 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200810 width += 1;
811
Namhyung Kim26d8b332014-03-03 16:16:20 +0900812 slsmg_write_nstring("", width);
813
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300814 ++row;
815 ++printed;
816 } else
817 --row_offset;
818
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300819 if (folded_sign == '-' && row != browser->b.rows) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300820 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300821 1, row, &row_offset,
822 &current_entry);
823 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300824 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300825 }
826
827 return printed;
828}
829
Jiri Olsa81a888f2014-06-14 15:44:52 +0200830static int advance_hpp_check(struct perf_hpp *hpp, int inc)
831{
832 advance_hpp(hpp, inc);
833 return hpp->size <= 0;
834}
835
836static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
837{
838 struct perf_hpp dummy_hpp = {
839 .buf = buf,
840 .size = size,
841 };
842 struct perf_hpp_fmt *fmt;
843 size_t ret = 0;
844
845 if (symbol_conf.use_callchain) {
846 ret = scnprintf(buf, size, " ");
847 if (advance_hpp_check(&dummy_hpp, ret))
848 return ret;
849 }
850
851 perf_hpp__for_each_format(fmt) {
852 if (perf_hpp__should_skip(fmt))
853 continue;
854
Jiri Olsa81a888f2014-06-14 15:44:52 +0200855 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
856 if (advance_hpp_check(&dummy_hpp, ret))
857 break;
858
859 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
860 if (advance_hpp_check(&dummy_hpp, ret))
861 break;
862 }
863
864 return ret;
865}
866
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200867static void hist_browser__show_headers(struct hist_browser *browser)
868{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200869 char headers[1024];
870
871 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200872 ui_browser__gotorc(&browser->b, 0, 0);
873 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200874 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200875}
876
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300877static void ui_browser__hists_init_top(struct ui_browser *browser)
878{
879 if (browser->top == NULL) {
880 struct hist_browser *hb;
881
882 hb = container_of(browser, struct hist_browser, b);
883 browser->top = rb_first(&hb->hists->entries);
884 }
885}
886
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300887static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300888{
889 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200890 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300891 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300892 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300893
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200894 if (hb->show_headers) {
895 hist_browser__show_headers(hb);
896 header_offset = 1;
897 }
898
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300899 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300900
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300901 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300902 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900903 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904
905 if (h->filtered)
906 continue;
907
Namhyung Kim14135662013-10-31 10:17:39 +0900908 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900909 if (percent < hb->min_pcnt)
910 continue;
911
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300912 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300913 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300914 break;
915 }
916
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200917 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300918}
919
Namhyung Kim064f1982013-05-14 11:09:04 +0900920static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900921 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300922{
923 while (nd != NULL) {
924 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900925 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900926
Namhyung Kimc0f15272014-04-16 11:16:33 +0900927 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300928 return nd;
929
930 nd = rb_next(nd);
931 }
932
933 return NULL;
934}
935
Namhyung Kim064f1982013-05-14 11:09:04 +0900936static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900937 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300938{
939 while (nd != NULL) {
940 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900941 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900942
943 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300944 return nd;
945
946 nd = rb_prev(nd);
947 }
948
949 return NULL;
950}
951
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300952static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300953 off_t offset, int whence)
954{
955 struct hist_entry *h;
956 struct rb_node *nd;
957 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900958 struct hist_browser *hb;
959
960 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300961
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300962 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300963 return;
964
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300965 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300966
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300967 switch (whence) {
968 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900969 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900970 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300971 break;
972 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300973 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300974 goto do_offset;
975 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900976 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900977 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300978 first = false;
979 break;
980 default:
981 return;
982 }
983
984 /*
985 * Moves not relative to the first visible entry invalidates its
986 * row_offset:
987 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300988 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300989 h->row_offset = 0;
990
991 /*
992 * Here we have to check if nd is expanded (+), if it is we can't go
993 * the next top level hist_entry, instead we must compute an offset of
994 * what _not_ to show and not change the first visible entry.
995 *
996 * This offset increments when we are going from top to bottom and
997 * decreases when we're going from bottom to top.
998 *
999 * As we don't have backpointers to the top level in the callchains
1000 * structure, we need to always print the whole hist_entry callchain,
1001 * skipping the first ones that are before the first visible entry
1002 * and stop when we printed enough lines to fill the screen.
1003 */
1004do_offset:
1005 if (offset > 0) {
1006 do {
1007 h = rb_entry(nd, struct hist_entry, rb_node);
1008 if (h->ms.unfolded) {
1009 u16 remaining = h->nr_rows - h->row_offset;
1010 if (offset > remaining) {
1011 offset -= remaining;
1012 h->row_offset = 0;
1013 } else {
1014 h->row_offset += offset;
1015 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001016 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001017 break;
1018 }
1019 }
Namhyung Kim14135662013-10-31 10:17:39 +09001020 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001021 if (nd == NULL)
1022 break;
1023 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001024 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001025 } while (offset != 0);
1026 } else if (offset < 0) {
1027 while (1) {
1028 h = rb_entry(nd, struct hist_entry, rb_node);
1029 if (h->ms.unfolded) {
1030 if (first) {
1031 if (-offset > h->row_offset) {
1032 offset += h->row_offset;
1033 h->row_offset = 0;
1034 } else {
1035 h->row_offset += offset;
1036 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001037 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001038 break;
1039 }
1040 } else {
1041 if (-offset > h->nr_rows) {
1042 offset += h->nr_rows;
1043 h->row_offset = 0;
1044 } else {
1045 h->row_offset = h->nr_rows + offset;
1046 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001047 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001048 break;
1049 }
1050 }
1051 }
1052
Namhyung Kim14135662013-10-31 10:17:39 +09001053 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001054 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001055 if (nd == NULL)
1056 break;
1057 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001058 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001059 if (offset == 0) {
1060 /*
1061 * Last unfiltered hist_entry, check if it is
1062 * unfolded, if it is then we should have
1063 * row_offset at its last entry.
1064 */
1065 h = rb_entry(nd, struct hist_entry, rb_node);
1066 if (h->ms.unfolded)
1067 h->row_offset = h->nr_rows;
1068 break;
1069 }
1070 first = false;
1071 }
1072 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001073 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001074 h = rb_entry(nd, struct hist_entry, rb_node);
1075 h->row_offset = 0;
1076 }
1077}
1078
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001079static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
1080 struct callchain_node *chain_node,
1081 u64 total, int level,
1082 FILE *fp)
1083{
1084 struct rb_node *node;
1085 int offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +09001086 u64 new_total;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001087 int printed = 0;
1088
1089 if (callchain_param.mode == CHAIN_GRAPH_REL)
1090 new_total = chain_node->children_hit;
1091 else
1092 new_total = total;
1093
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001094 node = rb_first(&chain_node->rb_root);
1095 while (node) {
1096 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1097 struct rb_node *next = rb_next(node);
1098 u64 cumul = callchain_cumul_hits(child);
1099 struct callchain_list *chain;
1100 char folded_sign = ' ';
1101 int first = true;
1102 int extra_offset = 0;
1103
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001104 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001105 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001106 const char *str;
1107 bool was_first = first;
1108
1109 if (first)
1110 first = false;
1111 else
1112 extra_offset = LEVEL_OFFSET_STEP;
1113
1114 folded_sign = callchain_list__folded(chain);
1115
1116 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001117 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1118 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001119 if (was_first) {
1120 double percent = cumul * 100.0 / new_total;
1121
1122 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1123 str = "Not enough memory!";
1124 else
1125 str = alloc_str;
1126 }
1127
1128 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1129 free(alloc_str);
1130 if (folded_sign == '+')
1131 break;
1132 }
1133
1134 if (folded_sign == '-') {
1135 const int new_level = level + (extra_offset ? 2 : 1);
1136 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1137 new_level, fp);
1138 }
1139
1140 node = next;
1141 }
1142
1143 return printed;
1144}
1145
1146static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1147 struct callchain_node *node,
1148 int level, FILE *fp)
1149{
1150 struct callchain_list *chain;
1151 int offset = level * LEVEL_OFFSET_STEP;
1152 char folded_sign = ' ';
1153 int printed = 0;
1154
1155 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001156 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001157
1158 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001159 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001160 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1161 }
1162
1163 if (folded_sign == '-')
1164 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1165 browser->hists->stats.total_period,
1166 level + 1, fp);
1167 return printed;
1168}
1169
1170static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1171 struct rb_root *chain, int level, FILE *fp)
1172{
1173 struct rb_node *nd;
1174 int printed = 0;
1175
1176 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1177 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1178
1179 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1180 }
1181
1182 return printed;
1183}
1184
1185static int hist_browser__fprintf_entry(struct hist_browser *browser,
1186 struct hist_entry *he, FILE *fp)
1187{
1188 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001189 int printed = 0;
1190 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001191 struct perf_hpp hpp = {
1192 .buf = s,
1193 .size = sizeof(s),
1194 };
1195 struct perf_hpp_fmt *fmt;
1196 bool first = true;
1197 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001198
1199 if (symbol_conf.use_callchain)
1200 folded_sign = hist_entry__folded(he);
1201
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001202 if (symbol_conf.use_callchain)
1203 printed += fprintf(fp, "%c ", folded_sign);
1204
Namhyung Kim26d8b332014-03-03 16:16:20 +09001205 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001206 if (perf_hpp__should_skip(fmt))
1207 continue;
1208
Namhyung Kim26d8b332014-03-03 16:16:20 +09001209 if (!first) {
1210 ret = scnprintf(hpp.buf, hpp.size, " ");
1211 advance_hpp(&hpp, ret);
1212 } else
1213 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001214
Namhyung Kim26d8b332014-03-03 16:16:20 +09001215 ret = fmt->entry(fmt, &hpp, he);
1216 advance_hpp(&hpp, ret);
1217 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001218 printed += fprintf(fp, "%s\n", rtrim(s));
1219
1220 if (folded_sign == '-')
1221 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1222
1223 return printed;
1224}
1225
1226static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1227{
Namhyung Kim064f1982013-05-14 11:09:04 +09001228 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001229 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001230 int printed = 0;
1231
1232 while (nd) {
1233 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1234
1235 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001236 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001237 }
1238
1239 return printed;
1240}
1241
1242static int hist_browser__dump(struct hist_browser *browser)
1243{
1244 char filename[64];
1245 FILE *fp;
1246
1247 while (1) {
1248 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1249 if (access(filename, F_OK))
1250 break;
1251 /*
1252 * XXX: Just an arbitrary lazy upper limit
1253 */
1254 if (++browser->print_seq == 8192) {
1255 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1256 return -1;
1257 }
1258 }
1259
1260 fp = fopen(filename, "w");
1261 if (fp == NULL) {
1262 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001263 const char *err = strerror_r(errno, bf, sizeof(bf));
1264 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001265 return -1;
1266 }
1267
1268 ++browser->print_seq;
1269 hist_browser__fprintf(browser, fp);
1270 fclose(fp);
1271 ui_helpline__fpush("%s written!", filename);
1272
1273 return 0;
1274}
1275
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001276static struct hist_browser *hist_browser__new(struct hists *hists)
1277{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001278 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001279
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001280 if (browser) {
1281 browser->hists = hists;
1282 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001283 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001284 browser->b.seek = ui_browser__hists_seek;
1285 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001286 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001287 }
1288
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001289 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001290}
1291
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001292static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001293{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001294 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001295}
1296
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001297static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001298{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001299 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001300}
1301
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001302static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001303{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001304 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001305}
1306
Jiri Olsadd00d482014-06-19 13:41:13 +02001307static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001308{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001309 char unit;
1310 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001311 const struct dso *dso = hists->dso_filter;
1312 const struct thread *thread = hists->thread_filter;
1313 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1314 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001315 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001316 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001317 char buf[512];
1318 size_t buflen = sizeof(buf);
1319
Namhyung Kimf2148332014-01-14 11:52:48 +09001320 if (symbol_conf.filter_relative) {
1321 nr_samples = hists->stats.nr_non_filtered_samples;
1322 nr_events = hists->stats.total_non_filtered_period;
1323 }
1324
Namhyung Kim759ff492013-03-05 14:53:26 +09001325 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001326 struct perf_evsel *pos;
1327
1328 perf_evsel__group_desc(evsel, buf, buflen);
1329 ev_name = buf;
1330
1331 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001332 if (symbol_conf.filter_relative) {
1333 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1334 nr_events += pos->hists.stats.total_non_filtered_period;
1335 } else {
1336 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1337 nr_events += pos->hists.stats.total_period;
1338 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001339 }
1340 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001341
Ashay Ranecc6862802012-04-05 21:01:01 -05001342 nr_samples = convert_unit(nr_samples, &unit);
1343 printed = scnprintf(bf, size,
1344 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1345 nr_samples, unit, ev_name, nr_events);
1346
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001347
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001348 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001349 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001350 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001351 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001352 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001353 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001354 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001355 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001356 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001357 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001358 ", DSO: %s", dso->short_name);
1359 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001360}
1361
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001362static inline void free_popup_options(char **options, int n)
1363{
1364 int i;
1365
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001366 for (i = 0; i < n; ++i)
1367 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001368}
1369
Feng Tangc77d8d72012-11-01 00:00:55 +08001370/* Check whether the browser is for 'top' or 'report' */
1371static inline bool is_report_browser(void *timer)
1372{
1373 return timer == NULL;
1374}
1375
Feng Tang341487ab2013-02-03 14:38:20 +08001376/*
1377 * Only runtime switching of perf data file will make "input_name" point
1378 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1379 * whether we need to call free() for current "input_name" during the switch.
1380 */
1381static bool is_input_name_malloced = false;
1382
1383static int switch_data_file(void)
1384{
1385 char *pwd, *options[32], *abs_path[32], *tmp;
1386 DIR *pwd_dir;
1387 int nr_options = 0, choice = -1, ret = -1;
1388 struct dirent *dent;
1389
1390 pwd = getenv("PWD");
1391 if (!pwd)
1392 return ret;
1393
1394 pwd_dir = opendir(pwd);
1395 if (!pwd_dir)
1396 return ret;
1397
1398 memset(options, 0, sizeof(options));
1399 memset(options, 0, sizeof(abs_path));
1400
1401 while ((dent = readdir(pwd_dir))) {
1402 char path[PATH_MAX];
1403 u64 magic;
1404 char *name = dent->d_name;
1405 FILE *file;
1406
1407 if (!(dent->d_type == DT_REG))
1408 continue;
1409
1410 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1411
1412 file = fopen(path, "r");
1413 if (!file)
1414 continue;
1415
1416 if (fread(&magic, 1, 8, file) < 8)
1417 goto close_file_and_continue;
1418
1419 if (is_perf_magic(magic)) {
1420 options[nr_options] = strdup(name);
1421 if (!options[nr_options])
1422 goto close_file_and_continue;
1423
1424 abs_path[nr_options] = strdup(path);
1425 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001426 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001427 ui__warning("Can't search all data files due to memory shortage.\n");
1428 fclose(file);
1429 break;
1430 }
1431
1432 nr_options++;
1433 }
1434
1435close_file_and_continue:
1436 fclose(file);
1437 if (nr_options >= 32) {
1438 ui__warning("Too many perf data files in PWD!\n"
1439 "Only the first 32 files will be listed.\n");
1440 break;
1441 }
1442 }
1443 closedir(pwd_dir);
1444
1445 if (nr_options) {
1446 choice = ui__popup_menu(nr_options, options);
1447 if (choice < nr_options && choice >= 0) {
1448 tmp = strdup(abs_path[choice]);
1449 if (tmp) {
1450 if (is_input_name_malloced)
1451 free((void *)input_name);
1452 input_name = tmp;
1453 is_input_name_malloced = true;
1454 ret = 0;
1455 } else
1456 ui__warning("Data switch failed due to memory shortage!\n");
1457 }
1458 }
1459
1460 free_popup_options(options, nr_options);
1461 free_popup_options(abs_path, nr_options);
1462 return ret;
1463}
1464
Namhyung Kim112f7612014-04-22 14:05:35 +09001465static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001466{
1467 u64 nr_entries = 0;
1468 struct rb_node *nd = rb_first(&hb->hists->entries);
1469
Namhyung Kim268397c2014-04-22 14:49:31 +09001470 if (hb->min_pcnt == 0) {
1471 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1472 return;
1473 }
1474
Namhyung Kim14135662013-10-31 10:17:39 +09001475 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001476 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001477 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001478 }
1479
Namhyung Kim112f7612014-04-22 14:05:35 +09001480 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001481}
Feng Tang341487ab2013-02-03 14:38:20 +08001482
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001483static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001484 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001485 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001486 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001487 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001488 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001489{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001490 struct hists *hists = &evsel->hists;
1491 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001492 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001493 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001494 char *options[16];
1495 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001496 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001497 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001498 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001499 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001500 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001501
Namhyung Kime8e684a2013-12-26 14:37:58 +09001502#define HIST_BROWSER_HELP_COMMON \
1503 "h/?/F1 Show this window\n" \
1504 "UP/DOWN/PGUP\n" \
1505 "PGDN/SPACE Navigate\n" \
1506 "q/ESC/CTRL+C Exit browser\n\n" \
1507 "For multiple event sessions:\n\n" \
1508 "TAB/UNTAB Switch events\n\n" \
1509 "For symbolic views (--sort has sym):\n\n" \
1510 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1511 "<- Zoom out\n" \
1512 "a Annotate current symbol\n" \
1513 "C Collapse all callchains\n" \
1514 "d Zoom into current DSO\n" \
1515 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001516 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001517 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001518
1519 /* help messages are sorted by lexical order of the hotkey */
1520 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001521 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001522 "P Print histograms to perf.hist.N\n"
1523 "r Run available scripts\n"
1524 "s Switch to another data file in PWD\n"
1525 "t Zoom into current Thread\n"
1526 "V Verbose (DSO names in callchains, etc)\n"
1527 "/ Filter symbol by name";
1528 const char top_help[] = HIST_BROWSER_HELP_COMMON
1529 "P Print histograms to perf.hist.N\n"
1530 "t Zoom into current Thread\n"
1531 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001532 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001533 "/ Filter symbol by name";
1534
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001535 if (browser == NULL)
1536 return -1;
1537
Namhyung Kim064f1982013-05-14 11:09:04 +09001538 if (min_pcnt) {
1539 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001540 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001541 }
1542
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001543 fstack = pstack__new(2);
1544 if (fstack == NULL)
1545 goto out;
1546
1547 ui_helpline__push(helpline);
1548
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001549 memset(options, 0, sizeof(options));
1550
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001551 perf_hpp__for_each_format(fmt)
1552 perf_hpp__reset_width(fmt, hists);
1553
Namhyung Kim5b591662014-07-31 14:47:38 +09001554 if (symbol_conf.col_width_list_str)
1555 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1556
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001557 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001558 const struct thread *thread = NULL;
1559 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001560 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001561 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001562 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001563 int scripts_comm = -2, scripts_symbol = -2,
1564 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001565
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001566 nr_options = 0;
1567
Jiri Olsadd00d482014-06-19 13:41:13 +02001568 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001569
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001570 if (browser->he_selection != NULL) {
1571 thread = hist_browser__selected_thread(browser);
1572 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1573 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001574 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001575 case K_TAB:
1576 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001577 if (nr_events == 1)
1578 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001579 /*
1580 * Exit the browser, let hists__browser_tree
1581 * go to the next or previous
1582 */
1583 goto out_free_stack;
1584 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001585 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001586 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001587 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001588 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001589 continue;
1590 }
1591
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001592 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001593 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001594 browser->selection->map->dso->annotate_warned)
1595 continue;
1596 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001597 case 'P':
1598 hist_browser__dump(browser);
1599 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001600 case 'd':
1601 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001602 case 'V':
1603 browser->show_dso = !browser->show_dso;
1604 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001605 case 't':
1606 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001607 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001608 if (ui_browser__input_window("Symbol to show",
1609 "Please enter the name of symbol you want to see",
1610 buf, "ENTER: OK, ESC: Cancel",
1611 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001612 hists->symbol_filter_str = *buf ? buf : NULL;
1613 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001614 hist_browser__reset(browser);
1615 }
1616 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001617 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001618 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001619 goto do_scripts;
1620 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001621 case 's':
1622 if (is_report_browser(hbt))
1623 goto do_data_switch;
1624 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001625 case 'i':
1626 /* env->arch is NULL for live-mode (i.e. perf top) */
1627 if (env->arch)
1628 tui__header_window(env);
1629 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001630 case 'F':
1631 symbol_conf.filter_relative ^= 1;
1632 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001633 case 'z':
1634 if (!is_report_browser(hbt)) {
1635 struct perf_top *top = hbt->arg;
1636
1637 top->zero = !top->zero;
1638 }
1639 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001640 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001641 case 'h':
1642 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001643 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001644 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001645 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001646 case K_ENTER:
1647 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001648 /* menu */
1649 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001650 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001651 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001652
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001653 if (pstack__empty(fstack)) {
1654 /*
1655 * Go back to the perf_evsel_menu__run or other user
1656 */
1657 if (left_exits)
1658 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001659 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001660 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001661 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001662 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001663 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001664 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001665 goto zoom_out_thread;
1666 continue;
1667 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001668 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001669 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001670 !ui_browser__dialog_yesno(&browser->b,
1671 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001672 continue;
1673 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001674 case 'q':
1675 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001676 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001677 default:
1678 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001679 }
1680
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001681 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001682 goto add_exit_option;
1683
Namhyung Kim55369fc2013-04-01 20:35:20 +09001684 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001685 bi = browser->he_selection->branch_info;
1686 if (browser->selection != NULL &&
1687 bi &&
1688 bi->from.sym != NULL &&
1689 !bi->from.map->dso->annotate_warned &&
1690 asprintf(&options[nr_options], "Annotate %s",
1691 bi->from.sym->name) > 0)
1692 annotate_f = nr_options++;
1693
1694 if (browser->selection != NULL &&
1695 bi &&
1696 bi->to.sym != NULL &&
1697 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001698 (bi->to.sym != bi->from.sym ||
1699 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001700 asprintf(&options[nr_options], "Annotate %s",
1701 bi->to.sym->name) > 0)
1702 annotate_t = nr_options++;
1703 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001704 if (browser->selection != NULL &&
1705 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001706 !browser->selection->map->dso->annotate_warned) {
1707 struct annotation *notes;
1708
1709 notes = symbol__annotation(browser->selection->sym);
1710
1711 if (notes->src &&
1712 asprintf(&options[nr_options], "Annotate %s",
1713 browser->selection->sym->name) > 0)
1714 annotate = nr_options++;
1715 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001716 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001717
1718 if (thread != NULL &&
1719 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001720 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001721 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001722 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001723 zoom_thread = nr_options++;
1724
1725 if (dso != NULL &&
1726 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001727 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001728 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1729 zoom_dso = nr_options++;
1730
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001731 if (browser->selection != NULL &&
1732 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001733 asprintf(&options[nr_options], "Browse map details") > 0)
1734 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001735
1736 /* perf script support */
1737 if (browser->he_selection) {
1738 struct symbol *sym;
1739
1740 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001741 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001742 scripts_comm = nr_options++;
1743
1744 sym = browser->he_selection->ms.sym;
1745 if (sym && sym->namelen &&
1746 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1747 sym->name) > 0)
1748 scripts_symbol = nr_options++;
1749 }
1750
1751 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1752 scripts_all = nr_options++;
1753
Feng Tang341487ab2013-02-03 14:38:20 +08001754 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1755 "Switch to another data file in PWD") > 0)
1756 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001757add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001759retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001760 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001762 if (choice == nr_options - 1)
1763 break;
1764
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001765 if (choice == -1) {
1766 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001767 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001768 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001770 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001771 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001772 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001773 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001774do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001775 if (!objdump_path && perf_session_env__lookup_objdump(env))
1776 continue;
1777
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001778 he = hist_browser__selected_entry(browser);
1779 if (he == NULL)
1780 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001781
1782 /*
1783 * we stash the branch_info symbol + map into the
1784 * the ms so we don't have to rewrite all the annotation
1785 * code to use branch_info.
1786 * in branch mode, the ms struct is not used
1787 */
1788 if (choice == annotate_f) {
1789 he->ms.sym = he->branch_info->from.sym;
1790 he->ms.map = he->branch_info->from.map;
1791 } else if (choice == annotate_t) {
1792 he->ms.sym = he->branch_info->to.sym;
1793 he->ms.map = he->branch_info->to.map;
1794 }
1795
Jiri Olsad7553302014-06-15 10:22:15 +02001796 notes = symbol__annotation(he->ms.sym);
1797 if (!notes->src)
1798 continue;
1799
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001800 /*
1801 * Don't let this be freed, say, by hists__decay_entry.
1802 */
1803 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001804 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001805 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001806 /*
1807 * offer option to annotate the other branch source or target
1808 * (if they exists) when returning from annotate
1809 */
1810 if ((err == 'q' || err == CTRL('c'))
1811 && annotate_t != -2 && annotate_f != -2)
1812 goto retry_popup_menu;
1813
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001814 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001815 if (err)
1816 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001817
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001818 } else if (choice == browse_map)
1819 map__browse(browser->selection->map);
1820 else if (choice == zoom_dso) {
1821zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001822 if (browser->hists->dso_filter) {
1823 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001824zoom_out_dso:
1825 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001826 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001827 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001828 } else {
1829 if (dso == NULL)
1830 continue;
1831 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1832 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001833 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001834 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001835 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001836 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001837 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001838 hist_browser__reset(browser);
1839 } else if (choice == zoom_thread) {
1840zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001841 if (browser->hists->thread_filter) {
1842 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001843zoom_out_thread:
1844 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001845 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001846 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001847 } else {
1848 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001849 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001850 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001851 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001852 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001853 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001854 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001855 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001856 hist_browser__reset(browser);
1857 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001858 /* perf scripts support */
1859 else if (choice == scripts_all || choice == scripts_comm ||
1860 choice == scripts_symbol) {
1861do_scripts:
1862 memset(script_opt, 0, 64);
1863
1864 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001865 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001866
1867 if (choice == scripts_symbol)
1868 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1869
1870 script_browse(script_opt);
1871 }
Feng Tang341487ab2013-02-03 14:38:20 +08001872 /* Switch to another data file */
1873 else if (choice == switch_data) {
1874do_data_switch:
1875 if (!switch_data_file()) {
1876 key = K_SWITCH_INPUT_DATA;
1877 break;
1878 } else
1879 ui__warning("Won't switch the data files due to\n"
1880 "no valid data file get selected!\n");
1881 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001882 }
1883out_free_stack:
1884 pstack__delete(fstack);
1885out:
1886 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001887 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001888 return key;
1889}
1890
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001891struct perf_evsel_menu {
1892 struct ui_browser b;
1893 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001894 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001895 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001896 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001897};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001898
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001899static void perf_evsel_menu__write(struct ui_browser *browser,
1900 void *entry, int row)
1901{
1902 struct perf_evsel_menu *menu = container_of(browser,
1903 struct perf_evsel_menu, b);
1904 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1905 bool current_entry = ui_browser__is_current_entry(browser, row);
1906 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001907 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001908 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001909 const char *warn = " ";
1910 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001911
1912 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1913 HE_COLORSET_NORMAL);
1914
Namhyung Kim759ff492013-03-05 14:53:26 +09001915 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001916 struct perf_evsel *pos;
1917
1918 ev_name = perf_evsel__group_name(evsel);
1919
1920 for_each_group_member(pos, evsel) {
1921 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1922 }
1923 }
1924
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001925 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001926 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001927 unit, unit == ' ' ? "" : " ", ev_name);
1928 slsmg_printf("%s", bf);
1929
1930 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1931 if (nr_events != 0) {
1932 menu->lost_events = true;
1933 if (!current_entry)
1934 ui_browser__set_color(browser, HE_COLORSET_TOP);
1935 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001936 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1937 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001938 warn = bf;
1939 }
1940
1941 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001942
1943 if (current_entry)
1944 menu->selection = evsel;
1945}
1946
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001947static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1948 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001949 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001950{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001951 struct perf_evlist *evlist = menu->b.priv;
1952 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001953 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001954 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001955 int key;
1956
1957 if (ui_browser__show(&menu->b, title,
1958 "ESC: exit, ENTER|->: Browse histograms") < 0)
1959 return -1;
1960
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001961 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001962 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001963
1964 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001965 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001966 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001967
1968 if (!menu->lost_events_warned && menu->lost_events) {
1969 ui_browser__warn_lost_events(&menu->b);
1970 menu->lost_events_warned = true;
1971 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001972 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001973 case K_RIGHT:
1974 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001975 if (!menu->selection)
1976 continue;
1977 pos = menu->selection;
1978browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001979 perf_evlist__set_selected(evlist, pos);
1980 /*
1981 * Give the calling tool a chance to populate the non
1982 * default evsel resorted hists tree.
1983 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001984 if (hbt)
1985 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001986 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001987 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001988 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001989 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001990 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001991 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001992 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001993 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001994 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001995 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001996 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001997 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001998 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001999 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002000 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002001 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002002 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002003 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002004 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002005 if (!ui_browser__dialog_yesno(&menu->b,
2006 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002007 continue;
2008 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08002009 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002010 case 'q':
2011 case CTRL('c'):
2012 goto out;
2013 default:
2014 continue;
2015 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002016 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002017 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002018 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002019 if (!ui_browser__dialog_yesno(&menu->b,
2020 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002021 continue;
2022 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002023 case 'q':
2024 case CTRL('c'):
2025 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002026 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002027 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002028 }
2029 }
2030
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002031out:
2032 ui_browser__hide(&menu->b);
2033 return key;
2034}
2035
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002036static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002037 void *entry)
2038{
2039 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2040
2041 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2042 return true;
2043
2044 return false;
2045}
2046
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002047static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002048 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002049 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002050 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002051 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002052{
2053 struct perf_evsel *pos;
2054 struct perf_evsel_menu menu = {
2055 .b = {
2056 .entries = &evlist->entries,
2057 .refresh = ui_browser__list_head_refresh,
2058 .seek = ui_browser__list_head_seek,
2059 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002060 .filter = filter_group_entries,
2061 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002062 .priv = evlist,
2063 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002064 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002065 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002066 };
2067
2068 ui_helpline__push("Press ESC to exit");
2069
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002070 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002071 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002072 size_t line_len = strlen(ev_name) + 7;
2073
2074 if (menu.b.width < line_len)
2075 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002076 }
2077
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002078 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002079}
2080
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002081int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002082 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002083 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002084 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002085{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002086 int nr_entries = evlist->nr_entries;
2087
2088single_entry:
2089 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002090 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002091
2092 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002093 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002094 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002095 }
2096
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002097 if (symbol_conf.event_group) {
2098 struct perf_evsel *pos;
2099
2100 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002101 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002102 if (perf_evsel__is_group_leader(pos))
2103 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002104 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002105
2106 if (nr_entries == 1)
2107 goto single_entry;
2108 }
2109
2110 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002111 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002112}