blob: 1bd35e8ed9f12f7cf94570a4676af43ef13ca204 [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"
20
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021struct hist_browser {
22 struct ui_browser b;
23 struct hists *hists;
24 struct hist_entry *he_selection;
25 struct map_symbol *selection;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030026 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030027 bool show_dso;
Namhyung Kim064f1982013-05-14 11:09:04 +090028 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090029 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090030 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030031};
32
Namhyung Kimf5951d52012-09-03 11:53:09 +090033extern void hist_browser__init_hpp(void);
34
Jiri Olsadd00d482014-06-19 13:41:13 +020035static int hists__browser_title(struct hists *hists, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090036static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030037
Namhyung Kimc3b78952014-04-22 15:56:17 +090038static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090039 float min_pcnt);
40
Namhyung Kim268397c2014-04-22 14:49:31 +090041static bool hist_browser__has_filter(struct hist_browser *hb)
42{
43 return hists__has_filter(hb->hists) || hb->min_pcnt;
44}
45
Namhyung Kimc3b78952014-04-22 15:56:17 +090046static u32 hist_browser__nr_entries(struct hist_browser *hb)
47{
48 u32 nr_entries;
49
50 if (hist_browser__has_filter(hb))
51 nr_entries = hb->nr_non_filtered_entries;
52 else
53 nr_entries = hb->hists->nr_entries;
54
55 return nr_entries + hb->nr_callchain_rows;
56}
57
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030058static void hist_browser__refresh_dimensions(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030059{
60 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030061 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030062 sizeof("[k]"));
63}
64
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030065static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030066{
Namhyung Kimc3b78952014-04-22 15:56:17 +090067 /*
68 * The hists__remove_entry_filter() already folds non-filtered
69 * entries so we can assume it has 0 callchain rows.
70 */
71 browser->nr_callchain_rows = 0;
72
Namhyung Kim268397c2014-04-22 14:49:31 +090073 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +090074 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030075 hist_browser__refresh_dimensions(browser);
76 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030077}
78
79static char tree__folded_sign(bool unfolded)
80{
81 return unfolded ? '-' : '+';
82}
83
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030084static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030085{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030086 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030087}
88
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030089static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030090{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030091 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030092}
93
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030094static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030095{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030096 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030097}
98
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030099static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300100{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300101 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300102}
103
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300104static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300105{
106 int n = 0;
107 struct rb_node *nd;
108
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300109 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300110 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
111 struct callchain_list *chain;
112 char folded_sign = ' '; /* No children */
113
114 list_for_each_entry(chain, &child->val, list) {
115 ++n;
116 /* We need this because we may not have children */
117 folded_sign = callchain_list__folded(chain);
118 if (folded_sign == '+')
119 break;
120 }
121
122 if (folded_sign == '-') /* Have children and they're unfolded */
123 n += callchain_node__count_rows_rb_tree(child);
124 }
125
126 return n;
127}
128
129static int callchain_node__count_rows(struct callchain_node *node)
130{
131 struct callchain_list *chain;
132 bool unfolded = false;
133 int n = 0;
134
135 list_for_each_entry(chain, &node->val, list) {
136 ++n;
137 unfolded = chain->ms.unfolded;
138 }
139
140 if (unfolded)
141 n += callchain_node__count_rows_rb_tree(node);
142
143 return n;
144}
145
146static int callchain__count_rows(struct rb_root *chain)
147{
148 struct rb_node *nd;
149 int n = 0;
150
151 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
152 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
153 n += callchain_node__count_rows(node);
154 }
155
156 return n;
157}
158
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300159static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300160{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300161 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200162 return false;
163
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300164 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300165 return false;
166
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300167 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300168 return true;
169}
170
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300171static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300172{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300173 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300174
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300175 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300176 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
177 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300178 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300179
180 list_for_each_entry(chain, &child->val, list) {
181 if (first) {
182 first = false;
183 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300184 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300185 } else
186 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300187 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300188 }
189
190 callchain_node__init_have_children_rb_tree(child);
191 }
192}
193
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300194static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300195{
196 struct callchain_list *chain;
197
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300198 list_for_each_entry(chain, &node->val, list)
199 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300200
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300201 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300202}
203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300204static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300205{
206 struct rb_node *nd;
207
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300208 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300209 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
210 callchain_node__init_have_children(node);
211 }
212}
213
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300214static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300215{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300216 if (!he->init_have_children) {
217 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
218 callchain__init_have_children(&he->sorted_chain);
219 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300220 }
221}
222
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300223static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300224{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300225 if (map_symbol__toggle_fold(browser->selection)) {
226 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300227
228 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900229 browser->b.nr_entries -= he->nr_rows;
230 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300231
232 if (he->ms.unfolded)
233 he->nr_rows = callchain__count_rows(&he->sorted_chain);
234 else
235 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900236
237 browser->b.nr_entries += he->nr_rows;
238 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300239
240 return true;
241 }
242
243 /* If it doesn't have children, no toggling performed */
244 return false;
245}
246
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300247static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300248{
249 int n = 0;
250 struct rb_node *nd;
251
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300252 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300253 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
254 struct callchain_list *chain;
255 bool has_children = false;
256
257 list_for_each_entry(chain, &child->val, list) {
258 ++n;
259 map_symbol__set_folding(&chain->ms, unfold);
260 has_children = chain->ms.has_children;
261 }
262
263 if (has_children)
264 n += callchain_node__set_folding_rb_tree(child, unfold);
265 }
266
267 return n;
268}
269
270static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
271{
272 struct callchain_list *chain;
273 bool has_children = false;
274 int n = 0;
275
276 list_for_each_entry(chain, &node->val, list) {
277 ++n;
278 map_symbol__set_folding(&chain->ms, unfold);
279 has_children = chain->ms.has_children;
280 }
281
282 if (has_children)
283 n += callchain_node__set_folding_rb_tree(node, unfold);
284
285 return n;
286}
287
288static int callchain__set_folding(struct rb_root *chain, bool unfold)
289{
290 struct rb_node *nd;
291 int n = 0;
292
293 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
294 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
295 n += callchain_node__set_folding(node, unfold);
296 }
297
298 return n;
299}
300
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300301static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300302{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300303 hist_entry__init_have_children(he);
304 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300305
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300306 if (he->ms.has_children) {
307 int n = callchain__set_folding(&he->sorted_chain, unfold);
308 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300309 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300310 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300311}
312
Namhyung Kimc3b78952014-04-22 15:56:17 +0900313static void
314__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300315{
316 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900317 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300318
Namhyung Kimc3b78952014-04-22 15:56:17 +0900319 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900320 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900321 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300322 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
323 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900324 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300325 }
326}
327
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300328static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300329{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900330 browser->nr_callchain_rows = 0;
331 __hist_browser__set_folding(browser, unfold);
332
333 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300334 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300335 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300336}
337
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200338static void ui_browser__warn_lost_events(struct ui_browser *browser)
339{
340 ui_browser__warning(browser, 4,
341 "Events are being lost, check IO/CPU overload!\n\n"
342 "You may want to run 'perf' using a RT scheduler policy:\n\n"
343 " perf top -r 80\n\n"
344 "Or reduce the sampling frequency.");
345}
346
Jiri Olsadd00d482014-06-19 13:41:13 +0200347static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900348 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300349{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300350 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300351 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900352 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300353
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300354 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900355 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300356
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300357 hist_browser__refresh_dimensions(browser);
Jiri Olsadd00d482014-06-19 13:41:13 +0200358 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300359
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300360 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300361 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300362 return -1;
363
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300364 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300365 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300366
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300367 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900368 case K_TIMER: {
369 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900370 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900371
Namhyung Kimc3b78952014-04-22 15:56:17 +0900372 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900373 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900374
Namhyung Kimc3b78952014-04-22 15:56:17 +0900375 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900376 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200377
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300378 if (browser->hists->stats.nr_lost_warned !=
379 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
380 browser->hists->stats.nr_lost_warned =
381 browser->hists->stats.nr_events[PERF_RECORD_LOST];
382 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200383 }
384
Jiri Olsadd00d482014-06-19 13:41:13 +0200385 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300386 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300387 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900388 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300389 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300390 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300391 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392 struct hist_entry, rb_node);
393 ui_helpline__pop();
394 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300395 seq++, browser->b.nr_entries,
396 browser->hists->nr_entries,
397 browser->b.height,
398 browser->b.index,
399 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300400 h->row_offset, h->nr_rows);
401 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300402 break;
403 case 'C':
404 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300405 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300406 break;
407 case 'E':
408 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300409 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300410 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200411 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300412 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300413 break;
414 /* fall thru */
415 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300416 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300417 }
418 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300419out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300420 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300421 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300422}
423
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300424static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300425 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300426{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300427 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300429 if (cl->ms.sym)
430 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
431 else
432 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
433
434 if (show_dso)
435 scnprintf(bf + printed, bfsize - printed, " %s",
436 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
437
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300438 return bf;
439}
440
441#define LEVEL_OFFSET_STEP 3
442
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300443static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300444 struct callchain_node *chain_node,
445 u64 total, int level,
446 unsigned short row,
447 off_t *row_offset,
448 bool *is_current_entry)
449{
450 struct rb_node *node;
451 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
452 u64 new_total, remaining;
453
454 if (callchain_param.mode == CHAIN_GRAPH_REL)
455 new_total = chain_node->children_hit;
456 else
457 new_total = total;
458
459 remaining = new_total;
460 node = rb_first(&chain_node->rb_root);
461 while (node) {
462 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
463 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100464 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300465 struct callchain_list *chain;
466 char folded_sign = ' ';
467 int first = true;
468 int extra_offset = 0;
469
470 remaining -= cumul;
471
472 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300473 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300474 const char *str;
475 int color;
476 bool was_first = first;
477
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300478 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300479 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300480 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300481 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300482
483 folded_sign = callchain_list__folded(chain);
484 if (*row_offset != 0) {
485 --*row_offset;
486 goto do_next;
487 }
488
489 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300490 str = callchain_list__sym_name(chain, bf, sizeof(bf),
491 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300492 if (was_first) {
493 double percent = cumul * 100.0 / new_total;
494
495 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
496 str = "Not enough memory!";
497 else
498 str = alloc_str;
499 }
500
501 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300502 width = browser->b.width - (offset + extra_offset + 2);
503 if (ui_browser__is_current_entry(&browser->b, row)) {
504 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300505 color = HE_COLORSET_SELECTED;
506 *is_current_entry = true;
507 }
508
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300509 ui_browser__set_color(&browser->b, color);
510 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300511 slsmg_write_nstring(" ", offset + extra_offset);
512 slsmg_printf("%c ", folded_sign);
513 slsmg_write_nstring(str, width);
514 free(alloc_str);
515
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300516 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300517 goto out;
518do_next:
519 if (folded_sign == '+')
520 break;
521 }
522
523 if (folded_sign == '-') {
524 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300525 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300526 new_level, row, row_offset,
527 is_current_entry);
528 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300529 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300530 goto out;
531 node = next;
532 }
533out:
534 return row - first_row;
535}
536
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300537static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300538 struct callchain_node *node,
539 int level, unsigned short row,
540 off_t *row_offset,
541 bool *is_current_entry)
542{
543 struct callchain_list *chain;
544 int first_row = row,
545 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300546 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300547 char folded_sign = ' ';
548
549 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300550 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300551 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300552
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300553 folded_sign = callchain_list__folded(chain);
554
555 if (*row_offset != 0) {
556 --*row_offset;
557 continue;
558 }
559
560 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300561 if (ui_browser__is_current_entry(&browser->b, row)) {
562 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300563 color = HE_COLORSET_SELECTED;
564 *is_current_entry = true;
565 }
566
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300567 s = callchain_list__sym_name(chain, bf, sizeof(bf),
568 browser->show_dso);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300569 ui_browser__gotorc(&browser->b, row, 0);
570 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300571 slsmg_write_nstring(" ", offset);
572 slsmg_printf("%c ", folded_sign);
573 slsmg_write_nstring(s, width - 2);
574
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300575 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300576 goto out;
577 }
578
579 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300580 row += hist_browser__show_callchain_node_rb_tree(browser, node,
581 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300582 level + 1, row,
583 row_offset,
584 is_current_entry);
585out:
586 return row - first_row;
587}
588
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300589static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590 struct rb_root *chain,
591 int level, unsigned short row,
592 off_t *row_offset,
593 bool *is_current_entry)
594{
595 struct rb_node *nd;
596 int first_row = row;
597
598 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
599 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
600
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300601 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300602 row, row_offset,
603 is_current_entry);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300604 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300605 break;
606 }
607
608 return row - first_row;
609}
610
Namhyung Kim89701462013-01-22 18:09:38 +0900611struct hpp_arg {
612 struct ui_browser *b;
613 char folded_sign;
614 bool current_entry;
615};
616
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900617static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
618{
619 struct hpp_arg *arg = hpp->ptr;
620 int ret;
621 va_list args;
622 double percent;
623
624 va_start(args, fmt);
625 percent = va_arg(args, double);
626 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900627
Namhyung Kim89701462013-01-22 18:09:38 +0900628 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900629
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900630 ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900631 slsmg_printf("%s", hpp->buf);
632
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900633 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900634 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900635}
636
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900637#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900638static u64 __hpp_get_##_field(struct hist_entry *he) \
639{ \
640 return he->stat._field; \
641} \
642 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100643static int \
644hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
645 struct perf_hpp *hpp, \
646 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900647{ \
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900648 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900649 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900650}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900651
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900652#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
653static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
654{ \
655 return he->stat_acc->_field; \
656} \
657 \
658static int \
659hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
660 struct perf_hpp *hpp, \
661 struct hist_entry *he) \
662{ \
663 if (!symbol_conf.cumulate_callchain) { \
664 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
665 slsmg_printf("%s", hpp->buf); \
666 \
667 return ret; \
668 } \
669 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \
670 __hpp__slsmg_color_printf, true); \
671}
672
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900673__HPP_COLOR_PERCENT_FN(overhead, period)
674__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
675__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
676__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
677__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900678__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900679
680#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900681#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900682
683void hist_browser__init_hpp(void)
684{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900685 perf_hpp__format[PERF_HPP__OVERHEAD].color =
686 hist_browser__hpp_color_overhead;
687 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
688 hist_browser__hpp_color_overhead_sys;
689 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
690 hist_browser__hpp_color_overhead_us;
691 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
692 hist_browser__hpp_color_overhead_guest_sys;
693 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
694 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900695 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
696 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900697}
698
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300699static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300700 struct hist_entry *entry,
701 unsigned short row)
702{
703 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200704 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900705 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300706 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300707 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300708 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300709 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200710 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300711
712 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300713 browser->he_selection = entry;
714 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300715 }
716
717 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300718 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300719 folded_sign = hist_entry__folded(entry);
720 }
721
722 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900723 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900724 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900725 .folded_sign = folded_sign,
726 .current_entry = current_entry,
727 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900728 struct perf_hpp hpp = {
729 .buf = s,
730 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900731 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900732 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300733
Namhyung Kim67d25912012-09-12 15:35:06 +0900734 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900735
Jiri Olsa12400052012-10-13 00:06:16 +0200736 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900737 if (perf_hpp__should_skip(fmt))
738 continue;
739
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900740 if (current_entry && browser->b.navkeypressed) {
741 ui_browser__set_color(&browser->b,
742 HE_COLORSET_SELECTED);
743 } else {
744 ui_browser__set_color(&browser->b,
745 HE_COLORSET_NORMAL);
746 }
747
748 if (first) {
749 if (symbol_conf.use_callchain) {
750 slsmg_printf("%c ", folded_sign);
751 width -= 2;
752 }
753 first = false;
754 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900755 slsmg_printf(" ");
756 width -= 2;
757 }
758
Jiri Olsa12400052012-10-13 00:06:16 +0200759 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100760 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900761 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100762 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900763 slsmg_printf("%s", s);
764 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300765 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200766
767 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300768 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200769 width += 1;
770
Namhyung Kim26d8b332014-03-03 16:16:20 +0900771 slsmg_write_nstring("", width);
772
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300773 ++row;
774 ++printed;
775 } else
776 --row_offset;
777
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300778 if (folded_sign == '-' && row != browser->b.height) {
779 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300780 1, row, &row_offset,
781 &current_entry);
782 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300783 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300784 }
785
786 return printed;
787}
788
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300789static void ui_browser__hists_init_top(struct ui_browser *browser)
790{
791 if (browser->top == NULL) {
792 struct hist_browser *hb;
793
794 hb = container_of(browser, struct hist_browser, b);
795 browser->top = rb_first(&hb->hists->entries);
796 }
797}
798
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300799static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300800{
801 unsigned row = 0;
802 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300803 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300804
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300805 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300806
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300807 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300808 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900809 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300810
811 if (h->filtered)
812 continue;
813
Namhyung Kim14135662013-10-31 10:17:39 +0900814 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900815 if (percent < hb->min_pcnt)
816 continue;
817
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300818 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300819 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300820 break;
821 }
822
823 return row;
824}
825
Namhyung Kim064f1982013-05-14 11:09:04 +0900826static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900827 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300828{
829 while (nd != NULL) {
830 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900831 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900832
Namhyung Kimc0f15272014-04-16 11:16:33 +0900833 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300834 return nd;
835
836 nd = rb_next(nd);
837 }
838
839 return NULL;
840}
841
Namhyung Kim064f1982013-05-14 11:09:04 +0900842static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900843 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300844{
845 while (nd != NULL) {
846 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900847 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900848
849 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300850 return nd;
851
852 nd = rb_prev(nd);
853 }
854
855 return NULL;
856}
857
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300858static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300859 off_t offset, int whence)
860{
861 struct hist_entry *h;
862 struct rb_node *nd;
863 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900864 struct hist_browser *hb;
865
866 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300867
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300868 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300869 return;
870
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300871 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300872
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300873 switch (whence) {
874 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900875 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900876 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300877 break;
878 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300879 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300880 goto do_offset;
881 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900882 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900883 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300884 first = false;
885 break;
886 default:
887 return;
888 }
889
890 /*
891 * Moves not relative to the first visible entry invalidates its
892 * row_offset:
893 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300894 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300895 h->row_offset = 0;
896
897 /*
898 * Here we have to check if nd is expanded (+), if it is we can't go
899 * the next top level hist_entry, instead we must compute an offset of
900 * what _not_ to show and not change the first visible entry.
901 *
902 * This offset increments when we are going from top to bottom and
903 * decreases when we're going from bottom to top.
904 *
905 * As we don't have backpointers to the top level in the callchains
906 * structure, we need to always print the whole hist_entry callchain,
907 * skipping the first ones that are before the first visible entry
908 * and stop when we printed enough lines to fill the screen.
909 */
910do_offset:
911 if (offset > 0) {
912 do {
913 h = rb_entry(nd, struct hist_entry, rb_node);
914 if (h->ms.unfolded) {
915 u16 remaining = h->nr_rows - h->row_offset;
916 if (offset > remaining) {
917 offset -= remaining;
918 h->row_offset = 0;
919 } else {
920 h->row_offset += offset;
921 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300922 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300923 break;
924 }
925 }
Namhyung Kim14135662013-10-31 10:17:39 +0900926 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300927 if (nd == NULL)
928 break;
929 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300930 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300931 } while (offset != 0);
932 } else if (offset < 0) {
933 while (1) {
934 h = rb_entry(nd, struct hist_entry, rb_node);
935 if (h->ms.unfolded) {
936 if (first) {
937 if (-offset > h->row_offset) {
938 offset += h->row_offset;
939 h->row_offset = 0;
940 } else {
941 h->row_offset += offset;
942 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300943 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300944 break;
945 }
946 } else {
947 if (-offset > h->nr_rows) {
948 offset += h->nr_rows;
949 h->row_offset = 0;
950 } else {
951 h->row_offset = h->nr_rows + offset;
952 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300953 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300954 break;
955 }
956 }
957 }
958
Namhyung Kim14135662013-10-31 10:17:39 +0900959 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +0900960 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300961 if (nd == NULL)
962 break;
963 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300964 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300965 if (offset == 0) {
966 /*
967 * Last unfiltered hist_entry, check if it is
968 * unfolded, if it is then we should have
969 * row_offset at its last entry.
970 */
971 h = rb_entry(nd, struct hist_entry, rb_node);
972 if (h->ms.unfolded)
973 h->row_offset = h->nr_rows;
974 break;
975 }
976 first = false;
977 }
978 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300979 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300980 h = rb_entry(nd, struct hist_entry, rb_node);
981 h->row_offset = 0;
982 }
983}
984
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300985static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
986 struct callchain_node *chain_node,
987 u64 total, int level,
988 FILE *fp)
989{
990 struct rb_node *node;
991 int offset = level * LEVEL_OFFSET_STEP;
992 u64 new_total, remaining;
993 int printed = 0;
994
995 if (callchain_param.mode == CHAIN_GRAPH_REL)
996 new_total = chain_node->children_hit;
997 else
998 new_total = total;
999
1000 remaining = new_total;
1001 node = rb_first(&chain_node->rb_root);
1002 while (node) {
1003 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1004 struct rb_node *next = rb_next(node);
1005 u64 cumul = callchain_cumul_hits(child);
1006 struct callchain_list *chain;
1007 char folded_sign = ' ';
1008 int first = true;
1009 int extra_offset = 0;
1010
1011 remaining -= cumul;
1012
1013 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001014 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001015 const char *str;
1016 bool was_first = first;
1017
1018 if (first)
1019 first = false;
1020 else
1021 extra_offset = LEVEL_OFFSET_STEP;
1022
1023 folded_sign = callchain_list__folded(chain);
1024
1025 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001026 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1027 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001028 if (was_first) {
1029 double percent = cumul * 100.0 / new_total;
1030
1031 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1032 str = "Not enough memory!";
1033 else
1034 str = alloc_str;
1035 }
1036
1037 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1038 free(alloc_str);
1039 if (folded_sign == '+')
1040 break;
1041 }
1042
1043 if (folded_sign == '-') {
1044 const int new_level = level + (extra_offset ? 2 : 1);
1045 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1046 new_level, fp);
1047 }
1048
1049 node = next;
1050 }
1051
1052 return printed;
1053}
1054
1055static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1056 struct callchain_node *node,
1057 int level, FILE *fp)
1058{
1059 struct callchain_list *chain;
1060 int offset = level * LEVEL_OFFSET_STEP;
1061 char folded_sign = ' ';
1062 int printed = 0;
1063
1064 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001065 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001066
1067 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001068 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001069 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1070 }
1071
1072 if (folded_sign == '-')
1073 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1074 browser->hists->stats.total_period,
1075 level + 1, fp);
1076 return printed;
1077}
1078
1079static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1080 struct rb_root *chain, int level, FILE *fp)
1081{
1082 struct rb_node *nd;
1083 int printed = 0;
1084
1085 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1086 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1087
1088 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1089 }
1090
1091 return printed;
1092}
1093
1094static int hist_browser__fprintf_entry(struct hist_browser *browser,
1095 struct hist_entry *he, FILE *fp)
1096{
1097 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001098 int printed = 0;
1099 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001100 struct perf_hpp hpp = {
1101 .buf = s,
1102 .size = sizeof(s),
1103 };
1104 struct perf_hpp_fmt *fmt;
1105 bool first = true;
1106 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001107
1108 if (symbol_conf.use_callchain)
1109 folded_sign = hist_entry__folded(he);
1110
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001111 if (symbol_conf.use_callchain)
1112 printed += fprintf(fp, "%c ", folded_sign);
1113
Namhyung Kim26d8b332014-03-03 16:16:20 +09001114 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001115 if (perf_hpp__should_skip(fmt))
1116 continue;
1117
Namhyung Kim26d8b332014-03-03 16:16:20 +09001118 if (!first) {
1119 ret = scnprintf(hpp.buf, hpp.size, " ");
1120 advance_hpp(&hpp, ret);
1121 } else
1122 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001123
Namhyung Kim26d8b332014-03-03 16:16:20 +09001124 ret = fmt->entry(fmt, &hpp, he);
1125 advance_hpp(&hpp, ret);
1126 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001127 printed += fprintf(fp, "%s\n", rtrim(s));
1128
1129 if (folded_sign == '-')
1130 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1131
1132 return printed;
1133}
1134
1135static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1136{
Namhyung Kim064f1982013-05-14 11:09:04 +09001137 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001138 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001139 int printed = 0;
1140
1141 while (nd) {
1142 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1143
1144 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001145 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001146 }
1147
1148 return printed;
1149}
1150
1151static int hist_browser__dump(struct hist_browser *browser)
1152{
1153 char filename[64];
1154 FILE *fp;
1155
1156 while (1) {
1157 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1158 if (access(filename, F_OK))
1159 break;
1160 /*
1161 * XXX: Just an arbitrary lazy upper limit
1162 */
1163 if (++browser->print_seq == 8192) {
1164 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1165 return -1;
1166 }
1167 }
1168
1169 fp = fopen(filename, "w");
1170 if (fp == NULL) {
1171 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001172 const char *err = strerror_r(errno, bf, sizeof(bf));
1173 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001174 return -1;
1175 }
1176
1177 ++browser->print_seq;
1178 hist_browser__fprintf(browser, fp);
1179 fclose(fp);
1180 ui_helpline__fpush("%s written!", filename);
1181
1182 return 0;
1183}
1184
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001185static struct hist_browser *hist_browser__new(struct hists *hists)
1186{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001187 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001188
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001189 if (browser) {
1190 browser->hists = hists;
1191 browser->b.refresh = hist_browser__refresh;
1192 browser->b.seek = ui_browser__hists_seek;
1193 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001194 }
1195
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001196 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001197}
1198
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001199static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001201 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202}
1203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001204static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001205{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001206 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207}
1208
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001209static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001210{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001211 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001212}
1213
Jiri Olsadd00d482014-06-19 13:41:13 +02001214static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001216 char unit;
1217 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001218 const struct dso *dso = hists->dso_filter;
1219 const struct thread *thread = hists->thread_filter;
1220 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1221 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001222 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001223 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001224 char buf[512];
1225 size_t buflen = sizeof(buf);
1226
Namhyung Kimf2148332014-01-14 11:52:48 +09001227 if (symbol_conf.filter_relative) {
1228 nr_samples = hists->stats.nr_non_filtered_samples;
1229 nr_events = hists->stats.total_non_filtered_period;
1230 }
1231
Namhyung Kim759ff492013-03-05 14:53:26 +09001232 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001233 struct perf_evsel *pos;
1234
1235 perf_evsel__group_desc(evsel, buf, buflen);
1236 ev_name = buf;
1237
1238 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001239 if (symbol_conf.filter_relative) {
1240 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1241 nr_events += pos->hists.stats.total_non_filtered_period;
1242 } else {
1243 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1244 nr_events += pos->hists.stats.total_period;
1245 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001246 }
1247 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001248
Ashay Ranecc686282012-04-05 21:01:01 -05001249 nr_samples = convert_unit(nr_samples, &unit);
1250 printed = scnprintf(bf, size,
1251 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1252 nr_samples, unit, ev_name, nr_events);
1253
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001254
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001255 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001256 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001257 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001258 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001259 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001260 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001261 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001262 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001263 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001264 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001265 ", DSO: %s", dso->short_name);
1266 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001267}
1268
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001269static inline void free_popup_options(char **options, int n)
1270{
1271 int i;
1272
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001273 for (i = 0; i < n; ++i)
1274 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001275}
1276
Feng Tangc77d8d72012-11-01 00:00:55 +08001277/* Check whether the browser is for 'top' or 'report' */
1278static inline bool is_report_browser(void *timer)
1279{
1280 return timer == NULL;
1281}
1282
Feng Tang341487ab2013-02-03 14:38:20 +08001283/*
1284 * Only runtime switching of perf data file will make "input_name" point
1285 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1286 * whether we need to call free() for current "input_name" during the switch.
1287 */
1288static bool is_input_name_malloced = false;
1289
1290static int switch_data_file(void)
1291{
1292 char *pwd, *options[32], *abs_path[32], *tmp;
1293 DIR *pwd_dir;
1294 int nr_options = 0, choice = -1, ret = -1;
1295 struct dirent *dent;
1296
1297 pwd = getenv("PWD");
1298 if (!pwd)
1299 return ret;
1300
1301 pwd_dir = opendir(pwd);
1302 if (!pwd_dir)
1303 return ret;
1304
1305 memset(options, 0, sizeof(options));
1306 memset(options, 0, sizeof(abs_path));
1307
1308 while ((dent = readdir(pwd_dir))) {
1309 char path[PATH_MAX];
1310 u64 magic;
1311 char *name = dent->d_name;
1312 FILE *file;
1313
1314 if (!(dent->d_type == DT_REG))
1315 continue;
1316
1317 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1318
1319 file = fopen(path, "r");
1320 if (!file)
1321 continue;
1322
1323 if (fread(&magic, 1, 8, file) < 8)
1324 goto close_file_and_continue;
1325
1326 if (is_perf_magic(magic)) {
1327 options[nr_options] = strdup(name);
1328 if (!options[nr_options])
1329 goto close_file_and_continue;
1330
1331 abs_path[nr_options] = strdup(path);
1332 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001333 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001334 ui__warning("Can't search all data files due to memory shortage.\n");
1335 fclose(file);
1336 break;
1337 }
1338
1339 nr_options++;
1340 }
1341
1342close_file_and_continue:
1343 fclose(file);
1344 if (nr_options >= 32) {
1345 ui__warning("Too many perf data files in PWD!\n"
1346 "Only the first 32 files will be listed.\n");
1347 break;
1348 }
1349 }
1350 closedir(pwd_dir);
1351
1352 if (nr_options) {
1353 choice = ui__popup_menu(nr_options, options);
1354 if (choice < nr_options && choice >= 0) {
1355 tmp = strdup(abs_path[choice]);
1356 if (tmp) {
1357 if (is_input_name_malloced)
1358 free((void *)input_name);
1359 input_name = tmp;
1360 is_input_name_malloced = true;
1361 ret = 0;
1362 } else
1363 ui__warning("Data switch failed due to memory shortage!\n");
1364 }
1365 }
1366
1367 free_popup_options(options, nr_options);
1368 free_popup_options(abs_path, nr_options);
1369 return ret;
1370}
1371
Namhyung Kim112f7612014-04-22 14:05:35 +09001372static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001373{
1374 u64 nr_entries = 0;
1375 struct rb_node *nd = rb_first(&hb->hists->entries);
1376
Namhyung Kim268397c2014-04-22 14:49:31 +09001377 if (hb->min_pcnt == 0) {
1378 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1379 return;
1380 }
1381
Namhyung Kim14135662013-10-31 10:17:39 +09001382 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001383 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001384 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001385 }
1386
Namhyung Kim112f7612014-04-22 14:05:35 +09001387 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001388}
Feng Tang341487ab2013-02-03 14:38:20 +08001389
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001390static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001391 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001392 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001393 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001394 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001395 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001396{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001397 struct hists *hists = &evsel->hists;
1398 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001399 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001400 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001401 char *options[16];
1402 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001403 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001404 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001405 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001406 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001407
Namhyung Kime8e684a2013-12-26 14:37:58 +09001408#define HIST_BROWSER_HELP_COMMON \
1409 "h/?/F1 Show this window\n" \
1410 "UP/DOWN/PGUP\n" \
1411 "PGDN/SPACE Navigate\n" \
1412 "q/ESC/CTRL+C Exit browser\n\n" \
1413 "For multiple event sessions:\n\n" \
1414 "TAB/UNTAB Switch events\n\n" \
1415 "For symbolic views (--sort has sym):\n\n" \
1416 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1417 "<- Zoom out\n" \
1418 "a Annotate current symbol\n" \
1419 "C Collapse all callchains\n" \
1420 "d Zoom into current DSO\n" \
1421 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001422 "F Toggle percentage of filtered entries\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001423
1424 /* help messages are sorted by lexical order of the hotkey */
1425 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001426 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001427 "P Print histograms to perf.hist.N\n"
1428 "r Run available scripts\n"
1429 "s Switch to another data file in PWD\n"
1430 "t Zoom into current Thread\n"
1431 "V Verbose (DSO names in callchains, etc)\n"
1432 "/ Filter symbol by name";
1433 const char top_help[] = HIST_BROWSER_HELP_COMMON
1434 "P Print histograms to perf.hist.N\n"
1435 "t Zoom into current Thread\n"
1436 "V Verbose (DSO names in callchains, etc)\n"
1437 "/ Filter symbol by name";
1438
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001439 if (browser == NULL)
1440 return -1;
1441
Namhyung Kim064f1982013-05-14 11:09:04 +09001442 if (min_pcnt) {
1443 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001444 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001445 }
1446
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001447 fstack = pstack__new(2);
1448 if (fstack == NULL)
1449 goto out;
1450
1451 ui_helpline__push(helpline);
1452
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001453 memset(options, 0, sizeof(options));
1454
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001455 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001456 const struct thread *thread = NULL;
1457 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001458 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001459 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001460 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001461 int scripts_comm = -2, scripts_symbol = -2,
1462 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001463
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001464 nr_options = 0;
1465
Jiri Olsadd00d482014-06-19 13:41:13 +02001466 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001467
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001468 if (browser->he_selection != NULL) {
1469 thread = hist_browser__selected_thread(browser);
1470 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1471 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001472 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001473 case K_TAB:
1474 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001475 if (nr_events == 1)
1476 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001477 /*
1478 * Exit the browser, let hists__browser_tree
1479 * go to the next or previous
1480 */
1481 goto out_free_stack;
1482 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001483 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001484 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001485 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001486 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001487 continue;
1488 }
1489
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001490 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001491 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001492 browser->selection->map->dso->annotate_warned)
1493 continue;
1494 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001495 case 'P':
1496 hist_browser__dump(browser);
1497 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001498 case 'd':
1499 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001500 case 'V':
1501 browser->show_dso = !browser->show_dso;
1502 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001503 case 't':
1504 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001505 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001506 if (ui_browser__input_window("Symbol to show",
1507 "Please enter the name of symbol you want to see",
1508 buf, "ENTER: OK, ESC: Cancel",
1509 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001510 hists->symbol_filter_str = *buf ? buf : NULL;
1511 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001512 hist_browser__reset(browser);
1513 }
1514 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001515 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001516 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001517 goto do_scripts;
1518 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001519 case 's':
1520 if (is_report_browser(hbt))
1521 goto do_data_switch;
1522 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001523 case 'i':
1524 /* env->arch is NULL for live-mode (i.e. perf top) */
1525 if (env->arch)
1526 tui__header_window(env);
1527 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001528 case 'F':
1529 symbol_conf.filter_relative ^= 1;
1530 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001531 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001532 case 'h':
1533 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001534 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001535 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001536 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001537 case K_ENTER:
1538 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001539 /* menu */
1540 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001541 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001542 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001543
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001544 if (pstack__empty(fstack)) {
1545 /*
1546 * Go back to the perf_evsel_menu__run or other user
1547 */
1548 if (left_exits)
1549 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001550 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001551 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001552 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001553 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001554 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001555 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001556 goto zoom_out_thread;
1557 continue;
1558 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001559 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001560 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001561 !ui_browser__dialog_yesno(&browser->b,
1562 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001563 continue;
1564 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001565 case 'q':
1566 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001567 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001568 default:
1569 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001570 }
1571
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001572 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001573 goto add_exit_option;
1574
Namhyung Kim55369fc2013-04-01 20:35:20 +09001575 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001576 bi = browser->he_selection->branch_info;
1577 if (browser->selection != NULL &&
1578 bi &&
1579 bi->from.sym != NULL &&
1580 !bi->from.map->dso->annotate_warned &&
1581 asprintf(&options[nr_options], "Annotate %s",
1582 bi->from.sym->name) > 0)
1583 annotate_f = nr_options++;
1584
1585 if (browser->selection != NULL &&
1586 bi &&
1587 bi->to.sym != NULL &&
1588 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001589 (bi->to.sym != bi->from.sym ||
1590 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001591 asprintf(&options[nr_options], "Annotate %s",
1592 bi->to.sym->name) > 0)
1593 annotate_t = nr_options++;
1594 } else {
1595
1596 if (browser->selection != NULL &&
1597 browser->selection->sym != NULL &&
1598 !browser->selection->map->dso->annotate_warned &&
1599 asprintf(&options[nr_options], "Annotate %s",
1600 browser->selection->sym->name) > 0)
1601 annotate = nr_options++;
1602 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001603
1604 if (thread != NULL &&
1605 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001606 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001607 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001608 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001609 zoom_thread = nr_options++;
1610
1611 if (dso != NULL &&
1612 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001613 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001614 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1615 zoom_dso = nr_options++;
1616
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001617 if (browser->selection != NULL &&
1618 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001619 asprintf(&options[nr_options], "Browse map details") > 0)
1620 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001621
1622 /* perf script support */
1623 if (browser->he_selection) {
1624 struct symbol *sym;
1625
1626 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001627 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001628 scripts_comm = nr_options++;
1629
1630 sym = browser->he_selection->ms.sym;
1631 if (sym && sym->namelen &&
1632 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1633 sym->name) > 0)
1634 scripts_symbol = nr_options++;
1635 }
1636
1637 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1638 scripts_all = nr_options++;
1639
Feng Tang341487ab2013-02-03 14:38:20 +08001640 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1641 "Switch to another data file in PWD") > 0)
1642 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001643add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001644 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001645retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001646 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001647
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001648 if (choice == nr_options - 1)
1649 break;
1650
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001651 if (choice == -1) {
1652 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001653 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001654 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001655
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001656 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001657 struct hist_entry *he;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001658 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001659do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001660 if (!objdump_path && perf_session_env__lookup_objdump(env))
1661 continue;
1662
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001663 he = hist_browser__selected_entry(browser);
1664 if (he == NULL)
1665 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001666
1667 /*
1668 * we stash the branch_info symbol + map into the
1669 * the ms so we don't have to rewrite all the annotation
1670 * code to use branch_info.
1671 * in branch mode, the ms struct is not used
1672 */
1673 if (choice == annotate_f) {
1674 he->ms.sym = he->branch_info->from.sym;
1675 he->ms.map = he->branch_info->from.map;
1676 } else if (choice == annotate_t) {
1677 he->ms.sym = he->branch_info->to.sym;
1678 he->ms.map = he->branch_info->to.map;
1679 }
1680
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001681 /*
1682 * Don't let this be freed, say, by hists__decay_entry.
1683 */
1684 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001685 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001686 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001687 /*
1688 * offer option to annotate the other branch source or target
1689 * (if they exists) when returning from annotate
1690 */
1691 if ((err == 'q' || err == CTRL('c'))
1692 && annotate_t != -2 && annotate_f != -2)
1693 goto retry_popup_menu;
1694
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001695 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001696 if (err)
1697 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001698
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001699 } else if (choice == browse_map)
1700 map__browse(browser->selection->map);
1701 else if (choice == zoom_dso) {
1702zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001703 if (browser->hists->dso_filter) {
1704 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001705zoom_out_dso:
1706 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001707 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001708 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001709 } else {
1710 if (dso == NULL)
1711 continue;
1712 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1713 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001714 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001715 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001716 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001717 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001718 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001719 hist_browser__reset(browser);
1720 } else if (choice == zoom_thread) {
1721zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001722 if (browser->hists->thread_filter) {
1723 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001724zoom_out_thread:
1725 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001726 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001727 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001728 } else {
1729 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001730 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001731 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001732 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001733 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001734 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001735 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001736 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001737 hist_browser__reset(browser);
1738 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001739 /* perf scripts support */
1740 else if (choice == scripts_all || choice == scripts_comm ||
1741 choice == scripts_symbol) {
1742do_scripts:
1743 memset(script_opt, 0, 64);
1744
1745 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001746 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001747
1748 if (choice == scripts_symbol)
1749 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1750
1751 script_browse(script_opt);
1752 }
Feng Tang341487ab2013-02-03 14:38:20 +08001753 /* Switch to another data file */
1754 else if (choice == switch_data) {
1755do_data_switch:
1756 if (!switch_data_file()) {
1757 key = K_SWITCH_INPUT_DATA;
1758 break;
1759 } else
1760 ui__warning("Won't switch the data files due to\n"
1761 "no valid data file get selected!\n");
1762 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001763 }
1764out_free_stack:
1765 pstack__delete(fstack);
1766out:
1767 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001768 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769 return key;
1770}
1771
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001772struct perf_evsel_menu {
1773 struct ui_browser b;
1774 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001775 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001776 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001777 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001778};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001779
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001780static void perf_evsel_menu__write(struct ui_browser *browser,
1781 void *entry, int row)
1782{
1783 struct perf_evsel_menu *menu = container_of(browser,
1784 struct perf_evsel_menu, b);
1785 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1786 bool current_entry = ui_browser__is_current_entry(browser, row);
1787 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001788 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001789 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001790 const char *warn = " ";
1791 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001792
1793 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1794 HE_COLORSET_NORMAL);
1795
Namhyung Kim759ff492013-03-05 14:53:26 +09001796 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001797 struct perf_evsel *pos;
1798
1799 ev_name = perf_evsel__group_name(evsel);
1800
1801 for_each_group_member(pos, evsel) {
1802 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1803 }
1804 }
1805
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001806 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001807 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001808 unit, unit == ' ' ? "" : " ", ev_name);
1809 slsmg_printf("%s", bf);
1810
1811 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1812 if (nr_events != 0) {
1813 menu->lost_events = true;
1814 if (!current_entry)
1815 ui_browser__set_color(browser, HE_COLORSET_TOP);
1816 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001817 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1818 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001819 warn = bf;
1820 }
1821
1822 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001823
1824 if (current_entry)
1825 menu->selection = evsel;
1826}
1827
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001828static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1829 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001830 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001831{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001832 struct perf_evlist *evlist = menu->b.priv;
1833 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001834 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001835 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001836 int key;
1837
1838 if (ui_browser__show(&menu->b, title,
1839 "ESC: exit, ENTER|->: Browse histograms") < 0)
1840 return -1;
1841
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001842 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001843 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001844
1845 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001846 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001847 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001848
1849 if (!menu->lost_events_warned && menu->lost_events) {
1850 ui_browser__warn_lost_events(&menu->b);
1851 menu->lost_events_warned = true;
1852 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001853 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001854 case K_RIGHT:
1855 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001856 if (!menu->selection)
1857 continue;
1858 pos = menu->selection;
1859browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001860 perf_evlist__set_selected(evlist, pos);
1861 /*
1862 * Give the calling tool a chance to populate the non
1863 * default evsel resorted hists tree.
1864 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001865 if (hbt)
1866 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001867 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001868 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001869 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001870 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001871 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001872 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001873 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001874 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001875 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001876 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001877 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001878 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001879 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001880 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001881 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001882 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001883 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001884 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001885 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001886 if (!ui_browser__dialog_yesno(&menu->b,
1887 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001888 continue;
1889 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001890 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001891 case 'q':
1892 case CTRL('c'):
1893 goto out;
1894 default:
1895 continue;
1896 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001897 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001898 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001899 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001900 if (!ui_browser__dialog_yesno(&menu->b,
1901 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001902 continue;
1903 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001904 case 'q':
1905 case CTRL('c'):
1906 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001907 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001908 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001909 }
1910 }
1911
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001912out:
1913 ui_browser__hide(&menu->b);
1914 return key;
1915}
1916
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001917static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001918 void *entry)
1919{
1920 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1921
1922 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1923 return true;
1924
1925 return false;
1926}
1927
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001928static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001929 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001930 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001931 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001932 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001933{
1934 struct perf_evsel *pos;
1935 struct perf_evsel_menu menu = {
1936 .b = {
1937 .entries = &evlist->entries,
1938 .refresh = ui_browser__list_head_refresh,
1939 .seek = ui_browser__list_head_seek,
1940 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001941 .filter = filter_group_entries,
1942 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001943 .priv = evlist,
1944 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001945 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001946 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001947 };
1948
1949 ui_helpline__push("Press ESC to exit");
1950
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001951 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001952 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001953 size_t line_len = strlen(ev_name) + 7;
1954
1955 if (menu.b.width < line_len)
1956 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001957 }
1958
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001959 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001960}
1961
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001962int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001963 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001964 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001965 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001966{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001967 int nr_entries = evlist->nr_entries;
1968
1969single_entry:
1970 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001971 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001972
1973 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001974 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001975 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001976 }
1977
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001978 if (symbol_conf.event_group) {
1979 struct perf_evsel *pos;
1980
1981 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001982 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001983 if (perf_evsel__is_group_leader(pos))
1984 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001985 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001986
1987 if (nr_entries == 1)
1988 goto single_entry;
1989 }
1990
1991 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001992 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001993}