blob: 02507ba944e32fcda6cf5982e7639fe0d11f0c6c [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 Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020020#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022struct hist_browser {
23 struct ui_browser b;
24 struct hists *hists;
25 struct hist_entry *he_selection;
26 struct map_symbol *selection;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030027 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030028 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020029 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090030 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090031 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090032 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030033};
34
Namhyung Kimf5951d52012-09-03 11:53:09 +090035extern void hist_browser__init_hpp(void);
36
Jiri Olsadd00d482014-06-19 13:41:13 +020037static int hists__browser_title(struct hists *hists, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090038static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030039
Namhyung Kimc3b78952014-04-22 15:56:17 +090040static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090041 float min_pcnt);
42
Namhyung Kim268397c2014-04-22 14:49:31 +090043static bool hist_browser__has_filter(struct hist_browser *hb)
44{
45 return hists__has_filter(hb->hists) || hb->min_pcnt;
46}
47
Namhyung Kimc3b78952014-04-22 15:56:17 +090048static u32 hist_browser__nr_entries(struct hist_browser *hb)
49{
50 u32 nr_entries;
51
52 if (hist_browser__has_filter(hb))
53 nr_entries = hb->nr_non_filtered_entries;
54 else
55 nr_entries = hb->hists->nr_entries;
56
57 return nr_entries + hb->nr_callchain_rows;
58}
59
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020060static void hist_browser__update_rows(struct hist_browser *hb)
61{
62 struct ui_browser *browser = &hb->b;
63 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
64
65 browser->rows = browser->height - header_offset;
66 /*
67 * Verify if we were at the last line and that line isn't
68 * visibe because we now show the header line(s).
69 */
70 index_row = browser->index - browser->top_idx;
71 if (index_row >= browser->rows)
72 browser->index -= index_row - browser->rows + 1;
73}
74
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030075static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030076{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030077 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
78
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030079 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030080 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
81 /*
82 * FIXME: Just keeping existing behaviour, but this really should be
83 * before updating browser->width, as it will invalidate the
84 * calculation above. Fix this and the fallout in another
85 * changeset.
86 */
87 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020088 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030089}
90
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030091static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
92{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020093 u16 header_offset = browser->show_headers ? 1 : 0;
94
95 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030096}
97
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030098static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030099{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900100 /*
101 * The hists__remove_entry_filter() already folds non-filtered
102 * entries so we can assume it has 0 callchain rows.
103 */
104 browser->nr_callchain_rows = 0;
105
Namhyung Kim268397c2014-04-22 14:49:31 +0900106 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900107 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300108 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300109 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300110}
111
112static char tree__folded_sign(bool unfolded)
113{
114 return unfolded ? '-' : '+';
115}
116
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300117static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300118{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300119 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300120}
121
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300122static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300123{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300124 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300125}
126
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300127static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300128{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300129 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300130}
131
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300133{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300134 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300135}
136
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300138{
139 int n = 0;
140 struct rb_node *nd;
141
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300142 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
144 struct callchain_list *chain;
145 char folded_sign = ' '; /* No children */
146
147 list_for_each_entry(chain, &child->val, list) {
148 ++n;
149 /* We need this because we may not have children */
150 folded_sign = callchain_list__folded(chain);
151 if (folded_sign == '+')
152 break;
153 }
154
155 if (folded_sign == '-') /* Have children and they're unfolded */
156 n += callchain_node__count_rows_rb_tree(child);
157 }
158
159 return n;
160}
161
162static int callchain_node__count_rows(struct callchain_node *node)
163{
164 struct callchain_list *chain;
165 bool unfolded = false;
166 int n = 0;
167
168 list_for_each_entry(chain, &node->val, list) {
169 ++n;
170 unfolded = chain->ms.unfolded;
171 }
172
173 if (unfolded)
174 n += callchain_node__count_rows_rb_tree(node);
175
176 return n;
177}
178
179static int callchain__count_rows(struct rb_root *chain)
180{
181 struct rb_node *nd;
182 int n = 0;
183
184 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
185 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
186 n += callchain_node__count_rows(node);
187 }
188
189 return n;
190}
191
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300192static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300193{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300194 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200195 return false;
196
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300197 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300198 return false;
199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300200 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300201 return true;
202}
203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300204static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300205{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300206 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300207
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300208 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300209 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
210 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300211 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300212
213 list_for_each_entry(chain, &child->val, list) {
214 if (first) {
215 first = false;
216 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300217 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300218 } else
219 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300220 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300221 }
222
223 callchain_node__init_have_children_rb_tree(child);
224 }
225}
226
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300227static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300228{
229 struct callchain_list *chain;
230
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300231 list_for_each_entry(chain, &node->val, list)
232 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300233
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300234 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300235}
236
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300237static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300238{
239 struct rb_node *nd;
240
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300241 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300242 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
243 callchain_node__init_have_children(node);
244 }
245}
246
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300247static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300248{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300249 if (!he->init_have_children) {
250 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
251 callchain__init_have_children(&he->sorted_chain);
252 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300253 }
254}
255
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300256static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300257{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300258 if (map_symbol__toggle_fold(browser->selection)) {
259 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300260
261 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900262 browser->b.nr_entries -= he->nr_rows;
263 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300264
265 if (he->ms.unfolded)
266 he->nr_rows = callchain__count_rows(&he->sorted_chain);
267 else
268 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900269
270 browser->b.nr_entries += he->nr_rows;
271 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300272
273 return true;
274 }
275
276 /* If it doesn't have children, no toggling performed */
277 return false;
278}
279
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300280static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300281{
282 int n = 0;
283 struct rb_node *nd;
284
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300285 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300286 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
287 struct callchain_list *chain;
288 bool has_children = false;
289
290 list_for_each_entry(chain, &child->val, list) {
291 ++n;
292 map_symbol__set_folding(&chain->ms, unfold);
293 has_children = chain->ms.has_children;
294 }
295
296 if (has_children)
297 n += callchain_node__set_folding_rb_tree(child, unfold);
298 }
299
300 return n;
301}
302
303static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
304{
305 struct callchain_list *chain;
306 bool has_children = false;
307 int n = 0;
308
309 list_for_each_entry(chain, &node->val, list) {
310 ++n;
311 map_symbol__set_folding(&chain->ms, unfold);
312 has_children = chain->ms.has_children;
313 }
314
315 if (has_children)
316 n += callchain_node__set_folding_rb_tree(node, unfold);
317
318 return n;
319}
320
321static int callchain__set_folding(struct rb_root *chain, bool unfold)
322{
323 struct rb_node *nd;
324 int n = 0;
325
326 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
327 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
328 n += callchain_node__set_folding(node, unfold);
329 }
330
331 return n;
332}
333
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300334static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300335{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300336 hist_entry__init_have_children(he);
337 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300338
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300339 if (he->ms.has_children) {
340 int n = callchain__set_folding(&he->sorted_chain, unfold);
341 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300342 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300343 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300344}
345
Namhyung Kimc3b78952014-04-22 15:56:17 +0900346static void
347__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300348{
349 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900350 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300351
Namhyung Kimc3b78952014-04-22 15:56:17 +0900352 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900353 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900354 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300355 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
356 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900357 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300358 }
359}
360
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300361static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300362{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900363 browser->nr_callchain_rows = 0;
364 __hist_browser__set_folding(browser, unfold);
365
366 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300367 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300369}
370
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200371static void ui_browser__warn_lost_events(struct ui_browser *browser)
372{
373 ui_browser__warning(browser, 4,
374 "Events are being lost, check IO/CPU overload!\n\n"
375 "You may want to run 'perf' using a RT scheduler policy:\n\n"
376 " perf top -r 80\n\n"
377 "Or reduce the sampling frequency.");
378}
379
Jiri Olsadd00d482014-06-19 13:41:13 +0200380static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900381 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300382{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300383 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300384 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900385 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300386
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300387 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900388 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300389
Jiri Olsadd00d482014-06-19 13:41:13 +0200390 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300391
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300392 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300393 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394 return -1;
395
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300396 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300397 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300398
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300399 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900400 case K_TIMER: {
401 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900402 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900403
Namhyung Kimc3b78952014-04-22 15:56:17 +0900404 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900405 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900406
Namhyung Kimc3b78952014-04-22 15:56:17 +0900407 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900408 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200409
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300410 if (browser->hists->stats.nr_lost_warned !=
411 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
412 browser->hists->stats.nr_lost_warned =
413 browser->hists->stats.nr_events[PERF_RECORD_LOST];
414 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200415 }
416
Jiri Olsadd00d482014-06-19 13:41:13 +0200417 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300418 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300419 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900420 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300421 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300422 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300423 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300424 struct hist_entry, rb_node);
425 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300426 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 -0300427 seq++, browser->b.nr_entries,
428 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300429 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300430 browser->b.index,
431 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300432 h->row_offset, h->nr_rows);
433 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300434 break;
435 case 'C':
436 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300437 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300438 break;
439 case 'E':
440 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300441 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300442 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200443 case 'H':
444 browser->show_headers = !browser->show_headers;
445 hist_browser__update_rows(browser);
446 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200447 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300448 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300449 break;
450 /* fall thru */
451 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300452 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300453 }
454 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300455out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300456 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300457 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300458}
459
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300460static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300461 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300462{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300463 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300464
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300465 if (cl->ms.sym)
466 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
467 else
468 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
469
470 if (show_dso)
471 scnprintf(bf + printed, bfsize - printed, " %s",
472 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
473
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300474 return bf;
475}
476
477#define LEVEL_OFFSET_STEP 3
478
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300479static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300480 struct callchain_node *chain_node,
481 u64 total, int level,
482 unsigned short row,
483 off_t *row_offset,
484 bool *is_current_entry)
485{
486 struct rb_node *node;
487 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
488 u64 new_total, remaining;
489
490 if (callchain_param.mode == CHAIN_GRAPH_REL)
491 new_total = chain_node->children_hit;
492 else
493 new_total = total;
494
495 remaining = new_total;
496 node = rb_first(&chain_node->rb_root);
497 while (node) {
498 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
499 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100500 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300501 struct callchain_list *chain;
502 char folded_sign = ' ';
503 int first = true;
504 int extra_offset = 0;
505
506 remaining -= cumul;
507
508 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300509 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300510 const char *str;
511 int color;
512 bool was_first = first;
513
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300514 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300515 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300516 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300517 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300518
519 folded_sign = callchain_list__folded(chain);
520 if (*row_offset != 0) {
521 --*row_offset;
522 goto do_next;
523 }
524
525 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300526 str = callchain_list__sym_name(chain, bf, sizeof(bf),
527 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300528 if (was_first) {
529 double percent = cumul * 100.0 / new_total;
530
531 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
532 str = "Not enough memory!";
533 else
534 str = alloc_str;
535 }
536
537 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300538 width = browser->b.width - (offset + extra_offset + 2);
539 if (ui_browser__is_current_entry(&browser->b, row)) {
540 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300541 color = HE_COLORSET_SELECTED;
542 *is_current_entry = true;
543 }
544
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300545 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300546 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300547 slsmg_write_nstring(" ", offset + extra_offset);
548 slsmg_printf("%c ", folded_sign);
549 slsmg_write_nstring(str, width);
550 free(alloc_str);
551
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300552 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300553 goto out;
554do_next:
555 if (folded_sign == '+')
556 break;
557 }
558
559 if (folded_sign == '-') {
560 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300561 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300562 new_level, row, row_offset,
563 is_current_entry);
564 }
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300565 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300566 goto out;
567 node = next;
568 }
569out:
570 return row - first_row;
571}
572
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300573static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300574 struct callchain_node *node,
575 int level, unsigned short row,
576 off_t *row_offset,
577 bool *is_current_entry)
578{
579 struct callchain_list *chain;
580 int first_row = row,
581 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300582 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300583 char folded_sign = ' ';
584
585 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300586 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300587 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300588
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300589 folded_sign = callchain_list__folded(chain);
590
591 if (*row_offset != 0) {
592 --*row_offset;
593 continue;
594 }
595
596 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300597 if (ui_browser__is_current_entry(&browser->b, row)) {
598 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300599 color = HE_COLORSET_SELECTED;
600 *is_current_entry = true;
601 }
602
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300603 s = callchain_list__sym_name(chain, bf, sizeof(bf),
604 browser->show_dso);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300605 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300606 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607 slsmg_write_nstring(" ", offset);
608 slsmg_printf("%c ", folded_sign);
609 slsmg_write_nstring(s, width - 2);
610
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300611 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300612 goto out;
613 }
614
615 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300616 row += hist_browser__show_callchain_node_rb_tree(browser, node,
617 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300618 level + 1, row,
619 row_offset,
620 is_current_entry);
621out:
622 return row - first_row;
623}
624
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300625static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300626 struct rb_root *chain,
627 int level, unsigned short row,
628 off_t *row_offset,
629 bool *is_current_entry)
630{
631 struct rb_node *nd;
632 int first_row = row;
633
634 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
635 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
636
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300637 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300638 row, row_offset,
639 is_current_entry);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300640 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300641 break;
642 }
643
644 return row - first_row;
645}
646
Namhyung Kim89701462013-01-22 18:09:38 +0900647struct hpp_arg {
648 struct ui_browser *b;
649 char folded_sign;
650 bool current_entry;
651};
652
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900653static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
654{
655 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900656 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900657 va_list args;
658 double percent;
659
660 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900661 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900662 percent = va_arg(args, double);
663 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900664
Namhyung Kim89701462013-01-22 18:09:38 +0900665 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900666
Namhyung Kimd6751072014-07-31 14:47:36 +0900667 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900668 slsmg_printf("%s", hpp->buf);
669
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900670 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900671 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900672}
673
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900674#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900675static u64 __hpp_get_##_field(struct hist_entry *he) \
676{ \
677 return he->stat._field; \
678} \
679 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100680static int \
681hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
682 struct perf_hpp *hpp, \
683 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900684{ \
Namhyung Kimd6751072014-07-31 14:47:36 +0900685 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %*.2f%%", 6, \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900686 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900687}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900688
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900689#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
690static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
691{ \
692 return he->stat_acc->_field; \
693} \
694 \
695static int \
696hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
697 struct perf_hpp *hpp, \
698 struct hist_entry *he) \
699{ \
700 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kimd6751072014-07-31 14:47:36 +0900701 int ret = scnprintf(hpp->buf, hpp->size, \
702 "%*s", 8, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900703 slsmg_printf("%s", hpp->buf); \
704 \
705 return ret; \
706 } \
Namhyung Kimd6751072014-07-31 14:47:36 +0900707 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %*.2f%%", \
708 6, __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900709}
710
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900711__HPP_COLOR_PERCENT_FN(overhead, period)
712__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
713__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
714__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
715__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900716__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900717
718#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900719#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900720
721void hist_browser__init_hpp(void)
722{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900723 perf_hpp__format[PERF_HPP__OVERHEAD].color =
724 hist_browser__hpp_color_overhead;
725 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
726 hist_browser__hpp_color_overhead_sys;
727 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
728 hist_browser__hpp_color_overhead_us;
729 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
730 hist_browser__hpp_color_overhead_guest_sys;
731 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
732 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900733 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
734 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900735}
736
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300737static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300738 struct hist_entry *entry,
739 unsigned short row)
740{
741 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200742 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900743 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300744 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300745 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300746 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300747 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200748 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300749
750 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300751 browser->he_selection = entry;
752 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300753 }
754
755 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300756 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300757 folded_sign = hist_entry__folded(entry);
758 }
759
760 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900761 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900762 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900763 .folded_sign = folded_sign,
764 .current_entry = current_entry,
765 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900766 struct perf_hpp hpp = {
767 .buf = s,
768 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900769 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900770 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300771
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300772 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900773
Jiri Olsa12400052012-10-13 00:06:16 +0200774 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900775 if (perf_hpp__should_skip(fmt))
776 continue;
777
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900778 if (current_entry && browser->b.navkeypressed) {
779 ui_browser__set_color(&browser->b,
780 HE_COLORSET_SELECTED);
781 } else {
782 ui_browser__set_color(&browser->b,
783 HE_COLORSET_NORMAL);
784 }
785
786 if (first) {
787 if (symbol_conf.use_callchain) {
788 slsmg_printf("%c ", folded_sign);
789 width -= 2;
790 }
791 first = false;
792 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900793 slsmg_printf(" ");
794 width -= 2;
795 }
796
Jiri Olsa12400052012-10-13 00:06:16 +0200797 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100798 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900799 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100800 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900801 slsmg_printf("%s", s);
802 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300803 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200804
805 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300806 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200807 width += 1;
808
Namhyung Kim26d8b332014-03-03 16:16:20 +0900809 slsmg_write_nstring("", width);
810
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300811 ++row;
812 ++printed;
813 } else
814 --row_offset;
815
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300816 if (folded_sign == '-' && row != browser->b.rows) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300817 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300818 1, row, &row_offset,
819 &current_entry);
820 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300821 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300822 }
823
824 return printed;
825}
826
Jiri Olsa81a888f2014-06-14 15:44:52 +0200827static int advance_hpp_check(struct perf_hpp *hpp, int inc)
828{
829 advance_hpp(hpp, inc);
830 return hpp->size <= 0;
831}
832
833static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
834{
835 struct perf_hpp dummy_hpp = {
836 .buf = buf,
837 .size = size,
838 };
839 struct perf_hpp_fmt *fmt;
840 size_t ret = 0;
841
842 if (symbol_conf.use_callchain) {
843 ret = scnprintf(buf, size, " ");
844 if (advance_hpp_check(&dummy_hpp, ret))
845 return ret;
846 }
847
848 perf_hpp__for_each_format(fmt) {
849 if (perf_hpp__should_skip(fmt))
850 continue;
851
852 /* We need to add the length of the columns header. */
853 perf_hpp__reset_width(fmt, hists);
854
855 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;
1086 u64 new_total, remaining;
1087 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
1094 remaining = new_total;
1095 node = rb_first(&chain_node->rb_root);
1096 while (node) {
1097 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1098 struct rb_node *next = rb_next(node);
1099 u64 cumul = callchain_cumul_hits(child);
1100 struct callchain_list *chain;
1101 char folded_sign = ' ';
1102 int first = true;
1103 int extra_offset = 0;
1104
1105 remaining -= cumul;
1106
1107 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001108 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001109 const char *str;
1110 bool was_first = first;
1111
1112 if (first)
1113 first = false;
1114 else
1115 extra_offset = LEVEL_OFFSET_STEP;
1116
1117 folded_sign = callchain_list__folded(chain);
1118
1119 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001120 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1121 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001122 if (was_first) {
1123 double percent = cumul * 100.0 / new_total;
1124
1125 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1126 str = "Not enough memory!";
1127 else
1128 str = alloc_str;
1129 }
1130
1131 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1132 free(alloc_str);
1133 if (folded_sign == '+')
1134 break;
1135 }
1136
1137 if (folded_sign == '-') {
1138 const int new_level = level + (extra_offset ? 2 : 1);
1139 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1140 new_level, fp);
1141 }
1142
1143 node = next;
1144 }
1145
1146 return printed;
1147}
1148
1149static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1150 struct callchain_node *node,
1151 int level, FILE *fp)
1152{
1153 struct callchain_list *chain;
1154 int offset = level * LEVEL_OFFSET_STEP;
1155 char folded_sign = ' ';
1156 int printed = 0;
1157
1158 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001159 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001160
1161 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001162 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001163 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1164 }
1165
1166 if (folded_sign == '-')
1167 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1168 browser->hists->stats.total_period,
1169 level + 1, fp);
1170 return printed;
1171}
1172
1173static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1174 struct rb_root *chain, int level, FILE *fp)
1175{
1176 struct rb_node *nd;
1177 int printed = 0;
1178
1179 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1180 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1181
1182 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1183 }
1184
1185 return printed;
1186}
1187
1188static int hist_browser__fprintf_entry(struct hist_browser *browser,
1189 struct hist_entry *he, FILE *fp)
1190{
1191 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001192 int printed = 0;
1193 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001194 struct perf_hpp hpp = {
1195 .buf = s,
1196 .size = sizeof(s),
1197 };
1198 struct perf_hpp_fmt *fmt;
1199 bool first = true;
1200 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001201
1202 if (symbol_conf.use_callchain)
1203 folded_sign = hist_entry__folded(he);
1204
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001205 if (symbol_conf.use_callchain)
1206 printed += fprintf(fp, "%c ", folded_sign);
1207
Namhyung Kim26d8b332014-03-03 16:16:20 +09001208 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001209 if (perf_hpp__should_skip(fmt))
1210 continue;
1211
Namhyung Kim26d8b332014-03-03 16:16:20 +09001212 if (!first) {
1213 ret = scnprintf(hpp.buf, hpp.size, " ");
1214 advance_hpp(&hpp, ret);
1215 } else
1216 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001217
Namhyung Kim26d8b332014-03-03 16:16:20 +09001218 ret = fmt->entry(fmt, &hpp, he);
1219 advance_hpp(&hpp, ret);
1220 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001221 printed += fprintf(fp, "%s\n", rtrim(s));
1222
1223 if (folded_sign == '-')
1224 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1225
1226 return printed;
1227}
1228
1229static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1230{
Namhyung Kim064f1982013-05-14 11:09:04 +09001231 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001232 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001233 int printed = 0;
1234
1235 while (nd) {
1236 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1237
1238 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001239 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001240 }
1241
1242 return printed;
1243}
1244
1245static int hist_browser__dump(struct hist_browser *browser)
1246{
1247 char filename[64];
1248 FILE *fp;
1249
1250 while (1) {
1251 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1252 if (access(filename, F_OK))
1253 break;
1254 /*
1255 * XXX: Just an arbitrary lazy upper limit
1256 */
1257 if (++browser->print_seq == 8192) {
1258 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1259 return -1;
1260 }
1261 }
1262
1263 fp = fopen(filename, "w");
1264 if (fp == NULL) {
1265 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001266 const char *err = strerror_r(errno, bf, sizeof(bf));
1267 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001268 return -1;
1269 }
1270
1271 ++browser->print_seq;
1272 hist_browser__fprintf(browser, fp);
1273 fclose(fp);
1274 ui_helpline__fpush("%s written!", filename);
1275
1276 return 0;
1277}
1278
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001279static struct hist_browser *hist_browser__new(struct hists *hists)
1280{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001281 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001282
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001283 if (browser) {
1284 browser->hists = hists;
1285 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001286 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001287 browser->b.seek = ui_browser__hists_seek;
1288 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001289 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001290 }
1291
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001292 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001293}
1294
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001295static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001296{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001297 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001298}
1299
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001300static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001301{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001302 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001303}
1304
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001305static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001306{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001307 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001308}
1309
Jiri Olsadd00d482014-06-19 13:41:13 +02001310static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001311{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001312 char unit;
1313 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001314 const struct dso *dso = hists->dso_filter;
1315 const struct thread *thread = hists->thread_filter;
1316 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1317 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001318 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001319 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001320 char buf[512];
1321 size_t buflen = sizeof(buf);
1322
Namhyung Kimf2148332014-01-14 11:52:48 +09001323 if (symbol_conf.filter_relative) {
1324 nr_samples = hists->stats.nr_non_filtered_samples;
1325 nr_events = hists->stats.total_non_filtered_period;
1326 }
1327
Namhyung Kim759ff492013-03-05 14:53:26 +09001328 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001329 struct perf_evsel *pos;
1330
1331 perf_evsel__group_desc(evsel, buf, buflen);
1332 ev_name = buf;
1333
1334 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001335 if (symbol_conf.filter_relative) {
1336 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1337 nr_events += pos->hists.stats.total_non_filtered_period;
1338 } else {
1339 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1340 nr_events += pos->hists.stats.total_period;
1341 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001342 }
1343 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001344
Ashay Ranecc686282012-04-05 21:01:01 -05001345 nr_samples = convert_unit(nr_samples, &unit);
1346 printed = scnprintf(bf, size,
1347 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1348 nr_samples, unit, ev_name, nr_events);
1349
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001350
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001351 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001352 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001353 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001354 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001355 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001356 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001357 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001358 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001359 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001360 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001361 ", DSO: %s", dso->short_name);
1362 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001363}
1364
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001365static inline void free_popup_options(char **options, int n)
1366{
1367 int i;
1368
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001369 for (i = 0; i < n; ++i)
1370 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001371}
1372
Feng Tangc77d8d72012-11-01 00:00:55 +08001373/* Check whether the browser is for 'top' or 'report' */
1374static inline bool is_report_browser(void *timer)
1375{
1376 return timer == NULL;
1377}
1378
Feng Tang341487ab2013-02-03 14:38:20 +08001379/*
1380 * Only runtime switching of perf data file will make "input_name" point
1381 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1382 * whether we need to call free() for current "input_name" during the switch.
1383 */
1384static bool is_input_name_malloced = false;
1385
1386static int switch_data_file(void)
1387{
1388 char *pwd, *options[32], *abs_path[32], *tmp;
1389 DIR *pwd_dir;
1390 int nr_options = 0, choice = -1, ret = -1;
1391 struct dirent *dent;
1392
1393 pwd = getenv("PWD");
1394 if (!pwd)
1395 return ret;
1396
1397 pwd_dir = opendir(pwd);
1398 if (!pwd_dir)
1399 return ret;
1400
1401 memset(options, 0, sizeof(options));
1402 memset(options, 0, sizeof(abs_path));
1403
1404 while ((dent = readdir(pwd_dir))) {
1405 char path[PATH_MAX];
1406 u64 magic;
1407 char *name = dent->d_name;
1408 FILE *file;
1409
1410 if (!(dent->d_type == DT_REG))
1411 continue;
1412
1413 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1414
1415 file = fopen(path, "r");
1416 if (!file)
1417 continue;
1418
1419 if (fread(&magic, 1, 8, file) < 8)
1420 goto close_file_and_continue;
1421
1422 if (is_perf_magic(magic)) {
1423 options[nr_options] = strdup(name);
1424 if (!options[nr_options])
1425 goto close_file_and_continue;
1426
1427 abs_path[nr_options] = strdup(path);
1428 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001429 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001430 ui__warning("Can't search all data files due to memory shortage.\n");
1431 fclose(file);
1432 break;
1433 }
1434
1435 nr_options++;
1436 }
1437
1438close_file_and_continue:
1439 fclose(file);
1440 if (nr_options >= 32) {
1441 ui__warning("Too many perf data files in PWD!\n"
1442 "Only the first 32 files will be listed.\n");
1443 break;
1444 }
1445 }
1446 closedir(pwd_dir);
1447
1448 if (nr_options) {
1449 choice = ui__popup_menu(nr_options, options);
1450 if (choice < nr_options && choice >= 0) {
1451 tmp = strdup(abs_path[choice]);
1452 if (tmp) {
1453 if (is_input_name_malloced)
1454 free((void *)input_name);
1455 input_name = tmp;
1456 is_input_name_malloced = true;
1457 ret = 0;
1458 } else
1459 ui__warning("Data switch failed due to memory shortage!\n");
1460 }
1461 }
1462
1463 free_popup_options(options, nr_options);
1464 free_popup_options(abs_path, nr_options);
1465 return ret;
1466}
1467
Namhyung Kim112f7612014-04-22 14:05:35 +09001468static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001469{
1470 u64 nr_entries = 0;
1471 struct rb_node *nd = rb_first(&hb->hists->entries);
1472
Namhyung Kim268397c2014-04-22 14:49:31 +09001473 if (hb->min_pcnt == 0) {
1474 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1475 return;
1476 }
1477
Namhyung Kim14135662013-10-31 10:17:39 +09001478 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001479 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001480 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001481 }
1482
Namhyung Kim112f7612014-04-22 14:05:35 +09001483 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001484}
Feng Tang341487ab2013-02-03 14:38:20 +08001485
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001486static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001487 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001488 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001489 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001490 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001491 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001492{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001493 struct hists *hists = &evsel->hists;
1494 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001495 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001496 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001497 char *options[16];
1498 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001499 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001500 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001501 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001502 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001503
Namhyung Kime8e684a2013-12-26 14:37:58 +09001504#define HIST_BROWSER_HELP_COMMON \
1505 "h/?/F1 Show this window\n" \
1506 "UP/DOWN/PGUP\n" \
1507 "PGDN/SPACE Navigate\n" \
1508 "q/ESC/CTRL+C Exit browser\n\n" \
1509 "For multiple event sessions:\n\n" \
1510 "TAB/UNTAB Switch events\n\n" \
1511 "For symbolic views (--sort has sym):\n\n" \
1512 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1513 "<- Zoom out\n" \
1514 "a Annotate current symbol\n" \
1515 "C Collapse all callchains\n" \
1516 "d Zoom into current DSO\n" \
1517 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001518 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001519 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001520
1521 /* help messages are sorted by lexical order of the hotkey */
1522 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001523 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001524 "P Print histograms to perf.hist.N\n"
1525 "r Run available scripts\n"
1526 "s Switch to another data file in PWD\n"
1527 "t Zoom into current Thread\n"
1528 "V Verbose (DSO names in callchains, etc)\n"
1529 "/ Filter symbol by name";
1530 const char top_help[] = HIST_BROWSER_HELP_COMMON
1531 "P Print histograms to perf.hist.N\n"
1532 "t Zoom into current Thread\n"
1533 "V Verbose (DSO names in callchains, etc)\n"
1534 "/ Filter symbol by name";
1535
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001536 if (browser == NULL)
1537 return -1;
1538
Namhyung Kim064f1982013-05-14 11:09:04 +09001539 if (min_pcnt) {
1540 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001541 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001542 }
1543
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001544 fstack = pstack__new(2);
1545 if (fstack == NULL)
1546 goto out;
1547
1548 ui_helpline__push(helpline);
1549
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001550 memset(options, 0, sizeof(options));
1551
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001552 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001553 const struct thread *thread = NULL;
1554 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001555 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001556 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001557 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001558 int scripts_comm = -2, scripts_symbol = -2,
1559 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001560
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001561 nr_options = 0;
1562
Jiri Olsadd00d482014-06-19 13:41:13 +02001563 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001564
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001565 if (browser->he_selection != NULL) {
1566 thread = hist_browser__selected_thread(browser);
1567 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1568 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001569 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001570 case K_TAB:
1571 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001572 if (nr_events == 1)
1573 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001574 /*
1575 * Exit the browser, let hists__browser_tree
1576 * go to the next or previous
1577 */
1578 goto out_free_stack;
1579 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001580 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001581 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001582 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001583 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001584 continue;
1585 }
1586
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001587 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001588 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001589 browser->selection->map->dso->annotate_warned)
1590 continue;
1591 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001592 case 'P':
1593 hist_browser__dump(browser);
1594 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001595 case 'd':
1596 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001597 case 'V':
1598 browser->show_dso = !browser->show_dso;
1599 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001600 case 't':
1601 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001602 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001603 if (ui_browser__input_window("Symbol to show",
1604 "Please enter the name of symbol you want to see",
1605 buf, "ENTER: OK, ESC: Cancel",
1606 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001607 hists->symbol_filter_str = *buf ? buf : NULL;
1608 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001609 hist_browser__reset(browser);
1610 }
1611 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001612 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001613 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001614 goto do_scripts;
1615 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001616 case 's':
1617 if (is_report_browser(hbt))
1618 goto do_data_switch;
1619 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001620 case 'i':
1621 /* env->arch is NULL for live-mode (i.e. perf top) */
1622 if (env->arch)
1623 tui__header_window(env);
1624 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001625 case 'F':
1626 symbol_conf.filter_relative ^= 1;
1627 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001628 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001629 case 'h':
1630 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001631 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001632 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001633 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001634 case K_ENTER:
1635 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001636 /* menu */
1637 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001638 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001639 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001640
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001641 if (pstack__empty(fstack)) {
1642 /*
1643 * Go back to the perf_evsel_menu__run or other user
1644 */
1645 if (left_exits)
1646 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001647 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001648 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001649 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001650 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001651 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001652 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001653 goto zoom_out_thread;
1654 continue;
1655 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001656 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001657 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001658 !ui_browser__dialog_yesno(&browser->b,
1659 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001660 continue;
1661 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001662 case 'q':
1663 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001664 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001665 default:
1666 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001667 }
1668
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001669 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001670 goto add_exit_option;
1671
Namhyung Kim55369fc2013-04-01 20:35:20 +09001672 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001673 bi = browser->he_selection->branch_info;
1674 if (browser->selection != NULL &&
1675 bi &&
1676 bi->from.sym != NULL &&
1677 !bi->from.map->dso->annotate_warned &&
1678 asprintf(&options[nr_options], "Annotate %s",
1679 bi->from.sym->name) > 0)
1680 annotate_f = nr_options++;
1681
1682 if (browser->selection != NULL &&
1683 bi &&
1684 bi->to.sym != NULL &&
1685 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001686 (bi->to.sym != bi->from.sym ||
1687 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001688 asprintf(&options[nr_options], "Annotate %s",
1689 bi->to.sym->name) > 0)
1690 annotate_t = nr_options++;
1691 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001692 if (browser->selection != NULL &&
1693 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001694 !browser->selection->map->dso->annotate_warned) {
1695 struct annotation *notes;
1696
1697 notes = symbol__annotation(browser->selection->sym);
1698
1699 if (notes->src &&
1700 asprintf(&options[nr_options], "Annotate %s",
1701 browser->selection->sym->name) > 0)
1702 annotate = nr_options++;
1703 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001704 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001705
1706 if (thread != NULL &&
1707 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001708 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001709 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001710 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001711 zoom_thread = nr_options++;
1712
1713 if (dso != NULL &&
1714 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001715 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001716 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1717 zoom_dso = nr_options++;
1718
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001719 if (browser->selection != NULL &&
1720 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001721 asprintf(&options[nr_options], "Browse map details") > 0)
1722 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001723
1724 /* perf script support */
1725 if (browser->he_selection) {
1726 struct symbol *sym;
1727
1728 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001729 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001730 scripts_comm = nr_options++;
1731
1732 sym = browser->he_selection->ms.sym;
1733 if (sym && sym->namelen &&
1734 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1735 sym->name) > 0)
1736 scripts_symbol = nr_options++;
1737 }
1738
1739 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1740 scripts_all = nr_options++;
1741
Feng Tang341487ab2013-02-03 14:38:20 +08001742 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1743 "Switch to another data file in PWD") > 0)
1744 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001745add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001746 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001747retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001748 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001749
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001750 if (choice == nr_options - 1)
1751 break;
1752
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001753 if (choice == -1) {
1754 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001755 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001756 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001758 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001759 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001760 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001761 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001762do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001763 if (!objdump_path && perf_session_env__lookup_objdump(env))
1764 continue;
1765
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766 he = hist_browser__selected_entry(browser);
1767 if (he == NULL)
1768 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001769
1770 /*
1771 * we stash the branch_info symbol + map into the
1772 * the ms so we don't have to rewrite all the annotation
1773 * code to use branch_info.
1774 * in branch mode, the ms struct is not used
1775 */
1776 if (choice == annotate_f) {
1777 he->ms.sym = he->branch_info->from.sym;
1778 he->ms.map = he->branch_info->from.map;
1779 } else if (choice == annotate_t) {
1780 he->ms.sym = he->branch_info->to.sym;
1781 he->ms.map = he->branch_info->to.map;
1782 }
1783
Jiri Olsad7553302014-06-15 10:22:15 +02001784 notes = symbol__annotation(he->ms.sym);
1785 if (!notes->src)
1786 continue;
1787
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001788 /*
1789 * Don't let this be freed, say, by hists__decay_entry.
1790 */
1791 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001792 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001793 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001794 /*
1795 * offer option to annotate the other branch source or target
1796 * (if they exists) when returning from annotate
1797 */
1798 if ((err == 'q' || err == CTRL('c'))
1799 && annotate_t != -2 && annotate_f != -2)
1800 goto retry_popup_menu;
1801
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001802 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001803 if (err)
1804 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001805
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001806 } else if (choice == browse_map)
1807 map__browse(browser->selection->map);
1808 else if (choice == zoom_dso) {
1809zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001810 if (browser->hists->dso_filter) {
1811 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001812zoom_out_dso:
1813 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001814 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001815 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001816 } else {
1817 if (dso == NULL)
1818 continue;
1819 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1820 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001821 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001822 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001823 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001824 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001825 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001826 hist_browser__reset(browser);
1827 } else if (choice == zoom_thread) {
1828zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001829 if (browser->hists->thread_filter) {
1830 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001831zoom_out_thread:
1832 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001833 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001834 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001835 } else {
1836 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001837 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001838 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001839 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001840 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001841 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001842 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001843 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001844 hist_browser__reset(browser);
1845 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001846 /* perf scripts support */
1847 else if (choice == scripts_all || choice == scripts_comm ||
1848 choice == scripts_symbol) {
1849do_scripts:
1850 memset(script_opt, 0, 64);
1851
1852 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001853 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001854
1855 if (choice == scripts_symbol)
1856 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1857
1858 script_browse(script_opt);
1859 }
Feng Tang341487ab2013-02-03 14:38:20 +08001860 /* Switch to another data file */
1861 else if (choice == switch_data) {
1862do_data_switch:
1863 if (!switch_data_file()) {
1864 key = K_SWITCH_INPUT_DATA;
1865 break;
1866 } else
1867 ui__warning("Won't switch the data files due to\n"
1868 "no valid data file get selected!\n");
1869 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001870 }
1871out_free_stack:
1872 pstack__delete(fstack);
1873out:
1874 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001875 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001876 return key;
1877}
1878
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001879struct perf_evsel_menu {
1880 struct ui_browser b;
1881 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001882 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001883 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001884 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001885};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001886
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001887static void perf_evsel_menu__write(struct ui_browser *browser,
1888 void *entry, int row)
1889{
1890 struct perf_evsel_menu *menu = container_of(browser,
1891 struct perf_evsel_menu, b);
1892 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1893 bool current_entry = ui_browser__is_current_entry(browser, row);
1894 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001895 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001896 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001897 const char *warn = " ";
1898 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001899
1900 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1901 HE_COLORSET_NORMAL);
1902
Namhyung Kim759ff492013-03-05 14:53:26 +09001903 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001904 struct perf_evsel *pos;
1905
1906 ev_name = perf_evsel__group_name(evsel);
1907
1908 for_each_group_member(pos, evsel) {
1909 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1910 }
1911 }
1912
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001913 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001914 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001915 unit, unit == ' ' ? "" : " ", ev_name);
1916 slsmg_printf("%s", bf);
1917
1918 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1919 if (nr_events != 0) {
1920 menu->lost_events = true;
1921 if (!current_entry)
1922 ui_browser__set_color(browser, HE_COLORSET_TOP);
1923 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001924 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1925 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001926 warn = bf;
1927 }
1928
1929 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001930
1931 if (current_entry)
1932 menu->selection = evsel;
1933}
1934
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001935static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1936 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001937 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001938{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001939 struct perf_evlist *evlist = menu->b.priv;
1940 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001941 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001942 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001943 int key;
1944
1945 if (ui_browser__show(&menu->b, title,
1946 "ESC: exit, ENTER|->: Browse histograms") < 0)
1947 return -1;
1948
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001949 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001950 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001951
1952 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001953 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001954 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001955
1956 if (!menu->lost_events_warned && menu->lost_events) {
1957 ui_browser__warn_lost_events(&menu->b);
1958 menu->lost_events_warned = true;
1959 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001960 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001961 case K_RIGHT:
1962 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001963 if (!menu->selection)
1964 continue;
1965 pos = menu->selection;
1966browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001967 perf_evlist__set_selected(evlist, pos);
1968 /*
1969 * Give the calling tool a chance to populate the non
1970 * default evsel resorted hists tree.
1971 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001972 if (hbt)
1973 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001974 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001975 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001976 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001977 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001978 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001979 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001980 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001981 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001982 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001983 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001984 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001985 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001986 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001987 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001988 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001989 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001990 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001991 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001992 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001993 if (!ui_browser__dialog_yesno(&menu->b,
1994 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001995 continue;
1996 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001997 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001998 case 'q':
1999 case CTRL('c'):
2000 goto out;
2001 default:
2002 continue;
2003 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002004 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002005 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002006 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002007 if (!ui_browser__dialog_yesno(&menu->b,
2008 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002009 continue;
2010 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002011 case 'q':
2012 case CTRL('c'):
2013 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002014 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002015 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002016 }
2017 }
2018
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002019out:
2020 ui_browser__hide(&menu->b);
2021 return key;
2022}
2023
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002024static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002025 void *entry)
2026{
2027 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2028
2029 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2030 return true;
2031
2032 return false;
2033}
2034
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002035static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002036 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002037 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002038 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002039 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002040{
2041 struct perf_evsel *pos;
2042 struct perf_evsel_menu menu = {
2043 .b = {
2044 .entries = &evlist->entries,
2045 .refresh = ui_browser__list_head_refresh,
2046 .seek = ui_browser__list_head_seek,
2047 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002048 .filter = filter_group_entries,
2049 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002050 .priv = evlist,
2051 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002052 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002053 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002054 };
2055
2056 ui_helpline__push("Press ESC to exit");
2057
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002058 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002059 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002060 size_t line_len = strlen(ev_name) + 7;
2061
2062 if (menu.b.width < line_len)
2063 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002064 }
2065
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002066 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002067}
2068
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002069int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002070 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002071 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002072 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002073{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002074 int nr_entries = evlist->nr_entries;
2075
2076single_entry:
2077 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002078 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002079
2080 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002081 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002082 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002083 }
2084
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002085 if (symbol_conf.event_group) {
2086 struct perf_evsel *pos;
2087
2088 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002089 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002090 if (perf_evsel__is_group_leader(pos))
2091 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002092 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002093
2094 if (nr_entries == 1)
2095 goto single_entry;
2096 }
2097
2098 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002099 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002100}