blob: 847de116b9ec0d4bce8e3622d394d8ca2c0de80f [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__overhead_callback(struct perf_hpp *hpp, bool front)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900620{
Namhyung Kim89701462013-01-22 18:09:38 +0900621 struct hpp_arg *arg = hpp->ptr;
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900622
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900623 if (arg->current_entry && arg->b->navkeypressed)
624 ui_browser__set_color(arg->b, HE_COLORSET_SELECTED);
625 else
626 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
627
628 if (front) {
629 if (!symbol_conf.use_callchain)
630 return 0;
631
632 slsmg_printf("%c ", arg->folded_sign);
633 return 2;
634 }
635
636 return 0;
637}
638
639static int __hpp__color_callback(struct perf_hpp *hpp, bool front __maybe_unused)
640{
641 struct hpp_arg *arg = hpp->ptr;
642
643 if (!arg->current_entry || !arg->b->navkeypressed)
644 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
645 return 0;
646}
647
648static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
649{
650 struct hpp_arg *arg = hpp->ptr;
651 int ret;
652 va_list args;
653 double percent;
654
655 va_start(args, fmt);
656 percent = va_arg(args, double);
657 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900658
Namhyung Kim89701462013-01-22 18:09:38 +0900659 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900660
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900661 ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900662 slsmg_printf("%s", hpp->buf);
663
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900664 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900665 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900666}
667
Namhyung Kim89701462013-01-22 18:09:38 +0900668#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900669static u64 __hpp_get_##_field(struct hist_entry *he) \
670{ \
671 return he->stat._field; \
672} \
673 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100674static int \
675hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
676 struct perf_hpp *hpp, \
677 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900678{ \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900679 return __hpp__fmt(hpp, he, __hpp_get_##_field, _cb, " %6.2f%%", \
680 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900681}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900682
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900683__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__overhead_callback)
684__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, __hpp__color_callback)
685__HPP_COLOR_PERCENT_FN(overhead_us, period_us, __hpp__color_callback)
686__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, __hpp__color_callback)
687__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, __hpp__color_callback)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900688
689#undef __HPP_COLOR_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900690
691void hist_browser__init_hpp(void)
692{
Jiri Olsa1d778222012-10-04 21:49:39 +0900693 perf_hpp__init();
Namhyung Kimf5951d52012-09-03 11:53:09 +0900694
695 perf_hpp__format[PERF_HPP__OVERHEAD].color =
696 hist_browser__hpp_color_overhead;
697 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
698 hist_browser__hpp_color_overhead_sys;
699 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
700 hist_browser__hpp_color_overhead_us;
701 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
702 hist_browser__hpp_color_overhead_guest_sys;
703 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
704 hist_browser__hpp_color_overhead_guest_us;
705}
706
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300707static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300708 struct hist_entry *entry,
709 unsigned short row)
710{
711 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200712 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900713 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300714 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300715 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300716 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300717 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200718 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300719
720 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300721 browser->he_selection = entry;
722 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300723 }
724
725 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300726 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300727 folded_sign = hist_entry__folded(entry);
728 }
729
730 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900731 struct hpp_arg arg = {
732 .b = &browser->b,
733 .folded_sign = folded_sign,
734 .current_entry = current_entry,
735 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900736 struct perf_hpp hpp = {
737 .buf = s,
738 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900739 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900740 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300741
Namhyung Kim67d25912012-09-12 15:35:06 +0900742 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900743
Jiri Olsa12400052012-10-13 00:06:16 +0200744 perf_hpp__for_each_format(fmt) {
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300745 if (!first) {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900746 slsmg_printf(" ");
747 width -= 2;
748 }
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300749 first = false;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900750
Jiri Olsa12400052012-10-13 00:06:16 +0200751 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100752 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900753 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100754 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900755 slsmg_printf("%s", s);
756 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300757 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200758
759 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300760 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200761 width += 1;
762
Namhyung Kim26d8b332014-03-03 16:16:20 +0900763 slsmg_write_nstring("", width);
764
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300765 ++row;
766 ++printed;
767 } else
768 --row_offset;
769
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300770 if (folded_sign == '-' && row != browser->b.height) {
771 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300772 1, row, &row_offset,
773 &current_entry);
774 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300775 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300776 }
777
778 return printed;
779}
780
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300781static void ui_browser__hists_init_top(struct ui_browser *browser)
782{
783 if (browser->top == NULL) {
784 struct hist_browser *hb;
785
786 hb = container_of(browser, struct hist_browser, b);
787 browser->top = rb_first(&hb->hists->entries);
788 }
789}
790
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300791static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300792{
793 unsigned row = 0;
794 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300795 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300796
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300797 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300798
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300799 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300800 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900801 u64 total = hists__total_period(h->hists);
802 float percent = 0.0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300803
804 if (h->filtered)
805 continue;
806
Namhyung Kimf2148332014-01-14 11:52:48 +0900807 if (total)
808 percent = h->stat.period * 100.0 / total;
809
Namhyung Kim064f1982013-05-14 11:09:04 +0900810 if (percent < hb->min_pcnt)
811 continue;
812
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300813 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300814 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300815 break;
816 }
817
818 return row;
819}
820
Namhyung Kim064f1982013-05-14 11:09:04 +0900821static struct rb_node *hists__filter_entries(struct rb_node *nd,
822 struct hists *hists,
823 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300824{
825 while (nd != NULL) {
826 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900827 u64 total = hists__total_period(hists);
828 float percent = 0.0;
829
830 if (total)
831 percent = h->stat.period * 100.0 / total;
Namhyung Kim064f1982013-05-14 11:09:04 +0900832
833 if (percent < min_pcnt)
834 return NULL;
835
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300836 if (!h->filtered)
837 return nd;
838
839 nd = rb_next(nd);
840 }
841
842 return NULL;
843}
844
Namhyung Kim064f1982013-05-14 11:09:04 +0900845static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
846 struct hists *hists,
847 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300848{
849 while (nd != NULL) {
850 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900851 u64 total = hists__total_period(hists);
852 float percent = 0.0;
853
854 if (total)
855 percent = h->stat.period * 100.0 / total;
Namhyung Kim064f1982013-05-14 11:09:04 +0900856
857 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300858 return nd;
859
860 nd = rb_prev(nd);
861 }
862
863 return NULL;
864}
865
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300866static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300867 off_t offset, int whence)
868{
869 struct hist_entry *h;
870 struct rb_node *nd;
871 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900872 struct hist_browser *hb;
873
874 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300875
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300876 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300877 return;
878
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300879 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300880
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300881 switch (whence) {
882 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900883 nd = hists__filter_entries(rb_first(browser->entries),
884 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300885 break;
886 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300887 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300888 goto do_offset;
889 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900890 nd = hists__filter_prev_entries(rb_last(browser->entries),
891 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300892 first = false;
893 break;
894 default:
895 return;
896 }
897
898 /*
899 * Moves not relative to the first visible entry invalidates its
900 * row_offset:
901 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300902 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300903 h->row_offset = 0;
904
905 /*
906 * Here we have to check if nd is expanded (+), if it is we can't go
907 * the next top level hist_entry, instead we must compute an offset of
908 * what _not_ to show and not change the first visible entry.
909 *
910 * This offset increments when we are going from top to bottom and
911 * decreases when we're going from bottom to top.
912 *
913 * As we don't have backpointers to the top level in the callchains
914 * structure, we need to always print the whole hist_entry callchain,
915 * skipping the first ones that are before the first visible entry
916 * and stop when we printed enough lines to fill the screen.
917 */
918do_offset:
919 if (offset > 0) {
920 do {
921 h = rb_entry(nd, struct hist_entry, rb_node);
922 if (h->ms.unfolded) {
923 u16 remaining = h->nr_rows - h->row_offset;
924 if (offset > remaining) {
925 offset -= remaining;
926 h->row_offset = 0;
927 } else {
928 h->row_offset += offset;
929 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300930 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300931 break;
932 }
933 }
Namhyung Kim064f1982013-05-14 11:09:04 +0900934 nd = hists__filter_entries(rb_next(nd), hb->hists,
935 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300936 if (nd == NULL)
937 break;
938 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300939 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300940 } while (offset != 0);
941 } else if (offset < 0) {
942 while (1) {
943 h = rb_entry(nd, struct hist_entry, rb_node);
944 if (h->ms.unfolded) {
945 if (first) {
946 if (-offset > h->row_offset) {
947 offset += h->row_offset;
948 h->row_offset = 0;
949 } else {
950 h->row_offset += offset;
951 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300952 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300953 break;
954 }
955 } else {
956 if (-offset > h->nr_rows) {
957 offset += h->nr_rows;
958 h->row_offset = 0;
959 } else {
960 h->row_offset = h->nr_rows + offset;
961 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300962 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300963 break;
964 }
965 }
966 }
967
Namhyung Kim064f1982013-05-14 11:09:04 +0900968 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
969 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300970 if (nd == NULL)
971 break;
972 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300973 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300974 if (offset == 0) {
975 /*
976 * Last unfiltered hist_entry, check if it is
977 * unfolded, if it is then we should have
978 * row_offset at its last entry.
979 */
980 h = rb_entry(nd, struct hist_entry, rb_node);
981 if (h->ms.unfolded)
982 h->row_offset = h->nr_rows;
983 break;
984 }
985 first = false;
986 }
987 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300988 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300989 h = rb_entry(nd, struct hist_entry, rb_node);
990 h->row_offset = 0;
991 }
992}
993
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300994static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
995 struct callchain_node *chain_node,
996 u64 total, int level,
997 FILE *fp)
998{
999 struct rb_node *node;
1000 int offset = level * LEVEL_OFFSET_STEP;
1001 u64 new_total, remaining;
1002 int printed = 0;
1003
1004 if (callchain_param.mode == CHAIN_GRAPH_REL)
1005 new_total = chain_node->children_hit;
1006 else
1007 new_total = total;
1008
1009 remaining = new_total;
1010 node = rb_first(&chain_node->rb_root);
1011 while (node) {
1012 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1013 struct rb_node *next = rb_next(node);
1014 u64 cumul = callchain_cumul_hits(child);
1015 struct callchain_list *chain;
1016 char folded_sign = ' ';
1017 int first = true;
1018 int extra_offset = 0;
1019
1020 remaining -= cumul;
1021
1022 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001023 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001024 const char *str;
1025 bool was_first = first;
1026
1027 if (first)
1028 first = false;
1029 else
1030 extra_offset = LEVEL_OFFSET_STEP;
1031
1032 folded_sign = callchain_list__folded(chain);
1033
1034 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001035 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1036 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001037 if (was_first) {
1038 double percent = cumul * 100.0 / new_total;
1039
1040 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1041 str = "Not enough memory!";
1042 else
1043 str = alloc_str;
1044 }
1045
1046 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1047 free(alloc_str);
1048 if (folded_sign == '+')
1049 break;
1050 }
1051
1052 if (folded_sign == '-') {
1053 const int new_level = level + (extra_offset ? 2 : 1);
1054 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1055 new_level, fp);
1056 }
1057
1058 node = next;
1059 }
1060
1061 return printed;
1062}
1063
1064static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1065 struct callchain_node *node,
1066 int level, FILE *fp)
1067{
1068 struct callchain_list *chain;
1069 int offset = level * LEVEL_OFFSET_STEP;
1070 char folded_sign = ' ';
1071 int printed = 0;
1072
1073 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001074 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001075
1076 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001077 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001078 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1079 }
1080
1081 if (folded_sign == '-')
1082 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1083 browser->hists->stats.total_period,
1084 level + 1, fp);
1085 return printed;
1086}
1087
1088static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1089 struct rb_root *chain, int level, FILE *fp)
1090{
1091 struct rb_node *nd;
1092 int printed = 0;
1093
1094 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1095 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1096
1097 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1098 }
1099
1100 return printed;
1101}
1102
1103static int hist_browser__fprintf_entry(struct hist_browser *browser,
1104 struct hist_entry *he, FILE *fp)
1105{
1106 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001107 int printed = 0;
1108 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001109 struct perf_hpp hpp = {
1110 .buf = s,
1111 .size = sizeof(s),
1112 };
1113 struct perf_hpp_fmt *fmt;
1114 bool first = true;
1115 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001116
1117 if (symbol_conf.use_callchain)
1118 folded_sign = hist_entry__folded(he);
1119
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001120 if (symbol_conf.use_callchain)
1121 printed += fprintf(fp, "%c ", folded_sign);
1122
Namhyung Kim26d8b332014-03-03 16:16:20 +09001123 perf_hpp__for_each_format(fmt) {
1124 if (!first) {
1125 ret = scnprintf(hpp.buf, hpp.size, " ");
1126 advance_hpp(&hpp, ret);
1127 } else
1128 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001129
Namhyung Kim26d8b332014-03-03 16:16:20 +09001130 ret = fmt->entry(fmt, &hpp, he);
1131 advance_hpp(&hpp, ret);
1132 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001133 printed += fprintf(fp, "%s\n", rtrim(s));
1134
1135 if (folded_sign == '-')
1136 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1137
1138 return printed;
1139}
1140
1141static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1142{
Namhyung Kim064f1982013-05-14 11:09:04 +09001143 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1144 browser->hists,
1145 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001146 int printed = 0;
1147
1148 while (nd) {
1149 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1150
1151 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim064f1982013-05-14 11:09:04 +09001152 nd = hists__filter_entries(rb_next(nd), browser->hists,
1153 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001154 }
1155
1156 return printed;
1157}
1158
1159static int hist_browser__dump(struct hist_browser *browser)
1160{
1161 char filename[64];
1162 FILE *fp;
1163
1164 while (1) {
1165 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1166 if (access(filename, F_OK))
1167 break;
1168 /*
1169 * XXX: Just an arbitrary lazy upper limit
1170 */
1171 if (++browser->print_seq == 8192) {
1172 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1173 return -1;
1174 }
1175 }
1176
1177 fp = fopen(filename, "w");
1178 if (fp == NULL) {
1179 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001180 const char *err = strerror_r(errno, bf, sizeof(bf));
1181 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001182 return -1;
1183 }
1184
1185 ++browser->print_seq;
1186 hist_browser__fprintf(browser, fp);
1187 fclose(fp);
1188 ui_helpline__fpush("%s written!", filename);
1189
1190 return 0;
1191}
1192
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001193static struct hist_browser *hist_browser__new(struct hists *hists)
1194{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001195 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001197 if (browser) {
1198 browser->hists = hists;
1199 browser->b.refresh = hist_browser__refresh;
1200 browser->b.seek = ui_browser__hists_seek;
1201 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202 }
1203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001204 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001205}
1206
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001207static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001208{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001209 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001210}
1211
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001212static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001213{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001214 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215}
1216
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001217static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001219 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220}
1221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001222static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001223 const char *ev_name)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001224{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001225 char unit;
1226 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001227 const struct dso *dso = hists->dso_filter;
1228 const struct thread *thread = hists->thread_filter;
1229 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1230 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001231 struct perf_evsel *evsel = hists_to_evsel(hists);
1232 char buf[512];
1233 size_t buflen = sizeof(buf);
1234
Namhyung Kimf2148332014-01-14 11:52:48 +09001235 if (symbol_conf.filter_relative) {
1236 nr_samples = hists->stats.nr_non_filtered_samples;
1237 nr_events = hists->stats.total_non_filtered_period;
1238 }
1239
Namhyung Kim759ff492013-03-05 14:53:26 +09001240 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001241 struct perf_evsel *pos;
1242
1243 perf_evsel__group_desc(evsel, buf, buflen);
1244 ev_name = buf;
1245
1246 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001247 if (symbol_conf.filter_relative) {
1248 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1249 nr_events += pos->hists.stats.total_non_filtered_period;
1250 } else {
1251 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1252 nr_events += pos->hists.stats.total_period;
1253 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001254 }
1255 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001256
Ashay Ranecc686282012-04-05 21:01:01 -05001257 nr_samples = convert_unit(nr_samples, &unit);
1258 printed = scnprintf(bf, size,
1259 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1260 nr_samples, unit, ev_name, nr_events);
1261
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001262
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001263 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001264 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001265 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001266 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001267 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001268 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001269 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001270 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001271 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001272 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001273 ", DSO: %s", dso->short_name);
1274 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001275}
1276
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001277static inline void free_popup_options(char **options, int n)
1278{
1279 int i;
1280
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001281 for (i = 0; i < n; ++i)
1282 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001283}
1284
Feng Tangc77d8d72012-11-01 00:00:55 +08001285/* Check whether the browser is for 'top' or 'report' */
1286static inline bool is_report_browser(void *timer)
1287{
1288 return timer == NULL;
1289}
1290
Feng Tang341487ab2013-02-03 14:38:20 +08001291/*
1292 * Only runtime switching of perf data file will make "input_name" point
1293 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1294 * whether we need to call free() for current "input_name" during the switch.
1295 */
1296static bool is_input_name_malloced = false;
1297
1298static int switch_data_file(void)
1299{
1300 char *pwd, *options[32], *abs_path[32], *tmp;
1301 DIR *pwd_dir;
1302 int nr_options = 0, choice = -1, ret = -1;
1303 struct dirent *dent;
1304
1305 pwd = getenv("PWD");
1306 if (!pwd)
1307 return ret;
1308
1309 pwd_dir = opendir(pwd);
1310 if (!pwd_dir)
1311 return ret;
1312
1313 memset(options, 0, sizeof(options));
1314 memset(options, 0, sizeof(abs_path));
1315
1316 while ((dent = readdir(pwd_dir))) {
1317 char path[PATH_MAX];
1318 u64 magic;
1319 char *name = dent->d_name;
1320 FILE *file;
1321
1322 if (!(dent->d_type == DT_REG))
1323 continue;
1324
1325 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1326
1327 file = fopen(path, "r");
1328 if (!file)
1329 continue;
1330
1331 if (fread(&magic, 1, 8, file) < 8)
1332 goto close_file_and_continue;
1333
1334 if (is_perf_magic(magic)) {
1335 options[nr_options] = strdup(name);
1336 if (!options[nr_options])
1337 goto close_file_and_continue;
1338
1339 abs_path[nr_options] = strdup(path);
1340 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001341 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001342 ui__warning("Can't search all data files due to memory shortage.\n");
1343 fclose(file);
1344 break;
1345 }
1346
1347 nr_options++;
1348 }
1349
1350close_file_and_continue:
1351 fclose(file);
1352 if (nr_options >= 32) {
1353 ui__warning("Too many perf data files in PWD!\n"
1354 "Only the first 32 files will be listed.\n");
1355 break;
1356 }
1357 }
1358 closedir(pwd_dir);
1359
1360 if (nr_options) {
1361 choice = ui__popup_menu(nr_options, options);
1362 if (choice < nr_options && choice >= 0) {
1363 tmp = strdup(abs_path[choice]);
1364 if (tmp) {
1365 if (is_input_name_malloced)
1366 free((void *)input_name);
1367 input_name = tmp;
1368 is_input_name_malloced = true;
1369 ret = 0;
1370 } else
1371 ui__warning("Data switch failed due to memory shortage!\n");
1372 }
1373 }
1374
1375 free_popup_options(options, nr_options);
1376 free_popup_options(abs_path, nr_options);
1377 return ret;
1378}
1379
Namhyung Kim112f7612014-04-22 14:05:35 +09001380static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001381{
1382 u64 nr_entries = 0;
1383 struct rb_node *nd = rb_first(&hb->hists->entries);
1384
Namhyung Kim268397c2014-04-22 14:49:31 +09001385 if (hb->min_pcnt == 0) {
1386 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1387 return;
1388 }
1389
Namhyung Kimc481f932014-04-22 13:56:11 +09001390 while ((nd = hists__filter_entries(nd, hb->hists,
1391 hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001392 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001393 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001394 }
1395
Namhyung Kim112f7612014-04-22 14:05:35 +09001396 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001397}
Feng Tang341487ab2013-02-03 14:38:20 +08001398
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001399static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001400 const char *helpline, const char *ev_name,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001401 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001402 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001403 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001404 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001405{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001406 struct hists *hists = &evsel->hists;
1407 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001408 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001409 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001410 char *options[16];
1411 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001412 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001413 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001414 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001415 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001416
Namhyung Kime8e684a2013-12-26 14:37:58 +09001417#define HIST_BROWSER_HELP_COMMON \
1418 "h/?/F1 Show this window\n" \
1419 "UP/DOWN/PGUP\n" \
1420 "PGDN/SPACE Navigate\n" \
1421 "q/ESC/CTRL+C Exit browser\n\n" \
1422 "For multiple event sessions:\n\n" \
1423 "TAB/UNTAB Switch events\n\n" \
1424 "For symbolic views (--sort has sym):\n\n" \
1425 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1426 "<- Zoom out\n" \
1427 "a Annotate current symbol\n" \
1428 "C Collapse all callchains\n" \
1429 "d Zoom into current DSO\n" \
1430 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001431 "F Toggle percentage of filtered entries\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001432
1433 /* help messages are sorted by lexical order of the hotkey */
1434 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001435 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001436 "P Print histograms to perf.hist.N\n"
1437 "r Run available scripts\n"
1438 "s Switch to another data file in PWD\n"
1439 "t Zoom into current Thread\n"
1440 "V Verbose (DSO names in callchains, etc)\n"
1441 "/ Filter symbol by name";
1442 const char top_help[] = HIST_BROWSER_HELP_COMMON
1443 "P Print histograms to perf.hist.N\n"
1444 "t Zoom into current Thread\n"
1445 "V Verbose (DSO names in callchains, etc)\n"
1446 "/ Filter symbol by name";
1447
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001448 if (browser == NULL)
1449 return -1;
1450
Namhyung Kim064f1982013-05-14 11:09:04 +09001451 if (min_pcnt) {
1452 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001453 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001454 }
1455
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001456 fstack = pstack__new(2);
1457 if (fstack == NULL)
1458 goto out;
1459
1460 ui_helpline__push(helpline);
1461
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001462 memset(options, 0, sizeof(options));
1463
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001464 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001465 const struct thread *thread = NULL;
1466 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001467 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001468 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001469 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001470 int scripts_comm = -2, scripts_symbol = -2,
1471 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001472
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001473 nr_options = 0;
1474
Namhyung Kim9783adf2012-11-02 14:50:05 +09001475 key = hist_browser__run(browser, ev_name, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001476
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001477 if (browser->he_selection != NULL) {
1478 thread = hist_browser__selected_thread(browser);
1479 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1480 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001481 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001482 case K_TAB:
1483 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001484 if (nr_events == 1)
1485 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001486 /*
1487 * Exit the browser, let hists__browser_tree
1488 * go to the next or previous
1489 */
1490 goto out_free_stack;
1491 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001492 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001493 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001494 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001495 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001496 continue;
1497 }
1498
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001499 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001500 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001501 browser->selection->map->dso->annotate_warned)
1502 continue;
1503 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001504 case 'P':
1505 hist_browser__dump(browser);
1506 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001507 case 'd':
1508 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001509 case 'V':
1510 browser->show_dso = !browser->show_dso;
1511 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001512 case 't':
1513 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001514 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001515 if (ui_browser__input_window("Symbol to show",
1516 "Please enter the name of symbol you want to see",
1517 buf, "ENTER: OK, ESC: Cancel",
1518 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001519 hists->symbol_filter_str = *buf ? buf : NULL;
1520 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001521 hist_browser__reset(browser);
1522 }
1523 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001524 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001525 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001526 goto do_scripts;
1527 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001528 case 's':
1529 if (is_report_browser(hbt))
1530 goto do_data_switch;
1531 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001532 case 'i':
1533 /* env->arch is NULL for live-mode (i.e. perf top) */
1534 if (env->arch)
1535 tui__header_window(env);
1536 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001537 case 'F':
1538 symbol_conf.filter_relative ^= 1;
1539 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001540 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001541 case 'h':
1542 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001543 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001544 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001545 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001546 case K_ENTER:
1547 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001548 /* menu */
1549 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001550 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001551 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001552
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001553 if (pstack__empty(fstack)) {
1554 /*
1555 * Go back to the perf_evsel_menu__run or other user
1556 */
1557 if (left_exits)
1558 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001559 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001560 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001561 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001562 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001563 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001564 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001565 goto zoom_out_thread;
1566 continue;
1567 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001568 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001569 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001570 !ui_browser__dialog_yesno(&browser->b,
1571 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001572 continue;
1573 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001574 case 'q':
1575 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001576 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001577 default:
1578 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001579 }
1580
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001581 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001582 goto add_exit_option;
1583
Namhyung Kim55369fc2013-04-01 20:35:20 +09001584 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001585 bi = browser->he_selection->branch_info;
1586 if (browser->selection != NULL &&
1587 bi &&
1588 bi->from.sym != NULL &&
1589 !bi->from.map->dso->annotate_warned &&
1590 asprintf(&options[nr_options], "Annotate %s",
1591 bi->from.sym->name) > 0)
1592 annotate_f = nr_options++;
1593
1594 if (browser->selection != NULL &&
1595 bi &&
1596 bi->to.sym != NULL &&
1597 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001598 (bi->to.sym != bi->from.sym ||
1599 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001600 asprintf(&options[nr_options], "Annotate %s",
1601 bi->to.sym->name) > 0)
1602 annotate_t = nr_options++;
1603 } else {
1604
1605 if (browser->selection != NULL &&
1606 browser->selection->sym != NULL &&
1607 !browser->selection->map->dso->annotate_warned &&
1608 asprintf(&options[nr_options], "Annotate %s",
1609 browser->selection->sym->name) > 0)
1610 annotate = nr_options++;
1611 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001612
1613 if (thread != NULL &&
1614 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001615 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001616 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001617 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001618 zoom_thread = nr_options++;
1619
1620 if (dso != NULL &&
1621 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001622 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001623 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1624 zoom_dso = nr_options++;
1625
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001626 if (browser->selection != NULL &&
1627 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001628 asprintf(&options[nr_options], "Browse map details") > 0)
1629 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001630
1631 /* perf script support */
1632 if (browser->he_selection) {
1633 struct symbol *sym;
1634
1635 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001636 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001637 scripts_comm = nr_options++;
1638
1639 sym = browser->he_selection->ms.sym;
1640 if (sym && sym->namelen &&
1641 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1642 sym->name) > 0)
1643 scripts_symbol = nr_options++;
1644 }
1645
1646 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1647 scripts_all = nr_options++;
1648
Feng Tang341487ab2013-02-03 14:38:20 +08001649 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1650 "Switch to another data file in PWD") > 0)
1651 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001652add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001653 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001654retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001655 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001656
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001657 if (choice == nr_options - 1)
1658 break;
1659
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001660 if (choice == -1) {
1661 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001662 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001663 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001664
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001665 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001666 struct hist_entry *he;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001667 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001668do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001669 if (!objdump_path && perf_session_env__lookup_objdump(env))
1670 continue;
1671
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001672 he = hist_browser__selected_entry(browser);
1673 if (he == NULL)
1674 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001675
1676 /*
1677 * we stash the branch_info symbol + map into the
1678 * the ms so we don't have to rewrite all the annotation
1679 * code to use branch_info.
1680 * in branch mode, the ms struct is not used
1681 */
1682 if (choice == annotate_f) {
1683 he->ms.sym = he->branch_info->from.sym;
1684 he->ms.map = he->branch_info->from.map;
1685 } else if (choice == annotate_t) {
1686 he->ms.sym = he->branch_info->to.sym;
1687 he->ms.map = he->branch_info->to.map;
1688 }
1689
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001690 /*
1691 * Don't let this be freed, say, by hists__decay_entry.
1692 */
1693 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001694 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001695 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001696 /*
1697 * offer option to annotate the other branch source or target
1698 * (if they exists) when returning from annotate
1699 */
1700 if ((err == 'q' || err == CTRL('c'))
1701 && annotate_t != -2 && annotate_f != -2)
1702 goto retry_popup_menu;
1703
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001704 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001705 if (err)
1706 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001707
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001708 } else if (choice == browse_map)
1709 map__browse(browser->selection->map);
1710 else if (choice == zoom_dso) {
1711zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001712 if (browser->hists->dso_filter) {
1713 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001714zoom_out_dso:
1715 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001716 browser->hists->dso_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001717 sort_dso.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001718 } else {
1719 if (dso == NULL)
1720 continue;
1721 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1722 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001723 browser->hists->dso_filter = dso;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001724 sort_dso.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001725 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001726 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001727 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001728 hist_browser__reset(browser);
1729 } else if (choice == zoom_thread) {
1730zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001731 if (browser->hists->thread_filter) {
1732 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001733zoom_out_thread:
1734 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001735 browser->hists->thread_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001736 sort_thread.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001737 } else {
1738 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001739 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001740 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001741 browser->hists->thread_filter = thread;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001742 sort_thread.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001743 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001744 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001745 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001746 hist_browser__reset(browser);
1747 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001748 /* perf scripts support */
1749 else if (choice == scripts_all || choice == scripts_comm ||
1750 choice == scripts_symbol) {
1751do_scripts:
1752 memset(script_opt, 0, 64);
1753
1754 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001755 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001756
1757 if (choice == scripts_symbol)
1758 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1759
1760 script_browse(script_opt);
1761 }
Feng Tang341487ab2013-02-03 14:38:20 +08001762 /* Switch to another data file */
1763 else if (choice == switch_data) {
1764do_data_switch:
1765 if (!switch_data_file()) {
1766 key = K_SWITCH_INPUT_DATA;
1767 break;
1768 } else
1769 ui__warning("Won't switch the data files due to\n"
1770 "no valid data file get selected!\n");
1771 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001772 }
1773out_free_stack:
1774 pstack__delete(fstack);
1775out:
1776 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001777 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001778 return key;
1779}
1780
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001781struct perf_evsel_menu {
1782 struct ui_browser b;
1783 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001784 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001785 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001786 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001787};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001788
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001789static void perf_evsel_menu__write(struct ui_browser *browser,
1790 void *entry, int row)
1791{
1792 struct perf_evsel_menu *menu = container_of(browser,
1793 struct perf_evsel_menu, b);
1794 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1795 bool current_entry = ui_browser__is_current_entry(browser, row);
1796 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001797 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001798 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001799 const char *warn = " ";
1800 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001801
1802 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1803 HE_COLORSET_NORMAL);
1804
Namhyung Kim759ff492013-03-05 14:53:26 +09001805 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001806 struct perf_evsel *pos;
1807
1808 ev_name = perf_evsel__group_name(evsel);
1809
1810 for_each_group_member(pos, evsel) {
1811 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1812 }
1813 }
1814
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001815 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001816 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001817 unit, unit == ' ' ? "" : " ", ev_name);
1818 slsmg_printf("%s", bf);
1819
1820 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1821 if (nr_events != 0) {
1822 menu->lost_events = true;
1823 if (!current_entry)
1824 ui_browser__set_color(browser, HE_COLORSET_TOP);
1825 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001826 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1827 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001828 warn = bf;
1829 }
1830
1831 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001832
1833 if (current_entry)
1834 menu->selection = evsel;
1835}
1836
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001837static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1838 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001839 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001840{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001841 struct perf_evlist *evlist = menu->b.priv;
1842 struct perf_evsel *pos;
1843 const char *ev_name, *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001844 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001845 int key;
1846
1847 if (ui_browser__show(&menu->b, title,
1848 "ESC: exit, ENTER|->: Browse histograms") < 0)
1849 return -1;
1850
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001851 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001852 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001853
1854 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001855 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001856 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001857
1858 if (!menu->lost_events_warned && menu->lost_events) {
1859 ui_browser__warn_lost_events(&menu->b);
1860 menu->lost_events_warned = true;
1861 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001862 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001863 case K_RIGHT:
1864 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001865 if (!menu->selection)
1866 continue;
1867 pos = menu->selection;
1868browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001869 perf_evlist__set_selected(evlist, pos);
1870 /*
1871 * Give the calling tool a chance to populate the non
1872 * default evsel resorted hists tree.
1873 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001874 if (hbt)
1875 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001876 ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001877 key = perf_evsel__hists_browse(pos, nr_events, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001878 ev_name, true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001879 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001880 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001881 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001882 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001883 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001884 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001885 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001886 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001887 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001888 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001889 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001890 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001891 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001892 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001893 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001894 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001895 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001896 if (!ui_browser__dialog_yesno(&menu->b,
1897 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001898 continue;
1899 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001900 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001901 case 'q':
1902 case CTRL('c'):
1903 goto out;
1904 default:
1905 continue;
1906 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001907 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001908 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001909 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001910 if (!ui_browser__dialog_yesno(&menu->b,
1911 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001912 continue;
1913 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001914 case 'q':
1915 case CTRL('c'):
1916 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001917 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001918 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001919 }
1920 }
1921
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001922out:
1923 ui_browser__hide(&menu->b);
1924 return key;
1925}
1926
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001927static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001928 void *entry)
1929{
1930 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1931
1932 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1933 return true;
1934
1935 return false;
1936}
1937
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001938static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001939 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001940 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001941 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001942 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001943{
1944 struct perf_evsel *pos;
1945 struct perf_evsel_menu menu = {
1946 .b = {
1947 .entries = &evlist->entries,
1948 .refresh = ui_browser__list_head_refresh,
1949 .seek = ui_browser__list_head_seek,
1950 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001951 .filter = filter_group_entries,
1952 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001953 .priv = evlist,
1954 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001955 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001956 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001957 };
1958
1959 ui_helpline__push("Press ESC to exit");
1960
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001961 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001962 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001963 size_t line_len = strlen(ev_name) + 7;
1964
1965 if (menu.b.width < line_len)
1966 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001967 }
1968
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001969 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001970}
1971
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001972int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001973 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001974 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001975 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001976{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001977 int nr_entries = evlist->nr_entries;
1978
1979single_entry:
1980 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001981 struct perf_evsel *first = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001982 const char *ev_name = perf_evsel__name(first);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001983
1984 return perf_evsel__hists_browse(first, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001985 ev_name, false, hbt, min_pcnt,
1986 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001987 }
1988
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001989 if (symbol_conf.event_group) {
1990 struct perf_evsel *pos;
1991
1992 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001993 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001994 if (perf_evsel__is_group_leader(pos))
1995 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001996 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001997
1998 if (nr_entries == 1)
1999 goto single_entry;
2000 }
2001
2002 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002003 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002004}