blob: 9dfde61505ccf8e1b14f7bdff8fb9e8b71af7d68 [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
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300313static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900314 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300315{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300316 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300317 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900318 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300319
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300320 browser->b.entries = &browser->hists->entries;
321 browser->b.nr_entries = browser->hists->nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +0900322 if (browser->min_pcnt)
323 browser->b.nr_entries = browser->nr_pcnt_entries;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300324
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300325 hist_browser__refresh_dimensions(browser);
326 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300327
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300328 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300329 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300330 return -1;
331
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300332 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300333 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300334
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300335 switch (key) {
Arnaldo Carvalho de Melo13d8f962011-10-26 08:05:34 -0200336 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +0900337 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300338 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200339
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300340 if (browser->hists->stats.nr_lost_warned !=
341 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
342 browser->hists->stats.nr_lost_warned =
343 browser->hists->stats.nr_events[PERF_RECORD_LOST];
344 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200345 }
346
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300347 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
348 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300349 continue;
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300350 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300351 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300352 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300353 struct hist_entry, rb_node);
354 ui_helpline__pop();
355 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 -0300356 seq++, browser->b.nr_entries,
357 browser->hists->nr_entries,
358 browser->b.height,
359 browser->b.index,
360 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300361 h->row_offset, h->nr_rows);
362 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300363 break;
364 case 'C':
365 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300367 break;
368 case 'E':
369 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300370 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300371 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200372 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300373 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300374 break;
375 /* fall thru */
376 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300377 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300378 }
379 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300380out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300381 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300382 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300383}
384
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300385static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300386 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300387{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300388 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300389
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300390 if (cl->ms.sym)
391 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
392 else
393 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
394
395 if (show_dso)
396 scnprintf(bf + printed, bfsize - printed, " %s",
397 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
398
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300399 return bf;
400}
401
402#define LEVEL_OFFSET_STEP 3
403
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300404static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300405 struct callchain_node *chain_node,
406 u64 total, int level,
407 unsigned short row,
408 off_t *row_offset,
409 bool *is_current_entry)
410{
411 struct rb_node *node;
412 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
413 u64 new_total, remaining;
414
415 if (callchain_param.mode == CHAIN_GRAPH_REL)
416 new_total = chain_node->children_hit;
417 else
418 new_total = total;
419
420 remaining = new_total;
421 node = rb_first(&chain_node->rb_root);
422 while (node) {
423 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
424 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100425 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300426 struct callchain_list *chain;
427 char folded_sign = ' ';
428 int first = true;
429 int extra_offset = 0;
430
431 remaining -= cumul;
432
433 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300434 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300435 const char *str;
436 int color;
437 bool was_first = first;
438
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300439 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300440 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300441 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300442 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300443
444 folded_sign = callchain_list__folded(chain);
445 if (*row_offset != 0) {
446 --*row_offset;
447 goto do_next;
448 }
449
450 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300451 str = callchain_list__sym_name(chain, bf, sizeof(bf),
452 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300453 if (was_first) {
454 double percent = cumul * 100.0 / new_total;
455
456 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
457 str = "Not enough memory!";
458 else
459 str = alloc_str;
460 }
461
462 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300463 width = browser->b.width - (offset + extra_offset + 2);
464 if (ui_browser__is_current_entry(&browser->b, row)) {
465 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300466 color = HE_COLORSET_SELECTED;
467 *is_current_entry = true;
468 }
469
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300470 ui_browser__set_color(&browser->b, color);
471 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300472 slsmg_write_nstring(" ", offset + extra_offset);
473 slsmg_printf("%c ", folded_sign);
474 slsmg_write_nstring(str, width);
475 free(alloc_str);
476
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300477 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300478 goto out;
479do_next:
480 if (folded_sign == '+')
481 break;
482 }
483
484 if (folded_sign == '-') {
485 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300486 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300487 new_level, row, row_offset,
488 is_current_entry);
489 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300490 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300491 goto out;
492 node = next;
493 }
494out:
495 return row - first_row;
496}
497
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300498static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300499 struct callchain_node *node,
500 int level, unsigned short row,
501 off_t *row_offset,
502 bool *is_current_entry)
503{
504 struct callchain_list *chain;
505 int first_row = row,
506 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300507 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300508 char folded_sign = ' ';
509
510 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300511 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300512 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300513
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300514 folded_sign = callchain_list__folded(chain);
515
516 if (*row_offset != 0) {
517 --*row_offset;
518 continue;
519 }
520
521 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300522 if (ui_browser__is_current_entry(&browser->b, row)) {
523 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300524 color = HE_COLORSET_SELECTED;
525 *is_current_entry = true;
526 }
527
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300528 s = callchain_list__sym_name(chain, bf, sizeof(bf),
529 browser->show_dso);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300530 ui_browser__gotorc(&browser->b, row, 0);
531 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300532 slsmg_write_nstring(" ", offset);
533 slsmg_printf("%c ", folded_sign);
534 slsmg_write_nstring(s, width - 2);
535
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300536 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300537 goto out;
538 }
539
540 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300541 row += hist_browser__show_callchain_node_rb_tree(browser, node,
542 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300543 level + 1, row,
544 row_offset,
545 is_current_entry);
546out:
547 return row - first_row;
548}
549
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300550static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300551 struct rb_root *chain,
552 int level, unsigned short row,
553 off_t *row_offset,
554 bool *is_current_entry)
555{
556 struct rb_node *nd;
557 int first_row = row;
558
559 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
560 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
561
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300562 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300563 row, row_offset,
564 is_current_entry);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300565 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300566 break;
567 }
568
569 return row - first_row;
570}
571
Namhyung Kim89701462013-01-22 18:09:38 +0900572struct hpp_arg {
573 struct ui_browser *b;
574 char folded_sign;
575 bool current_entry;
576};
577
578static int __hpp__color_callchain(struct hpp_arg *arg)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900579{
Namhyung Kim89701462013-01-22 18:09:38 +0900580 if (!symbol_conf.use_callchain)
581 return 0;
582
583 slsmg_printf("%c ", arg->folded_sign);
584 return 2;
585}
586
587static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
588 u64 (*get_field)(struct hist_entry *),
589 int (*callchain_cb)(struct hpp_arg *))
590{
591 int ret = 0;
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900592 double percent = 0.0;
593 struct hists *hists = he->hists;
Namhyung Kim89701462013-01-22 18:09:38 +0900594 struct hpp_arg *arg = hpp->ptr;
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900595
596 if (hists->stats.total_period)
597 percent = 100.0 * get_field(he) / hists->stats.total_period;
598
Namhyung Kim89701462013-01-22 18:09:38 +0900599 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900600
Namhyung Kim89701462013-01-22 18:09:38 +0900601 if (callchain_cb)
602 ret += callchain_cb(arg);
603
604 ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
605 slsmg_printf("%s", hpp->buf);
606
Namhyung Kim371d8c42013-01-22 18:09:39 +0900607 if (symbol_conf.event_group) {
608 int prev_idx, idx_delta;
609 struct perf_evsel *evsel = hists_to_evsel(hists);
610 struct hist_entry *pair;
611 int nr_members = evsel->nr_members;
612
613 if (nr_members <= 1)
614 goto out;
615
616 prev_idx = perf_evsel__group_idx(evsel);
617
618 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
619 u64 period = get_field(pair);
620 u64 total = pair->hists->stats.total_period;
621
622 if (!total)
623 continue;
624
625 evsel = hists_to_evsel(pair->hists);
626 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
627
628 while (idx_delta--) {
629 /*
630 * zero-fill group members in the middle which
631 * have no sample
632 */
633 ui_browser__set_percent_color(arg->b, 0.0,
634 arg->current_entry);
635 ret += scnprintf(hpp->buf, hpp->size,
636 " %6.2f%%", 0.0);
637 slsmg_printf("%s", hpp->buf);
638 }
639
640 percent = 100.0 * period / total;
641 ui_browser__set_percent_color(arg->b, percent,
642 arg->current_entry);
643 ret += scnprintf(hpp->buf, hpp->size,
644 " %6.2f%%", percent);
645 slsmg_printf("%s", hpp->buf);
646
647 prev_idx = perf_evsel__group_idx(evsel);
648 }
649
650 idx_delta = nr_members - prev_idx - 1;
651
652 while (idx_delta--) {
653 /*
654 * zero-fill group members at last which have no sample
655 */
656 ui_browser__set_percent_color(arg->b, 0.0,
657 arg->current_entry);
658 ret += scnprintf(hpp->buf, hpp->size,
659 " %6.2f%%", 0.0);
660 slsmg_printf("%s", hpp->buf);
661 }
662 }
663out:
Namhyung Kim89701462013-01-22 18:09:38 +0900664 if (!arg->current_entry || !arg->b->navkeypressed)
665 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
666
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900667 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900668}
669
Namhyung Kim89701462013-01-22 18:09:38 +0900670#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900671static u64 __hpp_get_##_field(struct hist_entry *he) \
672{ \
673 return he->stat._field; \
674} \
675 \
676static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \
677 struct hist_entry *he) \
678{ \
Namhyung Kim89701462013-01-22 18:09:38 +0900679 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900680}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900681
Namhyung Kim89701462013-01-22 18:09:38 +0900682__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
683__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
684__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
685__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
686__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900687
688#undef __HPP_COLOR_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900689
690void hist_browser__init_hpp(void)
691{
Jiri Olsa12400052012-10-13 00:06:16 +0200692 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
693
Jiri Olsa1d778222012-10-04 21:49:39 +0900694 perf_hpp__init();
Namhyung Kimf5951d52012-09-03 11:53:09 +0900695
696 perf_hpp__format[PERF_HPP__OVERHEAD].color =
697 hist_browser__hpp_color_overhead;
698 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
699 hist_browser__hpp_color_overhead_sys;
700 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
701 hist_browser__hpp_color_overhead_us;
702 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
703 hist_browser__hpp_color_overhead_guest_sys;
704 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
705 hist_browser__hpp_color_overhead_guest_us;
706}
707
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300708static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300709 struct hist_entry *entry,
710 unsigned short row)
711{
712 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200713 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900714 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300715 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300716 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300717 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300718 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200719 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300720
721 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300722 browser->he_selection = entry;
723 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300724 }
725
726 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300727 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300728 folded_sign = hist_entry__folded(entry);
729 }
730
731 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900732 struct hpp_arg arg = {
733 .b = &browser->b,
734 .folded_sign = folded_sign,
735 .current_entry = current_entry,
736 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900737 struct perf_hpp hpp = {
738 .buf = s,
739 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900740 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900741 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300742
Namhyung Kim67d25912012-09-12 15:35:06 +0900743 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900744
Jiri Olsa12400052012-10-13 00:06:16 +0200745 perf_hpp__for_each_format(fmt) {
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300746 if (!first) {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900747 slsmg_printf(" ");
748 width -= 2;
749 }
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300750 first = false;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900751
Jiri Olsa12400052012-10-13 00:06:16 +0200752 if (fmt->color) {
Jiri Olsa12400052012-10-13 00:06:16 +0200753 width -= fmt->color(&hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900754 } else {
Jiri Olsa12400052012-10-13 00:06:16 +0200755 width -= fmt->entry(&hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900756 slsmg_printf("%s", s);
757 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300758 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200759
760 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300761 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200762 width += 1;
763
Namhyung Kimf5951d52012-09-03 11:53:09 +0900764 hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300765 slsmg_write_nstring(s, width);
766 ++row;
767 ++printed;
768 } else
769 --row_offset;
770
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300771 if (folded_sign == '-' && row != browser->b.height) {
772 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300773 1, row, &row_offset,
774 &current_entry);
775 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300776 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300777 }
778
779 return printed;
780}
781
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300782static void ui_browser__hists_init_top(struct ui_browser *browser)
783{
784 if (browser->top == NULL) {
785 struct hist_browser *hb;
786
787 hb = container_of(browser, struct hist_browser, b);
788 browser->top = rb_first(&hb->hists->entries);
789 }
790}
791
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300792static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300793{
794 unsigned row = 0;
795 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300796 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300797
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300798 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300799
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300800 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300801 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim064f1982013-05-14 11:09:04 +0900802 float percent = h->stat.period * 100.0 /
803 hb->hists->stats.total_period;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300804
805 if (h->filtered)
806 continue;
807
Namhyung Kim064f1982013-05-14 11:09:04 +0900808 if (percent < hb->min_pcnt)
809 continue;
810
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300811 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300812 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300813 break;
814 }
815
816 return row;
817}
818
Namhyung Kim064f1982013-05-14 11:09:04 +0900819static struct rb_node *hists__filter_entries(struct rb_node *nd,
820 struct hists *hists,
821 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300822{
823 while (nd != NULL) {
824 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim064f1982013-05-14 11:09:04 +0900825 float percent = h->stat.period * 100.0 /
826 hists->stats.total_period;
827
828 if (percent < min_pcnt)
829 return NULL;
830
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300831 if (!h->filtered)
832 return nd;
833
834 nd = rb_next(nd);
835 }
836
837 return NULL;
838}
839
Namhyung Kim064f1982013-05-14 11:09:04 +0900840static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
841 struct hists *hists,
842 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300843{
844 while (nd != NULL) {
845 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim064f1982013-05-14 11:09:04 +0900846 float percent = h->stat.period * 100.0 /
847 hists->stats.total_period;
848
849 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300850 return nd;
851
852 nd = rb_prev(nd);
853 }
854
855 return NULL;
856}
857
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300858static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300859 off_t offset, int whence)
860{
861 struct hist_entry *h;
862 struct rb_node *nd;
863 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900864 struct hist_browser *hb;
865
866 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300867
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300868 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300869 return;
870
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300871 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300872
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300873 switch (whence) {
874 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900875 nd = hists__filter_entries(rb_first(browser->entries),
876 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300877 break;
878 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300879 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300880 goto do_offset;
881 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900882 nd = hists__filter_prev_entries(rb_last(browser->entries),
883 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300884 first = false;
885 break;
886 default:
887 return;
888 }
889
890 /*
891 * Moves not relative to the first visible entry invalidates its
892 * row_offset:
893 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300894 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300895 h->row_offset = 0;
896
897 /*
898 * Here we have to check if nd is expanded (+), if it is we can't go
899 * the next top level hist_entry, instead we must compute an offset of
900 * what _not_ to show and not change the first visible entry.
901 *
902 * This offset increments when we are going from top to bottom and
903 * decreases when we're going from bottom to top.
904 *
905 * As we don't have backpointers to the top level in the callchains
906 * structure, we need to always print the whole hist_entry callchain,
907 * skipping the first ones that are before the first visible entry
908 * and stop when we printed enough lines to fill the screen.
909 */
910do_offset:
911 if (offset > 0) {
912 do {
913 h = rb_entry(nd, struct hist_entry, rb_node);
914 if (h->ms.unfolded) {
915 u16 remaining = h->nr_rows - h->row_offset;
916 if (offset > remaining) {
917 offset -= remaining;
918 h->row_offset = 0;
919 } else {
920 h->row_offset += offset;
921 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300922 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300923 break;
924 }
925 }
Namhyung Kim064f1982013-05-14 11:09:04 +0900926 nd = hists__filter_entries(rb_next(nd), hb->hists,
927 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300928 if (nd == NULL)
929 break;
930 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300931 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300932 } while (offset != 0);
933 } else if (offset < 0) {
934 while (1) {
935 h = rb_entry(nd, struct hist_entry, rb_node);
936 if (h->ms.unfolded) {
937 if (first) {
938 if (-offset > h->row_offset) {
939 offset += h->row_offset;
940 h->row_offset = 0;
941 } else {
942 h->row_offset += offset;
943 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300944 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300945 break;
946 }
947 } else {
948 if (-offset > h->nr_rows) {
949 offset += h->nr_rows;
950 h->row_offset = 0;
951 } else {
952 h->row_offset = h->nr_rows + offset;
953 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300954 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300955 break;
956 }
957 }
958 }
959
Namhyung Kim064f1982013-05-14 11:09:04 +0900960 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
961 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300962 if (nd == NULL)
963 break;
964 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300965 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300966 if (offset == 0) {
967 /*
968 * Last unfiltered hist_entry, check if it is
969 * unfolded, if it is then we should have
970 * row_offset at its last entry.
971 */
972 h = rb_entry(nd, struct hist_entry, rb_node);
973 if (h->ms.unfolded)
974 h->row_offset = h->nr_rows;
975 break;
976 }
977 first = false;
978 }
979 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300980 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300981 h = rb_entry(nd, struct hist_entry, rb_node);
982 h->row_offset = 0;
983 }
984}
985
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300986static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
987 struct callchain_node *chain_node,
988 u64 total, int level,
989 FILE *fp)
990{
991 struct rb_node *node;
992 int offset = level * LEVEL_OFFSET_STEP;
993 u64 new_total, remaining;
994 int printed = 0;
995
996 if (callchain_param.mode == CHAIN_GRAPH_REL)
997 new_total = chain_node->children_hit;
998 else
999 new_total = total;
1000
1001 remaining = new_total;
1002 node = rb_first(&chain_node->rb_root);
1003 while (node) {
1004 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1005 struct rb_node *next = rb_next(node);
1006 u64 cumul = callchain_cumul_hits(child);
1007 struct callchain_list *chain;
1008 char folded_sign = ' ';
1009 int first = true;
1010 int extra_offset = 0;
1011
1012 remaining -= cumul;
1013
1014 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001015 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001016 const char *str;
1017 bool was_first = first;
1018
1019 if (first)
1020 first = false;
1021 else
1022 extra_offset = LEVEL_OFFSET_STEP;
1023
1024 folded_sign = callchain_list__folded(chain);
1025
1026 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001027 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1028 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001029 if (was_first) {
1030 double percent = cumul * 100.0 / new_total;
1031
1032 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1033 str = "Not enough memory!";
1034 else
1035 str = alloc_str;
1036 }
1037
1038 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1039 free(alloc_str);
1040 if (folded_sign == '+')
1041 break;
1042 }
1043
1044 if (folded_sign == '-') {
1045 const int new_level = level + (extra_offset ? 2 : 1);
1046 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1047 new_level, fp);
1048 }
1049
1050 node = next;
1051 }
1052
1053 return printed;
1054}
1055
1056static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1057 struct callchain_node *node,
1058 int level, FILE *fp)
1059{
1060 struct callchain_list *chain;
1061 int offset = level * LEVEL_OFFSET_STEP;
1062 char folded_sign = ' ';
1063 int printed = 0;
1064
1065 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001066 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001067
1068 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001069 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001070 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1071 }
1072
1073 if (folded_sign == '-')
1074 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1075 browser->hists->stats.total_period,
1076 level + 1, fp);
1077 return printed;
1078}
1079
1080static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1081 struct rb_root *chain, int level, FILE *fp)
1082{
1083 struct rb_node *nd;
1084 int printed = 0;
1085
1086 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1087 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1088
1089 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1090 }
1091
1092 return printed;
1093}
1094
1095static int hist_browser__fprintf_entry(struct hist_browser *browser,
1096 struct hist_entry *he, FILE *fp)
1097{
1098 char s[8192];
1099 double percent;
1100 int printed = 0;
1101 char folded_sign = ' ';
1102
1103 if (symbol_conf.use_callchain)
1104 folded_sign = hist_entry__folded(he);
1105
Namhyung Kim000078b2012-08-20 13:52:06 +09001106 hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001107 percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001108
1109 if (symbol_conf.use_callchain)
1110 printed += fprintf(fp, "%c ", folded_sign);
1111
1112 printed += fprintf(fp, " %5.2f%%", percent);
1113
1114 if (symbol_conf.show_nr_samples)
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001115 printed += fprintf(fp, " %11u", he->stat.nr_events);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001116
1117 if (symbol_conf.show_total_period)
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001118 printed += fprintf(fp, " %12" PRIu64, he->stat.period);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001119
1120 printed += fprintf(fp, "%s\n", rtrim(s));
1121
1122 if (folded_sign == '-')
1123 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1124
1125 return printed;
1126}
1127
1128static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1129{
Namhyung Kim064f1982013-05-14 11:09:04 +09001130 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1131 browser->hists,
1132 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001133 int printed = 0;
1134
1135 while (nd) {
1136 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1137
1138 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim064f1982013-05-14 11:09:04 +09001139 nd = hists__filter_entries(rb_next(nd), browser->hists,
1140 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001141 }
1142
1143 return printed;
1144}
1145
1146static int hist_browser__dump(struct hist_browser *browser)
1147{
1148 char filename[64];
1149 FILE *fp;
1150
1151 while (1) {
1152 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1153 if (access(filename, F_OK))
1154 break;
1155 /*
1156 * XXX: Just an arbitrary lazy upper limit
1157 */
1158 if (++browser->print_seq == 8192) {
1159 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1160 return -1;
1161 }
1162 }
1163
1164 fp = fopen(filename, "w");
1165 if (fp == NULL) {
1166 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001167 const char *err = strerror_r(errno, bf, sizeof(bf));
1168 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001169 return -1;
1170 }
1171
1172 ++browser->print_seq;
1173 hist_browser__fprintf(browser, fp);
1174 fclose(fp);
1175 ui_helpline__fpush("%s written!", filename);
1176
1177 return 0;
1178}
1179
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180static struct hist_browser *hist_browser__new(struct hists *hists)
1181{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001182 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001183
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001184 if (browser) {
1185 browser->hists = hists;
1186 browser->b.refresh = hist_browser__refresh;
1187 browser->b.seek = ui_browser__hists_seek;
1188 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001189 }
1190
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001191 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001192}
1193
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001194static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001195{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001196 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001197}
1198
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001199static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001201 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202}
1203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001204static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001205{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001206 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207}
1208
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001209static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001210 const char *ev_name)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001211{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001212 char unit;
1213 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001214 const struct dso *dso = hists->dso_filter;
1215 const struct thread *thread = hists->thread_filter;
1216 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1217 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001218 struct perf_evsel *evsel = hists_to_evsel(hists);
1219 char buf[512];
1220 size_t buflen = sizeof(buf);
1221
Namhyung Kim759ff492013-03-05 14:53:26 +09001222 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001223 struct perf_evsel *pos;
1224
1225 perf_evsel__group_desc(evsel, buf, buflen);
1226 ev_name = buf;
1227
1228 for_each_group_member(pos, evsel) {
1229 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1230 nr_events += pos->hists.stats.total_period;
1231 }
1232 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001233
Ashay Ranecc686282012-04-05 21:01:01 -05001234 nr_samples = convert_unit(nr_samples, &unit);
1235 printed = scnprintf(bf, size,
1236 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1237 nr_samples, unit, ev_name, nr_events);
1238
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001239
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001240 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001241 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001242 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001243 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001244 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001245 ", Thread: %s(%d)",
1246 (thread->comm_set ? thread->comm : ""),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001247 thread->pid);
1248 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001249 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001250 ", DSO: %s", dso->short_name);
1251 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001252}
1253
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001254static inline void free_popup_options(char **options, int n)
1255{
1256 int i;
1257
1258 for (i = 0; i < n; ++i) {
1259 free(options[i]);
1260 options[i] = NULL;
1261 }
1262}
1263
Feng Tangc77d8d72012-11-01 00:00:55 +08001264/* Check whether the browser is for 'top' or 'report' */
1265static inline bool is_report_browser(void *timer)
1266{
1267 return timer == NULL;
1268}
1269
Feng Tang341487ab2013-02-03 14:38:20 +08001270/*
1271 * Only runtime switching of perf data file will make "input_name" point
1272 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1273 * whether we need to call free() for current "input_name" during the switch.
1274 */
1275static bool is_input_name_malloced = false;
1276
1277static int switch_data_file(void)
1278{
1279 char *pwd, *options[32], *abs_path[32], *tmp;
1280 DIR *pwd_dir;
1281 int nr_options = 0, choice = -1, ret = -1;
1282 struct dirent *dent;
1283
1284 pwd = getenv("PWD");
1285 if (!pwd)
1286 return ret;
1287
1288 pwd_dir = opendir(pwd);
1289 if (!pwd_dir)
1290 return ret;
1291
1292 memset(options, 0, sizeof(options));
1293 memset(options, 0, sizeof(abs_path));
1294
1295 while ((dent = readdir(pwd_dir))) {
1296 char path[PATH_MAX];
1297 u64 magic;
1298 char *name = dent->d_name;
1299 FILE *file;
1300
1301 if (!(dent->d_type == DT_REG))
1302 continue;
1303
1304 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1305
1306 file = fopen(path, "r");
1307 if (!file)
1308 continue;
1309
1310 if (fread(&magic, 1, 8, file) < 8)
1311 goto close_file_and_continue;
1312
1313 if (is_perf_magic(magic)) {
1314 options[nr_options] = strdup(name);
1315 if (!options[nr_options])
1316 goto close_file_and_continue;
1317
1318 abs_path[nr_options] = strdup(path);
1319 if (!abs_path[nr_options]) {
1320 free(options[nr_options]);
1321 ui__warning("Can't search all data files due to memory shortage.\n");
1322 fclose(file);
1323 break;
1324 }
1325
1326 nr_options++;
1327 }
1328
1329close_file_and_continue:
1330 fclose(file);
1331 if (nr_options >= 32) {
1332 ui__warning("Too many perf data files in PWD!\n"
1333 "Only the first 32 files will be listed.\n");
1334 break;
1335 }
1336 }
1337 closedir(pwd_dir);
1338
1339 if (nr_options) {
1340 choice = ui__popup_menu(nr_options, options);
1341 if (choice < nr_options && choice >= 0) {
1342 tmp = strdup(abs_path[choice]);
1343 if (tmp) {
1344 if (is_input_name_malloced)
1345 free((void *)input_name);
1346 input_name = tmp;
1347 is_input_name_malloced = true;
1348 ret = 0;
1349 } else
1350 ui__warning("Data switch failed due to memory shortage!\n");
1351 }
1352 }
1353
1354 free_popup_options(options, nr_options);
1355 free_popup_options(abs_path, nr_options);
1356 return ret;
1357}
1358
Namhyung Kim064f1982013-05-14 11:09:04 +09001359static void hist_browser__update_pcnt_entries(struct hist_browser *hb)
1360{
1361 u64 nr_entries = 0;
1362 struct rb_node *nd = rb_first(&hb->hists->entries);
1363
1364 while (nd) {
1365 nr_entries++;
1366 nd = hists__filter_entries(rb_next(nd), hb->hists,
1367 hb->min_pcnt);
1368 }
1369
1370 hb->nr_pcnt_entries = nr_entries;
1371}
Feng Tang341487ab2013-02-03 14:38:20 +08001372
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001373static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001374 const char *helpline, const char *ev_name,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001375 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001376 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001377 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001378 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001379{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001380 struct hists *hists = &evsel->hists;
1381 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001382 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001383 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001384 char *options[16];
1385 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001386 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001387 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001388 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001389 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001390
1391 if (browser == NULL)
1392 return -1;
1393
Namhyung Kim064f1982013-05-14 11:09:04 +09001394 if (min_pcnt) {
1395 browser->min_pcnt = min_pcnt;
1396 hist_browser__update_pcnt_entries(browser);
1397 }
1398
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001399 fstack = pstack__new(2);
1400 if (fstack == NULL)
1401 goto out;
1402
1403 ui_helpline__push(helpline);
1404
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001405 memset(options, 0, sizeof(options));
1406
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001407 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001408 const struct thread *thread = NULL;
1409 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001410 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001411 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001412 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001413 int scripts_comm = -2, scripts_symbol = -2,
1414 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001415
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001416 nr_options = 0;
1417
Namhyung Kim9783adf2012-11-02 14:50:05 +09001418 key = hist_browser__run(browser, ev_name, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001419
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001420 if (browser->he_selection != NULL) {
1421 thread = hist_browser__selected_thread(browser);
1422 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1423 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001424 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001425 case K_TAB:
1426 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001427 if (nr_events == 1)
1428 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001429 /*
1430 * Exit the browser, let hists__browser_tree
1431 * go to the next or previous
1432 */
1433 goto out_free_stack;
1434 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001435 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001436 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001437 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001438 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001439 continue;
1440 }
1441
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001442 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001443 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001444 browser->selection->map->dso->annotate_warned)
1445 continue;
1446 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001447 case 'P':
1448 hist_browser__dump(browser);
1449 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001450 case 'd':
1451 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001452 case 'V':
1453 browser->show_dso = !browser->show_dso;
1454 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001455 case 't':
1456 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001457 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001458 if (ui_browser__input_window("Symbol to show",
1459 "Please enter the name of symbol you want to see",
1460 buf, "ENTER: OK, ESC: Cancel",
1461 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001462 hists->symbol_filter_str = *buf ? buf : NULL;
1463 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001464 hist_browser__reset(browser);
1465 }
1466 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001467 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001468 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001469 goto do_scripts;
1470 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001471 case 's':
1472 if (is_report_browser(hbt))
1473 goto do_data_switch;
1474 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001475 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001476 case 'h':
1477 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001478 ui_browser__help_window(&browser->b,
1479 "h/?/F1 Show this window\n"
Arnaldo Carvalho de Melo2d5646c2011-10-18 13:02:52 -02001480 "UP/DOWN/PGUP\n"
1481 "PGDN/SPACE Navigate\n"
1482 "q/ESC/CTRL+C Exit browser\n\n"
1483 "For multiple event sessions:\n\n"
1484 "TAB/UNTAB Switch events\n\n"
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001485 "For symbolic views (--sort has sym):\n\n"
Arnaldo Carvalho de Melo2d5646c2011-10-18 13:02:52 -02001486 "-> Zoom into DSO/Threads & Annotate current symbol\n"
1487 "<- Zoom out\n"
1488 "a Annotate current symbol\n"
1489 "C Collapse all callchains\n"
1490 "E Expand all callchains\n"
1491 "d Zoom into current DSO\n"
Namhyung Kim938a23a2012-03-16 17:50:53 +09001492 "t Zoom into current Thread\n"
Feng Tangc77d8d72012-11-01 00:00:55 +08001493 "r Run available scripts('perf report' only)\n"
Feng Tang341487ab2013-02-03 14:38:20 +08001494 "s Switch to another data file in PWD ('perf report' only)\n"
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001495 "P Print histograms to perf.hist.N\n"
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001496 "V Verbose (DSO names in callchains, etc)\n"
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001497 "/ Filter symbol by name");
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001498 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001499 case K_ENTER:
1500 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001501 /* menu */
1502 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001503 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001504 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001505
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001506 if (pstack__empty(fstack)) {
1507 /*
1508 * Go back to the perf_evsel_menu__run or other user
1509 */
1510 if (left_exits)
1511 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001512 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001513 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001514 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001515 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001516 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001517 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001518 goto zoom_out_thread;
1519 continue;
1520 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001521 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001522 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001523 !ui_browser__dialog_yesno(&browser->b,
1524 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001525 continue;
1526 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001527 case 'q':
1528 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001529 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001530 default:
1531 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001532 }
1533
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001534 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001535 goto add_exit_option;
1536
Namhyung Kim55369fc2013-04-01 20:35:20 +09001537 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001538 bi = browser->he_selection->branch_info;
1539 if (browser->selection != NULL &&
1540 bi &&
1541 bi->from.sym != NULL &&
1542 !bi->from.map->dso->annotate_warned &&
1543 asprintf(&options[nr_options], "Annotate %s",
1544 bi->from.sym->name) > 0)
1545 annotate_f = nr_options++;
1546
1547 if (browser->selection != NULL &&
1548 bi &&
1549 bi->to.sym != NULL &&
1550 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001551 (bi->to.sym != bi->from.sym ||
1552 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001553 asprintf(&options[nr_options], "Annotate %s",
1554 bi->to.sym->name) > 0)
1555 annotate_t = nr_options++;
1556 } else {
1557
1558 if (browser->selection != NULL &&
1559 browser->selection->sym != NULL &&
1560 !browser->selection->map->dso->annotate_warned &&
1561 asprintf(&options[nr_options], "Annotate %s",
1562 browser->selection->sym->name) > 0)
1563 annotate = nr_options++;
1564 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001565
1566 if (thread != NULL &&
1567 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001568 (browser->hists->thread_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001569 (thread->comm_set ? thread->comm : ""),
1570 thread->pid) > 0)
1571 zoom_thread = nr_options++;
1572
1573 if (dso != NULL &&
1574 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001575 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001576 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1577 zoom_dso = nr_options++;
1578
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001579 if (browser->selection != NULL &&
1580 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001581 asprintf(&options[nr_options], "Browse map details") > 0)
1582 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001583
1584 /* perf script support */
1585 if (browser->he_selection) {
1586 struct symbol *sym;
1587
1588 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
1589 browser->he_selection->thread->comm) > 0)
1590 scripts_comm = nr_options++;
1591
1592 sym = browser->he_selection->ms.sym;
1593 if (sym && sym->namelen &&
1594 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1595 sym->name) > 0)
1596 scripts_symbol = nr_options++;
1597 }
1598
1599 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1600 scripts_all = nr_options++;
1601
Feng Tang341487ab2013-02-03 14:38:20 +08001602 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1603 "Switch to another data file in PWD") > 0)
1604 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001605add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001606 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001607retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001608 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001609
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001610 if (choice == nr_options - 1)
1611 break;
1612
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001613 if (choice == -1) {
1614 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001615 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001616 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001617
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001618 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001619 struct hist_entry *he;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001620 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001621do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001622 if (!objdump_path && perf_session_env__lookup_objdump(env))
1623 continue;
1624
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001625 he = hist_browser__selected_entry(browser);
1626 if (he == NULL)
1627 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001628
1629 /*
1630 * we stash the branch_info symbol + map into the
1631 * the ms so we don't have to rewrite all the annotation
1632 * code to use branch_info.
1633 * in branch mode, the ms struct is not used
1634 */
1635 if (choice == annotate_f) {
1636 he->ms.sym = he->branch_info->from.sym;
1637 he->ms.map = he->branch_info->from.map;
1638 } else if (choice == annotate_t) {
1639 he->ms.sym = he->branch_info->to.sym;
1640 he->ms.map = he->branch_info->to.map;
1641 }
1642
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001643 /*
1644 * Don't let this be freed, say, by hists__decay_entry.
1645 */
1646 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001647 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001648 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001649 /*
1650 * offer option to annotate the other branch source or target
1651 * (if they exists) when returning from annotate
1652 */
1653 if ((err == 'q' || err == CTRL('c'))
1654 && annotate_t != -2 && annotate_f != -2)
1655 goto retry_popup_menu;
1656
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001657 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001658 if (err)
1659 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001660
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001661 } else if (choice == browse_map)
1662 map__browse(browser->selection->map);
1663 else if (choice == zoom_dso) {
1664zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001665 if (browser->hists->dso_filter) {
1666 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001667zoom_out_dso:
1668 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001669 browser->hists->dso_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001670 sort_dso.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001671 } else {
1672 if (dso == NULL)
1673 continue;
1674 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1675 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001676 browser->hists->dso_filter = dso;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001677 sort_dso.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001678 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001679 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001680 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001681 hist_browser__reset(browser);
1682 } else if (choice == zoom_thread) {
1683zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001684 if (browser->hists->thread_filter) {
1685 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001686zoom_out_thread:
1687 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001688 browser->hists->thread_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001689 sort_thread.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001690 } else {
1691 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1692 thread->comm_set ? thread->comm : "",
1693 thread->pid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001694 browser->hists->thread_filter = thread;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001695 sort_thread.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001696 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001697 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001698 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001699 hist_browser__reset(browser);
1700 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001701 /* perf scripts support */
1702 else if (choice == scripts_all || choice == scripts_comm ||
1703 choice == scripts_symbol) {
1704do_scripts:
1705 memset(script_opt, 0, 64);
1706
1707 if (choice == scripts_comm)
1708 sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm);
1709
1710 if (choice == scripts_symbol)
1711 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1712
1713 script_browse(script_opt);
1714 }
Feng Tang341487ab2013-02-03 14:38:20 +08001715 /* Switch to another data file */
1716 else if (choice == switch_data) {
1717do_data_switch:
1718 if (!switch_data_file()) {
1719 key = K_SWITCH_INPUT_DATA;
1720 break;
1721 } else
1722 ui__warning("Won't switch the data files due to\n"
1723 "no valid data file get selected!\n");
1724 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001725 }
1726out_free_stack:
1727 pstack__delete(fstack);
1728out:
1729 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001730 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001731 return key;
1732}
1733
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001734struct perf_evsel_menu {
1735 struct ui_browser b;
1736 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001737 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001738 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001739 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001740};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001741
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001742static void perf_evsel_menu__write(struct ui_browser *browser,
1743 void *entry, int row)
1744{
1745 struct perf_evsel_menu *menu = container_of(browser,
1746 struct perf_evsel_menu, b);
1747 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1748 bool current_entry = ui_browser__is_current_entry(browser, row);
1749 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001750 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001751 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001752 const char *warn = " ";
1753 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001754
1755 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1756 HE_COLORSET_NORMAL);
1757
Namhyung Kim759ff492013-03-05 14:53:26 +09001758 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001759 struct perf_evsel *pos;
1760
1761 ev_name = perf_evsel__group_name(evsel);
1762
1763 for_each_group_member(pos, evsel) {
1764 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1765 }
1766 }
1767
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001768 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001769 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001770 unit, unit == ' ' ? "" : " ", ev_name);
1771 slsmg_printf("%s", bf);
1772
1773 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1774 if (nr_events != 0) {
1775 menu->lost_events = true;
1776 if (!current_entry)
1777 ui_browser__set_color(browser, HE_COLORSET_TOP);
1778 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001779 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1780 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001781 warn = bf;
1782 }
1783
1784 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001785
1786 if (current_entry)
1787 menu->selection = evsel;
1788}
1789
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001790static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1791 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001792 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001793{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001794 struct perf_evlist *evlist = menu->b.priv;
1795 struct perf_evsel *pos;
1796 const char *ev_name, *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001797 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001798 int key;
1799
1800 if (ui_browser__show(&menu->b, title,
1801 "ESC: exit, ENTER|->: Browse histograms") < 0)
1802 return -1;
1803
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001804 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001805 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001806
1807 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001808 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001809 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001810
1811 if (!menu->lost_events_warned && menu->lost_events) {
1812 ui_browser__warn_lost_events(&menu->b);
1813 menu->lost_events_warned = true;
1814 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001815 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001816 case K_RIGHT:
1817 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001818 if (!menu->selection)
1819 continue;
1820 pos = menu->selection;
1821browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001822 perf_evlist__set_selected(evlist, pos);
1823 /*
1824 * Give the calling tool a chance to populate the non
1825 * default evsel resorted hists tree.
1826 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001827 if (hbt)
1828 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001829 ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001830 key = perf_evsel__hists_browse(pos, nr_events, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001831 ev_name, true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001832 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001833 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001834 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001835 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001836 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001837 if (pos->node.next == &evlist->entries)
1838 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1839 else
1840 pos = list_entry(pos->node.next, struct perf_evsel, node);
1841 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001842 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001843 if (pos->node.prev == &evlist->entries)
1844 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1845 else
1846 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1847 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001848 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001849 if (!ui_browser__dialog_yesno(&menu->b,
1850 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001851 continue;
1852 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001853 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001854 case 'q':
1855 case CTRL('c'):
1856 goto out;
1857 default:
1858 continue;
1859 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001860 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001861 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001862 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001863 if (!ui_browser__dialog_yesno(&menu->b,
1864 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001865 continue;
1866 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001867 case 'q':
1868 case CTRL('c'):
1869 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001870 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001871 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001872 }
1873 }
1874
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001875out:
1876 ui_browser__hide(&menu->b);
1877 return key;
1878}
1879
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001880static bool filter_group_entries(struct ui_browser *self __maybe_unused,
1881 void *entry)
1882{
1883 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1884
1885 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1886 return true;
1887
1888 return false;
1889}
1890
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001891static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001892 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001893 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001894 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001895 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001896{
1897 struct perf_evsel *pos;
1898 struct perf_evsel_menu menu = {
1899 .b = {
1900 .entries = &evlist->entries,
1901 .refresh = ui_browser__list_head_refresh,
1902 .seek = ui_browser__list_head_seek,
1903 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001904 .filter = filter_group_entries,
1905 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001906 .priv = evlist,
1907 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001908 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001909 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001910 };
1911
1912 ui_helpline__push("Press ESC to exit");
1913
1914 list_for_each_entry(pos, &evlist->entries, node) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001915 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001916 size_t line_len = strlen(ev_name) + 7;
1917
1918 if (menu.b.width < line_len)
1919 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001920 }
1921
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001922 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001923}
1924
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001925int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001926 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001927 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001928 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001929{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001930 int nr_entries = evlist->nr_entries;
1931
1932single_entry:
1933 if (nr_entries == 1) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001934 struct perf_evsel *first = list_entry(evlist->entries.next,
1935 struct perf_evsel, node);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001936 const char *ev_name = perf_evsel__name(first);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001937
1938 return perf_evsel__hists_browse(first, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001939 ev_name, false, hbt, min_pcnt,
1940 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001941 }
1942
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001943 if (symbol_conf.event_group) {
1944 struct perf_evsel *pos;
1945
1946 nr_entries = 0;
1947 list_for_each_entry(pos, &evlist->entries, node)
1948 if (perf_evsel__is_group_leader(pos))
1949 nr_entries++;
1950
1951 if (nr_entries == 1)
1952 goto single_entry;
1953 }
1954
1955 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001956 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001957}