blob: 04a229aa5c0fd0a5eb25b6cbdece82bdb0b9ba38 [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include "../libslang.h"
3#include <stdlib.h>
4#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <linux/rbtree.h>
6
Namhyung Kimaca7a942012-04-04 00:14:26 -07007#include "../../util/evsel.h"
8#include "../../util/evlist.h"
9#include "../../util/hist.h"
10#include "../../util/pstack.h"
11#include "../../util/sort.h"
12#include "../../util/util.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020020#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022struct hist_browser {
23 struct ui_browser b;
24 struct hists *hists;
25 struct hist_entry *he_selection;
26 struct map_symbol *selection;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030027 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030028 bool show_dso;
Namhyung Kim064f1982013-05-14 11:09:04 +090029 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090030 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090031 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030032};
33
Namhyung Kimf5951d52012-09-03 11:53:09 +090034extern void hist_browser__init_hpp(void);
35
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030036static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -020037 const char *ev_name);
Namhyung Kim112f7612014-04-22 14:05:35 +090038static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030039
Namhyung Kimc3b78952014-04-22 15:56:17 +090040static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090041 float min_pcnt);
42
Namhyung Kim268397c2014-04-22 14:49:31 +090043static bool hist_browser__has_filter(struct hist_browser *hb)
44{
45 return hists__has_filter(hb->hists) || hb->min_pcnt;
46}
47
Namhyung Kimc3b78952014-04-22 15:56:17 +090048static u32 hist_browser__nr_entries(struct hist_browser *hb)
49{
50 u32 nr_entries;
51
52 if (hist_browser__has_filter(hb))
53 nr_entries = hb->nr_non_filtered_entries;
54 else
55 nr_entries = hb->hists->nr_entries;
56
57 return nr_entries + hb->nr_callchain_rows;
58}
59
Arnaldo Carvalho de 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);
Namhyung Kim14135662013-10-31 10:17:39 +0900322 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900323 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300324 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
325 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900326 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300327 }
328}
329
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300330static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300331{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900332 browser->nr_callchain_rows = 0;
333 __hist_browser__set_folding(browser, unfold);
334
335 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300336 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300337 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300338}
339
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200340static void ui_browser__warn_lost_events(struct ui_browser *browser)
341{
342 ui_browser__warning(browser, 4,
343 "Events are being lost, check IO/CPU overload!\n\n"
344 "You may want to run 'perf' using a RT scheduler policy:\n\n"
345 " perf top -r 80\n\n"
346 "Or reduce the sampling frequency.");
347}
348
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300349static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900350 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300351{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300352 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300353 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900354 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300355
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300356 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900357 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300358
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300359 hist_browser__refresh_dimensions(browser);
360 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300361
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300362 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300363 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300364 return -1;
365
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300366 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300367 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300368
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300369 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900370 case K_TIMER: {
371 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900372 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900373
Namhyung Kimc3b78952014-04-22 15:56:17 +0900374 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900375 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900376
Namhyung Kimc3b78952014-04-22 15:56:17 +0900377 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900378 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200379
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300380 if (browser->hists->stats.nr_lost_warned !=
381 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
382 browser->hists->stats.nr_lost_warned =
383 browser->hists->stats.nr_events[PERF_RECORD_LOST];
384 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200385 }
386
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300387 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
388 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300389 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900390 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300391 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300393 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394 struct hist_entry, rb_node);
395 ui_helpline__pop();
396 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300397 seq++, browser->b.nr_entries,
398 browser->hists->nr_entries,
399 browser->b.height,
400 browser->b.index,
401 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300402 h->row_offset, h->nr_rows);
403 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300404 break;
405 case 'C':
406 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300407 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300408 break;
409 case 'E':
410 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300411 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300412 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200413 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300414 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300415 break;
416 /* fall thru */
417 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300418 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300419 }
420 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300421out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300422 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300423 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300424}
425
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300426static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300427 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300429 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300430
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300431 if (cl->ms.sym)
432 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
433 else
434 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
435
436 if (show_dso)
437 scnprintf(bf + printed, bfsize - printed, " %s",
438 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
439
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300440 return bf;
441}
442
443#define LEVEL_OFFSET_STEP 3
444
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300445static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300446 struct callchain_node *chain_node,
447 u64 total, int level,
448 unsigned short row,
449 off_t *row_offset,
450 bool *is_current_entry)
451{
452 struct rb_node *node;
453 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
454 u64 new_total, remaining;
455
456 if (callchain_param.mode == CHAIN_GRAPH_REL)
457 new_total = chain_node->children_hit;
458 else
459 new_total = total;
460
461 remaining = new_total;
462 node = rb_first(&chain_node->rb_root);
463 while (node) {
464 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
465 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100466 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300467 struct callchain_list *chain;
468 char folded_sign = ' ';
469 int first = true;
470 int extra_offset = 0;
471
472 remaining -= cumul;
473
474 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300475 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300476 const char *str;
477 int color;
478 bool was_first = first;
479
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300480 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300481 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300482 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300483 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300484
485 folded_sign = callchain_list__folded(chain);
486 if (*row_offset != 0) {
487 --*row_offset;
488 goto do_next;
489 }
490
491 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300492 str = callchain_list__sym_name(chain, bf, sizeof(bf),
493 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300494 if (was_first) {
495 double percent = cumul * 100.0 / new_total;
496
497 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
498 str = "Not enough memory!";
499 else
500 str = alloc_str;
501 }
502
503 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300504 width = browser->b.width - (offset + extra_offset + 2);
505 if (ui_browser__is_current_entry(&browser->b, row)) {
506 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300507 color = HE_COLORSET_SELECTED;
508 *is_current_entry = true;
509 }
510
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300511 ui_browser__set_color(&browser->b, color);
512 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300513 slsmg_write_nstring(" ", offset + extra_offset);
514 slsmg_printf("%c ", folded_sign);
515 slsmg_write_nstring(str, width);
516 free(alloc_str);
517
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300519 goto out;
520do_next:
521 if (folded_sign == '+')
522 break;
523 }
524
525 if (folded_sign == '-') {
526 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300527 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300528 new_level, row, row_offset,
529 is_current_entry);
530 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300531 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300532 goto out;
533 node = next;
534 }
535out:
536 return row - first_row;
537}
538
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300539static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300540 struct callchain_node *node,
541 int level, unsigned short row,
542 off_t *row_offset,
543 bool *is_current_entry)
544{
545 struct callchain_list *chain;
546 int first_row = row,
547 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300548 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300549 char folded_sign = ' ';
550
551 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300552 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300553 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300554
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300555 folded_sign = callchain_list__folded(chain);
556
557 if (*row_offset != 0) {
558 --*row_offset;
559 continue;
560 }
561
562 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300563 if (ui_browser__is_current_entry(&browser->b, row)) {
564 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300565 color = HE_COLORSET_SELECTED;
566 *is_current_entry = true;
567 }
568
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300569 s = callchain_list__sym_name(chain, bf, sizeof(bf),
570 browser->show_dso);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300571 ui_browser__gotorc(&browser->b, row, 0);
572 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300573 slsmg_write_nstring(" ", offset);
574 slsmg_printf("%c ", folded_sign);
575 slsmg_write_nstring(s, width - 2);
576
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300577 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300578 goto out;
579 }
580
581 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300582 row += hist_browser__show_callchain_node_rb_tree(browser, node,
583 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300584 level + 1, row,
585 row_offset,
586 is_current_entry);
587out:
588 return row - first_row;
589}
590
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300591static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592 struct rb_root *chain,
593 int level, unsigned short row,
594 off_t *row_offset,
595 bool *is_current_entry)
596{
597 struct rb_node *nd;
598 int first_row = row;
599
600 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
601 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
602
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300603 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300604 row, row_offset,
605 is_current_entry);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300606 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607 break;
608 }
609
610 return row - first_row;
611}
612
Namhyung Kim89701462013-01-22 18:09:38 +0900613struct hpp_arg {
614 struct ui_browser *b;
615 char folded_sign;
616 bool current_entry;
617};
618
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900619static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
620{
621 struct hpp_arg *arg = hpp->ptr;
622 int ret;
623 va_list args;
624 double percent;
625
626 va_start(args, fmt);
627 percent = va_arg(args, double);
628 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900629
Namhyung Kim89701462013-01-22 18:09:38 +0900630 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900631
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900632 ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900633 slsmg_printf("%s", hpp->buf);
634
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900635 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900636 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900637}
638
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900639#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900640static u64 __hpp_get_##_field(struct hist_entry *he) \
641{ \
642 return he->stat._field; \
643} \
644 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100645static int \
646hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
647 struct perf_hpp *hpp, \
648 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900649{ \
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900650 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900651 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900652}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900653
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900654#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
655static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
656{ \
657 return he->stat_acc->_field; \
658} \
659 \
660static int \
661hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
662 struct perf_hpp *hpp, \
663 struct hist_entry *he) \
664{ \
665 if (!symbol_conf.cumulate_callchain) { \
666 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
667 slsmg_printf("%s", hpp->buf); \
668 \
669 return ret; \
670 } \
671 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \
672 __hpp__slsmg_color_printf, true); \
673}
674
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900675__HPP_COLOR_PERCENT_FN(overhead, period)
676__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
677__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
678__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
679__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900680__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900681
682#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900683#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900684
685void hist_browser__init_hpp(void)
686{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900687 perf_hpp__format[PERF_HPP__OVERHEAD].color =
688 hist_browser__hpp_color_overhead;
689 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
690 hist_browser__hpp_color_overhead_sys;
691 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
692 hist_browser__hpp_color_overhead_us;
693 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
694 hist_browser__hpp_color_overhead_guest_sys;
695 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
696 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900697 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
698 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900699}
700
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300701static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300702 struct hist_entry *entry,
703 unsigned short row)
704{
705 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200706 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900707 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300708 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300709 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300710 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300711 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200712 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300713
714 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300715 browser->he_selection = entry;
716 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300717 }
718
719 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300720 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300721 folded_sign = hist_entry__folded(entry);
722 }
723
724 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900725 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900726 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900727 .folded_sign = folded_sign,
728 .current_entry = current_entry,
729 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900730 struct perf_hpp hpp = {
731 .buf = s,
732 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900733 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900734 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300735
Namhyung Kim67d25912012-09-12 15:35:06 +0900736 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900737
Jiri Olsa12400052012-10-13 00:06:16 +0200738 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900739 if (perf_hpp__should_skip(fmt))
740 continue;
741
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900742 if (current_entry && browser->b.navkeypressed) {
743 ui_browser__set_color(&browser->b,
744 HE_COLORSET_SELECTED);
745 } else {
746 ui_browser__set_color(&browser->b,
747 HE_COLORSET_NORMAL);
748 }
749
750 if (first) {
751 if (symbol_conf.use_callchain) {
752 slsmg_printf("%c ", folded_sign);
753 width -= 2;
754 }
755 first = false;
756 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900757 slsmg_printf(" ");
758 width -= 2;
759 }
760
Jiri Olsa12400052012-10-13 00:06:16 +0200761 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100762 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900763 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100764 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900765 slsmg_printf("%s", s);
766 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300767 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200768
769 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300770 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200771 width += 1;
772
Namhyung Kim26d8b332014-03-03 16:16:20 +0900773 slsmg_write_nstring("", width);
774
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300775 ++row;
776 ++printed;
777 } else
778 --row_offset;
779
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300780 if (folded_sign == '-' && row != browser->b.height) {
781 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300782 1, row, &row_offset,
783 &current_entry);
784 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300785 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300786 }
787
788 return printed;
789}
790
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300791static void ui_browser__hists_init_top(struct ui_browser *browser)
792{
793 if (browser->top == NULL) {
794 struct hist_browser *hb;
795
796 hb = container_of(browser, struct hist_browser, b);
797 browser->top = rb_first(&hb->hists->entries);
798 }
799}
800
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300801static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300802{
803 unsigned row = 0;
804 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300805 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300806
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300807 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300808
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300809 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300810 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900811 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300812
813 if (h->filtered)
814 continue;
815
Namhyung Kim14135662013-10-31 10:17:39 +0900816 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900817 if (percent < hb->min_pcnt)
818 continue;
819
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300820 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300821 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300822 break;
823 }
824
825 return row;
826}
827
Namhyung Kim064f1982013-05-14 11:09:04 +0900828static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900829 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300830{
831 while (nd != NULL) {
832 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900833 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900834
Namhyung Kimc0f15272014-04-16 11:16:33 +0900835 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300836 return nd;
837
838 nd = rb_next(nd);
839 }
840
841 return NULL;
842}
843
Namhyung Kim064f1982013-05-14 11:09:04 +0900844static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900845 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300846{
847 while (nd != NULL) {
848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900849 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900850
851 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300852 return nd;
853
854 nd = rb_prev(nd);
855 }
856
857 return NULL;
858}
859
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300860static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300861 off_t offset, int whence)
862{
863 struct hist_entry *h;
864 struct rb_node *nd;
865 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900866 struct hist_browser *hb;
867
868 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300869
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300870 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300871 return;
872
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300873 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300874
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300875 switch (whence) {
876 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900877 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900878 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300879 break;
880 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300881 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300882 goto do_offset;
883 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900884 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900885 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300886 first = false;
887 break;
888 default:
889 return;
890 }
891
892 /*
893 * Moves not relative to the first visible entry invalidates its
894 * row_offset:
895 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300896 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300897 h->row_offset = 0;
898
899 /*
900 * Here we have to check if nd is expanded (+), if it is we can't go
901 * the next top level hist_entry, instead we must compute an offset of
902 * what _not_ to show and not change the first visible entry.
903 *
904 * This offset increments when we are going from top to bottom and
905 * decreases when we're going from bottom to top.
906 *
907 * As we don't have backpointers to the top level in the callchains
908 * structure, we need to always print the whole hist_entry callchain,
909 * skipping the first ones that are before the first visible entry
910 * and stop when we printed enough lines to fill the screen.
911 */
912do_offset:
913 if (offset > 0) {
914 do {
915 h = rb_entry(nd, struct hist_entry, rb_node);
916 if (h->ms.unfolded) {
917 u16 remaining = h->nr_rows - h->row_offset;
918 if (offset > remaining) {
919 offset -= remaining;
920 h->row_offset = 0;
921 } else {
922 h->row_offset += offset;
923 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300924 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300925 break;
926 }
927 }
Namhyung Kim14135662013-10-31 10:17:39 +0900928 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300929 if (nd == NULL)
930 break;
931 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300932 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300933 } while (offset != 0);
934 } else if (offset < 0) {
935 while (1) {
936 h = rb_entry(nd, struct hist_entry, rb_node);
937 if (h->ms.unfolded) {
938 if (first) {
939 if (-offset > h->row_offset) {
940 offset += h->row_offset;
941 h->row_offset = 0;
942 } else {
943 h->row_offset += offset;
944 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300945 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300946 break;
947 }
948 } else {
949 if (-offset > h->nr_rows) {
950 offset += h->nr_rows;
951 h->row_offset = 0;
952 } else {
953 h->row_offset = h->nr_rows + offset;
954 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300955 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300956 break;
957 }
958 }
959 }
960
Namhyung Kim14135662013-10-31 10:17:39 +0900961 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +0900962 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300963 if (nd == NULL)
964 break;
965 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300966 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300967 if (offset == 0) {
968 /*
969 * Last unfiltered hist_entry, check if it is
970 * unfolded, if it is then we should have
971 * row_offset at its last entry.
972 */
973 h = rb_entry(nd, struct hist_entry, rb_node);
974 if (h->ms.unfolded)
975 h->row_offset = h->nr_rows;
976 break;
977 }
978 first = false;
979 }
980 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300981 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300982 h = rb_entry(nd, struct hist_entry, rb_node);
983 h->row_offset = 0;
984 }
985}
986
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300987static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
988 struct callchain_node *chain_node,
989 u64 total, int level,
990 FILE *fp)
991{
992 struct rb_node *node;
993 int offset = level * LEVEL_OFFSET_STEP;
994 u64 new_total, remaining;
995 int printed = 0;
996
997 if (callchain_param.mode == CHAIN_GRAPH_REL)
998 new_total = chain_node->children_hit;
999 else
1000 new_total = total;
1001
1002 remaining = new_total;
1003 node = rb_first(&chain_node->rb_root);
1004 while (node) {
1005 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1006 struct rb_node *next = rb_next(node);
1007 u64 cumul = callchain_cumul_hits(child);
1008 struct callchain_list *chain;
1009 char folded_sign = ' ';
1010 int first = true;
1011 int extra_offset = 0;
1012
1013 remaining -= cumul;
1014
1015 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001016 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001017 const char *str;
1018 bool was_first = first;
1019
1020 if (first)
1021 first = false;
1022 else
1023 extra_offset = LEVEL_OFFSET_STEP;
1024
1025 folded_sign = callchain_list__folded(chain);
1026
1027 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001028 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1029 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001030 if (was_first) {
1031 double percent = cumul * 100.0 / new_total;
1032
1033 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1034 str = "Not enough memory!";
1035 else
1036 str = alloc_str;
1037 }
1038
1039 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1040 free(alloc_str);
1041 if (folded_sign == '+')
1042 break;
1043 }
1044
1045 if (folded_sign == '-') {
1046 const int new_level = level + (extra_offset ? 2 : 1);
1047 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1048 new_level, fp);
1049 }
1050
1051 node = next;
1052 }
1053
1054 return printed;
1055}
1056
1057static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1058 struct callchain_node *node,
1059 int level, FILE *fp)
1060{
1061 struct callchain_list *chain;
1062 int offset = level * LEVEL_OFFSET_STEP;
1063 char folded_sign = ' ';
1064 int printed = 0;
1065
1066 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001067 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001068
1069 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001070 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001071 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1072 }
1073
1074 if (folded_sign == '-')
1075 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1076 browser->hists->stats.total_period,
1077 level + 1, fp);
1078 return printed;
1079}
1080
1081static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1082 struct rb_root *chain, int level, FILE *fp)
1083{
1084 struct rb_node *nd;
1085 int printed = 0;
1086
1087 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1088 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1089
1090 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1091 }
1092
1093 return printed;
1094}
1095
1096static int hist_browser__fprintf_entry(struct hist_browser *browser,
1097 struct hist_entry *he, FILE *fp)
1098{
1099 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001100 int printed = 0;
1101 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001102 struct perf_hpp hpp = {
1103 .buf = s,
1104 .size = sizeof(s),
1105 };
1106 struct perf_hpp_fmt *fmt;
1107 bool first = true;
1108 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001109
1110 if (symbol_conf.use_callchain)
1111 folded_sign = hist_entry__folded(he);
1112
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001113 if (symbol_conf.use_callchain)
1114 printed += fprintf(fp, "%c ", folded_sign);
1115
Namhyung Kim26d8b332014-03-03 16:16:20 +09001116 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001117 if (perf_hpp__should_skip(fmt))
1118 continue;
1119
Namhyung Kim26d8b332014-03-03 16:16:20 +09001120 if (!first) {
1121 ret = scnprintf(hpp.buf, hpp.size, " ");
1122 advance_hpp(&hpp, ret);
1123 } else
1124 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001125
Namhyung Kim26d8b332014-03-03 16:16:20 +09001126 ret = fmt->entry(fmt, &hpp, he);
1127 advance_hpp(&hpp, ret);
1128 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001129 printed += fprintf(fp, "%s\n", rtrim(s));
1130
1131 if (folded_sign == '-')
1132 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1133
1134 return printed;
1135}
1136
1137static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1138{
Namhyung Kim064f1982013-05-14 11:09:04 +09001139 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001140 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001141 int printed = 0;
1142
1143 while (nd) {
1144 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1145
1146 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001147 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001148 }
1149
1150 return printed;
1151}
1152
1153static int hist_browser__dump(struct hist_browser *browser)
1154{
1155 char filename[64];
1156 FILE *fp;
1157
1158 while (1) {
1159 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1160 if (access(filename, F_OK))
1161 break;
1162 /*
1163 * XXX: Just an arbitrary lazy upper limit
1164 */
1165 if (++browser->print_seq == 8192) {
1166 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1167 return -1;
1168 }
1169 }
1170
1171 fp = fopen(filename, "w");
1172 if (fp == NULL) {
1173 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001174 const char *err = strerror_r(errno, bf, sizeof(bf));
1175 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001176 return -1;
1177 }
1178
1179 ++browser->print_seq;
1180 hist_browser__fprintf(browser, fp);
1181 fclose(fp);
1182 ui_helpline__fpush("%s written!", filename);
1183
1184 return 0;
1185}
1186
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001187static struct hist_browser *hist_browser__new(struct hists *hists)
1188{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001189 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001190
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001191 if (browser) {
1192 browser->hists = hists;
1193 browser->b.refresh = hist_browser__refresh;
1194 browser->b.seek = ui_browser__hists_seek;
1195 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196 }
1197
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001198 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199}
1200
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001201static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001203 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204}
1205
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001206static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001208 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001209}
1210
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001211static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001212{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001213 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001214}
1215
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001216static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001217 const char *ev_name)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001219 char unit;
1220 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001221 const struct dso *dso = hists->dso_filter;
1222 const struct thread *thread = hists->thread_filter;
1223 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1224 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001225 struct perf_evsel *evsel = hists_to_evsel(hists);
1226 char buf[512];
1227 size_t buflen = sizeof(buf);
1228
Namhyung Kimf2148332014-01-14 11:52:48 +09001229 if (symbol_conf.filter_relative) {
1230 nr_samples = hists->stats.nr_non_filtered_samples;
1231 nr_events = hists->stats.total_non_filtered_period;
1232 }
1233
Namhyung Kim759ff492013-03-05 14:53:26 +09001234 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001235 struct perf_evsel *pos;
1236
1237 perf_evsel__group_desc(evsel, buf, buflen);
1238 ev_name = buf;
1239
1240 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001241 if (symbol_conf.filter_relative) {
1242 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1243 nr_events += pos->hists.stats.total_non_filtered_period;
1244 } else {
1245 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1246 nr_events += pos->hists.stats.total_period;
1247 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001248 }
1249 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001250
Ashay Ranecc686282012-04-05 21:01:01 -05001251 nr_samples = convert_unit(nr_samples, &unit);
1252 printed = scnprintf(bf, size,
1253 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1254 nr_samples, unit, ev_name, nr_events);
1255
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001256
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001257 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001258 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001259 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001260 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001261 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001262 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001263 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001264 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001265 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001266 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001267 ", DSO: %s", dso->short_name);
1268 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001269}
1270
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001271static inline void free_popup_options(char **options, int n)
1272{
1273 int i;
1274
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001275 for (i = 0; i < n; ++i)
1276 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001277}
1278
Feng Tangc77d8d72012-11-01 00:00:55 +08001279/* Check whether the browser is for 'top' or 'report' */
1280static inline bool is_report_browser(void *timer)
1281{
1282 return timer == NULL;
1283}
1284
Feng Tang341487ab2013-02-03 14:38:20 +08001285/*
1286 * Only runtime switching of perf data file will make "input_name" point
1287 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1288 * whether we need to call free() for current "input_name" during the switch.
1289 */
1290static bool is_input_name_malloced = false;
1291
1292static int switch_data_file(void)
1293{
1294 char *pwd, *options[32], *abs_path[32], *tmp;
1295 DIR *pwd_dir;
1296 int nr_options = 0, choice = -1, ret = -1;
1297 struct dirent *dent;
1298
1299 pwd = getenv("PWD");
1300 if (!pwd)
1301 return ret;
1302
1303 pwd_dir = opendir(pwd);
1304 if (!pwd_dir)
1305 return ret;
1306
1307 memset(options, 0, sizeof(options));
1308 memset(options, 0, sizeof(abs_path));
1309
1310 while ((dent = readdir(pwd_dir))) {
1311 char path[PATH_MAX];
1312 u64 magic;
1313 char *name = dent->d_name;
1314 FILE *file;
1315
1316 if (!(dent->d_type == DT_REG))
1317 continue;
1318
1319 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1320
1321 file = fopen(path, "r");
1322 if (!file)
1323 continue;
1324
1325 if (fread(&magic, 1, 8, file) < 8)
1326 goto close_file_and_continue;
1327
1328 if (is_perf_magic(magic)) {
1329 options[nr_options] = strdup(name);
1330 if (!options[nr_options])
1331 goto close_file_and_continue;
1332
1333 abs_path[nr_options] = strdup(path);
1334 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001335 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001336 ui__warning("Can't search all data files due to memory shortage.\n");
1337 fclose(file);
1338 break;
1339 }
1340
1341 nr_options++;
1342 }
1343
1344close_file_and_continue:
1345 fclose(file);
1346 if (nr_options >= 32) {
1347 ui__warning("Too many perf data files in PWD!\n"
1348 "Only the first 32 files will be listed.\n");
1349 break;
1350 }
1351 }
1352 closedir(pwd_dir);
1353
1354 if (nr_options) {
1355 choice = ui__popup_menu(nr_options, options);
1356 if (choice < nr_options && choice >= 0) {
1357 tmp = strdup(abs_path[choice]);
1358 if (tmp) {
1359 if (is_input_name_malloced)
1360 free((void *)input_name);
1361 input_name = tmp;
1362 is_input_name_malloced = true;
1363 ret = 0;
1364 } else
1365 ui__warning("Data switch failed due to memory shortage!\n");
1366 }
1367 }
1368
1369 free_popup_options(options, nr_options);
1370 free_popup_options(abs_path, nr_options);
1371 return ret;
1372}
1373
Namhyung Kim112f7612014-04-22 14:05:35 +09001374static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001375{
1376 u64 nr_entries = 0;
1377 struct rb_node *nd = rb_first(&hb->hists->entries);
1378
Namhyung Kim268397c2014-04-22 14:49:31 +09001379 if (hb->min_pcnt == 0) {
1380 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1381 return;
1382 }
1383
Namhyung Kim14135662013-10-31 10:17:39 +09001384 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001385 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001386 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001387 }
1388
Namhyung Kim112f7612014-04-22 14:05:35 +09001389 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001390}
Feng Tang341487ab2013-02-03 14:38:20 +08001391
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001392static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001393 const char *helpline, const char *ev_name,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001394 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001395 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001396 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001397 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001398{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001399 struct hists *hists = &evsel->hists;
1400 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001401 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001402 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001403 char *options[16];
1404 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001405 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001406 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001407 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001408 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001409
Namhyung Kime8e684a2013-12-26 14:37:58 +09001410#define HIST_BROWSER_HELP_COMMON \
1411 "h/?/F1 Show this window\n" \
1412 "UP/DOWN/PGUP\n" \
1413 "PGDN/SPACE Navigate\n" \
1414 "q/ESC/CTRL+C Exit browser\n\n" \
1415 "For multiple event sessions:\n\n" \
1416 "TAB/UNTAB Switch events\n\n" \
1417 "For symbolic views (--sort has sym):\n\n" \
1418 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1419 "<- Zoom out\n" \
1420 "a Annotate current symbol\n" \
1421 "C Collapse all callchains\n" \
1422 "d Zoom into current DSO\n" \
1423 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001424 "F Toggle percentage of filtered entries\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001425
1426 /* help messages are sorted by lexical order of the hotkey */
1427 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001428 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001429 "P Print histograms to perf.hist.N\n"
1430 "r Run available scripts\n"
1431 "s Switch to another data file in PWD\n"
1432 "t Zoom into current Thread\n"
1433 "V Verbose (DSO names in callchains, etc)\n"
1434 "/ Filter symbol by name";
1435 const char top_help[] = HIST_BROWSER_HELP_COMMON
1436 "P Print histograms to perf.hist.N\n"
1437 "t Zoom into current Thread\n"
1438 "V Verbose (DSO names in callchains, etc)\n"
1439 "/ Filter symbol by name";
1440
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001441 if (browser == NULL)
1442 return -1;
1443
Namhyung Kim064f1982013-05-14 11:09:04 +09001444 if (min_pcnt) {
1445 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001446 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001447 }
1448
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001449 fstack = pstack__new(2);
1450 if (fstack == NULL)
1451 goto out;
1452
1453 ui_helpline__push(helpline);
1454
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001455 memset(options, 0, sizeof(options));
1456
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001457 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001458 const struct thread *thread = NULL;
1459 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001460 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001461 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001462 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001463 int scripts_comm = -2, scripts_symbol = -2,
1464 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001465
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001466 nr_options = 0;
1467
Namhyung Kim9783adf2012-11-02 14:50:05 +09001468 key = hist_browser__run(browser, ev_name, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001469
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001470 if (browser->he_selection != NULL) {
1471 thread = hist_browser__selected_thread(browser);
1472 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1473 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001474 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001475 case K_TAB:
1476 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001477 if (nr_events == 1)
1478 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001479 /*
1480 * Exit the browser, let hists__browser_tree
1481 * go to the next or previous
1482 */
1483 goto out_free_stack;
1484 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001485 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001486 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001487 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001488 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001489 continue;
1490 }
1491
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001492 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001493 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001494 browser->selection->map->dso->annotate_warned)
1495 continue;
1496 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001497 case 'P':
1498 hist_browser__dump(browser);
1499 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001500 case 'd':
1501 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001502 case 'V':
1503 browser->show_dso = !browser->show_dso;
1504 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001505 case 't':
1506 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001507 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001508 if (ui_browser__input_window("Symbol to show",
1509 "Please enter the name of symbol you want to see",
1510 buf, "ENTER: OK, ESC: Cancel",
1511 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001512 hists->symbol_filter_str = *buf ? buf : NULL;
1513 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001514 hist_browser__reset(browser);
1515 }
1516 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001517 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001518 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001519 goto do_scripts;
1520 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001521 case 's':
1522 if (is_report_browser(hbt))
1523 goto do_data_switch;
1524 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001525 case 'i':
1526 /* env->arch is NULL for live-mode (i.e. perf top) */
1527 if (env->arch)
1528 tui__header_window(env);
1529 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001530 case 'F':
1531 symbol_conf.filter_relative ^= 1;
1532 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001533 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001534 case 'h':
1535 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001536 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001537 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001538 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001539 case K_ENTER:
1540 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001541 /* menu */
1542 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001543 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001544 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001545
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001546 if (pstack__empty(fstack)) {
1547 /*
1548 * Go back to the perf_evsel_menu__run or other user
1549 */
1550 if (left_exits)
1551 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001552 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001553 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001554 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001555 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001556 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001557 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001558 goto zoom_out_thread;
1559 continue;
1560 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001561 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001562 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001563 !ui_browser__dialog_yesno(&browser->b,
1564 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001565 continue;
1566 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001567 case 'q':
1568 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001569 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001570 default:
1571 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001572 }
1573
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001574 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001575 goto add_exit_option;
1576
Namhyung Kim55369fc2013-04-01 20:35:20 +09001577 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001578 bi = browser->he_selection->branch_info;
1579 if (browser->selection != NULL &&
1580 bi &&
1581 bi->from.sym != NULL &&
1582 !bi->from.map->dso->annotate_warned &&
1583 asprintf(&options[nr_options], "Annotate %s",
1584 bi->from.sym->name) > 0)
1585 annotate_f = nr_options++;
1586
1587 if (browser->selection != NULL &&
1588 bi &&
1589 bi->to.sym != NULL &&
1590 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001591 (bi->to.sym != bi->from.sym ||
1592 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001593 asprintf(&options[nr_options], "Annotate %s",
1594 bi->to.sym->name) > 0)
1595 annotate_t = nr_options++;
1596 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001597 if (browser->selection != NULL &&
1598 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001599 !browser->selection->map->dso->annotate_warned) {
1600 struct annotation *notes;
1601
1602 notes = symbol__annotation(browser->selection->sym);
1603
1604 if (notes->src &&
1605 asprintf(&options[nr_options], "Annotate %s",
1606 browser->selection->sym->name) > 0)
1607 annotate = nr_options++;
1608 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001609 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001610
1611 if (thread != NULL &&
1612 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001613 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001614 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001615 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001616 zoom_thread = nr_options++;
1617
1618 if (dso != NULL &&
1619 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001620 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001621 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1622 zoom_dso = nr_options++;
1623
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001624 if (browser->selection != NULL &&
1625 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001626 asprintf(&options[nr_options], "Browse map details") > 0)
1627 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001628
1629 /* perf script support */
1630 if (browser->he_selection) {
1631 struct symbol *sym;
1632
1633 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001634 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001635 scripts_comm = nr_options++;
1636
1637 sym = browser->he_selection->ms.sym;
1638 if (sym && sym->namelen &&
1639 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1640 sym->name) > 0)
1641 scripts_symbol = nr_options++;
1642 }
1643
1644 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1645 scripts_all = nr_options++;
1646
Feng Tang341487ab2013-02-03 14:38:20 +08001647 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1648 "Switch to another data file in PWD") > 0)
1649 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001650add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001651 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001652retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001653 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001654
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001655 if (choice == nr_options - 1)
1656 break;
1657
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001658 if (choice == -1) {
1659 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001660 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001661 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001662
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001663 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001664 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001665 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001666 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001667do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001668 if (!objdump_path && perf_session_env__lookup_objdump(env))
1669 continue;
1670
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001671 he = hist_browser__selected_entry(browser);
1672 if (he == NULL)
1673 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001674
1675 /*
1676 * we stash the branch_info symbol + map into the
1677 * the ms so we don't have to rewrite all the annotation
1678 * code to use branch_info.
1679 * in branch mode, the ms struct is not used
1680 */
1681 if (choice == annotate_f) {
1682 he->ms.sym = he->branch_info->from.sym;
1683 he->ms.map = he->branch_info->from.map;
1684 } else if (choice == annotate_t) {
1685 he->ms.sym = he->branch_info->to.sym;
1686 he->ms.map = he->branch_info->to.map;
1687 }
1688
Jiri Olsad7553302014-06-15 10:22:15 +02001689 notes = symbol__annotation(he->ms.sym);
1690 if (!notes->src)
1691 continue;
1692
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001693 /*
1694 * Don't let this be freed, say, by hists__decay_entry.
1695 */
1696 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001697 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001698 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001699 /*
1700 * offer option to annotate the other branch source or target
1701 * (if they exists) when returning from annotate
1702 */
1703 if ((err == 'q' || err == CTRL('c'))
1704 && annotate_t != -2 && annotate_f != -2)
1705 goto retry_popup_menu;
1706
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001707 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001708 if (err)
1709 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001710
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001711 } else if (choice == browse_map)
1712 map__browse(browser->selection->map);
1713 else if (choice == zoom_dso) {
1714zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001715 if (browser->hists->dso_filter) {
1716 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001717zoom_out_dso:
1718 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001719 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001720 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001721 } else {
1722 if (dso == NULL)
1723 continue;
1724 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1725 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001726 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001727 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001728 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001729 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001730 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001731 hist_browser__reset(browser);
1732 } else if (choice == zoom_thread) {
1733zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001734 if (browser->hists->thread_filter) {
1735 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001736zoom_out_thread:
1737 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001738 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001739 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001740 } else {
1741 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001742 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001743 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001744 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001745 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001746 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001747 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001748 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001749 hist_browser__reset(browser);
1750 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001751 /* perf scripts support */
1752 else if (choice == scripts_all || choice == scripts_comm ||
1753 choice == scripts_symbol) {
1754do_scripts:
1755 memset(script_opt, 0, 64);
1756
1757 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001758 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001759
1760 if (choice == scripts_symbol)
1761 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1762
1763 script_browse(script_opt);
1764 }
Feng Tang341487ab2013-02-03 14:38:20 +08001765 /* Switch to another data file */
1766 else if (choice == switch_data) {
1767do_data_switch:
1768 if (!switch_data_file()) {
1769 key = K_SWITCH_INPUT_DATA;
1770 break;
1771 } else
1772 ui__warning("Won't switch the data files due to\n"
1773 "no valid data file get selected!\n");
1774 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001775 }
1776out_free_stack:
1777 pstack__delete(fstack);
1778out:
1779 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001780 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001781 return key;
1782}
1783
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001784struct perf_evsel_menu {
1785 struct ui_browser b;
1786 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001787 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001788 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001789 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001790};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001791
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001792static void perf_evsel_menu__write(struct ui_browser *browser,
1793 void *entry, int row)
1794{
1795 struct perf_evsel_menu *menu = container_of(browser,
1796 struct perf_evsel_menu, b);
1797 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1798 bool current_entry = ui_browser__is_current_entry(browser, row);
1799 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001800 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001801 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001802 const char *warn = " ";
1803 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001804
1805 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1806 HE_COLORSET_NORMAL);
1807
Namhyung Kim759ff492013-03-05 14:53:26 +09001808 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001809 struct perf_evsel *pos;
1810
1811 ev_name = perf_evsel__group_name(evsel);
1812
1813 for_each_group_member(pos, evsel) {
1814 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1815 }
1816 }
1817
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001818 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001819 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001820 unit, unit == ' ' ? "" : " ", ev_name);
1821 slsmg_printf("%s", bf);
1822
1823 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1824 if (nr_events != 0) {
1825 menu->lost_events = true;
1826 if (!current_entry)
1827 ui_browser__set_color(browser, HE_COLORSET_TOP);
1828 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001829 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1830 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001831 warn = bf;
1832 }
1833
1834 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001835
1836 if (current_entry)
1837 menu->selection = evsel;
1838}
1839
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001840static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1841 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001842 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001843{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001844 struct perf_evlist *evlist = menu->b.priv;
1845 struct perf_evsel *pos;
1846 const char *ev_name, *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001847 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001848 int key;
1849
1850 if (ui_browser__show(&menu->b, title,
1851 "ESC: exit, ENTER|->: Browse histograms") < 0)
1852 return -1;
1853
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001854 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001855 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001856
1857 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001858 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001859 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001860
1861 if (!menu->lost_events_warned && menu->lost_events) {
1862 ui_browser__warn_lost_events(&menu->b);
1863 menu->lost_events_warned = true;
1864 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001865 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001866 case K_RIGHT:
1867 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001868 if (!menu->selection)
1869 continue;
1870 pos = menu->selection;
1871browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001872 perf_evlist__set_selected(evlist, pos);
1873 /*
1874 * Give the calling tool a chance to populate the non
1875 * default evsel resorted hists tree.
1876 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001877 if (hbt)
1878 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001879 ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001880 key = perf_evsel__hists_browse(pos, nr_events, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001881 ev_name, true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001882 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001883 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001884 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001885 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001886 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001887 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001888 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001889 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001890 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001891 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001892 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001893 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001894 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001895 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001896 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001897 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001898 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001899 if (!ui_browser__dialog_yesno(&menu->b,
1900 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001901 continue;
1902 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001903 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001904 case 'q':
1905 case CTRL('c'):
1906 goto out;
1907 default:
1908 continue;
1909 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001910 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001911 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001912 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001913 if (!ui_browser__dialog_yesno(&menu->b,
1914 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001915 continue;
1916 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001917 case 'q':
1918 case CTRL('c'):
1919 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001920 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001921 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001922 }
1923 }
1924
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001925out:
1926 ui_browser__hide(&menu->b);
1927 return key;
1928}
1929
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001930static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001931 void *entry)
1932{
1933 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1934
1935 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1936 return true;
1937
1938 return false;
1939}
1940
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001941static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001942 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001943 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001944 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001945 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001946{
1947 struct perf_evsel *pos;
1948 struct perf_evsel_menu menu = {
1949 .b = {
1950 .entries = &evlist->entries,
1951 .refresh = ui_browser__list_head_refresh,
1952 .seek = ui_browser__list_head_seek,
1953 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001954 .filter = filter_group_entries,
1955 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001956 .priv = evlist,
1957 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001958 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001959 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001960 };
1961
1962 ui_helpline__push("Press ESC to exit");
1963
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001964 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001965 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001966 size_t line_len = strlen(ev_name) + 7;
1967
1968 if (menu.b.width < line_len)
1969 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001970 }
1971
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001972 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001973}
1974
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001975int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001976 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001977 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001978 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001979{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001980 int nr_entries = evlist->nr_entries;
1981
1982single_entry:
1983 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001984 struct perf_evsel *first = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001985 const char *ev_name = perf_evsel__name(first);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001986
1987 return perf_evsel__hists_browse(first, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001988 ev_name, false, hbt, min_pcnt,
1989 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001990 }
1991
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001992 if (symbol_conf.event_group) {
1993 struct perf_evsel *pos;
1994
1995 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001996 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001997 if (perf_evsel__is_group_leader(pos))
1998 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001999 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002000
2001 if (nr_entries == 1)
2002 goto single_entry;
2003 }
2004
2005 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002006 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002007}