blob: 37c5188fd68adc43dd8384c2835048ba740a011a [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{
Jiri Olsa1d778222012-10-04 21:49:39 +0900664 perf_hpp__init();
Namhyung Kimf5951d52012-09-03 11:53:09 +0900665
666 perf_hpp__format[PERF_HPP__OVERHEAD].color =
667 hist_browser__hpp_color_overhead;
668 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
669 hist_browser__hpp_color_overhead_sys;
670 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
671 hist_browser__hpp_color_overhead_us;
672 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
673 hist_browser__hpp_color_overhead_guest_sys;
674 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
675 hist_browser__hpp_color_overhead_guest_us;
676}
677
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300678static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300679 struct hist_entry *entry,
680 unsigned short row)
681{
682 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200683 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900684 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300685 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300686 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300687 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300688 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200689 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300690
691 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300692 browser->he_selection = entry;
693 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300694 }
695
696 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300697 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300698 folded_sign = hist_entry__folded(entry);
699 }
700
701 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900702 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900703 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900704 .folded_sign = folded_sign,
705 .current_entry = current_entry,
706 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900707 struct perf_hpp hpp = {
708 .buf = s,
709 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900710 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900711 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300712
Namhyung Kim67d25912012-09-12 15:35:06 +0900713 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900714
Jiri Olsa12400052012-10-13 00:06:16 +0200715 perf_hpp__for_each_format(fmt) {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900716 if (current_entry && browser->b.navkeypressed) {
717 ui_browser__set_color(&browser->b,
718 HE_COLORSET_SELECTED);
719 } else {
720 ui_browser__set_color(&browser->b,
721 HE_COLORSET_NORMAL);
722 }
723
724 if (first) {
725 if (symbol_conf.use_callchain) {
726 slsmg_printf("%c ", folded_sign);
727 width -= 2;
728 }
729 first = false;
730 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900731 slsmg_printf(" ");
732 width -= 2;
733 }
734
Jiri Olsa12400052012-10-13 00:06:16 +0200735 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100736 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900737 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100738 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900739 slsmg_printf("%s", s);
740 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300741 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200742
743 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300744 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200745 width += 1;
746
Namhyung Kim26d8b332014-03-03 16:16:20 +0900747 slsmg_write_nstring("", width);
748
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300749 ++row;
750 ++printed;
751 } else
752 --row_offset;
753
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300754 if (folded_sign == '-' && row != browser->b.height) {
755 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300756 1, row, &row_offset,
757 &current_entry);
758 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300759 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300760 }
761
762 return printed;
763}
764
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300765static void ui_browser__hists_init_top(struct ui_browser *browser)
766{
767 if (browser->top == NULL) {
768 struct hist_browser *hb;
769
770 hb = container_of(browser, struct hist_browser, b);
771 browser->top = rb_first(&hb->hists->entries);
772 }
773}
774
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300775static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300776{
777 unsigned row = 0;
778 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300779 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300780
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300781 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300782
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300783 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300784 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900785 u64 total = hists__total_period(h->hists);
786 float percent = 0.0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300787
788 if (h->filtered)
789 continue;
790
Namhyung Kimf2148332014-01-14 11:52:48 +0900791 if (total)
792 percent = h->stat.period * 100.0 / total;
793
Namhyung Kim064f1982013-05-14 11:09:04 +0900794 if (percent < hb->min_pcnt)
795 continue;
796
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300797 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300798 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300799 break;
800 }
801
802 return row;
803}
804
Namhyung Kim064f1982013-05-14 11:09:04 +0900805static struct rb_node *hists__filter_entries(struct rb_node *nd,
806 struct hists *hists,
807 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300808{
809 while (nd != NULL) {
810 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900811 u64 total = hists__total_period(hists);
812 float percent = 0.0;
813
814 if (total)
815 percent = h->stat.period * 100.0 / total;
Namhyung Kim064f1982013-05-14 11:09:04 +0900816
817 if (percent < min_pcnt)
818 return NULL;
819
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300820 if (!h->filtered)
821 return nd;
822
823 nd = rb_next(nd);
824 }
825
826 return NULL;
827}
828
Namhyung Kim064f1982013-05-14 11:09:04 +0900829static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
830 struct hists *hists,
831 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300832{
833 while (nd != NULL) {
834 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900835 u64 total = hists__total_period(hists);
836 float percent = 0.0;
837
838 if (total)
839 percent = h->stat.period * 100.0 / total;
Namhyung Kim064f1982013-05-14 11:09:04 +0900840
841 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300842 return nd;
843
844 nd = rb_prev(nd);
845 }
846
847 return NULL;
848}
849
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300850static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300851 off_t offset, int whence)
852{
853 struct hist_entry *h;
854 struct rb_node *nd;
855 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900856 struct hist_browser *hb;
857
858 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300859
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300860 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300861 return;
862
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300863 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300864
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300865 switch (whence) {
866 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900867 nd = hists__filter_entries(rb_first(browser->entries),
868 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300869 break;
870 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300871 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300872 goto do_offset;
873 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900874 nd = hists__filter_prev_entries(rb_last(browser->entries),
875 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300876 first = false;
877 break;
878 default:
879 return;
880 }
881
882 /*
883 * Moves not relative to the first visible entry invalidates its
884 * row_offset:
885 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300886 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300887 h->row_offset = 0;
888
889 /*
890 * Here we have to check if nd is expanded (+), if it is we can't go
891 * the next top level hist_entry, instead we must compute an offset of
892 * what _not_ to show and not change the first visible entry.
893 *
894 * This offset increments when we are going from top to bottom and
895 * decreases when we're going from bottom to top.
896 *
897 * As we don't have backpointers to the top level in the callchains
898 * structure, we need to always print the whole hist_entry callchain,
899 * skipping the first ones that are before the first visible entry
900 * and stop when we printed enough lines to fill the screen.
901 */
902do_offset:
903 if (offset > 0) {
904 do {
905 h = rb_entry(nd, struct hist_entry, rb_node);
906 if (h->ms.unfolded) {
907 u16 remaining = h->nr_rows - h->row_offset;
908 if (offset > remaining) {
909 offset -= remaining;
910 h->row_offset = 0;
911 } else {
912 h->row_offset += offset;
913 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300914 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300915 break;
916 }
917 }
Namhyung Kim064f1982013-05-14 11:09:04 +0900918 nd = hists__filter_entries(rb_next(nd), hb->hists,
919 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300920 if (nd == NULL)
921 break;
922 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300923 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300924 } while (offset != 0);
925 } else if (offset < 0) {
926 while (1) {
927 h = rb_entry(nd, struct hist_entry, rb_node);
928 if (h->ms.unfolded) {
929 if (first) {
930 if (-offset > h->row_offset) {
931 offset += h->row_offset;
932 h->row_offset = 0;
933 } else {
934 h->row_offset += offset;
935 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300936 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300937 break;
938 }
939 } else {
940 if (-offset > h->nr_rows) {
941 offset += h->nr_rows;
942 h->row_offset = 0;
943 } else {
944 h->row_offset = h->nr_rows + offset;
945 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300946 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300947 break;
948 }
949 }
950 }
951
Namhyung Kim064f1982013-05-14 11:09:04 +0900952 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
953 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300954 if (nd == NULL)
955 break;
956 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300957 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300958 if (offset == 0) {
959 /*
960 * Last unfiltered hist_entry, check if it is
961 * unfolded, if it is then we should have
962 * row_offset at its last entry.
963 */
964 h = rb_entry(nd, struct hist_entry, rb_node);
965 if (h->ms.unfolded)
966 h->row_offset = h->nr_rows;
967 break;
968 }
969 first = false;
970 }
971 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300972 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300973 h = rb_entry(nd, struct hist_entry, rb_node);
974 h->row_offset = 0;
975 }
976}
977
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300978static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
979 struct callchain_node *chain_node,
980 u64 total, int level,
981 FILE *fp)
982{
983 struct rb_node *node;
984 int offset = level * LEVEL_OFFSET_STEP;
985 u64 new_total, remaining;
986 int printed = 0;
987
988 if (callchain_param.mode == CHAIN_GRAPH_REL)
989 new_total = chain_node->children_hit;
990 else
991 new_total = total;
992
993 remaining = new_total;
994 node = rb_first(&chain_node->rb_root);
995 while (node) {
996 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
997 struct rb_node *next = rb_next(node);
998 u64 cumul = callchain_cumul_hits(child);
999 struct callchain_list *chain;
1000 char folded_sign = ' ';
1001 int first = true;
1002 int extra_offset = 0;
1003
1004 remaining -= cumul;
1005
1006 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001007 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001008 const char *str;
1009 bool was_first = first;
1010
1011 if (first)
1012 first = false;
1013 else
1014 extra_offset = LEVEL_OFFSET_STEP;
1015
1016 folded_sign = callchain_list__folded(chain);
1017
1018 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001019 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1020 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001021 if (was_first) {
1022 double percent = cumul * 100.0 / new_total;
1023
1024 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1025 str = "Not enough memory!";
1026 else
1027 str = alloc_str;
1028 }
1029
1030 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1031 free(alloc_str);
1032 if (folded_sign == '+')
1033 break;
1034 }
1035
1036 if (folded_sign == '-') {
1037 const int new_level = level + (extra_offset ? 2 : 1);
1038 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1039 new_level, fp);
1040 }
1041
1042 node = next;
1043 }
1044
1045 return printed;
1046}
1047
1048static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1049 struct callchain_node *node,
1050 int level, FILE *fp)
1051{
1052 struct callchain_list *chain;
1053 int offset = level * LEVEL_OFFSET_STEP;
1054 char folded_sign = ' ';
1055 int printed = 0;
1056
1057 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001058 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001059
1060 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001061 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001062 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1063 }
1064
1065 if (folded_sign == '-')
1066 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1067 browser->hists->stats.total_period,
1068 level + 1, fp);
1069 return printed;
1070}
1071
1072static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1073 struct rb_root *chain, int level, FILE *fp)
1074{
1075 struct rb_node *nd;
1076 int printed = 0;
1077
1078 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1079 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1080
1081 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1082 }
1083
1084 return printed;
1085}
1086
1087static int hist_browser__fprintf_entry(struct hist_browser *browser,
1088 struct hist_entry *he, FILE *fp)
1089{
1090 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001091 int printed = 0;
1092 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001093 struct perf_hpp hpp = {
1094 .buf = s,
1095 .size = sizeof(s),
1096 };
1097 struct perf_hpp_fmt *fmt;
1098 bool first = true;
1099 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001100
1101 if (symbol_conf.use_callchain)
1102 folded_sign = hist_entry__folded(he);
1103
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001104 if (symbol_conf.use_callchain)
1105 printed += fprintf(fp, "%c ", folded_sign);
1106
Namhyung Kim26d8b332014-03-03 16:16:20 +09001107 perf_hpp__for_each_format(fmt) {
1108 if (!first) {
1109 ret = scnprintf(hpp.buf, hpp.size, " ");
1110 advance_hpp(&hpp, ret);
1111 } else
1112 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001113
Namhyung Kim26d8b332014-03-03 16:16:20 +09001114 ret = fmt->entry(fmt, &hpp, he);
1115 advance_hpp(&hpp, ret);
1116 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001117 printed += fprintf(fp, "%s\n", rtrim(s));
1118
1119 if (folded_sign == '-')
1120 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1121
1122 return printed;
1123}
1124
1125static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1126{
Namhyung Kim064f1982013-05-14 11:09:04 +09001127 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1128 browser->hists,
1129 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001130 int printed = 0;
1131
1132 while (nd) {
1133 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1134
1135 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim064f1982013-05-14 11:09:04 +09001136 nd = hists__filter_entries(rb_next(nd), browser->hists,
1137 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001138 }
1139
1140 return printed;
1141}
1142
1143static int hist_browser__dump(struct hist_browser *browser)
1144{
1145 char filename[64];
1146 FILE *fp;
1147
1148 while (1) {
1149 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1150 if (access(filename, F_OK))
1151 break;
1152 /*
1153 * XXX: Just an arbitrary lazy upper limit
1154 */
1155 if (++browser->print_seq == 8192) {
1156 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1157 return -1;
1158 }
1159 }
1160
1161 fp = fopen(filename, "w");
1162 if (fp == NULL) {
1163 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001164 const char *err = strerror_r(errno, bf, sizeof(bf));
1165 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001166 return -1;
1167 }
1168
1169 ++browser->print_seq;
1170 hist_browser__fprintf(browser, fp);
1171 fclose(fp);
1172 ui_helpline__fpush("%s written!", filename);
1173
1174 return 0;
1175}
1176
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001177static struct hist_browser *hist_browser__new(struct hists *hists)
1178{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001179 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001181 if (browser) {
1182 browser->hists = hists;
1183 browser->b.refresh = hist_browser__refresh;
1184 browser->b.seek = ui_browser__hists_seek;
1185 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001186 }
1187
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001188 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001189}
1190
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001191static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001192{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001193 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001194}
1195
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001196static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001197{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001198 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199}
1200
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001201static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001203 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204}
1205
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001206static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001207 const char *ev_name)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001208{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001209 char unit;
1210 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001211 const struct dso *dso = hists->dso_filter;
1212 const struct thread *thread = hists->thread_filter;
1213 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1214 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001215 struct perf_evsel *evsel = hists_to_evsel(hists);
1216 char buf[512];
1217 size_t buflen = sizeof(buf);
1218
Namhyung Kimf2148332014-01-14 11:52:48 +09001219 if (symbol_conf.filter_relative) {
1220 nr_samples = hists->stats.nr_non_filtered_samples;
1221 nr_events = hists->stats.total_non_filtered_period;
1222 }
1223
Namhyung Kim759ff492013-03-05 14:53:26 +09001224 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001225 struct perf_evsel *pos;
1226
1227 perf_evsel__group_desc(evsel, buf, buflen);
1228 ev_name = buf;
1229
1230 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001231 if (symbol_conf.filter_relative) {
1232 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1233 nr_events += pos->hists.stats.total_non_filtered_period;
1234 } else {
1235 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1236 nr_events += pos->hists.stats.total_period;
1237 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001238 }
1239 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001240
Ashay Ranecc686282012-04-05 21:01:01 -05001241 nr_samples = convert_unit(nr_samples, &unit);
1242 printed = scnprintf(bf, size,
1243 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1244 nr_samples, unit, ev_name, nr_events);
1245
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001246
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001247 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001248 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001249 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001250 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001251 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001252 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001253 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001254 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001255 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001256 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001257 ", DSO: %s", dso->short_name);
1258 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259}
1260
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001261static inline void free_popup_options(char **options, int n)
1262{
1263 int i;
1264
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001265 for (i = 0; i < n; ++i)
1266 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001267}
1268
Feng Tangc77d8d72012-11-01 00:00:55 +08001269/* Check whether the browser is for 'top' or 'report' */
1270static inline bool is_report_browser(void *timer)
1271{
1272 return timer == NULL;
1273}
1274
Feng Tang341487ab2013-02-03 14:38:20 +08001275/*
1276 * Only runtime switching of perf data file will make "input_name" point
1277 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1278 * whether we need to call free() for current "input_name" during the switch.
1279 */
1280static bool is_input_name_malloced = false;
1281
1282static int switch_data_file(void)
1283{
1284 char *pwd, *options[32], *abs_path[32], *tmp;
1285 DIR *pwd_dir;
1286 int nr_options = 0, choice = -1, ret = -1;
1287 struct dirent *dent;
1288
1289 pwd = getenv("PWD");
1290 if (!pwd)
1291 return ret;
1292
1293 pwd_dir = opendir(pwd);
1294 if (!pwd_dir)
1295 return ret;
1296
1297 memset(options, 0, sizeof(options));
1298 memset(options, 0, sizeof(abs_path));
1299
1300 while ((dent = readdir(pwd_dir))) {
1301 char path[PATH_MAX];
1302 u64 magic;
1303 char *name = dent->d_name;
1304 FILE *file;
1305
1306 if (!(dent->d_type == DT_REG))
1307 continue;
1308
1309 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1310
1311 file = fopen(path, "r");
1312 if (!file)
1313 continue;
1314
1315 if (fread(&magic, 1, 8, file) < 8)
1316 goto close_file_and_continue;
1317
1318 if (is_perf_magic(magic)) {
1319 options[nr_options] = strdup(name);
1320 if (!options[nr_options])
1321 goto close_file_and_continue;
1322
1323 abs_path[nr_options] = strdup(path);
1324 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001325 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001326 ui__warning("Can't search all data files due to memory shortage.\n");
1327 fclose(file);
1328 break;
1329 }
1330
1331 nr_options++;
1332 }
1333
1334close_file_and_continue:
1335 fclose(file);
1336 if (nr_options >= 32) {
1337 ui__warning("Too many perf data files in PWD!\n"
1338 "Only the first 32 files will be listed.\n");
1339 break;
1340 }
1341 }
1342 closedir(pwd_dir);
1343
1344 if (nr_options) {
1345 choice = ui__popup_menu(nr_options, options);
1346 if (choice < nr_options && choice >= 0) {
1347 tmp = strdup(abs_path[choice]);
1348 if (tmp) {
1349 if (is_input_name_malloced)
1350 free((void *)input_name);
1351 input_name = tmp;
1352 is_input_name_malloced = true;
1353 ret = 0;
1354 } else
1355 ui__warning("Data switch failed due to memory shortage!\n");
1356 }
1357 }
1358
1359 free_popup_options(options, nr_options);
1360 free_popup_options(abs_path, nr_options);
1361 return ret;
1362}
1363
Namhyung Kim112f7612014-04-22 14:05:35 +09001364static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001365{
1366 u64 nr_entries = 0;
1367 struct rb_node *nd = rb_first(&hb->hists->entries);
1368
Namhyung Kim268397c2014-04-22 14:49:31 +09001369 if (hb->min_pcnt == 0) {
1370 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1371 return;
1372 }
1373
Namhyung Kimc481f932014-04-22 13:56:11 +09001374 while ((nd = hists__filter_entries(nd, hb->hists,
1375 hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001376 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001377 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001378 }
1379
Namhyung Kim112f7612014-04-22 14:05:35 +09001380 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001381}
Feng Tang341487ab2013-02-03 14:38:20 +08001382
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001383static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001384 const char *helpline, const char *ev_name,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001385 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001386 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001387 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001388 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001389{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001390 struct hists *hists = &evsel->hists;
1391 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001392 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001393 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001394 char *options[16];
1395 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001396 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001397 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001398 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001399 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001400
Namhyung Kime8e684a2013-12-26 14:37:58 +09001401#define HIST_BROWSER_HELP_COMMON \
1402 "h/?/F1 Show this window\n" \
1403 "UP/DOWN/PGUP\n" \
1404 "PGDN/SPACE Navigate\n" \
1405 "q/ESC/CTRL+C Exit browser\n\n" \
1406 "For multiple event sessions:\n\n" \
1407 "TAB/UNTAB Switch events\n\n" \
1408 "For symbolic views (--sort has sym):\n\n" \
1409 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1410 "<- Zoom out\n" \
1411 "a Annotate current symbol\n" \
1412 "C Collapse all callchains\n" \
1413 "d Zoom into current DSO\n" \
1414 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001415 "F Toggle percentage of filtered entries\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001416
1417 /* help messages are sorted by lexical order of the hotkey */
1418 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001419 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001420 "P Print histograms to perf.hist.N\n"
1421 "r Run available scripts\n"
1422 "s Switch to another data file in PWD\n"
1423 "t Zoom into current Thread\n"
1424 "V Verbose (DSO names in callchains, etc)\n"
1425 "/ Filter symbol by name";
1426 const char top_help[] = HIST_BROWSER_HELP_COMMON
1427 "P Print histograms to perf.hist.N\n"
1428 "t Zoom into current Thread\n"
1429 "V Verbose (DSO names in callchains, etc)\n"
1430 "/ Filter symbol by name";
1431
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001432 if (browser == NULL)
1433 return -1;
1434
Namhyung Kim064f1982013-05-14 11:09:04 +09001435 if (min_pcnt) {
1436 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001437 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001438 }
1439
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001440 fstack = pstack__new(2);
1441 if (fstack == NULL)
1442 goto out;
1443
1444 ui_helpline__push(helpline);
1445
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001446 memset(options, 0, sizeof(options));
1447
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001448 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001449 const struct thread *thread = NULL;
1450 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001451 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001452 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001453 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001454 int scripts_comm = -2, scripts_symbol = -2,
1455 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001456
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001457 nr_options = 0;
1458
Namhyung Kim9783adf2012-11-02 14:50:05 +09001459 key = hist_browser__run(browser, ev_name, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001460
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001461 if (browser->he_selection != NULL) {
1462 thread = hist_browser__selected_thread(browser);
1463 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1464 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001465 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001466 case K_TAB:
1467 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001468 if (nr_events == 1)
1469 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001470 /*
1471 * Exit the browser, let hists__browser_tree
1472 * go to the next or previous
1473 */
1474 goto out_free_stack;
1475 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001476 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001477 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001478 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001479 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001480 continue;
1481 }
1482
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001483 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001484 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001485 browser->selection->map->dso->annotate_warned)
1486 continue;
1487 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001488 case 'P':
1489 hist_browser__dump(browser);
1490 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001491 case 'd':
1492 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001493 case 'V':
1494 browser->show_dso = !browser->show_dso;
1495 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001496 case 't':
1497 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001498 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001499 if (ui_browser__input_window("Symbol to show",
1500 "Please enter the name of symbol you want to see",
1501 buf, "ENTER: OK, ESC: Cancel",
1502 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001503 hists->symbol_filter_str = *buf ? buf : NULL;
1504 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001505 hist_browser__reset(browser);
1506 }
1507 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001508 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001509 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001510 goto do_scripts;
1511 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001512 case 's':
1513 if (is_report_browser(hbt))
1514 goto do_data_switch;
1515 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001516 case 'i':
1517 /* env->arch is NULL for live-mode (i.e. perf top) */
1518 if (env->arch)
1519 tui__header_window(env);
1520 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001521 case 'F':
1522 symbol_conf.filter_relative ^= 1;
1523 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001524 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001525 case 'h':
1526 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001527 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001528 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001529 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001530 case K_ENTER:
1531 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001532 /* menu */
1533 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001534 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001535 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001536
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001537 if (pstack__empty(fstack)) {
1538 /*
1539 * Go back to the perf_evsel_menu__run or other user
1540 */
1541 if (left_exits)
1542 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001543 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001544 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001545 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001546 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001547 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001548 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001549 goto zoom_out_thread;
1550 continue;
1551 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001552 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001553 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001554 !ui_browser__dialog_yesno(&browser->b,
1555 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001556 continue;
1557 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001558 case 'q':
1559 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001560 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001561 default:
1562 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001563 }
1564
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001565 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001566 goto add_exit_option;
1567
Namhyung Kim55369fc2013-04-01 20:35:20 +09001568 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001569 bi = browser->he_selection->branch_info;
1570 if (browser->selection != NULL &&
1571 bi &&
1572 bi->from.sym != NULL &&
1573 !bi->from.map->dso->annotate_warned &&
1574 asprintf(&options[nr_options], "Annotate %s",
1575 bi->from.sym->name) > 0)
1576 annotate_f = nr_options++;
1577
1578 if (browser->selection != NULL &&
1579 bi &&
1580 bi->to.sym != NULL &&
1581 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001582 (bi->to.sym != bi->from.sym ||
1583 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001584 asprintf(&options[nr_options], "Annotate %s",
1585 bi->to.sym->name) > 0)
1586 annotate_t = nr_options++;
1587 } else {
1588
1589 if (browser->selection != NULL &&
1590 browser->selection->sym != NULL &&
1591 !browser->selection->map->dso->annotate_warned &&
1592 asprintf(&options[nr_options], "Annotate %s",
1593 browser->selection->sym->name) > 0)
1594 annotate = nr_options++;
1595 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001596
1597 if (thread != NULL &&
1598 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001599 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001600 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001601 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001602 zoom_thread = nr_options++;
1603
1604 if (dso != NULL &&
1605 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001606 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001607 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1608 zoom_dso = nr_options++;
1609
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001610 if (browser->selection != NULL &&
1611 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001612 asprintf(&options[nr_options], "Browse map details") > 0)
1613 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001614
1615 /* perf script support */
1616 if (browser->he_selection) {
1617 struct symbol *sym;
1618
1619 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001620 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001621 scripts_comm = nr_options++;
1622
1623 sym = browser->he_selection->ms.sym;
1624 if (sym && sym->namelen &&
1625 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1626 sym->name) > 0)
1627 scripts_symbol = nr_options++;
1628 }
1629
1630 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1631 scripts_all = nr_options++;
1632
Feng Tang341487ab2013-02-03 14:38:20 +08001633 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1634 "Switch to another data file in PWD") > 0)
1635 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001636add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001637 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001638retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001639 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001640
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001641 if (choice == nr_options - 1)
1642 break;
1643
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001644 if (choice == -1) {
1645 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001646 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001647 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001648
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001649 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001650 struct hist_entry *he;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001651 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001652do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001653 if (!objdump_path && perf_session_env__lookup_objdump(env))
1654 continue;
1655
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001656 he = hist_browser__selected_entry(browser);
1657 if (he == NULL)
1658 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001659
1660 /*
1661 * we stash the branch_info symbol + map into the
1662 * the ms so we don't have to rewrite all the annotation
1663 * code to use branch_info.
1664 * in branch mode, the ms struct is not used
1665 */
1666 if (choice == annotate_f) {
1667 he->ms.sym = he->branch_info->from.sym;
1668 he->ms.map = he->branch_info->from.map;
1669 } else if (choice == annotate_t) {
1670 he->ms.sym = he->branch_info->to.sym;
1671 he->ms.map = he->branch_info->to.map;
1672 }
1673
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001674 /*
1675 * Don't let this be freed, say, by hists__decay_entry.
1676 */
1677 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001678 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001679 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001680 /*
1681 * offer option to annotate the other branch source or target
1682 * (if they exists) when returning from annotate
1683 */
1684 if ((err == 'q' || err == CTRL('c'))
1685 && annotate_t != -2 && annotate_f != -2)
1686 goto retry_popup_menu;
1687
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001688 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001689 if (err)
1690 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001691
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001692 } else if (choice == browse_map)
1693 map__browse(browser->selection->map);
1694 else if (choice == zoom_dso) {
1695zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001696 if (browser->hists->dso_filter) {
1697 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001698zoom_out_dso:
1699 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001700 browser->hists->dso_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001701 sort_dso.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001702 } else {
1703 if (dso == NULL)
1704 continue;
1705 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1706 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001707 browser->hists->dso_filter = dso;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001708 sort_dso.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001709 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001710 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001711 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001712 hist_browser__reset(browser);
1713 } else if (choice == zoom_thread) {
1714zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001715 if (browser->hists->thread_filter) {
1716 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001717zoom_out_thread:
1718 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001719 browser->hists->thread_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001720 sort_thread.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001721 } else {
1722 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001723 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001724 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001725 browser->hists->thread_filter = thread;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001726 sort_thread.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001727 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001728 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001729 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001730 hist_browser__reset(browser);
1731 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001732 /* perf scripts support */
1733 else if (choice == scripts_all || choice == scripts_comm ||
1734 choice == scripts_symbol) {
1735do_scripts:
1736 memset(script_opt, 0, 64);
1737
1738 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001739 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001740
1741 if (choice == scripts_symbol)
1742 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1743
1744 script_browse(script_opt);
1745 }
Feng Tang341487ab2013-02-03 14:38:20 +08001746 /* Switch to another data file */
1747 else if (choice == switch_data) {
1748do_data_switch:
1749 if (!switch_data_file()) {
1750 key = K_SWITCH_INPUT_DATA;
1751 break;
1752 } else
1753 ui__warning("Won't switch the data files due to\n"
1754 "no valid data file get selected!\n");
1755 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001756 }
1757out_free_stack:
1758 pstack__delete(fstack);
1759out:
1760 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001761 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001762 return key;
1763}
1764
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001765struct perf_evsel_menu {
1766 struct ui_browser b;
1767 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001768 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001769 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001770 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001771};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001772
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001773static void perf_evsel_menu__write(struct ui_browser *browser,
1774 void *entry, int row)
1775{
1776 struct perf_evsel_menu *menu = container_of(browser,
1777 struct perf_evsel_menu, b);
1778 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1779 bool current_entry = ui_browser__is_current_entry(browser, row);
1780 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001781 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001782 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001783 const char *warn = " ";
1784 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001785
1786 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1787 HE_COLORSET_NORMAL);
1788
Namhyung Kim759ff492013-03-05 14:53:26 +09001789 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001790 struct perf_evsel *pos;
1791
1792 ev_name = perf_evsel__group_name(evsel);
1793
1794 for_each_group_member(pos, evsel) {
1795 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1796 }
1797 }
1798
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001799 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001800 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001801 unit, unit == ' ' ? "" : " ", ev_name);
1802 slsmg_printf("%s", bf);
1803
1804 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1805 if (nr_events != 0) {
1806 menu->lost_events = true;
1807 if (!current_entry)
1808 ui_browser__set_color(browser, HE_COLORSET_TOP);
1809 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001810 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1811 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001812 warn = bf;
1813 }
1814
1815 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001816
1817 if (current_entry)
1818 menu->selection = evsel;
1819}
1820
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001821static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1822 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001823 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001824{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001825 struct perf_evlist *evlist = menu->b.priv;
1826 struct perf_evsel *pos;
1827 const char *ev_name, *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001828 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001829 int key;
1830
1831 if (ui_browser__show(&menu->b, title,
1832 "ESC: exit, ENTER|->: Browse histograms") < 0)
1833 return -1;
1834
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001835 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001836 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001837
1838 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001839 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001840 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001841
1842 if (!menu->lost_events_warned && menu->lost_events) {
1843 ui_browser__warn_lost_events(&menu->b);
1844 menu->lost_events_warned = true;
1845 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001846 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001847 case K_RIGHT:
1848 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001849 if (!menu->selection)
1850 continue;
1851 pos = menu->selection;
1852browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001853 perf_evlist__set_selected(evlist, pos);
1854 /*
1855 * Give the calling tool a chance to populate the non
1856 * default evsel resorted hists tree.
1857 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001858 if (hbt)
1859 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001860 ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001861 key = perf_evsel__hists_browse(pos, nr_events, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001862 ev_name, true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001863 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001864 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001865 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001866 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001867 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001868 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001869 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001870 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001871 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001872 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001873 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001874 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001875 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001876 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001877 pos = perf_evsel__prev(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_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001880 if (!ui_browser__dialog_yesno(&menu->b,
1881 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001882 continue;
1883 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001884 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001885 case 'q':
1886 case CTRL('c'):
1887 goto out;
1888 default:
1889 continue;
1890 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001891 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001892 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001893 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001894 if (!ui_browser__dialog_yesno(&menu->b,
1895 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001896 continue;
1897 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001898 case 'q':
1899 case CTRL('c'):
1900 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001901 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001902 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001903 }
1904 }
1905
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001906out:
1907 ui_browser__hide(&menu->b);
1908 return key;
1909}
1910
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001911static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001912 void *entry)
1913{
1914 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1915
1916 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1917 return true;
1918
1919 return false;
1920}
1921
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001922static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001923 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001924 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001925 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001926 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001927{
1928 struct perf_evsel *pos;
1929 struct perf_evsel_menu menu = {
1930 .b = {
1931 .entries = &evlist->entries,
1932 .refresh = ui_browser__list_head_refresh,
1933 .seek = ui_browser__list_head_seek,
1934 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001935 .filter = filter_group_entries,
1936 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001937 .priv = evlist,
1938 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001939 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001940 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001941 };
1942
1943 ui_helpline__push("Press ESC to exit");
1944
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001945 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001946 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001947 size_t line_len = strlen(ev_name) + 7;
1948
1949 if (menu.b.width < line_len)
1950 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001951 }
1952
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001953 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001954}
1955
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001956int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001957 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001958 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001959 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001960{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001961 int nr_entries = evlist->nr_entries;
1962
1963single_entry:
1964 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001965 struct perf_evsel *first = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001966 const char *ev_name = perf_evsel__name(first);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001967
1968 return perf_evsel__hists_browse(first, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001969 ev_name, false, hbt, min_pcnt,
1970 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001971 }
1972
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001973 if (symbol_conf.event_group) {
1974 struct perf_evsel *pos;
1975
1976 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001977 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001978 if (perf_evsel__is_group_leader(pos))
1979 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001980 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001981
1982 if (nr_entries == 1)
1983 goto single_entry;
1984 }
1985
1986 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001987 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001988}