blob: e07d4e848d5c4a3a4a9cd808d555cfbc21c7843b [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 \
Namhyung Kim5b591662014-07-31 14:47:38 +0900681hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100682 struct perf_hpp *hpp, \
683 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900684{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900685 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
686 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900687}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900688
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900689#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
690static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
691{ \
692 return he->stat_acc->_field; \
693} \
694 \
695static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900696hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900697 struct perf_hpp *hpp, \
698 struct hist_entry *he) \
699{ \
700 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900701 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900702 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900703 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900704 slsmg_printf("%s", hpp->buf); \
705 \
706 return ret; \
707 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900708 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
709 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900710}
711
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900712__HPP_COLOR_PERCENT_FN(overhead, period)
713__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
714__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
715__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
716__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900717__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900718
719#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900720#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900721
722void hist_browser__init_hpp(void)
723{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900724 perf_hpp__format[PERF_HPP__OVERHEAD].color =
725 hist_browser__hpp_color_overhead;
726 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
727 hist_browser__hpp_color_overhead_sys;
728 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
729 hist_browser__hpp_color_overhead_us;
730 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
731 hist_browser__hpp_color_overhead_guest_sys;
732 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
733 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900734 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
735 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900736}
737
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300738static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300739 struct hist_entry *entry,
740 unsigned short row)
741{
742 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200743 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900744 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300745 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300746 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300747 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300748 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200749 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300750
751 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300752 browser->he_selection = entry;
753 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300754 }
755
756 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300757 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300758 folded_sign = hist_entry__folded(entry);
759 }
760
761 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900762 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900763 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900764 .folded_sign = folded_sign,
765 .current_entry = current_entry,
766 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900767 struct perf_hpp hpp = {
768 .buf = s,
769 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900770 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900771 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300772
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300773 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900774
Jiri Olsa12400052012-10-13 00:06:16 +0200775 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900776 if (perf_hpp__should_skip(fmt))
777 continue;
778
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900779 if (current_entry && browser->b.navkeypressed) {
780 ui_browser__set_color(&browser->b,
781 HE_COLORSET_SELECTED);
782 } else {
783 ui_browser__set_color(&browser->b,
784 HE_COLORSET_NORMAL);
785 }
786
787 if (first) {
788 if (symbol_conf.use_callchain) {
789 slsmg_printf("%c ", folded_sign);
790 width -= 2;
791 }
792 first = false;
793 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900794 slsmg_printf(" ");
795 width -= 2;
796 }
797
Jiri Olsa12400052012-10-13 00:06:16 +0200798 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100799 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900800 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100801 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900802 slsmg_printf("%s", s);
803 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300804 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200805
806 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300807 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200808 width += 1;
809
Namhyung Kim26d8b332014-03-03 16:16:20 +0900810 slsmg_write_nstring("", width);
811
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300812 ++row;
813 ++printed;
814 } else
815 --row_offset;
816
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300817 if (folded_sign == '-' && row != browser->b.rows) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300818 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300819 1, row, &row_offset,
820 &current_entry);
821 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300822 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300823 }
824
825 return printed;
826}
827
Jiri Olsa81a888f2014-06-14 15:44:52 +0200828static int advance_hpp_check(struct perf_hpp *hpp, int inc)
829{
830 advance_hpp(hpp, inc);
831 return hpp->size <= 0;
832}
833
834static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
835{
836 struct perf_hpp dummy_hpp = {
837 .buf = buf,
838 .size = size,
839 };
840 struct perf_hpp_fmt *fmt;
841 size_t ret = 0;
842
843 if (symbol_conf.use_callchain) {
844 ret = scnprintf(buf, size, " ");
845 if (advance_hpp_check(&dummy_hpp, ret))
846 return ret;
847 }
848
849 perf_hpp__for_each_format(fmt) {
850 if (perf_hpp__should_skip(fmt))
851 continue;
852
Namhyung Kime0d66c72014-07-31 14:47:37 +0900853 /* We need to ensure length of the columns header. */
Jiri Olsa81a888f2014-06-14 15:44:52 +0200854 perf_hpp__reset_width(fmt, hists);
855
856 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
857 if (advance_hpp_check(&dummy_hpp, ret))
858 break;
859
860 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
861 if (advance_hpp_check(&dummy_hpp, ret))
862 break;
863 }
864
865 return ret;
866}
867
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200868static void hist_browser__show_headers(struct hist_browser *browser)
869{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200870 char headers[1024];
871
872 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200873 ui_browser__gotorc(&browser->b, 0, 0);
874 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200875 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200876}
877
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300878static void ui_browser__hists_init_top(struct ui_browser *browser)
879{
880 if (browser->top == NULL) {
881 struct hist_browser *hb;
882
883 hb = container_of(browser, struct hist_browser, b);
884 browser->top = rb_first(&hb->hists->entries);
885 }
886}
887
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300888static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300889{
890 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200891 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300892 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300893 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300894
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200895 if (hb->show_headers) {
896 hist_browser__show_headers(hb);
897 header_offset = 1;
898 }
899
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300900 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300901
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300902 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300903 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900904 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300905
906 if (h->filtered)
907 continue;
908
Namhyung Kim14135662013-10-31 10:17:39 +0900909 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900910 if (percent < hb->min_pcnt)
911 continue;
912
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300913 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300914 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300915 break;
916 }
917
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200918 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300919}
920
Namhyung Kim064f1982013-05-14 11:09:04 +0900921static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900922 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300923{
924 while (nd != NULL) {
925 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900926 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900927
Namhyung Kimc0f15272014-04-16 11:16:33 +0900928 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300929 return nd;
930
931 nd = rb_next(nd);
932 }
933
934 return NULL;
935}
936
Namhyung Kim064f1982013-05-14 11:09:04 +0900937static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900938 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300939{
940 while (nd != NULL) {
941 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900942 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900943
944 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300945 return nd;
946
947 nd = rb_prev(nd);
948 }
949
950 return NULL;
951}
952
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300953static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300954 off_t offset, int whence)
955{
956 struct hist_entry *h;
957 struct rb_node *nd;
958 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900959 struct hist_browser *hb;
960
961 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300962
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300963 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300964 return;
965
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300966 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300967
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300968 switch (whence) {
969 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900970 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900971 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300972 break;
973 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300974 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300975 goto do_offset;
976 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900977 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900978 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300979 first = false;
980 break;
981 default:
982 return;
983 }
984
985 /*
986 * Moves not relative to the first visible entry invalidates its
987 * row_offset:
988 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300989 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300990 h->row_offset = 0;
991
992 /*
993 * Here we have to check if nd is expanded (+), if it is we can't go
994 * the next top level hist_entry, instead we must compute an offset of
995 * what _not_ to show and not change the first visible entry.
996 *
997 * This offset increments when we are going from top to bottom and
998 * decreases when we're going from bottom to top.
999 *
1000 * As we don't have backpointers to the top level in the callchains
1001 * structure, we need to always print the whole hist_entry callchain,
1002 * skipping the first ones that are before the first visible entry
1003 * and stop when we printed enough lines to fill the screen.
1004 */
1005do_offset:
1006 if (offset > 0) {
1007 do {
1008 h = rb_entry(nd, struct hist_entry, rb_node);
1009 if (h->ms.unfolded) {
1010 u16 remaining = h->nr_rows - h->row_offset;
1011 if (offset > remaining) {
1012 offset -= remaining;
1013 h->row_offset = 0;
1014 } else {
1015 h->row_offset += offset;
1016 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001017 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001018 break;
1019 }
1020 }
Namhyung Kim14135662013-10-31 10:17:39 +09001021 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001022 if (nd == NULL)
1023 break;
1024 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001025 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001026 } while (offset != 0);
1027 } else if (offset < 0) {
1028 while (1) {
1029 h = rb_entry(nd, struct hist_entry, rb_node);
1030 if (h->ms.unfolded) {
1031 if (first) {
1032 if (-offset > h->row_offset) {
1033 offset += h->row_offset;
1034 h->row_offset = 0;
1035 } else {
1036 h->row_offset += offset;
1037 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001038 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001039 break;
1040 }
1041 } else {
1042 if (-offset > h->nr_rows) {
1043 offset += h->nr_rows;
1044 h->row_offset = 0;
1045 } else {
1046 h->row_offset = h->nr_rows + offset;
1047 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001048 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001049 break;
1050 }
1051 }
1052 }
1053
Namhyung Kim14135662013-10-31 10:17:39 +09001054 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001055 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001056 if (nd == NULL)
1057 break;
1058 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001059 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001060 if (offset == 0) {
1061 /*
1062 * Last unfiltered hist_entry, check if it is
1063 * unfolded, if it is then we should have
1064 * row_offset at its last entry.
1065 */
1066 h = rb_entry(nd, struct hist_entry, rb_node);
1067 if (h->ms.unfolded)
1068 h->row_offset = h->nr_rows;
1069 break;
1070 }
1071 first = false;
1072 }
1073 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001074 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001075 h = rb_entry(nd, struct hist_entry, rb_node);
1076 h->row_offset = 0;
1077 }
1078}
1079
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001080static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
1081 struct callchain_node *chain_node,
1082 u64 total, int level,
1083 FILE *fp)
1084{
1085 struct rb_node *node;
1086 int offset = level * LEVEL_OFFSET_STEP;
1087 u64 new_total, remaining;
1088 int printed = 0;
1089
1090 if (callchain_param.mode == CHAIN_GRAPH_REL)
1091 new_total = chain_node->children_hit;
1092 else
1093 new_total = total;
1094
1095 remaining = new_total;
1096 node = rb_first(&chain_node->rb_root);
1097 while (node) {
1098 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1099 struct rb_node *next = rb_next(node);
1100 u64 cumul = callchain_cumul_hits(child);
1101 struct callchain_list *chain;
1102 char folded_sign = ' ';
1103 int first = true;
1104 int extra_offset = 0;
1105
1106 remaining -= cumul;
1107
1108 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001109 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001110 const char *str;
1111 bool was_first = first;
1112
1113 if (first)
1114 first = false;
1115 else
1116 extra_offset = LEVEL_OFFSET_STEP;
1117
1118 folded_sign = callchain_list__folded(chain);
1119
1120 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001121 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1122 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001123 if (was_first) {
1124 double percent = cumul * 100.0 / new_total;
1125
1126 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1127 str = "Not enough memory!";
1128 else
1129 str = alloc_str;
1130 }
1131
1132 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1133 free(alloc_str);
1134 if (folded_sign == '+')
1135 break;
1136 }
1137
1138 if (folded_sign == '-') {
1139 const int new_level = level + (extra_offset ? 2 : 1);
1140 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1141 new_level, fp);
1142 }
1143
1144 node = next;
1145 }
1146
1147 return printed;
1148}
1149
1150static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1151 struct callchain_node *node,
1152 int level, FILE *fp)
1153{
1154 struct callchain_list *chain;
1155 int offset = level * LEVEL_OFFSET_STEP;
1156 char folded_sign = ' ';
1157 int printed = 0;
1158
1159 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001160 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001161
1162 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001163 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001164 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1165 }
1166
1167 if (folded_sign == '-')
1168 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1169 browser->hists->stats.total_period,
1170 level + 1, fp);
1171 return printed;
1172}
1173
1174static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1175 struct rb_root *chain, int level, FILE *fp)
1176{
1177 struct rb_node *nd;
1178 int printed = 0;
1179
1180 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1181 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1182
1183 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1184 }
1185
1186 return printed;
1187}
1188
1189static int hist_browser__fprintf_entry(struct hist_browser *browser,
1190 struct hist_entry *he, FILE *fp)
1191{
1192 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001193 int printed = 0;
1194 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001195 struct perf_hpp hpp = {
1196 .buf = s,
1197 .size = sizeof(s),
1198 };
1199 struct perf_hpp_fmt *fmt;
1200 bool first = true;
1201 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001202
1203 if (symbol_conf.use_callchain)
1204 folded_sign = hist_entry__folded(he);
1205
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001206 if (symbol_conf.use_callchain)
1207 printed += fprintf(fp, "%c ", folded_sign);
1208
Namhyung Kim26d8b332014-03-03 16:16:20 +09001209 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001210 if (perf_hpp__should_skip(fmt))
1211 continue;
1212
Namhyung Kim26d8b332014-03-03 16:16:20 +09001213 if (!first) {
1214 ret = scnprintf(hpp.buf, hpp.size, " ");
1215 advance_hpp(&hpp, ret);
1216 } else
1217 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001218
Namhyung Kim26d8b332014-03-03 16:16:20 +09001219 ret = fmt->entry(fmt, &hpp, he);
1220 advance_hpp(&hpp, ret);
1221 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001222 printed += fprintf(fp, "%s\n", rtrim(s));
1223
1224 if (folded_sign == '-')
1225 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1226
1227 return printed;
1228}
1229
1230static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1231{
Namhyung Kim064f1982013-05-14 11:09:04 +09001232 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001233 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001234 int printed = 0;
1235
1236 while (nd) {
1237 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1238
1239 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001240 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001241 }
1242
1243 return printed;
1244}
1245
1246static int hist_browser__dump(struct hist_browser *browser)
1247{
1248 char filename[64];
1249 FILE *fp;
1250
1251 while (1) {
1252 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1253 if (access(filename, F_OK))
1254 break;
1255 /*
1256 * XXX: Just an arbitrary lazy upper limit
1257 */
1258 if (++browser->print_seq == 8192) {
1259 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1260 return -1;
1261 }
1262 }
1263
1264 fp = fopen(filename, "w");
1265 if (fp == NULL) {
1266 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001267 const char *err = strerror_r(errno, bf, sizeof(bf));
1268 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001269 return -1;
1270 }
1271
1272 ++browser->print_seq;
1273 hist_browser__fprintf(browser, fp);
1274 fclose(fp);
1275 ui_helpline__fpush("%s written!", filename);
1276
1277 return 0;
1278}
1279
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001280static struct hist_browser *hist_browser__new(struct hists *hists)
1281{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001282 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001283
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001284 if (browser) {
1285 browser->hists = hists;
1286 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001287 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001288 browser->b.seek = ui_browser__hists_seek;
1289 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001290 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001291 }
1292
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001293 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001294}
1295
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001296static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001297{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001298 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001299}
1300
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001301static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001302{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001303 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001304}
1305
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001306static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001307{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001308 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001309}
1310
Jiri Olsadd00d482014-06-19 13:41:13 +02001311static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001312{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001313 char unit;
1314 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001315 const struct dso *dso = hists->dso_filter;
1316 const struct thread *thread = hists->thread_filter;
1317 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1318 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001319 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001320 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001321 char buf[512];
1322 size_t buflen = sizeof(buf);
1323
Namhyung Kimf2148332014-01-14 11:52:48 +09001324 if (symbol_conf.filter_relative) {
1325 nr_samples = hists->stats.nr_non_filtered_samples;
1326 nr_events = hists->stats.total_non_filtered_period;
1327 }
1328
Namhyung Kim759ff492013-03-05 14:53:26 +09001329 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001330 struct perf_evsel *pos;
1331
1332 perf_evsel__group_desc(evsel, buf, buflen);
1333 ev_name = buf;
1334
1335 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001336 if (symbol_conf.filter_relative) {
1337 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1338 nr_events += pos->hists.stats.total_non_filtered_period;
1339 } else {
1340 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1341 nr_events += pos->hists.stats.total_period;
1342 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001343 }
1344 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001345
Ashay Ranecc6862802012-04-05 21:01:01 -05001346 nr_samples = convert_unit(nr_samples, &unit);
1347 printed = scnprintf(bf, size,
1348 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1349 nr_samples, unit, ev_name, nr_events);
1350
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001351
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001352 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001353 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001354 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001355 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001356 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001357 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001358 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001359 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001360 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001361 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001362 ", DSO: %s", dso->short_name);
1363 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001364}
1365
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001366static inline void free_popup_options(char **options, int n)
1367{
1368 int i;
1369
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001370 for (i = 0; i < n; ++i)
1371 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001372}
1373
Feng Tangc77d8d72012-11-01 00:00:55 +08001374/* Check whether the browser is for 'top' or 'report' */
1375static inline bool is_report_browser(void *timer)
1376{
1377 return timer == NULL;
1378}
1379
Feng Tang341487ab2013-02-03 14:38:20 +08001380/*
1381 * Only runtime switching of perf data file will make "input_name" point
1382 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1383 * whether we need to call free() for current "input_name" during the switch.
1384 */
1385static bool is_input_name_malloced = false;
1386
1387static int switch_data_file(void)
1388{
1389 char *pwd, *options[32], *abs_path[32], *tmp;
1390 DIR *pwd_dir;
1391 int nr_options = 0, choice = -1, ret = -1;
1392 struct dirent *dent;
1393
1394 pwd = getenv("PWD");
1395 if (!pwd)
1396 return ret;
1397
1398 pwd_dir = opendir(pwd);
1399 if (!pwd_dir)
1400 return ret;
1401
1402 memset(options, 0, sizeof(options));
1403 memset(options, 0, sizeof(abs_path));
1404
1405 while ((dent = readdir(pwd_dir))) {
1406 char path[PATH_MAX];
1407 u64 magic;
1408 char *name = dent->d_name;
1409 FILE *file;
1410
1411 if (!(dent->d_type == DT_REG))
1412 continue;
1413
1414 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1415
1416 file = fopen(path, "r");
1417 if (!file)
1418 continue;
1419
1420 if (fread(&magic, 1, 8, file) < 8)
1421 goto close_file_and_continue;
1422
1423 if (is_perf_magic(magic)) {
1424 options[nr_options] = strdup(name);
1425 if (!options[nr_options])
1426 goto close_file_and_continue;
1427
1428 abs_path[nr_options] = strdup(path);
1429 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001430 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001431 ui__warning("Can't search all data files due to memory shortage.\n");
1432 fclose(file);
1433 break;
1434 }
1435
1436 nr_options++;
1437 }
1438
1439close_file_and_continue:
1440 fclose(file);
1441 if (nr_options >= 32) {
1442 ui__warning("Too many perf data files in PWD!\n"
1443 "Only the first 32 files will be listed.\n");
1444 break;
1445 }
1446 }
1447 closedir(pwd_dir);
1448
1449 if (nr_options) {
1450 choice = ui__popup_menu(nr_options, options);
1451 if (choice < nr_options && choice >= 0) {
1452 tmp = strdup(abs_path[choice]);
1453 if (tmp) {
1454 if (is_input_name_malloced)
1455 free((void *)input_name);
1456 input_name = tmp;
1457 is_input_name_malloced = true;
1458 ret = 0;
1459 } else
1460 ui__warning("Data switch failed due to memory shortage!\n");
1461 }
1462 }
1463
1464 free_popup_options(options, nr_options);
1465 free_popup_options(abs_path, nr_options);
1466 return ret;
1467}
1468
Namhyung Kim112f7612014-04-22 14:05:35 +09001469static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001470{
1471 u64 nr_entries = 0;
1472 struct rb_node *nd = rb_first(&hb->hists->entries);
1473
Namhyung Kim268397c2014-04-22 14:49:31 +09001474 if (hb->min_pcnt == 0) {
1475 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1476 return;
1477 }
1478
Namhyung Kim14135662013-10-31 10:17:39 +09001479 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001480 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001481 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001482 }
1483
Namhyung Kim112f7612014-04-22 14:05:35 +09001484 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001485}
Feng Tang341487ab2013-02-03 14:38:20 +08001486
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001487static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001488 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001489 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001490 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001491 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001492 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001493{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001494 struct hists *hists = &evsel->hists;
1495 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001496 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001497 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001498 char *options[16];
1499 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001500 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001501 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001502 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001503 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001504
Namhyung Kime8e684a2013-12-26 14:37:58 +09001505#define HIST_BROWSER_HELP_COMMON \
1506 "h/?/F1 Show this window\n" \
1507 "UP/DOWN/PGUP\n" \
1508 "PGDN/SPACE Navigate\n" \
1509 "q/ESC/CTRL+C Exit browser\n\n" \
1510 "For multiple event sessions:\n\n" \
1511 "TAB/UNTAB Switch events\n\n" \
1512 "For symbolic views (--sort has sym):\n\n" \
1513 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1514 "<- Zoom out\n" \
1515 "a Annotate current symbol\n" \
1516 "C Collapse all callchains\n" \
1517 "d Zoom into current DSO\n" \
1518 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001519 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001520 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001521
1522 /* help messages are sorted by lexical order of the hotkey */
1523 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001524 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001525 "P Print histograms to perf.hist.N\n"
1526 "r Run available scripts\n"
1527 "s Switch to another data file in PWD\n"
1528 "t Zoom into current Thread\n"
1529 "V Verbose (DSO names in callchains, etc)\n"
1530 "/ Filter symbol by name";
1531 const char top_help[] = HIST_BROWSER_HELP_COMMON
1532 "P Print histograms to perf.hist.N\n"
1533 "t Zoom into current Thread\n"
1534 "V Verbose (DSO names in callchains, etc)\n"
1535 "/ Filter symbol by name";
1536
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001537 if (browser == NULL)
1538 return -1;
1539
Namhyung Kim064f1982013-05-14 11:09:04 +09001540 if (min_pcnt) {
1541 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001542 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001543 }
1544
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001545 fstack = pstack__new(2);
1546 if (fstack == NULL)
1547 goto out;
1548
1549 ui_helpline__push(helpline);
1550
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001551 memset(options, 0, sizeof(options));
1552
Namhyung Kim5b591662014-07-31 14:47:38 +09001553 if (symbol_conf.col_width_list_str)
1554 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1555
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001556 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001557 const struct thread *thread = NULL;
1558 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001559 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001560 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001561 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001562 int scripts_comm = -2, scripts_symbol = -2,
1563 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001564
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001565 nr_options = 0;
1566
Jiri Olsadd00d482014-06-19 13:41:13 +02001567 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001568
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001569 if (browser->he_selection != NULL) {
1570 thread = hist_browser__selected_thread(browser);
1571 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1572 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001573 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001574 case K_TAB:
1575 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001576 if (nr_events == 1)
1577 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001578 /*
1579 * Exit the browser, let hists__browser_tree
1580 * go to the next or previous
1581 */
1582 goto out_free_stack;
1583 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001584 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001585 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001586 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001587 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001588 continue;
1589 }
1590
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001591 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001592 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001593 browser->selection->map->dso->annotate_warned)
1594 continue;
1595 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001596 case 'P':
1597 hist_browser__dump(browser);
1598 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001599 case 'd':
1600 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001601 case 'V':
1602 browser->show_dso = !browser->show_dso;
1603 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001604 case 't':
1605 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001606 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001607 if (ui_browser__input_window("Symbol to show",
1608 "Please enter the name of symbol you want to see",
1609 buf, "ENTER: OK, ESC: Cancel",
1610 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001611 hists->symbol_filter_str = *buf ? buf : NULL;
1612 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001613 hist_browser__reset(browser);
1614 }
1615 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001616 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001617 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001618 goto do_scripts;
1619 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001620 case 's':
1621 if (is_report_browser(hbt))
1622 goto do_data_switch;
1623 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001624 case 'i':
1625 /* env->arch is NULL for live-mode (i.e. perf top) */
1626 if (env->arch)
1627 tui__header_window(env);
1628 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001629 case 'F':
1630 symbol_conf.filter_relative ^= 1;
1631 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001632 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001633 case 'h':
1634 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001635 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001636 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001637 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001638 case K_ENTER:
1639 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001640 /* menu */
1641 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001642 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001643 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001644
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001645 if (pstack__empty(fstack)) {
1646 /*
1647 * Go back to the perf_evsel_menu__run or other user
1648 */
1649 if (left_exits)
1650 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001651 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001652 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001653 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001654 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001655 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001656 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001657 goto zoom_out_thread;
1658 continue;
1659 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001660 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001661 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001662 !ui_browser__dialog_yesno(&browser->b,
1663 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001664 continue;
1665 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001666 case 'q':
1667 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001668 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001669 default:
1670 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001671 }
1672
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001673 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001674 goto add_exit_option;
1675
Namhyung Kim55369fc2013-04-01 20:35:20 +09001676 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001677 bi = browser->he_selection->branch_info;
1678 if (browser->selection != NULL &&
1679 bi &&
1680 bi->from.sym != NULL &&
1681 !bi->from.map->dso->annotate_warned &&
1682 asprintf(&options[nr_options], "Annotate %s",
1683 bi->from.sym->name) > 0)
1684 annotate_f = nr_options++;
1685
1686 if (browser->selection != NULL &&
1687 bi &&
1688 bi->to.sym != NULL &&
1689 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001690 (bi->to.sym != bi->from.sym ||
1691 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001692 asprintf(&options[nr_options], "Annotate %s",
1693 bi->to.sym->name) > 0)
1694 annotate_t = nr_options++;
1695 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001696 if (browser->selection != NULL &&
1697 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001698 !browser->selection->map->dso->annotate_warned) {
1699 struct annotation *notes;
1700
1701 notes = symbol__annotation(browser->selection->sym);
1702
1703 if (notes->src &&
1704 asprintf(&options[nr_options], "Annotate %s",
1705 browser->selection->sym->name) > 0)
1706 annotate = nr_options++;
1707 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001708 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001709
1710 if (thread != NULL &&
1711 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001712 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001713 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001714 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001715 zoom_thread = nr_options++;
1716
1717 if (dso != NULL &&
1718 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001719 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001720 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1721 zoom_dso = nr_options++;
1722
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001723 if (browser->selection != NULL &&
1724 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001725 asprintf(&options[nr_options], "Browse map details") > 0)
1726 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001727
1728 /* perf script support */
1729 if (browser->he_selection) {
1730 struct symbol *sym;
1731
1732 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001733 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001734 scripts_comm = nr_options++;
1735
1736 sym = browser->he_selection->ms.sym;
1737 if (sym && sym->namelen &&
1738 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1739 sym->name) > 0)
1740 scripts_symbol = nr_options++;
1741 }
1742
1743 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1744 scripts_all = nr_options++;
1745
Feng Tang341487ab2013-02-03 14:38:20 +08001746 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1747 "Switch to another data file in PWD") > 0)
1748 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001749add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001750 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001751retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001752 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001753
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001754 if (choice == nr_options - 1)
1755 break;
1756
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001757 if (choice == -1) {
1758 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001759 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001760 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001762 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001763 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001764 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001765 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001767 if (!objdump_path && perf_session_env__lookup_objdump(env))
1768 continue;
1769
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001770 he = hist_browser__selected_entry(browser);
1771 if (he == NULL)
1772 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001773
1774 /*
1775 * we stash the branch_info symbol + map into the
1776 * the ms so we don't have to rewrite all the annotation
1777 * code to use branch_info.
1778 * in branch mode, the ms struct is not used
1779 */
1780 if (choice == annotate_f) {
1781 he->ms.sym = he->branch_info->from.sym;
1782 he->ms.map = he->branch_info->from.map;
1783 } else if (choice == annotate_t) {
1784 he->ms.sym = he->branch_info->to.sym;
1785 he->ms.map = he->branch_info->to.map;
1786 }
1787
Jiri Olsad7553302014-06-15 10:22:15 +02001788 notes = symbol__annotation(he->ms.sym);
1789 if (!notes->src)
1790 continue;
1791
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001792 /*
1793 * Don't let this be freed, say, by hists__decay_entry.
1794 */
1795 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001796 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001797 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001798 /*
1799 * offer option to annotate the other branch source or target
1800 * (if they exists) when returning from annotate
1801 */
1802 if ((err == 'q' || err == CTRL('c'))
1803 && annotate_t != -2 && annotate_f != -2)
1804 goto retry_popup_menu;
1805
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001806 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001807 if (err)
1808 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001809
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001810 } else if (choice == browse_map)
1811 map__browse(browser->selection->map);
1812 else if (choice == zoom_dso) {
1813zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001814 if (browser->hists->dso_filter) {
1815 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001816zoom_out_dso:
1817 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001818 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001819 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001820 } else {
1821 if (dso == NULL)
1822 continue;
1823 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1824 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001825 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001826 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001827 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001828 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001829 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001830 hist_browser__reset(browser);
1831 } else if (choice == zoom_thread) {
1832zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001833 if (browser->hists->thread_filter) {
1834 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001835zoom_out_thread:
1836 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001837 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001838 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001839 } else {
1840 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001841 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001842 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001843 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001844 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001845 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001846 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001847 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001848 hist_browser__reset(browser);
1849 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001850 /* perf scripts support */
1851 else if (choice == scripts_all || choice == scripts_comm ||
1852 choice == scripts_symbol) {
1853do_scripts:
1854 memset(script_opt, 0, 64);
1855
1856 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001857 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001858
1859 if (choice == scripts_symbol)
1860 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1861
1862 script_browse(script_opt);
1863 }
Feng Tang341487ab2013-02-03 14:38:20 +08001864 /* Switch to another data file */
1865 else if (choice == switch_data) {
1866do_data_switch:
1867 if (!switch_data_file()) {
1868 key = K_SWITCH_INPUT_DATA;
1869 break;
1870 } else
1871 ui__warning("Won't switch the data files due to\n"
1872 "no valid data file get selected!\n");
1873 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001874 }
1875out_free_stack:
1876 pstack__delete(fstack);
1877out:
1878 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001879 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001880 return key;
1881}
1882
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001883struct perf_evsel_menu {
1884 struct ui_browser b;
1885 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001886 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001887 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001888 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001889};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001890
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001891static void perf_evsel_menu__write(struct ui_browser *browser,
1892 void *entry, int row)
1893{
1894 struct perf_evsel_menu *menu = container_of(browser,
1895 struct perf_evsel_menu, b);
1896 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1897 bool current_entry = ui_browser__is_current_entry(browser, row);
1898 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001899 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001900 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001901 const char *warn = " ";
1902 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001903
1904 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1905 HE_COLORSET_NORMAL);
1906
Namhyung Kim759ff492013-03-05 14:53:26 +09001907 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001908 struct perf_evsel *pos;
1909
1910 ev_name = perf_evsel__group_name(evsel);
1911
1912 for_each_group_member(pos, evsel) {
1913 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1914 }
1915 }
1916
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001917 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001918 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001919 unit, unit == ' ' ? "" : " ", ev_name);
1920 slsmg_printf("%s", bf);
1921
1922 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1923 if (nr_events != 0) {
1924 menu->lost_events = true;
1925 if (!current_entry)
1926 ui_browser__set_color(browser, HE_COLORSET_TOP);
1927 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001928 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1929 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001930 warn = bf;
1931 }
1932
1933 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001934
1935 if (current_entry)
1936 menu->selection = evsel;
1937}
1938
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001939static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1940 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001941 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001942{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001943 struct perf_evlist *evlist = menu->b.priv;
1944 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001945 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001946 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001947 int key;
1948
1949 if (ui_browser__show(&menu->b, title,
1950 "ESC: exit, ENTER|->: Browse histograms") < 0)
1951 return -1;
1952
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001953 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001954 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001955
1956 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001957 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001958 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001959
1960 if (!menu->lost_events_warned && menu->lost_events) {
1961 ui_browser__warn_lost_events(&menu->b);
1962 menu->lost_events_warned = true;
1963 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001964 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001965 case K_RIGHT:
1966 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001967 if (!menu->selection)
1968 continue;
1969 pos = menu->selection;
1970browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001971 perf_evlist__set_selected(evlist, pos);
1972 /*
1973 * Give the calling tool a chance to populate the non
1974 * default evsel resorted hists tree.
1975 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001976 if (hbt)
1977 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001978 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001979 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001980 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001981 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001982 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001983 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001984 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001985 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001986 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001987 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001988 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001989 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001990 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001991 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001992 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001993 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001994 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001995 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001996 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001997 if (!ui_browser__dialog_yesno(&menu->b,
1998 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001999 continue;
2000 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08002001 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002002 case 'q':
2003 case CTRL('c'):
2004 goto out;
2005 default:
2006 continue;
2007 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002008 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002009 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002010 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002011 if (!ui_browser__dialog_yesno(&menu->b,
2012 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002013 continue;
2014 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002015 case 'q':
2016 case CTRL('c'):
2017 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002018 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002019 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002020 }
2021 }
2022
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002023out:
2024 ui_browser__hide(&menu->b);
2025 return key;
2026}
2027
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002028static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002029 void *entry)
2030{
2031 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2032
2033 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2034 return true;
2035
2036 return false;
2037}
2038
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002039static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002040 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002041 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002042 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002043 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002044{
2045 struct perf_evsel *pos;
2046 struct perf_evsel_menu menu = {
2047 .b = {
2048 .entries = &evlist->entries,
2049 .refresh = ui_browser__list_head_refresh,
2050 .seek = ui_browser__list_head_seek,
2051 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002052 .filter = filter_group_entries,
2053 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002054 .priv = evlist,
2055 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002056 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002057 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002058 };
2059
2060 ui_helpline__push("Press ESC to exit");
2061
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002062 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002063 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002064 size_t line_len = strlen(ev_name) + 7;
2065
2066 if (menu.b.width < line_len)
2067 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002068 }
2069
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002070 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002071}
2072
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002073int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002074 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002075 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002076 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002077{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002078 int nr_entries = evlist->nr_entries;
2079
2080single_entry:
2081 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002082 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002083
2084 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002085 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002086 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002087 }
2088
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002089 if (symbol_conf.event_group) {
2090 struct perf_evsel *pos;
2091
2092 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002093 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002094 if (perf_evsel__is_group_leader(pos))
2095 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002096 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002097
2098 if (nr_entries == 1)
2099 goto single_entry;
2100 }
2101
2102 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002103 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002104}