blob: 1c331b934ffc50747c1b6df0ba6658e81fe8971d [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
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030035static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -020036 const char *ev_name);
Namhyung Kim112f7612014-04-22 14:05:35 +090037static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030038
Namhyung Kimc3b78952014-04-22 15:56:17 +090039static struct rb_node *hists__filter_entries(struct rb_node *nd,
40 struct hists *hists,
41 float min_pcnt);
42
Namhyung Kim268397c2014-04-22 14:49:31 +090043static bool hist_browser__has_filter(struct hist_browser *hb)
44{
45 return hists__has_filter(hb->hists) || hb->min_pcnt;
46}
47
Namhyung Kimc3b78952014-04-22 15:56:17 +090048static u32 hist_browser__nr_entries(struct hist_browser *hb)
49{
50 u32 nr_entries;
51
52 if (hist_browser__has_filter(hb))
53 nr_entries = hb->nr_non_filtered_entries;
54 else
55 nr_entries = hb->hists->nr_entries;
56
57 return nr_entries + hb->nr_callchain_rows;
58}
59
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030060static void hist_browser__refresh_dimensions(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030061{
62 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030063 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030064 sizeof("[k]"));
65}
66
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030067static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030068{
Namhyung Kimc3b78952014-04-22 15:56:17 +090069 /*
70 * The hists__remove_entry_filter() already folds non-filtered
71 * entries so we can assume it has 0 callchain rows.
72 */
73 browser->nr_callchain_rows = 0;
74
Namhyung Kim268397c2014-04-22 14:49:31 +090075 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +090076 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030077 hist_browser__refresh_dimensions(browser);
78 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030079}
80
81static char tree__folded_sign(bool unfolded)
82{
83 return unfolded ? '-' : '+';
84}
85
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030086static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030087{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030088 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030089}
90
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030091static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030092{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030093 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030094}
95
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030096static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030097{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030098 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030099}
100
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300101static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300102{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300103 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300104}
105
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300106static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300107{
108 int n = 0;
109 struct rb_node *nd;
110
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300111 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300112 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
113 struct callchain_list *chain;
114 char folded_sign = ' '; /* No children */
115
116 list_for_each_entry(chain, &child->val, list) {
117 ++n;
118 /* We need this because we may not have children */
119 folded_sign = callchain_list__folded(chain);
120 if (folded_sign == '+')
121 break;
122 }
123
124 if (folded_sign == '-') /* Have children and they're unfolded */
125 n += callchain_node__count_rows_rb_tree(child);
126 }
127
128 return n;
129}
130
131static int callchain_node__count_rows(struct callchain_node *node)
132{
133 struct callchain_list *chain;
134 bool unfolded = false;
135 int n = 0;
136
137 list_for_each_entry(chain, &node->val, list) {
138 ++n;
139 unfolded = chain->ms.unfolded;
140 }
141
142 if (unfolded)
143 n += callchain_node__count_rows_rb_tree(node);
144
145 return n;
146}
147
148static int callchain__count_rows(struct rb_root *chain)
149{
150 struct rb_node *nd;
151 int n = 0;
152
153 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
154 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
155 n += callchain_node__count_rows(node);
156 }
157
158 return n;
159}
160
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300161static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300162{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300163 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200164 return false;
165
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300166 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300167 return false;
168
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300169 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300170 return true;
171}
172
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300173static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300174{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300175 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300176
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300177 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300178 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
179 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300180 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300181
182 list_for_each_entry(chain, &child->val, list) {
183 if (first) {
184 first = false;
185 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300186 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300187 } else
188 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300189 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300190 }
191
192 callchain_node__init_have_children_rb_tree(child);
193 }
194}
195
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300196static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300197{
198 struct callchain_list *chain;
199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300200 list_for_each_entry(chain, &node->val, list)
201 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300202
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300203 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300204}
205
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300206static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300207{
208 struct rb_node *nd;
209
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300210 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300211 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
212 callchain_node__init_have_children(node);
213 }
214}
215
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300216static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300217{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300218 if (!he->init_have_children) {
219 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
220 callchain__init_have_children(&he->sorted_chain);
221 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300222 }
223}
224
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300225static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300226{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300227 if (map_symbol__toggle_fold(browser->selection)) {
228 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229
230 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900231 browser->b.nr_entries -= he->nr_rows;
232 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300233
234 if (he->ms.unfolded)
235 he->nr_rows = callchain__count_rows(&he->sorted_chain);
236 else
237 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900238
239 browser->b.nr_entries += he->nr_rows;
240 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300241
242 return true;
243 }
244
245 /* If it doesn't have children, no toggling performed */
246 return false;
247}
248
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300249static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300250{
251 int n = 0;
252 struct rb_node *nd;
253
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300254 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300255 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
256 struct callchain_list *chain;
257 bool has_children = false;
258
259 list_for_each_entry(chain, &child->val, list) {
260 ++n;
261 map_symbol__set_folding(&chain->ms, unfold);
262 has_children = chain->ms.has_children;
263 }
264
265 if (has_children)
266 n += callchain_node__set_folding_rb_tree(child, unfold);
267 }
268
269 return n;
270}
271
272static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
273{
274 struct callchain_list *chain;
275 bool has_children = false;
276 int n = 0;
277
278 list_for_each_entry(chain, &node->val, list) {
279 ++n;
280 map_symbol__set_folding(&chain->ms, unfold);
281 has_children = chain->ms.has_children;
282 }
283
284 if (has_children)
285 n += callchain_node__set_folding_rb_tree(node, unfold);
286
287 return n;
288}
289
290static int callchain__set_folding(struct rb_root *chain, bool unfold)
291{
292 struct rb_node *nd;
293 int n = 0;
294
295 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
296 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
297 n += callchain_node__set_folding(node, unfold);
298 }
299
300 return n;
301}
302
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300303static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300304{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300305 hist_entry__init_have_children(he);
306 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300307
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300308 if (he->ms.has_children) {
309 int n = callchain__set_folding(&he->sorted_chain, unfold);
310 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300311 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300312 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300313}
314
Namhyung Kimc3b78952014-04-22 15:56:17 +0900315static void
316__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300317{
318 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900319 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300320
Namhyung Kimc3b78952014-04-22 15:56:17 +0900321 for (nd = rb_first(&hists->entries);
322 (nd = hists__filter_entries(nd, hists, browser->min_pcnt)) != NULL;
323 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300324 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
325 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900326 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300327 }
328}
329
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300330static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300331{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900332 browser->nr_callchain_rows = 0;
333 __hist_browser__set_folding(browser, unfold);
334
335 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300336 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300337 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300338}
339
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200340static void ui_browser__warn_lost_events(struct ui_browser *browser)
341{
342 ui_browser__warning(browser, 4,
343 "Events are being lost, check IO/CPU overload!\n\n"
344 "You may want to run 'perf' using a RT scheduler policy:\n\n"
345 " perf top -r 80\n\n"
346 "Or reduce the sampling frequency.");
347}
348
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300349static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900350 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300351{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300352 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300353 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900354 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300355
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300356 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900357 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300358
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300359 hist_browser__refresh_dimensions(browser);
360 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300361
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300362 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300363 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300364 return -1;
365
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300366 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300367 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300368
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300369 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900370 case K_TIMER: {
371 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900372 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900373
Namhyung Kimc3b78952014-04-22 15:56:17 +0900374 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900375 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900376
Namhyung Kimc3b78952014-04-22 15:56:17 +0900377 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900378 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200379
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300380 if (browser->hists->stats.nr_lost_warned !=
381 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
382 browser->hists->stats.nr_lost_warned =
383 browser->hists->stats.nr_events[PERF_RECORD_LOST];
384 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200385 }
386
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300387 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
388 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300389 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900390 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300391 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300393 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394 struct hist_entry, rb_node);
395 ui_helpline__pop();
396 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 -0300397 seq++, browser->b.nr_entries,
398 browser->hists->nr_entries,
399 browser->b.height,
400 browser->b.index,
401 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300402 h->row_offset, h->nr_rows);
403 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300404 break;
405 case 'C':
406 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300407 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300408 break;
409 case 'E':
410 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300411 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300412 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200413 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300414 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300415 break;
416 /* fall thru */
417 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300418 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300419 }
420 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300421out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300422 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300423 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300424}
425
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300426static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300427 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300429 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300430
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300431 if (cl->ms.sym)
432 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
433 else
434 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
435
436 if (show_dso)
437 scnprintf(bf + printed, bfsize - printed, " %s",
438 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
439
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300440 return bf;
441}
442
443#define LEVEL_OFFSET_STEP 3
444
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300445static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300446 struct callchain_node *chain_node,
447 u64 total, int level,
448 unsigned short row,
449 off_t *row_offset,
450 bool *is_current_entry)
451{
452 struct rb_node *node;
453 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
454 u64 new_total, remaining;
455
456 if (callchain_param.mode == CHAIN_GRAPH_REL)
457 new_total = chain_node->children_hit;
458 else
459 new_total = total;
460
461 remaining = new_total;
462 node = rb_first(&chain_node->rb_root);
463 while (node) {
464 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
465 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100466 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300467 struct callchain_list *chain;
468 char folded_sign = ' ';
469 int first = true;
470 int extra_offset = 0;
471
472 remaining -= cumul;
473
474 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300475 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300476 const char *str;
477 int color;
478 bool was_first = first;
479
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300480 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300481 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300482 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300483 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300484
485 folded_sign = callchain_list__folded(chain);
486 if (*row_offset != 0) {
487 --*row_offset;
488 goto do_next;
489 }
490
491 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300492 str = callchain_list__sym_name(chain, bf, sizeof(bf),
493 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300494 if (was_first) {
495 double percent = cumul * 100.0 / new_total;
496
497 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
498 str = "Not enough memory!";
499 else
500 str = alloc_str;
501 }
502
503 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300504 width = browser->b.width - (offset + extra_offset + 2);
505 if (ui_browser__is_current_entry(&browser->b, row)) {
506 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300507 color = HE_COLORSET_SELECTED;
508 *is_current_entry = true;
509 }
510
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300511 ui_browser__set_color(&browser->b, color);
512 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300513 slsmg_write_nstring(" ", offset + extra_offset);
514 slsmg_printf("%c ", folded_sign);
515 slsmg_write_nstring(str, width);
516 free(alloc_str);
517
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300519 goto out;
520do_next:
521 if (folded_sign == '+')
522 break;
523 }
524
525 if (folded_sign == '-') {
526 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300527 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300528 new_level, row, row_offset,
529 is_current_entry);
530 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300531 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300532 goto out;
533 node = next;
534 }
535out:
536 return row - first_row;
537}
538
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300539static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300540 struct callchain_node *node,
541 int level, unsigned short row,
542 off_t *row_offset,
543 bool *is_current_entry)
544{
545 struct callchain_list *chain;
546 int first_row = row,
547 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300548 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300549 char folded_sign = ' ';
550
551 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300552 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300553 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300554
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300555 folded_sign = callchain_list__folded(chain);
556
557 if (*row_offset != 0) {
558 --*row_offset;
559 continue;
560 }
561
562 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300563 if (ui_browser__is_current_entry(&browser->b, row)) {
564 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300565 color = HE_COLORSET_SELECTED;
566 *is_current_entry = true;
567 }
568
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300569 s = callchain_list__sym_name(chain, bf, sizeof(bf),
570 browser->show_dso);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300571 ui_browser__gotorc(&browser->b, row, 0);
572 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300573 slsmg_write_nstring(" ", offset);
574 slsmg_printf("%c ", folded_sign);
575 slsmg_write_nstring(s, width - 2);
576
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300577 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300578 goto out;
579 }
580
581 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300582 row += hist_browser__show_callchain_node_rb_tree(browser, node,
583 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300584 level + 1, row,
585 row_offset,
586 is_current_entry);
587out:
588 return row - first_row;
589}
590
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300591static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592 struct rb_root *chain,
593 int level, unsigned short row,
594 off_t *row_offset,
595 bool *is_current_entry)
596{
597 struct rb_node *nd;
598 int first_row = row;
599
600 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
601 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
602
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300603 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300604 row, row_offset,
605 is_current_entry);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300606 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607 break;
608 }
609
610 return row - first_row;
611}
612
Namhyung Kim89701462013-01-22 18:09:38 +0900613struct hpp_arg {
614 struct ui_browser *b;
615 char folded_sign;
616 bool current_entry;
617};
618
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900619static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
620{
621 struct hpp_arg *arg = hpp->ptr;
622 int ret;
623 va_list args;
624 double percent;
625
626 va_start(args, fmt);
627 percent = va_arg(args, double);
628 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900629
Namhyung Kim89701462013-01-22 18:09:38 +0900630 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900631
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900632 ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900633 slsmg_printf("%s", hpp->buf);
634
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900635 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900636 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900637}
638
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900639#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900640static u64 __hpp_get_##_field(struct hist_entry *he) \
641{ \
642 return he->stat._field; \
643} \
644 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100645static int \
646hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
647 struct perf_hpp *hpp, \
648 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900649{ \
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900650 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900651 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900652}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900653
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900654__HPP_COLOR_PERCENT_FN(overhead, period)
655__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
656__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
657__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
658__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900659
660#undef __HPP_COLOR_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900661
662void hist_browser__init_hpp(void)
663{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900664 perf_hpp__format[PERF_HPP__OVERHEAD].color =
665 hist_browser__hpp_color_overhead;
666 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
667 hist_browser__hpp_color_overhead_sys;
668 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
669 hist_browser__hpp_color_overhead_us;
670 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
671 hist_browser__hpp_color_overhead_guest_sys;
672 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
673 hist_browser__hpp_color_overhead_guest_us;
674}
675
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300676static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300677 struct hist_entry *entry,
678 unsigned short row)
679{
680 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200681 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900682 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300683 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300684 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300685 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300686 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200687 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300688
689 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300690 browser->he_selection = entry;
691 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300692 }
693
694 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300695 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300696 folded_sign = hist_entry__folded(entry);
697 }
698
699 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900700 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900701 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900702 .folded_sign = folded_sign,
703 .current_entry = current_entry,
704 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900705 struct perf_hpp hpp = {
706 .buf = s,
707 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900708 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900709 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300710
Namhyung Kim67d25912012-09-12 15:35:06 +0900711 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900712
Jiri Olsa12400052012-10-13 00:06:16 +0200713 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900714 if (perf_hpp__should_skip(fmt))
715 continue;
716
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900717 if (current_entry && browser->b.navkeypressed) {
718 ui_browser__set_color(&browser->b,
719 HE_COLORSET_SELECTED);
720 } else {
721 ui_browser__set_color(&browser->b,
722 HE_COLORSET_NORMAL);
723 }
724
725 if (first) {
726 if (symbol_conf.use_callchain) {
727 slsmg_printf("%c ", folded_sign);
728 width -= 2;
729 }
730 first = false;
731 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900732 slsmg_printf(" ");
733 width -= 2;
734 }
735
Jiri Olsa12400052012-10-13 00:06:16 +0200736 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100737 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900738 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100739 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900740 slsmg_printf("%s", s);
741 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300742 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200743
744 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300745 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200746 width += 1;
747
Namhyung Kim26d8b332014-03-03 16:16:20 +0900748 slsmg_write_nstring("", width);
749
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300750 ++row;
751 ++printed;
752 } else
753 --row_offset;
754
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300755 if (folded_sign == '-' && row != browser->b.height) {
756 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300757 1, row, &row_offset,
758 &current_entry);
759 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300760 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300761 }
762
763 return printed;
764}
765
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300766static void ui_browser__hists_init_top(struct ui_browser *browser)
767{
768 if (browser->top == NULL) {
769 struct hist_browser *hb;
770
771 hb = container_of(browser, struct hist_browser, b);
772 browser->top = rb_first(&hb->hists->entries);
773 }
774}
775
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300776static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300777{
778 unsigned row = 0;
779 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300780 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300781
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300782 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300783
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300784 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300785 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900786 u64 total = hists__total_period(h->hists);
787 float percent = 0.0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300788
789 if (h->filtered)
790 continue;
791
Namhyung Kimf2148332014-01-14 11:52:48 +0900792 if (total)
793 percent = h->stat.period * 100.0 / total;
794
Namhyung Kim064f1982013-05-14 11:09:04 +0900795 if (percent < hb->min_pcnt)
796 continue;
797
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300798 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300799 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300800 break;
801 }
802
803 return row;
804}
805
Namhyung Kim064f1982013-05-14 11:09:04 +0900806static struct rb_node *hists__filter_entries(struct rb_node *nd,
807 struct hists *hists,
808 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300809{
810 while (nd != NULL) {
811 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900812 u64 total = hists__total_period(hists);
813 float percent = 0.0;
814
815 if (total)
816 percent = h->stat.period * 100.0 / total;
Namhyung Kim064f1982013-05-14 11:09:04 +0900817
Namhyung Kimc0f15272014-04-16 11:16:33 +0900818 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300819 return nd;
820
821 nd = rb_next(nd);
822 }
823
824 return NULL;
825}
826
Namhyung Kim064f1982013-05-14 11:09:04 +0900827static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
828 struct hists *hists,
829 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300830{
831 while (nd != NULL) {
832 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900833 u64 total = hists__total_period(hists);
834 float percent = 0.0;
835
836 if (total)
837 percent = h->stat.period * 100.0 / total;
Namhyung Kim064f1982013-05-14 11:09:04 +0900838
839 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300840 return nd;
841
842 nd = rb_prev(nd);
843 }
844
845 return NULL;
846}
847
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300848static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300849 off_t offset, int whence)
850{
851 struct hist_entry *h;
852 struct rb_node *nd;
853 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900854 struct hist_browser *hb;
855
856 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300857
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300858 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300859 return;
860
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300861 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300862
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300863 switch (whence) {
864 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900865 nd = hists__filter_entries(rb_first(browser->entries),
866 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300867 break;
868 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300869 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300870 goto do_offset;
871 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900872 nd = hists__filter_prev_entries(rb_last(browser->entries),
873 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300874 first = false;
875 break;
876 default:
877 return;
878 }
879
880 /*
881 * Moves not relative to the first visible entry invalidates its
882 * row_offset:
883 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300884 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300885 h->row_offset = 0;
886
887 /*
888 * Here we have to check if nd is expanded (+), if it is we can't go
889 * the next top level hist_entry, instead we must compute an offset of
890 * what _not_ to show and not change the first visible entry.
891 *
892 * This offset increments when we are going from top to bottom and
893 * decreases when we're going from bottom to top.
894 *
895 * As we don't have backpointers to the top level in the callchains
896 * structure, we need to always print the whole hist_entry callchain,
897 * skipping the first ones that are before the first visible entry
898 * and stop when we printed enough lines to fill the screen.
899 */
900do_offset:
901 if (offset > 0) {
902 do {
903 h = rb_entry(nd, struct hist_entry, rb_node);
904 if (h->ms.unfolded) {
905 u16 remaining = h->nr_rows - h->row_offset;
906 if (offset > remaining) {
907 offset -= remaining;
908 h->row_offset = 0;
909 } else {
910 h->row_offset += offset;
911 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300912 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300913 break;
914 }
915 }
Namhyung Kim064f1982013-05-14 11:09:04 +0900916 nd = hists__filter_entries(rb_next(nd), hb->hists,
917 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300918 if (nd == NULL)
919 break;
920 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300921 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300922 } while (offset != 0);
923 } else if (offset < 0) {
924 while (1) {
925 h = rb_entry(nd, struct hist_entry, rb_node);
926 if (h->ms.unfolded) {
927 if (first) {
928 if (-offset > h->row_offset) {
929 offset += h->row_offset;
930 h->row_offset = 0;
931 } else {
932 h->row_offset += offset;
933 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300934 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300935 break;
936 }
937 } else {
938 if (-offset > h->nr_rows) {
939 offset += h->nr_rows;
940 h->row_offset = 0;
941 } else {
942 h->row_offset = h->nr_rows + offset;
943 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300944 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300945 break;
946 }
947 }
948 }
949
Namhyung Kim064f1982013-05-14 11:09:04 +0900950 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
951 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300952 if (nd == NULL)
953 break;
954 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300955 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300956 if (offset == 0) {
957 /*
958 * Last unfiltered hist_entry, check if it is
959 * unfolded, if it is then we should have
960 * row_offset at its last entry.
961 */
962 h = rb_entry(nd, struct hist_entry, rb_node);
963 if (h->ms.unfolded)
964 h->row_offset = h->nr_rows;
965 break;
966 }
967 first = false;
968 }
969 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300970 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300971 h = rb_entry(nd, struct hist_entry, rb_node);
972 h->row_offset = 0;
973 }
974}
975
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300976static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
977 struct callchain_node *chain_node,
978 u64 total, int level,
979 FILE *fp)
980{
981 struct rb_node *node;
982 int offset = level * LEVEL_OFFSET_STEP;
983 u64 new_total, remaining;
984 int printed = 0;
985
986 if (callchain_param.mode == CHAIN_GRAPH_REL)
987 new_total = chain_node->children_hit;
988 else
989 new_total = total;
990
991 remaining = new_total;
992 node = rb_first(&chain_node->rb_root);
993 while (node) {
994 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
995 struct rb_node *next = rb_next(node);
996 u64 cumul = callchain_cumul_hits(child);
997 struct callchain_list *chain;
998 char folded_sign = ' ';
999 int first = true;
1000 int extra_offset = 0;
1001
1002 remaining -= cumul;
1003
1004 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001005 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001006 const char *str;
1007 bool was_first = first;
1008
1009 if (first)
1010 first = false;
1011 else
1012 extra_offset = LEVEL_OFFSET_STEP;
1013
1014 folded_sign = callchain_list__folded(chain);
1015
1016 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001017 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1018 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001019 if (was_first) {
1020 double percent = cumul * 100.0 / new_total;
1021
1022 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1023 str = "Not enough memory!";
1024 else
1025 str = alloc_str;
1026 }
1027
1028 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1029 free(alloc_str);
1030 if (folded_sign == '+')
1031 break;
1032 }
1033
1034 if (folded_sign == '-') {
1035 const int new_level = level + (extra_offset ? 2 : 1);
1036 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1037 new_level, fp);
1038 }
1039
1040 node = next;
1041 }
1042
1043 return printed;
1044}
1045
1046static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1047 struct callchain_node *node,
1048 int level, FILE *fp)
1049{
1050 struct callchain_list *chain;
1051 int offset = level * LEVEL_OFFSET_STEP;
1052 char folded_sign = ' ';
1053 int printed = 0;
1054
1055 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001056 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001057
1058 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001059 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001060 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1061 }
1062
1063 if (folded_sign == '-')
1064 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1065 browser->hists->stats.total_period,
1066 level + 1, fp);
1067 return printed;
1068}
1069
1070static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1071 struct rb_root *chain, int level, FILE *fp)
1072{
1073 struct rb_node *nd;
1074 int printed = 0;
1075
1076 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1077 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1078
1079 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1080 }
1081
1082 return printed;
1083}
1084
1085static int hist_browser__fprintf_entry(struct hist_browser *browser,
1086 struct hist_entry *he, FILE *fp)
1087{
1088 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001089 int printed = 0;
1090 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001091 struct perf_hpp hpp = {
1092 .buf = s,
1093 .size = sizeof(s),
1094 };
1095 struct perf_hpp_fmt *fmt;
1096 bool first = true;
1097 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001098
1099 if (symbol_conf.use_callchain)
1100 folded_sign = hist_entry__folded(he);
1101
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001102 if (symbol_conf.use_callchain)
1103 printed += fprintf(fp, "%c ", folded_sign);
1104
Namhyung Kim26d8b332014-03-03 16:16:20 +09001105 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001106 if (perf_hpp__should_skip(fmt))
1107 continue;
1108
Namhyung Kim26d8b332014-03-03 16:16:20 +09001109 if (!first) {
1110 ret = scnprintf(hpp.buf, hpp.size, " ");
1111 advance_hpp(&hpp, ret);
1112 } else
1113 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001114
Namhyung Kim26d8b332014-03-03 16:16:20 +09001115 ret = fmt->entry(fmt, &hpp, he);
1116 advance_hpp(&hpp, ret);
1117 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001118 printed += fprintf(fp, "%s\n", rtrim(s));
1119
1120 if (folded_sign == '-')
1121 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1122
1123 return printed;
1124}
1125
1126static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1127{
Namhyung Kim064f1982013-05-14 11:09:04 +09001128 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1129 browser->hists,
1130 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001131 int printed = 0;
1132
1133 while (nd) {
1134 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1135
1136 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim064f1982013-05-14 11:09:04 +09001137 nd = hists__filter_entries(rb_next(nd), browser->hists,
1138 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001139 }
1140
1141 return printed;
1142}
1143
1144static int hist_browser__dump(struct hist_browser *browser)
1145{
1146 char filename[64];
1147 FILE *fp;
1148
1149 while (1) {
1150 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1151 if (access(filename, F_OK))
1152 break;
1153 /*
1154 * XXX: Just an arbitrary lazy upper limit
1155 */
1156 if (++browser->print_seq == 8192) {
1157 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1158 return -1;
1159 }
1160 }
1161
1162 fp = fopen(filename, "w");
1163 if (fp == NULL) {
1164 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001165 const char *err = strerror_r(errno, bf, sizeof(bf));
1166 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001167 return -1;
1168 }
1169
1170 ++browser->print_seq;
1171 hist_browser__fprintf(browser, fp);
1172 fclose(fp);
1173 ui_helpline__fpush("%s written!", filename);
1174
1175 return 0;
1176}
1177
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001178static struct hist_browser *hist_browser__new(struct hists *hists)
1179{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001180 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001181
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001182 if (browser) {
1183 browser->hists = hists;
1184 browser->b.refresh = hist_browser__refresh;
1185 browser->b.seek = ui_browser__hists_seek;
1186 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001187 }
1188
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001189 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001190}
1191
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001192static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001193{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001194 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001195}
1196
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001197static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001199 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200}
1201
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001202static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001203{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001204 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001205}
1206
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001207static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001208 const char *ev_name)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001209{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001210 char unit;
1211 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001212 const struct dso *dso = hists->dso_filter;
1213 const struct thread *thread = hists->thread_filter;
1214 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1215 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001216 struct perf_evsel *evsel = hists_to_evsel(hists);
1217 char buf[512];
1218 size_t buflen = sizeof(buf);
1219
Namhyung Kimf2148332014-01-14 11:52:48 +09001220 if (symbol_conf.filter_relative) {
1221 nr_samples = hists->stats.nr_non_filtered_samples;
1222 nr_events = hists->stats.total_non_filtered_period;
1223 }
1224
Namhyung Kim759ff492013-03-05 14:53:26 +09001225 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001226 struct perf_evsel *pos;
1227
1228 perf_evsel__group_desc(evsel, buf, buflen);
1229 ev_name = buf;
1230
1231 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001232 if (symbol_conf.filter_relative) {
1233 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1234 nr_events += pos->hists.stats.total_non_filtered_period;
1235 } else {
1236 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1237 nr_events += pos->hists.stats.total_period;
1238 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001239 }
1240 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001241
Ashay Ranecc686282012-04-05 21:01:01 -05001242 nr_samples = convert_unit(nr_samples, &unit);
1243 printed = scnprintf(bf, size,
1244 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1245 nr_samples, unit, ev_name, nr_events);
1246
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001247
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001248 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001249 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001250 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001251 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001252 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001253 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001254 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001255 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001256 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001257 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001258 ", DSO: %s", dso->short_name);
1259 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001260}
1261
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001262static inline void free_popup_options(char **options, int n)
1263{
1264 int i;
1265
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001266 for (i = 0; i < n; ++i)
1267 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001268}
1269
Feng Tangc77d8d72012-11-01 00:00:55 +08001270/* Check whether the browser is for 'top' or 'report' */
1271static inline bool is_report_browser(void *timer)
1272{
1273 return timer == NULL;
1274}
1275
Feng Tang341487ab2013-02-03 14:38:20 +08001276/*
1277 * Only runtime switching of perf data file will make "input_name" point
1278 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1279 * whether we need to call free() for current "input_name" during the switch.
1280 */
1281static bool is_input_name_malloced = false;
1282
1283static int switch_data_file(void)
1284{
1285 char *pwd, *options[32], *abs_path[32], *tmp;
1286 DIR *pwd_dir;
1287 int nr_options = 0, choice = -1, ret = -1;
1288 struct dirent *dent;
1289
1290 pwd = getenv("PWD");
1291 if (!pwd)
1292 return ret;
1293
1294 pwd_dir = opendir(pwd);
1295 if (!pwd_dir)
1296 return ret;
1297
1298 memset(options, 0, sizeof(options));
1299 memset(options, 0, sizeof(abs_path));
1300
1301 while ((dent = readdir(pwd_dir))) {
1302 char path[PATH_MAX];
1303 u64 magic;
1304 char *name = dent->d_name;
1305 FILE *file;
1306
1307 if (!(dent->d_type == DT_REG))
1308 continue;
1309
1310 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1311
1312 file = fopen(path, "r");
1313 if (!file)
1314 continue;
1315
1316 if (fread(&magic, 1, 8, file) < 8)
1317 goto close_file_and_continue;
1318
1319 if (is_perf_magic(magic)) {
1320 options[nr_options] = strdup(name);
1321 if (!options[nr_options])
1322 goto close_file_and_continue;
1323
1324 abs_path[nr_options] = strdup(path);
1325 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001326 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001327 ui__warning("Can't search all data files due to memory shortage.\n");
1328 fclose(file);
1329 break;
1330 }
1331
1332 nr_options++;
1333 }
1334
1335close_file_and_continue:
1336 fclose(file);
1337 if (nr_options >= 32) {
1338 ui__warning("Too many perf data files in PWD!\n"
1339 "Only the first 32 files will be listed.\n");
1340 break;
1341 }
1342 }
1343 closedir(pwd_dir);
1344
1345 if (nr_options) {
1346 choice = ui__popup_menu(nr_options, options);
1347 if (choice < nr_options && choice >= 0) {
1348 tmp = strdup(abs_path[choice]);
1349 if (tmp) {
1350 if (is_input_name_malloced)
1351 free((void *)input_name);
1352 input_name = tmp;
1353 is_input_name_malloced = true;
1354 ret = 0;
1355 } else
1356 ui__warning("Data switch failed due to memory shortage!\n");
1357 }
1358 }
1359
1360 free_popup_options(options, nr_options);
1361 free_popup_options(abs_path, nr_options);
1362 return ret;
1363}
1364
Namhyung Kim112f7612014-04-22 14:05:35 +09001365static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001366{
1367 u64 nr_entries = 0;
1368 struct rb_node *nd = rb_first(&hb->hists->entries);
1369
Namhyung Kim268397c2014-04-22 14:49:31 +09001370 if (hb->min_pcnt == 0) {
1371 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1372 return;
1373 }
1374
Namhyung Kimc481f932014-04-22 13:56:11 +09001375 while ((nd = hists__filter_entries(nd, hb->hists,
1376 hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001377 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001378 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001379 }
1380
Namhyung Kim112f7612014-04-22 14:05:35 +09001381 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001382}
Feng Tang341487ab2013-02-03 14:38:20 +08001383
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001384static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001385 const char *helpline, const char *ev_name,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001386 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001387 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001388 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001389 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001390{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001391 struct hists *hists = &evsel->hists;
1392 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001393 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001394 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001395 char *options[16];
1396 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001397 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001398 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001399 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001400 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001401
Namhyung Kime8e684a2013-12-26 14:37:58 +09001402#define HIST_BROWSER_HELP_COMMON \
1403 "h/?/F1 Show this window\n" \
1404 "UP/DOWN/PGUP\n" \
1405 "PGDN/SPACE Navigate\n" \
1406 "q/ESC/CTRL+C Exit browser\n\n" \
1407 "For multiple event sessions:\n\n" \
1408 "TAB/UNTAB Switch events\n\n" \
1409 "For symbolic views (--sort has sym):\n\n" \
1410 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1411 "<- Zoom out\n" \
1412 "a Annotate current symbol\n" \
1413 "C Collapse all callchains\n" \
1414 "d Zoom into current DSO\n" \
1415 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001416 "F Toggle percentage of filtered entries\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001417
1418 /* help messages are sorted by lexical order of the hotkey */
1419 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001420 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001421 "P Print histograms to perf.hist.N\n"
1422 "r Run available scripts\n"
1423 "s Switch to another data file in PWD\n"
1424 "t Zoom into current Thread\n"
1425 "V Verbose (DSO names in callchains, etc)\n"
1426 "/ Filter symbol by name";
1427 const char top_help[] = HIST_BROWSER_HELP_COMMON
1428 "P Print histograms to perf.hist.N\n"
1429 "t Zoom into current Thread\n"
1430 "V Verbose (DSO names in callchains, etc)\n"
1431 "/ Filter symbol by name";
1432
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001433 if (browser == NULL)
1434 return -1;
1435
Namhyung Kim064f1982013-05-14 11:09:04 +09001436 if (min_pcnt) {
1437 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001438 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001439 }
1440
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001441 fstack = pstack__new(2);
1442 if (fstack == NULL)
1443 goto out;
1444
1445 ui_helpline__push(helpline);
1446
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001447 memset(options, 0, sizeof(options));
1448
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001449 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001450 const struct thread *thread = NULL;
1451 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001452 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001453 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001454 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001455 int scripts_comm = -2, scripts_symbol = -2,
1456 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001457
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001458 nr_options = 0;
1459
Namhyung Kim9783adf2012-11-02 14:50:05 +09001460 key = hist_browser__run(browser, ev_name, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001461
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001462 if (browser->he_selection != NULL) {
1463 thread = hist_browser__selected_thread(browser);
1464 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1465 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001466 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001467 case K_TAB:
1468 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001469 if (nr_events == 1)
1470 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001471 /*
1472 * Exit the browser, let hists__browser_tree
1473 * go to the next or previous
1474 */
1475 goto out_free_stack;
1476 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001477 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001478 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001479 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001480 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001481 continue;
1482 }
1483
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001484 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001485 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001486 browser->selection->map->dso->annotate_warned)
1487 continue;
1488 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001489 case 'P':
1490 hist_browser__dump(browser);
1491 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001492 case 'd':
1493 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001494 case 'V':
1495 browser->show_dso = !browser->show_dso;
1496 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001497 case 't':
1498 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001499 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001500 if (ui_browser__input_window("Symbol to show",
1501 "Please enter the name of symbol you want to see",
1502 buf, "ENTER: OK, ESC: Cancel",
1503 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001504 hists->symbol_filter_str = *buf ? buf : NULL;
1505 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001506 hist_browser__reset(browser);
1507 }
1508 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001509 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001510 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001511 goto do_scripts;
1512 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001513 case 's':
1514 if (is_report_browser(hbt))
1515 goto do_data_switch;
1516 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001517 case 'i':
1518 /* env->arch is NULL for live-mode (i.e. perf top) */
1519 if (env->arch)
1520 tui__header_window(env);
1521 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001522 case 'F':
1523 symbol_conf.filter_relative ^= 1;
1524 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001525 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001526 case 'h':
1527 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001528 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001529 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001530 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001531 case K_ENTER:
1532 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001533 /* menu */
1534 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001535 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001536 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001537
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001538 if (pstack__empty(fstack)) {
1539 /*
1540 * Go back to the perf_evsel_menu__run or other user
1541 */
1542 if (left_exits)
1543 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001544 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001545 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001546 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001547 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001548 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001549 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001550 goto zoom_out_thread;
1551 continue;
1552 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001553 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001554 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001555 !ui_browser__dialog_yesno(&browser->b,
1556 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001557 continue;
1558 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001559 case 'q':
1560 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001561 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001562 default:
1563 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001564 }
1565
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001566 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001567 goto add_exit_option;
1568
Namhyung Kim55369fc2013-04-01 20:35:20 +09001569 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001570 bi = browser->he_selection->branch_info;
1571 if (browser->selection != NULL &&
1572 bi &&
1573 bi->from.sym != NULL &&
1574 !bi->from.map->dso->annotate_warned &&
1575 asprintf(&options[nr_options], "Annotate %s",
1576 bi->from.sym->name) > 0)
1577 annotate_f = nr_options++;
1578
1579 if (browser->selection != NULL &&
1580 bi &&
1581 bi->to.sym != NULL &&
1582 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001583 (bi->to.sym != bi->from.sym ||
1584 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001585 asprintf(&options[nr_options], "Annotate %s",
1586 bi->to.sym->name) > 0)
1587 annotate_t = nr_options++;
1588 } else {
1589
1590 if (browser->selection != NULL &&
1591 browser->selection->sym != NULL &&
1592 !browser->selection->map->dso->annotate_warned &&
1593 asprintf(&options[nr_options], "Annotate %s",
1594 browser->selection->sym->name) > 0)
1595 annotate = nr_options++;
1596 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001597
1598 if (thread != NULL &&
1599 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001600 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001601 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001602 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001603 zoom_thread = nr_options++;
1604
1605 if (dso != NULL &&
1606 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001607 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001608 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1609 zoom_dso = nr_options++;
1610
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001611 if (browser->selection != NULL &&
1612 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001613 asprintf(&options[nr_options], "Browse map details") > 0)
1614 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001615
1616 /* perf script support */
1617 if (browser->he_selection) {
1618 struct symbol *sym;
1619
1620 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001621 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001622 scripts_comm = nr_options++;
1623
1624 sym = browser->he_selection->ms.sym;
1625 if (sym && sym->namelen &&
1626 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1627 sym->name) > 0)
1628 scripts_symbol = nr_options++;
1629 }
1630
1631 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1632 scripts_all = nr_options++;
1633
Feng Tang341487ab2013-02-03 14:38:20 +08001634 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1635 "Switch to another data file in PWD") > 0)
1636 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001637add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001638 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001639retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001640 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001641
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001642 if (choice == nr_options - 1)
1643 break;
1644
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001645 if (choice == -1) {
1646 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001647 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001648 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001649
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001650 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001651 struct hist_entry *he;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001652 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001653do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001654 if (!objdump_path && perf_session_env__lookup_objdump(env))
1655 continue;
1656
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001657 he = hist_browser__selected_entry(browser);
1658 if (he == NULL)
1659 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001660
1661 /*
1662 * we stash the branch_info symbol + map into the
1663 * the ms so we don't have to rewrite all the annotation
1664 * code to use branch_info.
1665 * in branch mode, the ms struct is not used
1666 */
1667 if (choice == annotate_f) {
1668 he->ms.sym = he->branch_info->from.sym;
1669 he->ms.map = he->branch_info->from.map;
1670 } else if (choice == annotate_t) {
1671 he->ms.sym = he->branch_info->to.sym;
1672 he->ms.map = he->branch_info->to.map;
1673 }
1674
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001675 /*
1676 * Don't let this be freed, say, by hists__decay_entry.
1677 */
1678 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001679 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001680 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001681 /*
1682 * offer option to annotate the other branch source or target
1683 * (if they exists) when returning from annotate
1684 */
1685 if ((err == 'q' || err == CTRL('c'))
1686 && annotate_t != -2 && annotate_f != -2)
1687 goto retry_popup_menu;
1688
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001689 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001690 if (err)
1691 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001692
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001693 } else if (choice == browse_map)
1694 map__browse(browser->selection->map);
1695 else if (choice == zoom_dso) {
1696zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001697 if (browser->hists->dso_filter) {
1698 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001699zoom_out_dso:
1700 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001701 browser->hists->dso_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001702 sort_dso.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001703 } else {
1704 if (dso == NULL)
1705 continue;
1706 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1707 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001708 browser->hists->dso_filter = dso;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001709 sort_dso.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001710 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001711 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001712 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001713 hist_browser__reset(browser);
1714 } else if (choice == zoom_thread) {
1715zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001716 if (browser->hists->thread_filter) {
1717 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001718zoom_out_thread:
1719 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001720 browser->hists->thread_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001721 sort_thread.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001722 } else {
1723 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001724 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001725 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001726 browser->hists->thread_filter = thread;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001727 sort_thread.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001728 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001729 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001730 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001731 hist_browser__reset(browser);
1732 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001733 /* perf scripts support */
1734 else if (choice == scripts_all || choice == scripts_comm ||
1735 choice == scripts_symbol) {
1736do_scripts:
1737 memset(script_opt, 0, 64);
1738
1739 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001740 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001741
1742 if (choice == scripts_symbol)
1743 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1744
1745 script_browse(script_opt);
1746 }
Feng Tang341487ab2013-02-03 14:38:20 +08001747 /* Switch to another data file */
1748 else if (choice == switch_data) {
1749do_data_switch:
1750 if (!switch_data_file()) {
1751 key = K_SWITCH_INPUT_DATA;
1752 break;
1753 } else
1754 ui__warning("Won't switch the data files due to\n"
1755 "no valid data file get selected!\n");
1756 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757 }
1758out_free_stack:
1759 pstack__delete(fstack);
1760out:
1761 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001762 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001763 return key;
1764}
1765
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001766struct perf_evsel_menu {
1767 struct ui_browser b;
1768 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001769 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001770 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001771 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001772};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001773
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001774static void perf_evsel_menu__write(struct ui_browser *browser,
1775 void *entry, int row)
1776{
1777 struct perf_evsel_menu *menu = container_of(browser,
1778 struct perf_evsel_menu, b);
1779 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1780 bool current_entry = ui_browser__is_current_entry(browser, row);
1781 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001782 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001783 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001784 const char *warn = " ";
1785 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001786
1787 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1788 HE_COLORSET_NORMAL);
1789
Namhyung Kim759ff492013-03-05 14:53:26 +09001790 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001791 struct perf_evsel *pos;
1792
1793 ev_name = perf_evsel__group_name(evsel);
1794
1795 for_each_group_member(pos, evsel) {
1796 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1797 }
1798 }
1799
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001800 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001801 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001802 unit, unit == ' ' ? "" : " ", ev_name);
1803 slsmg_printf("%s", bf);
1804
1805 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1806 if (nr_events != 0) {
1807 menu->lost_events = true;
1808 if (!current_entry)
1809 ui_browser__set_color(browser, HE_COLORSET_TOP);
1810 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001811 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1812 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001813 warn = bf;
1814 }
1815
1816 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001817
1818 if (current_entry)
1819 menu->selection = evsel;
1820}
1821
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001822static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1823 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001824 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001825{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001826 struct perf_evlist *evlist = menu->b.priv;
1827 struct perf_evsel *pos;
1828 const char *ev_name, *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001829 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001830 int key;
1831
1832 if (ui_browser__show(&menu->b, title,
1833 "ESC: exit, ENTER|->: Browse histograms") < 0)
1834 return -1;
1835
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001836 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001837 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001838
1839 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001840 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001841 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001842
1843 if (!menu->lost_events_warned && menu->lost_events) {
1844 ui_browser__warn_lost_events(&menu->b);
1845 menu->lost_events_warned = true;
1846 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001847 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001848 case K_RIGHT:
1849 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001850 if (!menu->selection)
1851 continue;
1852 pos = menu->selection;
1853browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001854 perf_evlist__set_selected(evlist, pos);
1855 /*
1856 * Give the calling tool a chance to populate the non
1857 * default evsel resorted hists tree.
1858 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001859 if (hbt)
1860 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001861 ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001862 key = perf_evsel__hists_browse(pos, nr_events, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001863 ev_name, true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001864 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001865 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001866 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001867 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001868 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001869 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001870 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001871 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001872 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001873 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001874 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001875 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001876 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001877 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001878 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001879 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001880 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001881 if (!ui_browser__dialog_yesno(&menu->b,
1882 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001883 continue;
1884 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001885 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001886 case 'q':
1887 case CTRL('c'):
1888 goto out;
1889 default:
1890 continue;
1891 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001892 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001893 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001894 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001895 if (!ui_browser__dialog_yesno(&menu->b,
1896 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001897 continue;
1898 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001899 case 'q':
1900 case CTRL('c'):
1901 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001902 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001903 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001904 }
1905 }
1906
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001907out:
1908 ui_browser__hide(&menu->b);
1909 return key;
1910}
1911
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001912static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001913 void *entry)
1914{
1915 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1916
1917 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1918 return true;
1919
1920 return false;
1921}
1922
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001923static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001924 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001925 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001926 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001927 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001928{
1929 struct perf_evsel *pos;
1930 struct perf_evsel_menu menu = {
1931 .b = {
1932 .entries = &evlist->entries,
1933 .refresh = ui_browser__list_head_refresh,
1934 .seek = ui_browser__list_head_seek,
1935 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001936 .filter = filter_group_entries,
1937 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001938 .priv = evlist,
1939 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001940 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001941 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001942 };
1943
1944 ui_helpline__push("Press ESC to exit");
1945
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001946 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001947 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001948 size_t line_len = strlen(ev_name) + 7;
1949
1950 if (menu.b.width < line_len)
1951 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001952 }
1953
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001954 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001955}
1956
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001957int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001958 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001959 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001960 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001961{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001962 int nr_entries = evlist->nr_entries;
1963
1964single_entry:
1965 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001966 struct perf_evsel *first = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001967 const char *ev_name = perf_evsel__name(first);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001968
1969 return perf_evsel__hists_browse(first, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001970 ev_name, false, hbt, min_pcnt,
1971 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001972 }
1973
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001974 if (symbol_conf.event_group) {
1975 struct perf_evsel *pos;
1976
1977 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001978 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001979 if (perf_evsel__is_group_leader(pos))
1980 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001981 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001982
1983 if (nr_entries == 1)
1984 goto single_entry;
1985 }
1986
1987 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001988 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001989}