blob: b720b92eba6eb95cc7dd9bd4a57693f0a79d91b9 [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include "../libslang.h"
3#include <stdlib.h>
4#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <linux/rbtree.h>
6
Namhyung Kimaca7a942012-04-04 00:14:26 -07007#include "../../util/evsel.h"
8#include "../../util/evlist.h"
9#include "../../util/hist.h"
10#include "../../util/pstack.h"
11#include "../../util/sort.h"
12#include "../../util/util.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
20
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021struct hist_browser {
22 struct ui_browser b;
23 struct hists *hists;
24 struct hist_entry *he_selection;
25 struct map_symbol *selection;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030026 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030027 bool show_dso;
Namhyung Kim064f1982013-05-14 11:09:04 +090028 float min_pcnt;
29 u64 nr_pcnt_entries;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030030};
31
Namhyung Kimf5951d52012-09-03 11:53:09 +090032extern void hist_browser__init_hpp(void);
33
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030034static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -020035 const char *ev_name);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030036
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030037static void hist_browser__refresh_dimensions(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030038{
39 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030040 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030041 sizeof("[k]"));
42}
43
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030044static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030045{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030046 browser->b.nr_entries = browser->hists->nr_entries;
47 hist_browser__refresh_dimensions(browser);
48 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030049}
50
51static char tree__folded_sign(bool unfolded)
52{
53 return unfolded ? '-' : '+';
54}
55
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030056static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030057{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030058 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030059}
60
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030061static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030062{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030063 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030064}
65
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030066static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030067{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030068 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030069}
70
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030071static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -030072{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030073 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -030074}
75
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030076static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030077{
78 int n = 0;
79 struct rb_node *nd;
80
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030081 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030082 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
83 struct callchain_list *chain;
84 char folded_sign = ' '; /* No children */
85
86 list_for_each_entry(chain, &child->val, list) {
87 ++n;
88 /* We need this because we may not have children */
89 folded_sign = callchain_list__folded(chain);
90 if (folded_sign == '+')
91 break;
92 }
93
94 if (folded_sign == '-') /* Have children and they're unfolded */
95 n += callchain_node__count_rows_rb_tree(child);
96 }
97
98 return n;
99}
100
101static int callchain_node__count_rows(struct callchain_node *node)
102{
103 struct callchain_list *chain;
104 bool unfolded = false;
105 int n = 0;
106
107 list_for_each_entry(chain, &node->val, list) {
108 ++n;
109 unfolded = chain->ms.unfolded;
110 }
111
112 if (unfolded)
113 n += callchain_node__count_rows_rb_tree(node);
114
115 return n;
116}
117
118static int callchain__count_rows(struct rb_root *chain)
119{
120 struct rb_node *nd;
121 int n = 0;
122
123 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
124 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
125 n += callchain_node__count_rows(node);
126 }
127
128 return n;
129}
130
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300131static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300132{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300133 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200134 return false;
135
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300136 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300137 return false;
138
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300139 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300140 return true;
141}
142
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300143static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300145 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300146
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
149 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300150 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300151
152 list_for_each_entry(chain, &child->val, list) {
153 if (first) {
154 first = false;
155 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300156 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300157 } else
158 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300159 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300160 }
161
162 callchain_node__init_have_children_rb_tree(child);
163 }
164}
165
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300166static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300167{
168 struct callchain_list *chain;
169
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300170 list_for_each_entry(chain, &node->val, list)
171 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300172
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300173 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300174}
175
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300176static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300177{
178 struct rb_node *nd;
179
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300180 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300181 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
182 callchain_node__init_have_children(node);
183 }
184}
185
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300186static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300187{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300188 if (!he->init_have_children) {
189 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
190 callchain__init_have_children(&he->sorted_chain);
191 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300192 }
193}
194
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300195static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300196{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300197 if (map_symbol__toggle_fold(browser->selection)) {
198 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300199
200 hist_entry__init_have_children(he);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300201 browser->hists->nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300202
203 if (he->ms.unfolded)
204 he->nr_rows = callchain__count_rows(&he->sorted_chain);
205 else
206 he->nr_rows = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300207 browser->hists->nr_entries += he->nr_rows;
208 browser->b.nr_entries = browser->hists->nr_entries;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300209
210 return true;
211 }
212
213 /* If it doesn't have children, no toggling performed */
214 return false;
215}
216
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300217static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300218{
219 int n = 0;
220 struct rb_node *nd;
221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300222 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300223 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
224 struct callchain_list *chain;
225 bool has_children = false;
226
227 list_for_each_entry(chain, &child->val, list) {
228 ++n;
229 map_symbol__set_folding(&chain->ms, unfold);
230 has_children = chain->ms.has_children;
231 }
232
233 if (has_children)
234 n += callchain_node__set_folding_rb_tree(child, unfold);
235 }
236
237 return n;
238}
239
240static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
241{
242 struct callchain_list *chain;
243 bool has_children = false;
244 int n = 0;
245
246 list_for_each_entry(chain, &node->val, list) {
247 ++n;
248 map_symbol__set_folding(&chain->ms, unfold);
249 has_children = chain->ms.has_children;
250 }
251
252 if (has_children)
253 n += callchain_node__set_folding_rb_tree(node, unfold);
254
255 return n;
256}
257
258static int callchain__set_folding(struct rb_root *chain, bool unfold)
259{
260 struct rb_node *nd;
261 int n = 0;
262
263 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
264 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
265 n += callchain_node__set_folding(node, unfold);
266 }
267
268 return n;
269}
270
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300271static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300272{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300273 hist_entry__init_have_children(he);
274 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300275
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300276 if (he->ms.has_children) {
277 int n = callchain__set_folding(&he->sorted_chain, unfold);
278 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300279 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300280 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300281}
282
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300283static void hists__set_folding(struct hists *hists, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300284{
285 struct rb_node *nd;
286
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300287 hists->nr_entries = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300288
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300289 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300290 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
291 hist_entry__set_folding(he, unfold);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300292 hists->nr_entries += 1 + he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300293 }
294}
295
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300296static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300297{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300298 hists__set_folding(browser->hists, unfold);
299 browser->b.nr_entries = browser->hists->nr_entries;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300300 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300301 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300302}
303
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200304static void ui_browser__warn_lost_events(struct ui_browser *browser)
305{
306 ui_browser__warning(browser, 4,
307 "Events are being lost, check IO/CPU overload!\n\n"
308 "You may want to run 'perf' using a RT scheduler policy:\n\n"
309 " perf top -r 80\n\n"
310 "Or reduce the sampling frequency.");
311}
312
Namhyung Kimfa5df942013-05-14 11:09:05 +0900313static void hist_browser__update_pcnt_entries(struct hist_browser *hb);
314
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300315static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900316 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300317{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300318 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300319 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900320 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300321
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300322 browser->b.entries = &browser->hists->entries;
323 browser->b.nr_entries = browser->hists->nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +0900324 if (browser->min_pcnt)
325 browser->b.nr_entries = browser->nr_pcnt_entries;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300326
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300327 hist_browser__refresh_dimensions(browser);
328 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300329
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300330 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300331 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300332 return -1;
333
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300334 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300335 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300336
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300337 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900338 case K_TIMER: {
339 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900340 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900341
342 if (browser->min_pcnt) {
343 hist_browser__update_pcnt_entries(browser);
344 nr_entries = browser->nr_pcnt_entries;
345 } else {
346 nr_entries = browser->hists->nr_entries;
347 }
348
349 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200350
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300351 if (browser->hists->stats.nr_lost_warned !=
352 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
353 browser->hists->stats.nr_lost_warned =
354 browser->hists->stats.nr_events[PERF_RECORD_LOST];
355 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200356 }
357
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300358 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
359 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300360 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900361 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300362 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300364 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300365 struct hist_entry, rb_node);
366 ui_helpline__pop();
367 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 -0300368 seq++, browser->b.nr_entries,
369 browser->hists->nr_entries,
370 browser->b.height,
371 browser->b.index,
372 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300373 h->row_offset, h->nr_rows);
374 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300375 break;
376 case 'C':
377 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300378 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300379 break;
380 case 'E':
381 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300382 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300383 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200384 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300385 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300386 break;
387 /* fall thru */
388 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300389 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300390 }
391 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300392out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300393 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300394 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300395}
396
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300397static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300398 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300399{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300400 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300402 if (cl->ms.sym)
403 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
404 else
405 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
406
407 if (show_dso)
408 scnprintf(bf + printed, bfsize - printed, " %s",
409 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
410
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300411 return bf;
412}
413
414#define LEVEL_OFFSET_STEP 3
415
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300416static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300417 struct callchain_node *chain_node,
418 u64 total, int level,
419 unsigned short row,
420 off_t *row_offset,
421 bool *is_current_entry)
422{
423 struct rb_node *node;
424 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
425 u64 new_total, remaining;
426
427 if (callchain_param.mode == CHAIN_GRAPH_REL)
428 new_total = chain_node->children_hit;
429 else
430 new_total = total;
431
432 remaining = new_total;
433 node = rb_first(&chain_node->rb_root);
434 while (node) {
435 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
436 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100437 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300438 struct callchain_list *chain;
439 char folded_sign = ' ';
440 int first = true;
441 int extra_offset = 0;
442
443 remaining -= cumul;
444
445 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300446 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300447 const char *str;
448 int color;
449 bool was_first = first;
450
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300451 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300452 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300453 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300454 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300455
456 folded_sign = callchain_list__folded(chain);
457 if (*row_offset != 0) {
458 --*row_offset;
459 goto do_next;
460 }
461
462 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300463 str = callchain_list__sym_name(chain, bf, sizeof(bf),
464 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300465 if (was_first) {
466 double percent = cumul * 100.0 / new_total;
467
468 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
469 str = "Not enough memory!";
470 else
471 str = alloc_str;
472 }
473
474 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300475 width = browser->b.width - (offset + extra_offset + 2);
476 if (ui_browser__is_current_entry(&browser->b, row)) {
477 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300478 color = HE_COLORSET_SELECTED;
479 *is_current_entry = true;
480 }
481
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300482 ui_browser__set_color(&browser->b, color);
483 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300484 slsmg_write_nstring(" ", offset + extra_offset);
485 slsmg_printf("%c ", folded_sign);
486 slsmg_write_nstring(str, width);
487 free(alloc_str);
488
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300489 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300490 goto out;
491do_next:
492 if (folded_sign == '+')
493 break;
494 }
495
496 if (folded_sign == '-') {
497 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300498 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300499 new_level, row, row_offset,
500 is_current_entry);
501 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300502 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300503 goto out;
504 node = next;
505 }
506out:
507 return row - first_row;
508}
509
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300510static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300511 struct callchain_node *node,
512 int level, unsigned short row,
513 off_t *row_offset,
514 bool *is_current_entry)
515{
516 struct callchain_list *chain;
517 int first_row = row,
518 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300519 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300520 char folded_sign = ' ';
521
522 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300523 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300524 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300525
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300526 folded_sign = callchain_list__folded(chain);
527
528 if (*row_offset != 0) {
529 --*row_offset;
530 continue;
531 }
532
533 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300534 if (ui_browser__is_current_entry(&browser->b, row)) {
535 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300536 color = HE_COLORSET_SELECTED;
537 *is_current_entry = true;
538 }
539
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300540 s = callchain_list__sym_name(chain, bf, sizeof(bf),
541 browser->show_dso);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300542 ui_browser__gotorc(&browser->b, row, 0);
543 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300544 slsmg_write_nstring(" ", offset);
545 slsmg_printf("%c ", folded_sign);
546 slsmg_write_nstring(s, width - 2);
547
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300548 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300549 goto out;
550 }
551
552 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300553 row += hist_browser__show_callchain_node_rb_tree(browser, node,
554 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300555 level + 1, row,
556 row_offset,
557 is_current_entry);
558out:
559 return row - first_row;
560}
561
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300562static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300563 struct rb_root *chain,
564 int level, unsigned short row,
565 off_t *row_offset,
566 bool *is_current_entry)
567{
568 struct rb_node *nd;
569 int first_row = row;
570
571 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
572 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
573
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300574 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300575 row, row_offset,
576 is_current_entry);
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 break;
579 }
580
581 return row - first_row;
582}
583
Namhyung Kim89701462013-01-22 18:09:38 +0900584struct hpp_arg {
585 struct ui_browser *b;
586 char folded_sign;
587 bool current_entry;
588};
589
590static int __hpp__color_callchain(struct hpp_arg *arg)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900591{
Namhyung Kim89701462013-01-22 18:09:38 +0900592 if (!symbol_conf.use_callchain)
593 return 0;
594
595 slsmg_printf("%c ", arg->folded_sign);
596 return 2;
597}
598
599static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
600 u64 (*get_field)(struct hist_entry *),
601 int (*callchain_cb)(struct hpp_arg *))
602{
603 int ret = 0;
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900604 double percent = 0.0;
605 struct hists *hists = he->hists;
Namhyung Kim89701462013-01-22 18:09:38 +0900606 struct hpp_arg *arg = hpp->ptr;
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900607
608 if (hists->stats.total_period)
609 percent = 100.0 * get_field(he) / hists->stats.total_period;
610
Namhyung Kim89701462013-01-22 18:09:38 +0900611 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900612
Namhyung Kim89701462013-01-22 18:09:38 +0900613 if (callchain_cb)
614 ret += callchain_cb(arg);
615
616 ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
617 slsmg_printf("%s", hpp->buf);
618
Namhyung Kim371d8c42013-01-22 18:09:39 +0900619 if (symbol_conf.event_group) {
620 int prev_idx, idx_delta;
621 struct perf_evsel *evsel = hists_to_evsel(hists);
622 struct hist_entry *pair;
623 int nr_members = evsel->nr_members;
624
625 if (nr_members <= 1)
626 goto out;
627
628 prev_idx = perf_evsel__group_idx(evsel);
629
630 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
631 u64 period = get_field(pair);
632 u64 total = pair->hists->stats.total_period;
633
634 if (!total)
635 continue;
636
637 evsel = hists_to_evsel(pair->hists);
638 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
639
640 while (idx_delta--) {
641 /*
642 * zero-fill group members in the middle which
643 * have no sample
644 */
645 ui_browser__set_percent_color(arg->b, 0.0,
646 arg->current_entry);
647 ret += scnprintf(hpp->buf, hpp->size,
648 " %6.2f%%", 0.0);
649 slsmg_printf("%s", hpp->buf);
650 }
651
652 percent = 100.0 * period / total;
653 ui_browser__set_percent_color(arg->b, percent,
654 arg->current_entry);
655 ret += scnprintf(hpp->buf, hpp->size,
656 " %6.2f%%", percent);
657 slsmg_printf("%s", hpp->buf);
658
659 prev_idx = perf_evsel__group_idx(evsel);
660 }
661
662 idx_delta = nr_members - prev_idx - 1;
663
664 while (idx_delta--) {
665 /*
666 * zero-fill group members at last which have no sample
667 */
668 ui_browser__set_percent_color(arg->b, 0.0,
669 arg->current_entry);
670 ret += scnprintf(hpp->buf, hpp->size,
671 " %6.2f%%", 0.0);
672 slsmg_printf("%s", hpp->buf);
673 }
674 }
675out:
Namhyung Kim89701462013-01-22 18:09:38 +0900676 if (!arg->current_entry || !arg->b->navkeypressed)
677 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
678
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900679 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900680}
681
Namhyung Kim89701462013-01-22 18:09:38 +0900682#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900683static u64 __hpp_get_##_field(struct hist_entry *he) \
684{ \
685 return he->stat._field; \
686} \
687 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100688static int \
689hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
690 struct perf_hpp *hpp, \
691 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900692{ \
Namhyung Kim89701462013-01-22 18:09:38 +0900693 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900694}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900695
Namhyung Kim89701462013-01-22 18:09:38 +0900696__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
697__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
698__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
699__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
700__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900701
702#undef __HPP_COLOR_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900703
704void hist_browser__init_hpp(void)
705{
Jiri Olsa1d778222012-10-04 21:49:39 +0900706 perf_hpp__init();
Namhyung Kimf5951d52012-09-03 11:53:09 +0900707
708 perf_hpp__format[PERF_HPP__OVERHEAD].color =
709 hist_browser__hpp_color_overhead;
710 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
711 hist_browser__hpp_color_overhead_sys;
712 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
713 hist_browser__hpp_color_overhead_us;
714 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
715 hist_browser__hpp_color_overhead_guest_sys;
716 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
717 hist_browser__hpp_color_overhead_guest_us;
718}
719
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300720static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300721 struct hist_entry *entry,
722 unsigned short row)
723{
724 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200725 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900726 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300727 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300728 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300729 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300730 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200731 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300732
733 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300734 browser->he_selection = entry;
735 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300736 }
737
738 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300739 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300740 folded_sign = hist_entry__folded(entry);
741 }
742
743 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900744 struct hpp_arg arg = {
745 .b = &browser->b,
746 .folded_sign = folded_sign,
747 .current_entry = current_entry,
748 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900749 struct perf_hpp hpp = {
750 .buf = s,
751 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900752 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900753 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300754
Namhyung Kim67d25912012-09-12 15:35:06 +0900755 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900756
Jiri Olsa12400052012-10-13 00:06:16 +0200757 perf_hpp__for_each_format(fmt) {
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300758 if (!first) {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900759 slsmg_printf(" ");
760 width -= 2;
761 }
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300762 first = false;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900763
Jiri Olsa12400052012-10-13 00:06:16 +0200764 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100765 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900766 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100767 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900768 slsmg_printf("%s", s);
769 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300770 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200771
772 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300773 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200774 width += 1;
775
Namhyung Kimf5951d52012-09-03 11:53:09 +0900776 hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300777 slsmg_write_nstring(s, width);
778 ++row;
779 ++printed;
780 } else
781 --row_offset;
782
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300783 if (folded_sign == '-' && row != browser->b.height) {
784 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300785 1, row, &row_offset,
786 &current_entry);
787 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300788 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300789 }
790
791 return printed;
792}
793
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300794static void ui_browser__hists_init_top(struct ui_browser *browser)
795{
796 if (browser->top == NULL) {
797 struct hist_browser *hb;
798
799 hb = container_of(browser, struct hist_browser, b);
800 browser->top = rb_first(&hb->hists->entries);
801 }
802}
803
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300804static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300805{
806 unsigned row = 0;
807 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300808 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300809
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300810 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300811
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300812 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300813 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim064f1982013-05-14 11:09:04 +0900814 float percent = h->stat.period * 100.0 /
815 hb->hists->stats.total_period;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300816
817 if (h->filtered)
818 continue;
819
Namhyung Kim064f1982013-05-14 11:09:04 +0900820 if (percent < hb->min_pcnt)
821 continue;
822
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300823 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300824 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300825 break;
826 }
827
828 return row;
829}
830
Namhyung Kim064f1982013-05-14 11:09:04 +0900831static struct rb_node *hists__filter_entries(struct rb_node *nd,
832 struct hists *hists,
833 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300834{
835 while (nd != NULL) {
836 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim064f1982013-05-14 11:09:04 +0900837 float percent = h->stat.period * 100.0 /
838 hists->stats.total_period;
839
840 if (percent < min_pcnt)
841 return NULL;
842
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300843 if (!h->filtered)
844 return nd;
845
846 nd = rb_next(nd);
847 }
848
849 return NULL;
850}
851
Namhyung Kim064f1982013-05-14 11:09:04 +0900852static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
853 struct hists *hists,
854 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300855{
856 while (nd != NULL) {
857 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim064f1982013-05-14 11:09:04 +0900858 float percent = h->stat.period * 100.0 /
859 hists->stats.total_period;
860
861 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300862 return nd;
863
864 nd = rb_prev(nd);
865 }
866
867 return NULL;
868}
869
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300870static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300871 off_t offset, int whence)
872{
873 struct hist_entry *h;
874 struct rb_node *nd;
875 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900876 struct hist_browser *hb;
877
878 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300879
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300880 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300881 return;
882
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300883 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300884
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300885 switch (whence) {
886 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900887 nd = hists__filter_entries(rb_first(browser->entries),
888 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300889 break;
890 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300891 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300892 goto do_offset;
893 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900894 nd = hists__filter_prev_entries(rb_last(browser->entries),
895 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300896 first = false;
897 break;
898 default:
899 return;
900 }
901
902 /*
903 * Moves not relative to the first visible entry invalidates its
904 * row_offset:
905 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300906 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300907 h->row_offset = 0;
908
909 /*
910 * Here we have to check if nd is expanded (+), if it is we can't go
911 * the next top level hist_entry, instead we must compute an offset of
912 * what _not_ to show and not change the first visible entry.
913 *
914 * This offset increments when we are going from top to bottom and
915 * decreases when we're going from bottom to top.
916 *
917 * As we don't have backpointers to the top level in the callchains
918 * structure, we need to always print the whole hist_entry callchain,
919 * skipping the first ones that are before the first visible entry
920 * and stop when we printed enough lines to fill the screen.
921 */
922do_offset:
923 if (offset > 0) {
924 do {
925 h = rb_entry(nd, struct hist_entry, rb_node);
926 if (h->ms.unfolded) {
927 u16 remaining = h->nr_rows - h->row_offset;
928 if (offset > remaining) {
929 offset -= remaining;
930 h->row_offset = 0;
931 } else {
932 h->row_offset += offset;
933 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300934 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300935 break;
936 }
937 }
Namhyung Kim064f1982013-05-14 11:09:04 +0900938 nd = hists__filter_entries(rb_next(nd), hb->hists,
939 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300940 if (nd == NULL)
941 break;
942 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300943 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300944 } while (offset != 0);
945 } else if (offset < 0) {
946 while (1) {
947 h = rb_entry(nd, struct hist_entry, rb_node);
948 if (h->ms.unfolded) {
949 if (first) {
950 if (-offset > h->row_offset) {
951 offset += h->row_offset;
952 h->row_offset = 0;
953 } else {
954 h->row_offset += offset;
955 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300956 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300957 break;
958 }
959 } else {
960 if (-offset > h->nr_rows) {
961 offset += h->nr_rows;
962 h->row_offset = 0;
963 } else {
964 h->row_offset = h->nr_rows + offset;
965 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300966 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300967 break;
968 }
969 }
970 }
971
Namhyung Kim064f1982013-05-14 11:09:04 +0900972 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
973 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300974 if (nd == NULL)
975 break;
976 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300977 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300978 if (offset == 0) {
979 /*
980 * Last unfiltered hist_entry, check if it is
981 * unfolded, if it is then we should have
982 * row_offset at its last entry.
983 */
984 h = rb_entry(nd, struct hist_entry, rb_node);
985 if (h->ms.unfolded)
986 h->row_offset = h->nr_rows;
987 break;
988 }
989 first = false;
990 }
991 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300992 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300993 h = rb_entry(nd, struct hist_entry, rb_node);
994 h->row_offset = 0;
995 }
996}
997
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300998static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
999 struct callchain_node *chain_node,
1000 u64 total, int level,
1001 FILE *fp)
1002{
1003 struct rb_node *node;
1004 int offset = level * LEVEL_OFFSET_STEP;
1005 u64 new_total, remaining;
1006 int printed = 0;
1007
1008 if (callchain_param.mode == CHAIN_GRAPH_REL)
1009 new_total = chain_node->children_hit;
1010 else
1011 new_total = total;
1012
1013 remaining = new_total;
1014 node = rb_first(&chain_node->rb_root);
1015 while (node) {
1016 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1017 struct rb_node *next = rb_next(node);
1018 u64 cumul = callchain_cumul_hits(child);
1019 struct callchain_list *chain;
1020 char folded_sign = ' ';
1021 int first = true;
1022 int extra_offset = 0;
1023
1024 remaining -= cumul;
1025
1026 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001027 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001028 const char *str;
1029 bool was_first = first;
1030
1031 if (first)
1032 first = false;
1033 else
1034 extra_offset = LEVEL_OFFSET_STEP;
1035
1036 folded_sign = callchain_list__folded(chain);
1037
1038 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001039 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1040 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001041 if (was_first) {
1042 double percent = cumul * 100.0 / new_total;
1043
1044 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1045 str = "Not enough memory!";
1046 else
1047 str = alloc_str;
1048 }
1049
1050 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1051 free(alloc_str);
1052 if (folded_sign == '+')
1053 break;
1054 }
1055
1056 if (folded_sign == '-') {
1057 const int new_level = level + (extra_offset ? 2 : 1);
1058 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1059 new_level, fp);
1060 }
1061
1062 node = next;
1063 }
1064
1065 return printed;
1066}
1067
1068static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1069 struct callchain_node *node,
1070 int level, FILE *fp)
1071{
1072 struct callchain_list *chain;
1073 int offset = level * LEVEL_OFFSET_STEP;
1074 char folded_sign = ' ';
1075 int printed = 0;
1076
1077 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001078 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001079
1080 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001081 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001082 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1083 }
1084
1085 if (folded_sign == '-')
1086 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1087 browser->hists->stats.total_period,
1088 level + 1, fp);
1089 return printed;
1090}
1091
1092static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1093 struct rb_root *chain, int level, FILE *fp)
1094{
1095 struct rb_node *nd;
1096 int printed = 0;
1097
1098 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1099 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1100
1101 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1102 }
1103
1104 return printed;
1105}
1106
1107static int hist_browser__fprintf_entry(struct hist_browser *browser,
1108 struct hist_entry *he, FILE *fp)
1109{
1110 char s[8192];
1111 double percent;
1112 int printed = 0;
1113 char folded_sign = ' ';
1114
1115 if (symbol_conf.use_callchain)
1116 folded_sign = hist_entry__folded(he);
1117
Namhyung Kim000078b2012-08-20 13:52:06 +09001118 hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001119 percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001120
1121 if (symbol_conf.use_callchain)
1122 printed += fprintf(fp, "%c ", folded_sign);
1123
1124 printed += fprintf(fp, " %5.2f%%", percent);
1125
1126 if (symbol_conf.show_nr_samples)
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001127 printed += fprintf(fp, " %11u", he->stat.nr_events);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001128
1129 if (symbol_conf.show_total_period)
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001130 printed += fprintf(fp, " %12" PRIu64, he->stat.period);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001131
1132 printed += fprintf(fp, "%s\n", rtrim(s));
1133
1134 if (folded_sign == '-')
1135 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1136
1137 return printed;
1138}
1139
1140static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1141{
Namhyung Kim064f1982013-05-14 11:09:04 +09001142 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1143 browser->hists,
1144 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001145 int printed = 0;
1146
1147 while (nd) {
1148 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1149
1150 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim064f1982013-05-14 11:09:04 +09001151 nd = hists__filter_entries(rb_next(nd), browser->hists,
1152 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001153 }
1154
1155 return printed;
1156}
1157
1158static int hist_browser__dump(struct hist_browser *browser)
1159{
1160 char filename[64];
1161 FILE *fp;
1162
1163 while (1) {
1164 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1165 if (access(filename, F_OK))
1166 break;
1167 /*
1168 * XXX: Just an arbitrary lazy upper limit
1169 */
1170 if (++browser->print_seq == 8192) {
1171 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1172 return -1;
1173 }
1174 }
1175
1176 fp = fopen(filename, "w");
1177 if (fp == NULL) {
1178 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001179 const char *err = strerror_r(errno, bf, sizeof(bf));
1180 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001181 return -1;
1182 }
1183
1184 ++browser->print_seq;
1185 hist_browser__fprintf(browser, fp);
1186 fclose(fp);
1187 ui_helpline__fpush("%s written!", filename);
1188
1189 return 0;
1190}
1191
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001192static struct hist_browser *hist_browser__new(struct hists *hists)
1193{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001194 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001195
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001196 if (browser) {
1197 browser->hists = hists;
1198 browser->b.refresh = hist_browser__refresh;
1199 browser->b.seek = ui_browser__hists_seek;
1200 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201 }
1202
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001203 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204}
1205
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001206static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001208 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001209}
1210
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001211static struct hist_entry *hist_browser__selected_entry(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;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001214}
1215
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001216static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001217{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001218 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219}
1220
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001221static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001222 const char *ev_name)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001223{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001224 char unit;
1225 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001226 const struct dso *dso = hists->dso_filter;
1227 const struct thread *thread = hists->thread_filter;
1228 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1229 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001230 struct perf_evsel *evsel = hists_to_evsel(hists);
1231 char buf[512];
1232 size_t buflen = sizeof(buf);
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) {
1241 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1242 nr_events += pos->hists.stats.total_period;
1243 }
1244 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001245
Ashay Ranecc686282012-04-05 21:01:01 -05001246 nr_samples = convert_unit(nr_samples, &unit);
1247 printed = scnprintf(bf, size,
1248 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1249 nr_samples, unit, ev_name, nr_events);
1250
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001251
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001252 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001253 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001254 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001255 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001256 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001257 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001258 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001259 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001260 if (dso)
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 ", DSO: %s", dso->short_name);
1263 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001264}
1265
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001266static inline void free_popup_options(char **options, int n)
1267{
1268 int i;
1269
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001270 for (i = 0; i < n; ++i)
1271 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001272}
1273
Feng Tangc77d8d72012-11-01 00:00:55 +08001274/* Check whether the browser is for 'top' or 'report' */
1275static inline bool is_report_browser(void *timer)
1276{
1277 return timer == NULL;
1278}
1279
Feng Tang341487ab2013-02-03 14:38:20 +08001280/*
1281 * Only runtime switching of perf data file will make "input_name" point
1282 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1283 * whether we need to call free() for current "input_name" during the switch.
1284 */
1285static bool is_input_name_malloced = false;
1286
1287static int switch_data_file(void)
1288{
1289 char *pwd, *options[32], *abs_path[32], *tmp;
1290 DIR *pwd_dir;
1291 int nr_options = 0, choice = -1, ret = -1;
1292 struct dirent *dent;
1293
1294 pwd = getenv("PWD");
1295 if (!pwd)
1296 return ret;
1297
1298 pwd_dir = opendir(pwd);
1299 if (!pwd_dir)
1300 return ret;
1301
1302 memset(options, 0, sizeof(options));
1303 memset(options, 0, sizeof(abs_path));
1304
1305 while ((dent = readdir(pwd_dir))) {
1306 char path[PATH_MAX];
1307 u64 magic;
1308 char *name = dent->d_name;
1309 FILE *file;
1310
1311 if (!(dent->d_type == DT_REG))
1312 continue;
1313
1314 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1315
1316 file = fopen(path, "r");
1317 if (!file)
1318 continue;
1319
1320 if (fread(&magic, 1, 8, file) < 8)
1321 goto close_file_and_continue;
1322
1323 if (is_perf_magic(magic)) {
1324 options[nr_options] = strdup(name);
1325 if (!options[nr_options])
1326 goto close_file_and_continue;
1327
1328 abs_path[nr_options] = strdup(path);
1329 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001330 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001331 ui__warning("Can't search all data files due to memory shortage.\n");
1332 fclose(file);
1333 break;
1334 }
1335
1336 nr_options++;
1337 }
1338
1339close_file_and_continue:
1340 fclose(file);
1341 if (nr_options >= 32) {
1342 ui__warning("Too many perf data files in PWD!\n"
1343 "Only the first 32 files will be listed.\n");
1344 break;
1345 }
1346 }
1347 closedir(pwd_dir);
1348
1349 if (nr_options) {
1350 choice = ui__popup_menu(nr_options, options);
1351 if (choice < nr_options && choice >= 0) {
1352 tmp = strdup(abs_path[choice]);
1353 if (tmp) {
1354 if (is_input_name_malloced)
1355 free((void *)input_name);
1356 input_name = tmp;
1357 is_input_name_malloced = true;
1358 ret = 0;
1359 } else
1360 ui__warning("Data switch failed due to memory shortage!\n");
1361 }
1362 }
1363
1364 free_popup_options(options, nr_options);
1365 free_popup_options(abs_path, nr_options);
1366 return ret;
1367}
1368
Namhyung Kim064f1982013-05-14 11:09:04 +09001369static void hist_browser__update_pcnt_entries(struct hist_browser *hb)
1370{
1371 u64 nr_entries = 0;
1372 struct rb_node *nd = rb_first(&hb->hists->entries);
1373
1374 while (nd) {
1375 nr_entries++;
1376 nd = hists__filter_entries(rb_next(nd), hb->hists,
1377 hb->min_pcnt);
1378 }
1379
1380 hb->nr_pcnt_entries = nr_entries;
1381}
Feng Tang341487ab2013-02-03 14:38:20 +08001382
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001383static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001384 const char *helpline, const char *ev_name,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001385 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001386 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001387 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001388 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001389{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001390 struct hists *hists = &evsel->hists;
1391 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001392 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001393 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001394 char *options[16];
1395 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001396 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001397 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001398 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001399 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001400
Namhyung Kime8e684a2013-12-26 14:37:58 +09001401#define HIST_BROWSER_HELP_COMMON \
1402 "h/?/F1 Show this window\n" \
1403 "UP/DOWN/PGUP\n" \
1404 "PGDN/SPACE Navigate\n" \
1405 "q/ESC/CTRL+C Exit browser\n\n" \
1406 "For multiple event sessions:\n\n" \
1407 "TAB/UNTAB Switch events\n\n" \
1408 "For symbolic views (--sort has sym):\n\n" \
1409 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1410 "<- Zoom out\n" \
1411 "a Annotate current symbol\n" \
1412 "C Collapse all callchains\n" \
1413 "d Zoom into current DSO\n" \
1414 "E Expand all callchains\n" \
1415
1416 /* help messages are sorted by lexical order of the hotkey */
1417 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001418 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001419 "P Print histograms to perf.hist.N\n"
1420 "r Run available scripts\n"
1421 "s Switch to another data file in PWD\n"
1422 "t Zoom into current Thread\n"
1423 "V Verbose (DSO names in callchains, etc)\n"
1424 "/ Filter symbol by name";
1425 const char top_help[] = HIST_BROWSER_HELP_COMMON
1426 "P Print histograms to perf.hist.N\n"
1427 "t Zoom into current Thread\n"
1428 "V Verbose (DSO names in callchains, etc)\n"
1429 "/ Filter symbol by name";
1430
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001431 if (browser == NULL)
1432 return -1;
1433
Namhyung Kim064f1982013-05-14 11:09:04 +09001434 if (min_pcnt) {
1435 browser->min_pcnt = min_pcnt;
1436 hist_browser__update_pcnt_entries(browser);
1437 }
1438
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001439 fstack = pstack__new(2);
1440 if (fstack == NULL)
1441 goto out;
1442
1443 ui_helpline__push(helpline);
1444
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001445 memset(options, 0, sizeof(options));
1446
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001447 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001448 const struct thread *thread = NULL;
1449 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001450 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001451 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001452 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001453 int scripts_comm = -2, scripts_symbol = -2,
1454 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001455
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001456 nr_options = 0;
1457
Namhyung Kim9783adf2012-11-02 14:50:05 +09001458 key = hist_browser__run(browser, ev_name, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001459
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001460 if (browser->he_selection != NULL) {
1461 thread = hist_browser__selected_thread(browser);
1462 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1463 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001464 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001465 case K_TAB:
1466 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001467 if (nr_events == 1)
1468 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001469 /*
1470 * Exit the browser, let hists__browser_tree
1471 * go to the next or previous
1472 */
1473 goto out_free_stack;
1474 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001475 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001476 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001477 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001478 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001479 continue;
1480 }
1481
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001482 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001483 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001484 browser->selection->map->dso->annotate_warned)
1485 continue;
1486 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001487 case 'P':
1488 hist_browser__dump(browser);
1489 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001490 case 'd':
1491 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001492 case 'V':
1493 browser->show_dso = !browser->show_dso;
1494 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001495 case 't':
1496 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001497 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001498 if (ui_browser__input_window("Symbol to show",
1499 "Please enter the name of symbol you want to see",
1500 buf, "ENTER: OK, ESC: Cancel",
1501 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001502 hists->symbol_filter_str = *buf ? buf : NULL;
1503 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001504 hist_browser__reset(browser);
1505 }
1506 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001507 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001508 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001509 goto do_scripts;
1510 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001511 case 's':
1512 if (is_report_browser(hbt))
1513 goto do_data_switch;
1514 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001515 case 'i':
1516 /* env->arch is NULL for live-mode (i.e. perf top) */
1517 if (env->arch)
1518 tui__header_window(env);
1519 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001520 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001521 case 'h':
1522 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001523 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001524 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001525 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001526 case K_ENTER:
1527 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001528 /* menu */
1529 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001530 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001531 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001532
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001533 if (pstack__empty(fstack)) {
1534 /*
1535 * Go back to the perf_evsel_menu__run or other user
1536 */
1537 if (left_exits)
1538 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001539 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001540 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001541 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001542 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001543 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001544 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001545 goto zoom_out_thread;
1546 continue;
1547 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001548 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001549 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001550 !ui_browser__dialog_yesno(&browser->b,
1551 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001552 continue;
1553 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001554 case 'q':
1555 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001556 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001557 default:
1558 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001559 }
1560
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001561 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001562 goto add_exit_option;
1563
Namhyung Kim55369fc2013-04-01 20:35:20 +09001564 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001565 bi = browser->he_selection->branch_info;
1566 if (browser->selection != NULL &&
1567 bi &&
1568 bi->from.sym != NULL &&
1569 !bi->from.map->dso->annotate_warned &&
1570 asprintf(&options[nr_options], "Annotate %s",
1571 bi->from.sym->name) > 0)
1572 annotate_f = nr_options++;
1573
1574 if (browser->selection != NULL &&
1575 bi &&
1576 bi->to.sym != NULL &&
1577 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001578 (bi->to.sym != bi->from.sym ||
1579 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001580 asprintf(&options[nr_options], "Annotate %s",
1581 bi->to.sym->name) > 0)
1582 annotate_t = nr_options++;
1583 } else {
1584
1585 if (browser->selection != NULL &&
1586 browser->selection->sym != NULL &&
1587 !browser->selection->map->dso->annotate_warned &&
1588 asprintf(&options[nr_options], "Annotate %s",
1589 browser->selection->sym->name) > 0)
1590 annotate = nr_options++;
1591 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001592
1593 if (thread != NULL &&
1594 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001595 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001596 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001597 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001598 zoom_thread = nr_options++;
1599
1600 if (dso != NULL &&
1601 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001602 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001603 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1604 zoom_dso = nr_options++;
1605
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001606 if (browser->selection != NULL &&
1607 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001608 asprintf(&options[nr_options], "Browse map details") > 0)
1609 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001610
1611 /* perf script support */
1612 if (browser->he_selection) {
1613 struct symbol *sym;
1614
1615 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001616 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001617 scripts_comm = nr_options++;
1618
1619 sym = browser->he_selection->ms.sym;
1620 if (sym && sym->namelen &&
1621 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1622 sym->name) > 0)
1623 scripts_symbol = nr_options++;
1624 }
1625
1626 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1627 scripts_all = nr_options++;
1628
Feng Tang341487ab2013-02-03 14:38:20 +08001629 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1630 "Switch to another data file in PWD") > 0)
1631 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001632add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001633 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001634retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001635 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001636
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001637 if (choice == nr_options - 1)
1638 break;
1639
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001640 if (choice == -1) {
1641 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001642 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001643 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001644
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001645 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001646 struct hist_entry *he;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001647 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001648do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001649 if (!objdump_path && perf_session_env__lookup_objdump(env))
1650 continue;
1651
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001652 he = hist_browser__selected_entry(browser);
1653 if (he == NULL)
1654 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001655
1656 /*
1657 * we stash the branch_info symbol + map into the
1658 * the ms so we don't have to rewrite all the annotation
1659 * code to use branch_info.
1660 * in branch mode, the ms struct is not used
1661 */
1662 if (choice == annotate_f) {
1663 he->ms.sym = he->branch_info->from.sym;
1664 he->ms.map = he->branch_info->from.map;
1665 } else if (choice == annotate_t) {
1666 he->ms.sym = he->branch_info->to.sym;
1667 he->ms.map = he->branch_info->to.map;
1668 }
1669
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001670 /*
1671 * Don't let this be freed, say, by hists__decay_entry.
1672 */
1673 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001674 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001675 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001676 /*
1677 * offer option to annotate the other branch source or target
1678 * (if they exists) when returning from annotate
1679 */
1680 if ((err == 'q' || err == CTRL('c'))
1681 && annotate_t != -2 && annotate_f != -2)
1682 goto retry_popup_menu;
1683
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001684 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001685 if (err)
1686 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001687
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001688 } else if (choice == browse_map)
1689 map__browse(browser->selection->map);
1690 else if (choice == zoom_dso) {
1691zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001692 if (browser->hists->dso_filter) {
1693 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001694zoom_out_dso:
1695 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001696 browser->hists->dso_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001697 sort_dso.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001698 } else {
1699 if (dso == NULL)
1700 continue;
1701 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1702 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001703 browser->hists->dso_filter = dso;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001704 sort_dso.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001705 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001706 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001707 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001708 hist_browser__reset(browser);
1709 } else if (choice == zoom_thread) {
1710zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001711 if (browser->hists->thread_filter) {
1712 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001713zoom_out_thread:
1714 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001715 browser->hists->thread_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001716 sort_thread.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001717 } else {
1718 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001719 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001720 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001721 browser->hists->thread_filter = thread;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001722 sort_thread.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001723 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001724 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001725 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001726 hist_browser__reset(browser);
1727 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001728 /* perf scripts support */
1729 else if (choice == scripts_all || choice == scripts_comm ||
1730 choice == scripts_symbol) {
1731do_scripts:
1732 memset(script_opt, 0, 64);
1733
1734 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001735 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001736
1737 if (choice == scripts_symbol)
1738 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1739
1740 script_browse(script_opt);
1741 }
Feng Tang341487ab2013-02-03 14:38:20 +08001742 /* Switch to another data file */
1743 else if (choice == switch_data) {
1744do_data_switch:
1745 if (!switch_data_file()) {
1746 key = K_SWITCH_INPUT_DATA;
1747 break;
1748 } else
1749 ui__warning("Won't switch the data files due to\n"
1750 "no valid data file get selected!\n");
1751 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001752 }
1753out_free_stack:
1754 pstack__delete(fstack);
1755out:
1756 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001757 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758 return key;
1759}
1760
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001761struct perf_evsel_menu {
1762 struct ui_browser b;
1763 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001764 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001765 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001766 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001767};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001768
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001769static void perf_evsel_menu__write(struct ui_browser *browser,
1770 void *entry, int row)
1771{
1772 struct perf_evsel_menu *menu = container_of(browser,
1773 struct perf_evsel_menu, b);
1774 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1775 bool current_entry = ui_browser__is_current_entry(browser, row);
1776 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001777 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001778 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001779 const char *warn = " ";
1780 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001781
1782 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1783 HE_COLORSET_NORMAL);
1784
Namhyung Kim759ff492013-03-05 14:53:26 +09001785 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001786 struct perf_evsel *pos;
1787
1788 ev_name = perf_evsel__group_name(evsel);
1789
1790 for_each_group_member(pos, evsel) {
1791 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1792 }
1793 }
1794
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001795 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001796 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001797 unit, unit == ' ' ? "" : " ", ev_name);
1798 slsmg_printf("%s", bf);
1799
1800 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1801 if (nr_events != 0) {
1802 menu->lost_events = true;
1803 if (!current_entry)
1804 ui_browser__set_color(browser, HE_COLORSET_TOP);
1805 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001806 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1807 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001808 warn = bf;
1809 }
1810
1811 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001812
1813 if (current_entry)
1814 menu->selection = evsel;
1815}
1816
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001817static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1818 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001819 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001820{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001821 struct perf_evlist *evlist = menu->b.priv;
1822 struct perf_evsel *pos;
1823 const char *ev_name, *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001824 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001825 int key;
1826
1827 if (ui_browser__show(&menu->b, title,
1828 "ESC: exit, ENTER|->: Browse histograms") < 0)
1829 return -1;
1830
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001831 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001832 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001833
1834 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001835 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001836 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001837
1838 if (!menu->lost_events_warned && menu->lost_events) {
1839 ui_browser__warn_lost_events(&menu->b);
1840 menu->lost_events_warned = true;
1841 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001842 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001843 case K_RIGHT:
1844 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001845 if (!menu->selection)
1846 continue;
1847 pos = menu->selection;
1848browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001849 perf_evlist__set_selected(evlist, pos);
1850 /*
1851 * Give the calling tool a chance to populate the non
1852 * default evsel resorted hists tree.
1853 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001854 if (hbt)
1855 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001856 ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001857 key = perf_evsel__hists_browse(pos, nr_events, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001858 ev_name, true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001859 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001860 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001861 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001862 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001863 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001864 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001865 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001866 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001867 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001868 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001869 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001870 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001871 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001872 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001873 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001874 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001875 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001876 if (!ui_browser__dialog_yesno(&menu->b,
1877 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001878 continue;
1879 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001880 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001881 case 'q':
1882 case CTRL('c'):
1883 goto out;
1884 default:
1885 continue;
1886 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001887 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001888 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001889 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001890 if (!ui_browser__dialog_yesno(&menu->b,
1891 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001892 continue;
1893 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001894 case 'q':
1895 case CTRL('c'):
1896 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001897 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001898 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001899 }
1900 }
1901
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001902out:
1903 ui_browser__hide(&menu->b);
1904 return key;
1905}
1906
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001907static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001908 void *entry)
1909{
1910 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1911
1912 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1913 return true;
1914
1915 return false;
1916}
1917
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001918static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001919 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001920 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001921 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001922 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001923{
1924 struct perf_evsel *pos;
1925 struct perf_evsel_menu menu = {
1926 .b = {
1927 .entries = &evlist->entries,
1928 .refresh = ui_browser__list_head_refresh,
1929 .seek = ui_browser__list_head_seek,
1930 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001931 .filter = filter_group_entries,
1932 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001933 .priv = evlist,
1934 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001935 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001936 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001937 };
1938
1939 ui_helpline__push("Press ESC to exit");
1940
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001941 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001942 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001943 size_t line_len = strlen(ev_name) + 7;
1944
1945 if (menu.b.width < line_len)
1946 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001947 }
1948
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001949 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001950}
1951
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001952int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001953 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001954 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001955 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001956{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001957 int nr_entries = evlist->nr_entries;
1958
1959single_entry:
1960 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001961 struct perf_evsel *first = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001962 const char *ev_name = perf_evsel__name(first);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001963
1964 return perf_evsel__hists_browse(first, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001965 ev_name, false, hbt, min_pcnt,
1966 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001967 }
1968
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001969 if (symbol_conf.event_group) {
1970 struct perf_evsel *pos;
1971
1972 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001973 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001974 if (perf_evsel__is_group_leader(pos))
1975 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001976 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001977
1978 if (nr_entries == 1)
1979 goto single_entry;
1980 }
1981
1982 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001983 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001984}