blob: a4268cab1921aed7a31920b5beffcc4808b983ab [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;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030028};
29
Namhyung Kimf5951d52012-09-03 11:53:09 +090030extern void hist_browser__init_hpp(void);
31
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030032static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -020033 const char *ev_name);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030034
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030035static void hist_browser__refresh_dimensions(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030036{
37 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030038 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030039 sizeof("[k]"));
40}
41
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030042static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030043{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030044 browser->b.nr_entries = browser->hists->nr_entries;
45 hist_browser__refresh_dimensions(browser);
46 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030047}
48
49static char tree__folded_sign(bool unfolded)
50{
51 return unfolded ? '-' : '+';
52}
53
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030054static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030055{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030056 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030057}
58
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030059static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030060{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030061 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030062}
63
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030064static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030065{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030066 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030067}
68
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030069static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -030070{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030071 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -030072}
73
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030074static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030075{
76 int n = 0;
77 struct rb_node *nd;
78
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030079 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030080 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
81 struct callchain_list *chain;
82 char folded_sign = ' '; /* No children */
83
84 list_for_each_entry(chain, &child->val, list) {
85 ++n;
86 /* We need this because we may not have children */
87 folded_sign = callchain_list__folded(chain);
88 if (folded_sign == '+')
89 break;
90 }
91
92 if (folded_sign == '-') /* Have children and they're unfolded */
93 n += callchain_node__count_rows_rb_tree(child);
94 }
95
96 return n;
97}
98
99static int callchain_node__count_rows(struct callchain_node *node)
100{
101 struct callchain_list *chain;
102 bool unfolded = false;
103 int n = 0;
104
105 list_for_each_entry(chain, &node->val, list) {
106 ++n;
107 unfolded = chain->ms.unfolded;
108 }
109
110 if (unfolded)
111 n += callchain_node__count_rows_rb_tree(node);
112
113 return n;
114}
115
116static int callchain__count_rows(struct rb_root *chain)
117{
118 struct rb_node *nd;
119 int n = 0;
120
121 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
122 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
123 n += callchain_node__count_rows(node);
124 }
125
126 return n;
127}
128
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300129static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300130{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300131 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200132 return false;
133
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300134 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300135 return false;
136
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300138 return true;
139}
140
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300141static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300142{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300143 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300145 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300146 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
147 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300148 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300149
150 list_for_each_entry(chain, &child->val, list) {
151 if (first) {
152 first = false;
153 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300154 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300155 } else
156 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300157 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300158 }
159
160 callchain_node__init_have_children_rb_tree(child);
161 }
162}
163
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300164static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300165{
166 struct callchain_list *chain;
167
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300168 list_for_each_entry(chain, &node->val, list)
169 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300170
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300171 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300172}
173
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300174static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300175{
176 struct rb_node *nd;
177
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300178 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300179 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
180 callchain_node__init_have_children(node);
181 }
182}
183
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300184static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300185{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300186 if (!he->init_have_children) {
187 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
188 callchain__init_have_children(&he->sorted_chain);
189 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300190 }
191}
192
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300193static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300194{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300195 if (map_symbol__toggle_fold(browser->selection)) {
196 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300197
198 hist_entry__init_have_children(he);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300199 browser->hists->nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300200
201 if (he->ms.unfolded)
202 he->nr_rows = callchain__count_rows(&he->sorted_chain);
203 else
204 he->nr_rows = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300205 browser->hists->nr_entries += he->nr_rows;
206 browser->b.nr_entries = browser->hists->nr_entries;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300207
208 return true;
209 }
210
211 /* If it doesn't have children, no toggling performed */
212 return false;
213}
214
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300215static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300216{
217 int n = 0;
218 struct rb_node *nd;
219
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300220 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300221 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
222 struct callchain_list *chain;
223 bool has_children = false;
224
225 list_for_each_entry(chain, &child->val, list) {
226 ++n;
227 map_symbol__set_folding(&chain->ms, unfold);
228 has_children = chain->ms.has_children;
229 }
230
231 if (has_children)
232 n += callchain_node__set_folding_rb_tree(child, unfold);
233 }
234
235 return n;
236}
237
238static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
239{
240 struct callchain_list *chain;
241 bool has_children = false;
242 int n = 0;
243
244 list_for_each_entry(chain, &node->val, list) {
245 ++n;
246 map_symbol__set_folding(&chain->ms, unfold);
247 has_children = chain->ms.has_children;
248 }
249
250 if (has_children)
251 n += callchain_node__set_folding_rb_tree(node, unfold);
252
253 return n;
254}
255
256static int callchain__set_folding(struct rb_root *chain, bool unfold)
257{
258 struct rb_node *nd;
259 int n = 0;
260
261 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
262 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
263 n += callchain_node__set_folding(node, unfold);
264 }
265
266 return n;
267}
268
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300269static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300270{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300271 hist_entry__init_have_children(he);
272 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300273
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300274 if (he->ms.has_children) {
275 int n = callchain__set_folding(&he->sorted_chain, unfold);
276 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300277 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300278 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300279}
280
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300281static void hists__set_folding(struct hists *hists, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300282{
283 struct rb_node *nd;
284
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300285 hists->nr_entries = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300286
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300287 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300288 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
289 hist_entry__set_folding(he, unfold);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300290 hists->nr_entries += 1 + he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300291 }
292}
293
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300294static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300295{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300296 hists__set_folding(browser->hists, unfold);
297 browser->b.nr_entries = browser->hists->nr_entries;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300298 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300299 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300300}
301
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200302static void ui_browser__warn_lost_events(struct ui_browser *browser)
303{
304 ui_browser__warning(browser, 4,
305 "Events are being lost, check IO/CPU overload!\n\n"
306 "You may want to run 'perf' using a RT scheduler policy:\n\n"
307 " perf top -r 80\n\n"
308 "Or reduce the sampling frequency.");
309}
310
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300311static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900312 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300313{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300314 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300315 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900316 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300317
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300318 browser->b.entries = &browser->hists->entries;
319 browser->b.nr_entries = browser->hists->nr_entries;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300320
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300321 hist_browser__refresh_dimensions(browser);
322 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300323
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300324 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300325 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300326 return -1;
327
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300328 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300329 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300330
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300331 switch (key) {
Arnaldo Carvalho de Melo13d8f962011-10-26 08:05:34 -0200332 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +0900333 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300334 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200335
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300336 if (browser->hists->stats.nr_lost_warned !=
337 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
338 browser->hists->stats.nr_lost_warned =
339 browser->hists->stats.nr_events[PERF_RECORD_LOST];
340 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200341 }
342
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300343 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
344 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300345 continue;
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300346 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300347 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300348 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300349 struct hist_entry, rb_node);
350 ui_helpline__pop();
351 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 -0300352 seq++, browser->b.nr_entries,
353 browser->hists->nr_entries,
354 browser->b.height,
355 browser->b.index,
356 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300357 h->row_offset, h->nr_rows);
358 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300359 break;
360 case 'C':
361 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300362 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300363 break;
364 case 'E':
365 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300367 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200368 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300369 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300370 break;
371 /* fall thru */
372 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300373 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300374 }
375 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300376out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300377 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300378 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300379}
380
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300381static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300382 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300383{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300384 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300386 if (cl->ms.sym)
387 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
388 else
389 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
390
391 if (show_dso)
392 scnprintf(bf + printed, bfsize - printed, " %s",
393 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
394
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300395 return bf;
396}
397
398#define LEVEL_OFFSET_STEP 3
399
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300400static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401 struct callchain_node *chain_node,
402 u64 total, int level,
403 unsigned short row,
404 off_t *row_offset,
405 bool *is_current_entry)
406{
407 struct rb_node *node;
408 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
409 u64 new_total, remaining;
410
411 if (callchain_param.mode == CHAIN_GRAPH_REL)
412 new_total = chain_node->children_hit;
413 else
414 new_total = total;
415
416 remaining = new_total;
417 node = rb_first(&chain_node->rb_root);
418 while (node) {
419 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
420 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100421 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300422 struct callchain_list *chain;
423 char folded_sign = ' ';
424 int first = true;
425 int extra_offset = 0;
426
427 remaining -= cumul;
428
429 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300430 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300431 const char *str;
432 int color;
433 bool was_first = first;
434
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300435 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300436 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300437 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300438 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300439
440 folded_sign = callchain_list__folded(chain);
441 if (*row_offset != 0) {
442 --*row_offset;
443 goto do_next;
444 }
445
446 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300447 str = callchain_list__sym_name(chain, bf, sizeof(bf),
448 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300449 if (was_first) {
450 double percent = cumul * 100.0 / new_total;
451
452 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
453 str = "Not enough memory!";
454 else
455 str = alloc_str;
456 }
457
458 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300459 width = browser->b.width - (offset + extra_offset + 2);
460 if (ui_browser__is_current_entry(&browser->b, row)) {
461 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300462 color = HE_COLORSET_SELECTED;
463 *is_current_entry = true;
464 }
465
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300466 ui_browser__set_color(&browser->b, color);
467 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300468 slsmg_write_nstring(" ", offset + extra_offset);
469 slsmg_printf("%c ", folded_sign);
470 slsmg_write_nstring(str, width);
471 free(alloc_str);
472
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300473 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300474 goto out;
475do_next:
476 if (folded_sign == '+')
477 break;
478 }
479
480 if (folded_sign == '-') {
481 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300482 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300483 new_level, row, row_offset,
484 is_current_entry);
485 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300486 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300487 goto out;
488 node = next;
489 }
490out:
491 return row - first_row;
492}
493
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300494static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300495 struct callchain_node *node,
496 int level, unsigned short row,
497 off_t *row_offset,
498 bool *is_current_entry)
499{
500 struct callchain_list *chain;
501 int first_row = row,
502 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300503 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300504 char folded_sign = ' ';
505
506 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300507 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300508 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300509
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300510 folded_sign = callchain_list__folded(chain);
511
512 if (*row_offset != 0) {
513 --*row_offset;
514 continue;
515 }
516
517 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518 if (ui_browser__is_current_entry(&browser->b, row)) {
519 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300520 color = HE_COLORSET_SELECTED;
521 *is_current_entry = true;
522 }
523
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300524 s = callchain_list__sym_name(chain, bf, sizeof(bf),
525 browser->show_dso);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300526 ui_browser__gotorc(&browser->b, row, 0);
527 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300528 slsmg_write_nstring(" ", offset);
529 slsmg_printf("%c ", folded_sign);
530 slsmg_write_nstring(s, width - 2);
531
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300532 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300533 goto out;
534 }
535
536 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300537 row += hist_browser__show_callchain_node_rb_tree(browser, node,
538 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300539 level + 1, row,
540 row_offset,
541 is_current_entry);
542out:
543 return row - first_row;
544}
545
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300546static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300547 struct rb_root *chain,
548 int level, unsigned short row,
549 off_t *row_offset,
550 bool *is_current_entry)
551{
552 struct rb_node *nd;
553 int first_row = row;
554
555 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
556 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
557
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300558 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300559 row, row_offset,
560 is_current_entry);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300561 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300562 break;
563 }
564
565 return row - first_row;
566}
567
Namhyung Kim89701462013-01-22 18:09:38 +0900568struct hpp_arg {
569 struct ui_browser *b;
570 char folded_sign;
571 bool current_entry;
572};
573
574static int __hpp__color_callchain(struct hpp_arg *arg)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900575{
Namhyung Kim89701462013-01-22 18:09:38 +0900576 if (!symbol_conf.use_callchain)
577 return 0;
578
579 slsmg_printf("%c ", arg->folded_sign);
580 return 2;
581}
582
583static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
584 u64 (*get_field)(struct hist_entry *),
585 int (*callchain_cb)(struct hpp_arg *))
586{
587 int ret = 0;
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900588 double percent = 0.0;
589 struct hists *hists = he->hists;
Namhyung Kim89701462013-01-22 18:09:38 +0900590 struct hpp_arg *arg = hpp->ptr;
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900591
592 if (hists->stats.total_period)
593 percent = 100.0 * get_field(he) / hists->stats.total_period;
594
Namhyung Kim89701462013-01-22 18:09:38 +0900595 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900596
Namhyung Kim89701462013-01-22 18:09:38 +0900597 if (callchain_cb)
598 ret += callchain_cb(arg);
599
600 ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
601 slsmg_printf("%s", hpp->buf);
602
Namhyung Kim371d8c42013-01-22 18:09:39 +0900603 if (symbol_conf.event_group) {
604 int prev_idx, idx_delta;
605 struct perf_evsel *evsel = hists_to_evsel(hists);
606 struct hist_entry *pair;
607 int nr_members = evsel->nr_members;
608
609 if (nr_members <= 1)
610 goto out;
611
612 prev_idx = perf_evsel__group_idx(evsel);
613
614 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
615 u64 period = get_field(pair);
616 u64 total = pair->hists->stats.total_period;
617
618 if (!total)
619 continue;
620
621 evsel = hists_to_evsel(pair->hists);
622 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
623
624 while (idx_delta--) {
625 /*
626 * zero-fill group members in the middle which
627 * have no sample
628 */
629 ui_browser__set_percent_color(arg->b, 0.0,
630 arg->current_entry);
631 ret += scnprintf(hpp->buf, hpp->size,
632 " %6.2f%%", 0.0);
633 slsmg_printf("%s", hpp->buf);
634 }
635
636 percent = 100.0 * period / total;
637 ui_browser__set_percent_color(arg->b, percent,
638 arg->current_entry);
639 ret += scnprintf(hpp->buf, hpp->size,
640 " %6.2f%%", percent);
641 slsmg_printf("%s", hpp->buf);
642
643 prev_idx = perf_evsel__group_idx(evsel);
644 }
645
646 idx_delta = nr_members - prev_idx - 1;
647
648 while (idx_delta--) {
649 /*
650 * zero-fill group members at last which have no sample
651 */
652 ui_browser__set_percent_color(arg->b, 0.0,
653 arg->current_entry);
654 ret += scnprintf(hpp->buf, hpp->size,
655 " %6.2f%%", 0.0);
656 slsmg_printf("%s", hpp->buf);
657 }
658 }
659out:
Namhyung Kim89701462013-01-22 18:09:38 +0900660 if (!arg->current_entry || !arg->b->navkeypressed)
661 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
662
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900663 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900664}
665
Namhyung Kim89701462013-01-22 18:09:38 +0900666#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900667static u64 __hpp_get_##_field(struct hist_entry *he) \
668{ \
669 return he->stat._field; \
670} \
671 \
672static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \
673 struct hist_entry *he) \
674{ \
Namhyung Kim89701462013-01-22 18:09:38 +0900675 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900676}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900677
Namhyung Kim89701462013-01-22 18:09:38 +0900678__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
679__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
680__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
681__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
682__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900683
684#undef __HPP_COLOR_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900685
686void hist_browser__init_hpp(void)
687{
Jiri Olsa12400052012-10-13 00:06:16 +0200688 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
689
Jiri Olsa1d778222012-10-04 21:49:39 +0900690 perf_hpp__init();
Namhyung Kimf5951d52012-09-03 11:53:09 +0900691
692 perf_hpp__format[PERF_HPP__OVERHEAD].color =
693 hist_browser__hpp_color_overhead;
694 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
695 hist_browser__hpp_color_overhead_sys;
696 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
697 hist_browser__hpp_color_overhead_us;
698 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
699 hist_browser__hpp_color_overhead_guest_sys;
700 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
701 hist_browser__hpp_color_overhead_guest_us;
702}
703
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300704static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300705 struct hist_entry *entry,
706 unsigned short row)
707{
708 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200709 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900710 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300711 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300712 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300713 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300714 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200715 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300716
717 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300718 browser->he_selection = entry;
719 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300720 }
721
722 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300723 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300724 folded_sign = hist_entry__folded(entry);
725 }
726
727 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900728 struct hpp_arg arg = {
729 .b = &browser->b,
730 .folded_sign = folded_sign,
731 .current_entry = current_entry,
732 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900733 struct perf_hpp hpp = {
734 .buf = s,
735 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900736 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900737 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300738
Namhyung Kim67d25912012-09-12 15:35:06 +0900739 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900740
Jiri Olsa12400052012-10-13 00:06:16 +0200741 perf_hpp__for_each_format(fmt) {
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300742 if (!first) {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900743 slsmg_printf(" ");
744 width -= 2;
745 }
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300746 first = false;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900747
Jiri Olsa12400052012-10-13 00:06:16 +0200748 if (fmt->color) {
Jiri Olsa12400052012-10-13 00:06:16 +0200749 width -= fmt->color(&hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900750 } else {
Jiri Olsa12400052012-10-13 00:06:16 +0200751 width -= fmt->entry(&hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900752 slsmg_printf("%s", s);
753 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300754 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200755
756 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300757 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200758 width += 1;
759
Namhyung Kimf5951d52012-09-03 11:53:09 +0900760 hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300761 slsmg_write_nstring(s, width);
762 ++row;
763 ++printed;
764 } else
765 --row_offset;
766
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300767 if (folded_sign == '-' && row != browser->b.height) {
768 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300769 1, row, &row_offset,
770 &current_entry);
771 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300772 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300773 }
774
775 return printed;
776}
777
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300778static void ui_browser__hists_init_top(struct ui_browser *browser)
779{
780 if (browser->top == NULL) {
781 struct hist_browser *hb;
782
783 hb = container_of(browser, struct hist_browser, b);
784 browser->top = rb_first(&hb->hists->entries);
785 }
786}
787
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300788static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300789{
790 unsigned row = 0;
791 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300792 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300793
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300794 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300795
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300796 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300797 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
798
799 if (h->filtered)
800 continue;
801
802 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300803 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300804 break;
805 }
806
807 return row;
808}
809
810static struct rb_node *hists__filter_entries(struct rb_node *nd)
811{
812 while (nd != NULL) {
813 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
814 if (!h->filtered)
815 return nd;
816
817 nd = rb_next(nd);
818 }
819
820 return NULL;
821}
822
823static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
824{
825 while (nd != NULL) {
826 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
827 if (!h->filtered)
828 return nd;
829
830 nd = rb_prev(nd);
831 }
832
833 return NULL;
834}
835
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300836static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300837 off_t offset, int whence)
838{
839 struct hist_entry *h;
840 struct rb_node *nd;
841 bool first = true;
842
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300843 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300844 return;
845
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300846 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300847
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300848 switch (whence) {
849 case SEEK_SET:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300850 nd = hists__filter_entries(rb_first(browser->entries));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300851 break;
852 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300853 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300854 goto do_offset;
855 case SEEK_END:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300856 nd = hists__filter_prev_entries(rb_last(browser->entries));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300857 first = false;
858 break;
859 default:
860 return;
861 }
862
863 /*
864 * Moves not relative to the first visible entry invalidates its
865 * row_offset:
866 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300867 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300868 h->row_offset = 0;
869
870 /*
871 * Here we have to check if nd is expanded (+), if it is we can't go
872 * the next top level hist_entry, instead we must compute an offset of
873 * what _not_ to show and not change the first visible entry.
874 *
875 * This offset increments when we are going from top to bottom and
876 * decreases when we're going from bottom to top.
877 *
878 * As we don't have backpointers to the top level in the callchains
879 * structure, we need to always print the whole hist_entry callchain,
880 * skipping the first ones that are before the first visible entry
881 * and stop when we printed enough lines to fill the screen.
882 */
883do_offset:
884 if (offset > 0) {
885 do {
886 h = rb_entry(nd, struct hist_entry, rb_node);
887 if (h->ms.unfolded) {
888 u16 remaining = h->nr_rows - h->row_offset;
889 if (offset > remaining) {
890 offset -= remaining;
891 h->row_offset = 0;
892 } else {
893 h->row_offset += offset;
894 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300895 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300896 break;
897 }
898 }
899 nd = hists__filter_entries(rb_next(nd));
900 if (nd == NULL)
901 break;
902 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300903 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904 } while (offset != 0);
905 } else if (offset < 0) {
906 while (1) {
907 h = rb_entry(nd, struct hist_entry, rb_node);
908 if (h->ms.unfolded) {
909 if (first) {
910 if (-offset > h->row_offset) {
911 offset += h->row_offset;
912 h->row_offset = 0;
913 } else {
914 h->row_offset += offset;
915 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300916 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300917 break;
918 }
919 } else {
920 if (-offset > h->nr_rows) {
921 offset += h->nr_rows;
922 h->row_offset = 0;
923 } else {
924 h->row_offset = h->nr_rows + offset;
925 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300926 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300927 break;
928 }
929 }
930 }
931
932 nd = hists__filter_prev_entries(rb_prev(nd));
933 if (nd == NULL)
934 break;
935 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300936 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300937 if (offset == 0) {
938 /*
939 * Last unfiltered hist_entry, check if it is
940 * unfolded, if it is then we should have
941 * row_offset at its last entry.
942 */
943 h = rb_entry(nd, struct hist_entry, rb_node);
944 if (h->ms.unfolded)
945 h->row_offset = h->nr_rows;
946 break;
947 }
948 first = false;
949 }
950 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300951 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300952 h = rb_entry(nd, struct hist_entry, rb_node);
953 h->row_offset = 0;
954 }
955}
956
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300957static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
958 struct callchain_node *chain_node,
959 u64 total, int level,
960 FILE *fp)
961{
962 struct rb_node *node;
963 int offset = level * LEVEL_OFFSET_STEP;
964 u64 new_total, remaining;
965 int printed = 0;
966
967 if (callchain_param.mode == CHAIN_GRAPH_REL)
968 new_total = chain_node->children_hit;
969 else
970 new_total = total;
971
972 remaining = new_total;
973 node = rb_first(&chain_node->rb_root);
974 while (node) {
975 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
976 struct rb_node *next = rb_next(node);
977 u64 cumul = callchain_cumul_hits(child);
978 struct callchain_list *chain;
979 char folded_sign = ' ';
980 int first = true;
981 int extra_offset = 0;
982
983 remaining -= cumul;
984
985 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300986 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300987 const char *str;
988 bool was_first = first;
989
990 if (first)
991 first = false;
992 else
993 extra_offset = LEVEL_OFFSET_STEP;
994
995 folded_sign = callchain_list__folded(chain);
996
997 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300998 str = callchain_list__sym_name(chain, bf, sizeof(bf),
999 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001000 if (was_first) {
1001 double percent = cumul * 100.0 / new_total;
1002
1003 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1004 str = "Not enough memory!";
1005 else
1006 str = alloc_str;
1007 }
1008
1009 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1010 free(alloc_str);
1011 if (folded_sign == '+')
1012 break;
1013 }
1014
1015 if (folded_sign == '-') {
1016 const int new_level = level + (extra_offset ? 2 : 1);
1017 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1018 new_level, fp);
1019 }
1020
1021 node = next;
1022 }
1023
1024 return printed;
1025}
1026
1027static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1028 struct callchain_node *node,
1029 int level, FILE *fp)
1030{
1031 struct callchain_list *chain;
1032 int offset = level * LEVEL_OFFSET_STEP;
1033 char folded_sign = ' ';
1034 int printed = 0;
1035
1036 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001037 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001038
1039 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001040 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001041 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1042 }
1043
1044 if (folded_sign == '-')
1045 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1046 browser->hists->stats.total_period,
1047 level + 1, fp);
1048 return printed;
1049}
1050
1051static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1052 struct rb_root *chain, int level, FILE *fp)
1053{
1054 struct rb_node *nd;
1055 int printed = 0;
1056
1057 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1058 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1059
1060 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1061 }
1062
1063 return printed;
1064}
1065
1066static int hist_browser__fprintf_entry(struct hist_browser *browser,
1067 struct hist_entry *he, FILE *fp)
1068{
1069 char s[8192];
1070 double percent;
1071 int printed = 0;
1072 char folded_sign = ' ';
1073
1074 if (symbol_conf.use_callchain)
1075 folded_sign = hist_entry__folded(he);
1076
Namhyung Kim000078b2012-08-20 13:52:06 +09001077 hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001078 percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001079
1080 if (symbol_conf.use_callchain)
1081 printed += fprintf(fp, "%c ", folded_sign);
1082
1083 printed += fprintf(fp, " %5.2f%%", percent);
1084
1085 if (symbol_conf.show_nr_samples)
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001086 printed += fprintf(fp, " %11u", he->stat.nr_events);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001087
1088 if (symbol_conf.show_total_period)
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001089 printed += fprintf(fp, " %12" PRIu64, he->stat.period);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001090
1091 printed += fprintf(fp, "%s\n", rtrim(s));
1092
1093 if (folded_sign == '-')
1094 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1095
1096 return printed;
1097}
1098
1099static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1100{
1101 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
1102 int printed = 0;
1103
1104 while (nd) {
1105 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1106
1107 printed += hist_browser__fprintf_entry(browser, h, fp);
1108 nd = hists__filter_entries(rb_next(nd));
1109 }
1110
1111 return printed;
1112}
1113
1114static int hist_browser__dump(struct hist_browser *browser)
1115{
1116 char filename[64];
1117 FILE *fp;
1118
1119 while (1) {
1120 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1121 if (access(filename, F_OK))
1122 break;
1123 /*
1124 * XXX: Just an arbitrary lazy upper limit
1125 */
1126 if (++browser->print_seq == 8192) {
1127 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1128 return -1;
1129 }
1130 }
1131
1132 fp = fopen(filename, "w");
1133 if (fp == NULL) {
1134 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001135 const char *err = strerror_r(errno, bf, sizeof(bf));
1136 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001137 return -1;
1138 }
1139
1140 ++browser->print_seq;
1141 hist_browser__fprintf(browser, fp);
1142 fclose(fp);
1143 ui_helpline__fpush("%s written!", filename);
1144
1145 return 0;
1146}
1147
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001148static struct hist_browser *hist_browser__new(struct hists *hists)
1149{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001150 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001151
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001152 if (browser) {
1153 browser->hists = hists;
1154 browser->b.refresh = hist_browser__refresh;
1155 browser->b.seek = ui_browser__hists_seek;
1156 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001157 }
1158
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001159 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001160}
1161
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001162static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001163{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001164 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001165}
1166
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001167static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001168{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001169 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001170}
1171
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001172static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001173{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001174 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001175}
1176
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001177static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001178 const char *ev_name)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001179{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001180 char unit;
1181 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001182 const struct dso *dso = hists->dso_filter;
1183 const struct thread *thread = hists->thread_filter;
1184 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1185 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001186 struct perf_evsel *evsel = hists_to_evsel(hists);
1187 char buf[512];
1188 size_t buflen = sizeof(buf);
1189
Namhyung Kim759ff492013-03-05 14:53:26 +09001190 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001191 struct perf_evsel *pos;
1192
1193 perf_evsel__group_desc(evsel, buf, buflen);
1194 ev_name = buf;
1195
1196 for_each_group_member(pos, evsel) {
1197 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1198 nr_events += pos->hists.stats.total_period;
1199 }
1200 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001201
Ashay Ranecc686282012-04-05 21:01:01 -05001202 nr_samples = convert_unit(nr_samples, &unit);
1203 printed = scnprintf(bf, size,
1204 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1205 nr_samples, unit, ev_name, nr_events);
1206
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001208 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001209 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001210 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001211 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001212 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001213 ", Thread: %s(%d)",
1214 (thread->comm_set ? thread->comm : ""),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215 thread->pid);
1216 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001217 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001218 ", DSO: %s", dso->short_name);
1219 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220}
1221
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001222static inline void free_popup_options(char **options, int n)
1223{
1224 int i;
1225
1226 for (i = 0; i < n; ++i) {
1227 free(options[i]);
1228 options[i] = NULL;
1229 }
1230}
1231
Feng Tangc77d8d72012-11-01 00:00:55 +08001232/* Check whether the browser is for 'top' or 'report' */
1233static inline bool is_report_browser(void *timer)
1234{
1235 return timer == NULL;
1236}
1237
Feng Tang341487ab2013-02-03 14:38:20 +08001238/*
1239 * Only runtime switching of perf data file will make "input_name" point
1240 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1241 * whether we need to call free() for current "input_name" during the switch.
1242 */
1243static bool is_input_name_malloced = false;
1244
1245static int switch_data_file(void)
1246{
1247 char *pwd, *options[32], *abs_path[32], *tmp;
1248 DIR *pwd_dir;
1249 int nr_options = 0, choice = -1, ret = -1;
1250 struct dirent *dent;
1251
1252 pwd = getenv("PWD");
1253 if (!pwd)
1254 return ret;
1255
1256 pwd_dir = opendir(pwd);
1257 if (!pwd_dir)
1258 return ret;
1259
1260 memset(options, 0, sizeof(options));
1261 memset(options, 0, sizeof(abs_path));
1262
1263 while ((dent = readdir(pwd_dir))) {
1264 char path[PATH_MAX];
1265 u64 magic;
1266 char *name = dent->d_name;
1267 FILE *file;
1268
1269 if (!(dent->d_type == DT_REG))
1270 continue;
1271
1272 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1273
1274 file = fopen(path, "r");
1275 if (!file)
1276 continue;
1277
1278 if (fread(&magic, 1, 8, file) < 8)
1279 goto close_file_and_continue;
1280
1281 if (is_perf_magic(magic)) {
1282 options[nr_options] = strdup(name);
1283 if (!options[nr_options])
1284 goto close_file_and_continue;
1285
1286 abs_path[nr_options] = strdup(path);
1287 if (!abs_path[nr_options]) {
1288 free(options[nr_options]);
1289 ui__warning("Can't search all data files due to memory shortage.\n");
1290 fclose(file);
1291 break;
1292 }
1293
1294 nr_options++;
1295 }
1296
1297close_file_and_continue:
1298 fclose(file);
1299 if (nr_options >= 32) {
1300 ui__warning("Too many perf data files in PWD!\n"
1301 "Only the first 32 files will be listed.\n");
1302 break;
1303 }
1304 }
1305 closedir(pwd_dir);
1306
1307 if (nr_options) {
1308 choice = ui__popup_menu(nr_options, options);
1309 if (choice < nr_options && choice >= 0) {
1310 tmp = strdup(abs_path[choice]);
1311 if (tmp) {
1312 if (is_input_name_malloced)
1313 free((void *)input_name);
1314 input_name = tmp;
1315 is_input_name_malloced = true;
1316 ret = 0;
1317 } else
1318 ui__warning("Data switch failed due to memory shortage!\n");
1319 }
1320 }
1321
1322 free_popup_options(options, nr_options);
1323 free_popup_options(abs_path, nr_options);
1324 return ret;
1325}
1326
1327
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001328static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001329 const char *helpline, const char *ev_name,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001330 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001331 struct hist_browser_timer *hbt,
1332 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001333{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001334 struct hists *hists = &evsel->hists;
1335 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001336 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001337 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001338 char *options[16];
1339 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001340 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001341 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001342 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001343 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001344
1345 if (browser == NULL)
1346 return -1;
1347
1348 fstack = pstack__new(2);
1349 if (fstack == NULL)
1350 goto out;
1351
1352 ui_helpline__push(helpline);
1353
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001354 memset(options, 0, sizeof(options));
1355
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001356 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001357 const struct thread *thread = NULL;
1358 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001359 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001360 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001361 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001362 int scripts_comm = -2, scripts_symbol = -2,
1363 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001364
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001365 nr_options = 0;
1366
Namhyung Kim9783adf2012-11-02 14:50:05 +09001367 key = hist_browser__run(browser, ev_name, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001368
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001369 if (browser->he_selection != NULL) {
1370 thread = hist_browser__selected_thread(browser);
1371 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1372 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001373 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001374 case K_TAB:
1375 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001376 if (nr_events == 1)
1377 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001378 /*
1379 * Exit the browser, let hists__browser_tree
1380 * go to the next or previous
1381 */
1382 goto out_free_stack;
1383 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001384 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001385 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001386 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001387 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001388 continue;
1389 }
1390
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001391 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001392 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001393 browser->selection->map->dso->annotate_warned)
1394 continue;
1395 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001396 case 'P':
1397 hist_browser__dump(browser);
1398 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001399 case 'd':
1400 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001401 case 'V':
1402 browser->show_dso = !browser->show_dso;
1403 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001404 case 't':
1405 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001406 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001407 if (ui_browser__input_window("Symbol to show",
1408 "Please enter the name of symbol you want to see",
1409 buf, "ENTER: OK, ESC: Cancel",
1410 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001411 hists->symbol_filter_str = *buf ? buf : NULL;
1412 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001413 hist_browser__reset(browser);
1414 }
1415 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001416 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001417 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001418 goto do_scripts;
1419 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001420 case 's':
1421 if (is_report_browser(hbt))
1422 goto do_data_switch;
1423 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001424 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001425 case 'h':
1426 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001427 ui_browser__help_window(&browser->b,
1428 "h/?/F1 Show this window\n"
Arnaldo Carvalho de Melo2d5646c2011-10-18 13:02:52 -02001429 "UP/DOWN/PGUP\n"
1430 "PGDN/SPACE Navigate\n"
1431 "q/ESC/CTRL+C Exit browser\n\n"
1432 "For multiple event sessions:\n\n"
1433 "TAB/UNTAB Switch events\n\n"
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001434 "For symbolic views (--sort has sym):\n\n"
Arnaldo Carvalho de Melo2d5646c2011-10-18 13:02:52 -02001435 "-> Zoom into DSO/Threads & Annotate current symbol\n"
1436 "<- Zoom out\n"
1437 "a Annotate current symbol\n"
1438 "C Collapse all callchains\n"
1439 "E Expand all callchains\n"
1440 "d Zoom into current DSO\n"
Namhyung Kim938a23a2012-03-16 17:50:53 +09001441 "t Zoom into current Thread\n"
Feng Tangc77d8d72012-11-01 00:00:55 +08001442 "r Run available scripts('perf report' only)\n"
Feng Tang341487ab2013-02-03 14:38:20 +08001443 "s Switch to another data file in PWD ('perf report' only)\n"
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001444 "P Print histograms to perf.hist.N\n"
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001445 "V Verbose (DSO names in callchains, etc)\n"
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001446 "/ Filter symbol by name");
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001447 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001448 case K_ENTER:
1449 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001450 /* menu */
1451 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001452 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001453 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001454
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001455 if (pstack__empty(fstack)) {
1456 /*
1457 * Go back to the perf_evsel_menu__run or other user
1458 */
1459 if (left_exits)
1460 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001461 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001462 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001463 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001464 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001465 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001466 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001467 goto zoom_out_thread;
1468 continue;
1469 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001470 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001471 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001472 !ui_browser__dialog_yesno(&browser->b,
1473 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001474 continue;
1475 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001476 case 'q':
1477 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001478 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001479 default:
1480 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001481 }
1482
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001483 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001484 goto add_exit_option;
1485
Namhyung Kim55369fc2013-04-01 20:35:20 +09001486 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001487 bi = browser->he_selection->branch_info;
1488 if (browser->selection != NULL &&
1489 bi &&
1490 bi->from.sym != NULL &&
1491 !bi->from.map->dso->annotate_warned &&
1492 asprintf(&options[nr_options], "Annotate %s",
1493 bi->from.sym->name) > 0)
1494 annotate_f = nr_options++;
1495
1496 if (browser->selection != NULL &&
1497 bi &&
1498 bi->to.sym != NULL &&
1499 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001500 (bi->to.sym != bi->from.sym ||
1501 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001502 asprintf(&options[nr_options], "Annotate %s",
1503 bi->to.sym->name) > 0)
1504 annotate_t = nr_options++;
1505 } else {
1506
1507 if (browser->selection != NULL &&
1508 browser->selection->sym != NULL &&
1509 !browser->selection->map->dso->annotate_warned &&
1510 asprintf(&options[nr_options], "Annotate %s",
1511 browser->selection->sym->name) > 0)
1512 annotate = nr_options++;
1513 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001514
1515 if (thread != NULL &&
1516 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001517 (browser->hists->thread_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001518 (thread->comm_set ? thread->comm : ""),
1519 thread->pid) > 0)
1520 zoom_thread = nr_options++;
1521
1522 if (dso != NULL &&
1523 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001524 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001525 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1526 zoom_dso = nr_options++;
1527
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001528 if (browser->selection != NULL &&
1529 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001530 asprintf(&options[nr_options], "Browse map details") > 0)
1531 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001532
1533 /* perf script support */
1534 if (browser->he_selection) {
1535 struct symbol *sym;
1536
1537 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
1538 browser->he_selection->thread->comm) > 0)
1539 scripts_comm = nr_options++;
1540
1541 sym = browser->he_selection->ms.sym;
1542 if (sym && sym->namelen &&
1543 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1544 sym->name) > 0)
1545 scripts_symbol = nr_options++;
1546 }
1547
1548 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1549 scripts_all = nr_options++;
1550
Feng Tang341487ab2013-02-03 14:38:20 +08001551 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1552 "Switch to another data file in PWD") > 0)
1553 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001554add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001555 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001556retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001557 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001558
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001559 if (choice == nr_options - 1)
1560 break;
1561
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001562 if (choice == -1) {
1563 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001564 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001565 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001566
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001567 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001568 struct hist_entry *he;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001569 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001570do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001571 if (!objdump_path && perf_session_env__lookup_objdump(env))
1572 continue;
1573
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001574 he = hist_browser__selected_entry(browser);
1575 if (he == NULL)
1576 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001577
1578 /*
1579 * we stash the branch_info symbol + map into the
1580 * the ms so we don't have to rewrite all the annotation
1581 * code to use branch_info.
1582 * in branch mode, the ms struct is not used
1583 */
1584 if (choice == annotate_f) {
1585 he->ms.sym = he->branch_info->from.sym;
1586 he->ms.map = he->branch_info->from.map;
1587 } else if (choice == annotate_t) {
1588 he->ms.sym = he->branch_info->to.sym;
1589 he->ms.map = he->branch_info->to.map;
1590 }
1591
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001592 /*
1593 * Don't let this be freed, say, by hists__decay_entry.
1594 */
1595 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001596 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001597 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001598 /*
1599 * offer option to annotate the other branch source or target
1600 * (if they exists) when returning from annotate
1601 */
1602 if ((err == 'q' || err == CTRL('c'))
1603 && annotate_t != -2 && annotate_f != -2)
1604 goto retry_popup_menu;
1605
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001606 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001607 if (err)
1608 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001609
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001610 } else if (choice == browse_map)
1611 map__browse(browser->selection->map);
1612 else if (choice == zoom_dso) {
1613zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001614 if (browser->hists->dso_filter) {
1615 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001616zoom_out_dso:
1617 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001618 browser->hists->dso_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001619 sort_dso.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001620 } else {
1621 if (dso == NULL)
1622 continue;
1623 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1624 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001625 browser->hists->dso_filter = dso;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001626 sort_dso.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001627 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001628 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001629 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001630 hist_browser__reset(browser);
1631 } else if (choice == zoom_thread) {
1632zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001633 if (browser->hists->thread_filter) {
1634 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001635zoom_out_thread:
1636 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001637 browser->hists->thread_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001638 sort_thread.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001639 } else {
1640 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1641 thread->comm_set ? thread->comm : "",
1642 thread->pid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001643 browser->hists->thread_filter = thread;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001644 sort_thread.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001645 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001646 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001647 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001648 hist_browser__reset(browser);
1649 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001650 /* perf scripts support */
1651 else if (choice == scripts_all || choice == scripts_comm ||
1652 choice == scripts_symbol) {
1653do_scripts:
1654 memset(script_opt, 0, 64);
1655
1656 if (choice == scripts_comm)
1657 sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm);
1658
1659 if (choice == scripts_symbol)
1660 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1661
1662 script_browse(script_opt);
1663 }
Feng Tang341487ab2013-02-03 14:38:20 +08001664 /* Switch to another data file */
1665 else if (choice == switch_data) {
1666do_data_switch:
1667 if (!switch_data_file()) {
1668 key = K_SWITCH_INPUT_DATA;
1669 break;
1670 } else
1671 ui__warning("Won't switch the data files due to\n"
1672 "no valid data file get selected!\n");
1673 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001674 }
1675out_free_stack:
1676 pstack__delete(fstack);
1677out:
1678 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001679 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001680 return key;
1681}
1682
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001683struct perf_evsel_menu {
1684 struct ui_browser b;
1685 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001686 bool lost_events, lost_events_warned;
Namhyung Kim68d80752012-11-02 14:50:06 +09001687 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001688};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001689
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001690static void perf_evsel_menu__write(struct ui_browser *browser,
1691 void *entry, int row)
1692{
1693 struct perf_evsel_menu *menu = container_of(browser,
1694 struct perf_evsel_menu, b);
1695 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1696 bool current_entry = ui_browser__is_current_entry(browser, row);
1697 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001698 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001699 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001700 const char *warn = " ";
1701 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001702
1703 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1704 HE_COLORSET_NORMAL);
1705
Namhyung Kim759ff492013-03-05 14:53:26 +09001706 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001707 struct perf_evsel *pos;
1708
1709 ev_name = perf_evsel__group_name(evsel);
1710
1711 for_each_group_member(pos, evsel) {
1712 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1713 }
1714 }
1715
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001716 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001717 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001718 unit, unit == ' ' ? "" : " ", ev_name);
1719 slsmg_printf("%s", bf);
1720
1721 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1722 if (nr_events != 0) {
1723 menu->lost_events = true;
1724 if (!current_entry)
1725 ui_browser__set_color(browser, HE_COLORSET_TOP);
1726 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001727 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1728 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001729 warn = bf;
1730 }
1731
1732 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001733
1734 if (current_entry)
1735 menu->selection = evsel;
1736}
1737
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001738static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1739 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001740 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001741{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001742 struct perf_evlist *evlist = menu->b.priv;
1743 struct perf_evsel *pos;
1744 const char *ev_name, *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001745 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001746 int key;
1747
1748 if (ui_browser__show(&menu->b, title,
1749 "ESC: exit, ENTER|->: Browse histograms") < 0)
1750 return -1;
1751
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001752 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001753 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001754
1755 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001756 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001757 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001758
1759 if (!menu->lost_events_warned && menu->lost_events) {
1760 ui_browser__warn_lost_events(&menu->b);
1761 menu->lost_events_warned = true;
1762 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001763 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001764 case K_RIGHT:
1765 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001766 if (!menu->selection)
1767 continue;
1768 pos = menu->selection;
1769browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001770 perf_evlist__set_selected(evlist, pos);
1771 /*
1772 * Give the calling tool a chance to populate the non
1773 * default evsel resorted hists tree.
1774 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001775 if (hbt)
1776 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001777 ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001778 key = perf_evsel__hists_browse(pos, nr_events, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001779 ev_name, true, hbt,
1780 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001781 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001782 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001783 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001784 if (pos->node.next == &evlist->entries)
1785 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1786 else
1787 pos = list_entry(pos->node.next, struct perf_evsel, node);
1788 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001789 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001790 if (pos->node.prev == &evlist->entries)
1791 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1792 else
1793 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1794 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001795 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001796 if (!ui_browser__dialog_yesno(&menu->b,
1797 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001798 continue;
1799 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001800 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001801 case 'q':
1802 case CTRL('c'):
1803 goto out;
1804 default:
1805 continue;
1806 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001807 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001808 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001809 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001810 if (!ui_browser__dialog_yesno(&menu->b,
1811 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001812 continue;
1813 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001814 case 'q':
1815 case CTRL('c'):
1816 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001817 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001818 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001819 }
1820 }
1821
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001822out:
1823 ui_browser__hide(&menu->b);
1824 return key;
1825}
1826
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001827static bool filter_group_entries(struct ui_browser *self __maybe_unused,
1828 void *entry)
1829{
1830 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1831
1832 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1833 return true;
1834
1835 return false;
1836}
1837
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001838static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001839 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001840 struct hist_browser_timer *hbt,
1841 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001842{
1843 struct perf_evsel *pos;
1844 struct perf_evsel_menu menu = {
1845 .b = {
1846 .entries = &evlist->entries,
1847 .refresh = ui_browser__list_head_refresh,
1848 .seek = ui_browser__list_head_seek,
1849 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001850 .filter = filter_group_entries,
1851 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001852 .priv = evlist,
1853 },
Namhyung Kim68d80752012-11-02 14:50:06 +09001854 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001855 };
1856
1857 ui_helpline__push("Press ESC to exit");
1858
1859 list_for_each_entry(pos, &evlist->entries, node) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001860 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001861 size_t line_len = strlen(ev_name) + 7;
1862
1863 if (menu.b.width < line_len)
1864 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001865 }
1866
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001867 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001868}
1869
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001870int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001871 struct hist_browser_timer *hbt,
1872 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001873{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001874 int nr_entries = evlist->nr_entries;
1875
1876single_entry:
1877 if (nr_entries == 1) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001878 struct perf_evsel *first = list_entry(evlist->entries.next,
1879 struct perf_evsel, node);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001880 const char *ev_name = perf_evsel__name(first);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001881
1882 return perf_evsel__hists_browse(first, nr_entries, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001883 ev_name, false, hbt, env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001884 }
1885
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001886 if (symbol_conf.event_group) {
1887 struct perf_evsel *pos;
1888
1889 nr_entries = 0;
1890 list_for_each_entry(pos, &evlist->entries, node)
1891 if (perf_evsel__is_group_leader(pos))
1892 nr_entries++;
1893
1894 if (nr_entries == 1)
1895 goto single_entry;
1896 }
1897
1898 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
1899 hbt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001900}