blob: 769295bf2c104ac1f529221b2d4eb4bf82a93c9f [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include "../libslang.h"
3#include <stdlib.h>
4#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <linux/rbtree.h>
6
Namhyung Kimaca7a942012-04-04 00:14:26 -07007#include "../../util/evsel.h"
8#include "../../util/evlist.h"
9#include "../../util/hist.h"
10#include "../../util/pstack.h"
11#include "../../util/sort.h"
12#include "../../util/util.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
20
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021struct hist_browser {
22 struct ui_browser b;
23 struct hists *hists;
24 struct hist_entry *he_selection;
25 struct map_symbol *selection;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030026 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030027 bool show_dso;
Namhyung Kim064f1982013-05-14 11:09:04 +090028 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090029 u64 nr_non_filtered_entries;
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);
Namhyung Kim112f7612014-04-22 14:05:35 +090036static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030037
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030038static void hist_browser__refresh_dimensions(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030039{
40 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030041 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030042 sizeof("[k]"));
43}
44
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030045static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030046{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030047 browser->b.nr_entries = browser->hists->nr_entries;
48 hist_browser__refresh_dimensions(browser);
49 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030050}
51
52static char tree__folded_sign(bool unfolded)
53{
54 return unfolded ? '-' : '+';
55}
56
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030057static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030058{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030059 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030060}
61
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030062static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030063{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030064 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030065}
66
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030067static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030068{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030069 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030070}
71
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030072static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -030073{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030074 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -030075}
76
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030077static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030078{
79 int n = 0;
80 struct rb_node *nd;
81
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030082 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030083 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
84 struct callchain_list *chain;
85 char folded_sign = ' '; /* No children */
86
87 list_for_each_entry(chain, &child->val, list) {
88 ++n;
89 /* We need this because we may not have children */
90 folded_sign = callchain_list__folded(chain);
91 if (folded_sign == '+')
92 break;
93 }
94
95 if (folded_sign == '-') /* Have children and they're unfolded */
96 n += callchain_node__count_rows_rb_tree(child);
97 }
98
99 return n;
100}
101
102static int callchain_node__count_rows(struct callchain_node *node)
103{
104 struct callchain_list *chain;
105 bool unfolded = false;
106 int n = 0;
107
108 list_for_each_entry(chain, &node->val, list) {
109 ++n;
110 unfolded = chain->ms.unfolded;
111 }
112
113 if (unfolded)
114 n += callchain_node__count_rows_rb_tree(node);
115
116 return n;
117}
118
119static int callchain__count_rows(struct rb_root *chain)
120{
121 struct rb_node *nd;
122 int n = 0;
123
124 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
125 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
126 n += callchain_node__count_rows(node);
127 }
128
129 return n;
130}
131
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300134 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200135 return false;
136
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300138 return false;
139
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300140 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300141 return true;
142}
143
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300144static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300146 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300147
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300148 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300149 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
150 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300151 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300152
153 list_for_each_entry(chain, &child->val, list) {
154 if (first) {
155 first = false;
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 } else
159 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300160 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300161 }
162
163 callchain_node__init_have_children_rb_tree(child);
164 }
165}
166
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300167static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300168{
169 struct callchain_list *chain;
170
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300171 list_for_each_entry(chain, &node->val, list)
172 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300173
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300174 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300175}
176
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300177static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300178{
179 struct rb_node *nd;
180
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300181 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300182 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
183 callchain_node__init_have_children(node);
184 }
185}
186
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300187static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300188{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300189 if (!he->init_have_children) {
190 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
191 callchain__init_have_children(&he->sorted_chain);
192 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300193 }
194}
195
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300196static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300197{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300198 if (map_symbol__toggle_fold(browser->selection)) {
199 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300200
201 hist_entry__init_have_children(he);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300202 browser->hists->nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300203
204 if (he->ms.unfolded)
205 he->nr_rows = callchain__count_rows(&he->sorted_chain);
206 else
207 he->nr_rows = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300208 browser->hists->nr_entries += he->nr_rows;
209 browser->b.nr_entries = browser->hists->nr_entries;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300210
211 return true;
212 }
213
214 /* If it doesn't have children, no toggling performed */
215 return false;
216}
217
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300218static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300219{
220 int n = 0;
221 struct rb_node *nd;
222
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300223 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300224 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
225 struct callchain_list *chain;
226 bool has_children = false;
227
228 list_for_each_entry(chain, &child->val, list) {
229 ++n;
230 map_symbol__set_folding(&chain->ms, unfold);
231 has_children = chain->ms.has_children;
232 }
233
234 if (has_children)
235 n += callchain_node__set_folding_rb_tree(child, unfold);
236 }
237
238 return n;
239}
240
241static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
242{
243 struct callchain_list *chain;
244 bool has_children = false;
245 int n = 0;
246
247 list_for_each_entry(chain, &node->val, list) {
248 ++n;
249 map_symbol__set_folding(&chain->ms, unfold);
250 has_children = chain->ms.has_children;
251 }
252
253 if (has_children)
254 n += callchain_node__set_folding_rb_tree(node, unfold);
255
256 return n;
257}
258
259static int callchain__set_folding(struct rb_root *chain, bool unfold)
260{
261 struct rb_node *nd;
262 int n = 0;
263
264 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
265 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
266 n += callchain_node__set_folding(node, unfold);
267 }
268
269 return n;
270}
271
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300272static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300273{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300274 hist_entry__init_have_children(he);
275 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300276
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300277 if (he->ms.has_children) {
278 int n = callchain__set_folding(&he->sorted_chain, unfold);
279 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300280 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300281 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300282}
283
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300284static void hists__set_folding(struct hists *hists, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300285{
286 struct rb_node *nd;
287
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300288 hists->nr_entries = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300289
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300290 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300291 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
292 hist_entry__set_folding(he, unfold);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300293 hists->nr_entries += 1 + he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300294 }
295}
296
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300297static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300298{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300299 hists__set_folding(browser->hists, unfold);
300 browser->b.nr_entries = browser->hists->nr_entries;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300301 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300302 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300303}
304
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200305static void ui_browser__warn_lost_events(struct ui_browser *browser)
306{
307 ui_browser__warning(browser, 4,
308 "Events are being lost, check IO/CPU overload!\n\n"
309 "You may want to run 'perf' using a RT scheduler policy:\n\n"
310 " perf top -r 80\n\n"
311 "Or reduce the sampling frequency.");
312}
313
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300314static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900315 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300316{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300317 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300318 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900319 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300320
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300321 browser->b.entries = &browser->hists->entries;
322 browser->b.nr_entries = browser->hists->nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +0900323 if (browser->min_pcnt)
Namhyung Kim112f7612014-04-22 14:05:35 +0900324 browser->b.nr_entries = browser->nr_non_filtered_entries;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300325
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300326 hist_browser__refresh_dimensions(browser);
327 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300328
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300329 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300330 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300331 return -1;
332
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300333 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300334 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300335
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300336 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900337 case K_TIMER: {
338 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900339 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900340
341 if (browser->min_pcnt) {
Namhyung Kim112f7612014-04-22 14:05:35 +0900342 hist_browser__update_nr_entries(browser);
343 nr_entries = browser->nr_non_filtered_entries;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900344 } else {
345 nr_entries = browser->hists->nr_entries;
346 }
347
348 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200349
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300350 if (browser->hists->stats.nr_lost_warned !=
351 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
352 browser->hists->stats.nr_lost_warned =
353 browser->hists->stats.nr_events[PERF_RECORD_LOST];
354 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200355 }
356
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300357 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
358 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300359 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900360 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300361 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300362 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300363 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300364 struct hist_entry, rb_node);
365 ui_helpline__pop();
366 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 -0300367 seq++, browser->b.nr_entries,
368 browser->hists->nr_entries,
369 browser->b.height,
370 browser->b.index,
371 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372 h->row_offset, h->nr_rows);
373 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300374 break;
375 case 'C':
376 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300377 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300378 break;
379 case 'E':
380 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300381 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300382 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200383 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300384 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385 break;
386 /* fall thru */
387 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300388 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300389 }
390 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300391out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300392 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300393 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394}
395
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300396static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300397 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300398{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300399 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300400
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300401 if (cl->ms.sym)
402 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
403 else
404 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
405
406 if (show_dso)
407 scnprintf(bf + printed, bfsize - printed, " %s",
408 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
409
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300410 return bf;
411}
412
413#define LEVEL_OFFSET_STEP 3
414
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300415static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300416 struct callchain_node *chain_node,
417 u64 total, int level,
418 unsigned short row,
419 off_t *row_offset,
420 bool *is_current_entry)
421{
422 struct rb_node *node;
423 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
424 u64 new_total, remaining;
425
426 if (callchain_param.mode == CHAIN_GRAPH_REL)
427 new_total = chain_node->children_hit;
428 else
429 new_total = total;
430
431 remaining = new_total;
432 node = rb_first(&chain_node->rb_root);
433 while (node) {
434 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
435 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100436 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300437 struct callchain_list *chain;
438 char folded_sign = ' ';
439 int first = true;
440 int extra_offset = 0;
441
442 remaining -= cumul;
443
444 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300445 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300446 const char *str;
447 int color;
448 bool was_first = first;
449
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300450 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300451 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300452 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300453 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300454
455 folded_sign = callchain_list__folded(chain);
456 if (*row_offset != 0) {
457 --*row_offset;
458 goto do_next;
459 }
460
461 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300462 str = callchain_list__sym_name(chain, bf, sizeof(bf),
463 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300464 if (was_first) {
465 double percent = cumul * 100.0 / new_total;
466
467 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
468 str = "Not enough memory!";
469 else
470 str = alloc_str;
471 }
472
473 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300474 width = browser->b.width - (offset + extra_offset + 2);
475 if (ui_browser__is_current_entry(&browser->b, row)) {
476 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300477 color = HE_COLORSET_SELECTED;
478 *is_current_entry = true;
479 }
480
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300481 ui_browser__set_color(&browser->b, color);
482 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300483 slsmg_write_nstring(" ", offset + extra_offset);
484 slsmg_printf("%c ", folded_sign);
485 slsmg_write_nstring(str, width);
486 free(alloc_str);
487
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300488 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300489 goto out;
490do_next:
491 if (folded_sign == '+')
492 break;
493 }
494
495 if (folded_sign == '-') {
496 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300497 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300498 new_level, row, row_offset,
499 is_current_entry);
500 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300501 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300502 goto out;
503 node = next;
504 }
505out:
506 return row - first_row;
507}
508
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300509static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300510 struct callchain_node *node,
511 int level, unsigned short row,
512 off_t *row_offset,
513 bool *is_current_entry)
514{
515 struct callchain_list *chain;
516 int first_row = row,
517 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300519 char folded_sign = ' ';
520
521 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300522 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300523 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300524
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300525 folded_sign = callchain_list__folded(chain);
526
527 if (*row_offset != 0) {
528 --*row_offset;
529 continue;
530 }
531
532 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300533 if (ui_browser__is_current_entry(&browser->b, row)) {
534 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300535 color = HE_COLORSET_SELECTED;
536 *is_current_entry = true;
537 }
538
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300539 s = callchain_list__sym_name(chain, bf, sizeof(bf),
540 browser->show_dso);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300541 ui_browser__gotorc(&browser->b, row, 0);
542 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300543 slsmg_write_nstring(" ", offset);
544 slsmg_printf("%c ", folded_sign);
545 slsmg_write_nstring(s, width - 2);
546
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300547 if (++row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300548 goto out;
549 }
550
551 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300552 row += hist_browser__show_callchain_node_rb_tree(browser, node,
553 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300554 level + 1, row,
555 row_offset,
556 is_current_entry);
557out:
558 return row - first_row;
559}
560
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300561static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300562 struct rb_root *chain,
563 int level, unsigned short row,
564 off_t *row_offset,
565 bool *is_current_entry)
566{
567 struct rb_node *nd;
568 int first_row = row;
569
570 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
571 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
572
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300573 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300574 row, row_offset,
575 is_current_entry);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300576 if (row == browser->b.height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300577 break;
578 }
579
580 return row - first_row;
581}
582
Namhyung Kim89701462013-01-22 18:09:38 +0900583struct hpp_arg {
584 struct ui_browser *b;
585 char folded_sign;
586 bool current_entry;
587};
588
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900589static int __hpp__overhead_callback(struct perf_hpp *hpp, bool front)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900590{
Namhyung Kim89701462013-01-22 18:09:38 +0900591 struct hpp_arg *arg = hpp->ptr;
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900592
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900593 if (arg->current_entry && arg->b->navkeypressed)
594 ui_browser__set_color(arg->b, HE_COLORSET_SELECTED);
595 else
596 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
597
598 if (front) {
599 if (!symbol_conf.use_callchain)
600 return 0;
601
602 slsmg_printf("%c ", arg->folded_sign);
603 return 2;
604 }
605
606 return 0;
607}
608
609static int __hpp__color_callback(struct perf_hpp *hpp, bool front __maybe_unused)
610{
611 struct hpp_arg *arg = hpp->ptr;
612
613 if (!arg->current_entry || !arg->b->navkeypressed)
614 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
615 return 0;
616}
617
618static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
619{
620 struct hpp_arg *arg = hpp->ptr;
621 int ret;
622 va_list args;
623 double percent;
624
625 va_start(args, fmt);
626 percent = va_arg(args, double);
627 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900628
Namhyung Kim89701462013-01-22 18:09:38 +0900629 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900630
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900631 ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900632 slsmg_printf("%s", hpp->buf);
633
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900634 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900635 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900636}
637
Namhyung Kim89701462013-01-22 18:09:38 +0900638#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900639static u64 __hpp_get_##_field(struct hist_entry *he) \
640{ \
641 return he->stat._field; \
642} \
643 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100644static int \
645hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
646 struct perf_hpp *hpp, \
647 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900648{ \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900649 return __hpp__fmt(hpp, he, __hpp_get_##_field, _cb, " %6.2f%%", \
650 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900651}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900652
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900653__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__overhead_callback)
654__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, __hpp__color_callback)
655__HPP_COLOR_PERCENT_FN(overhead_us, period_us, __hpp__color_callback)
656__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, __hpp__color_callback)
657__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, __hpp__color_callback)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900658
659#undef __HPP_COLOR_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900660
661void hist_browser__init_hpp(void)
662{
Jiri Olsa1d778222012-10-04 21:49:39 +0900663 perf_hpp__init();
Namhyung Kimf5951d52012-09-03 11:53:09 +0900664
665 perf_hpp__format[PERF_HPP__OVERHEAD].color =
666 hist_browser__hpp_color_overhead;
667 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
668 hist_browser__hpp_color_overhead_sys;
669 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
670 hist_browser__hpp_color_overhead_us;
671 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
672 hist_browser__hpp_color_overhead_guest_sys;
673 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
674 hist_browser__hpp_color_overhead_guest_us;
675}
676
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300677static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300678 struct hist_entry *entry,
679 unsigned short row)
680{
681 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200682 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900683 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300684 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300685 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300686 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300687 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200688 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300689
690 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300691 browser->he_selection = entry;
692 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300693 }
694
695 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300696 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300697 folded_sign = hist_entry__folded(entry);
698 }
699
700 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900701 struct hpp_arg arg = {
702 .b = &browser->b,
703 .folded_sign = folded_sign,
704 .current_entry = current_entry,
705 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900706 struct perf_hpp hpp = {
707 .buf = s,
708 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900709 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900710 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300711
Namhyung Kim67d25912012-09-12 15:35:06 +0900712 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900713
Jiri Olsa12400052012-10-13 00:06:16 +0200714 perf_hpp__for_each_format(fmt) {
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300715 if (!first) {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900716 slsmg_printf(" ");
717 width -= 2;
718 }
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300719 first = false;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900720
Jiri Olsa12400052012-10-13 00:06:16 +0200721 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100722 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900723 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100724 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900725 slsmg_printf("%s", s);
726 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300727 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200728
729 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300730 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200731 width += 1;
732
Namhyung Kimf5951d52012-09-03 11:53:09 +0900733 hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300734 slsmg_write_nstring(s, width);
735 ++row;
736 ++printed;
737 } else
738 --row_offset;
739
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300740 if (folded_sign == '-' && row != browser->b.height) {
741 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300742 1, row, &row_offset,
743 &current_entry);
744 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300745 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300746 }
747
748 return printed;
749}
750
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300751static void ui_browser__hists_init_top(struct ui_browser *browser)
752{
753 if (browser->top == NULL) {
754 struct hist_browser *hb;
755
756 hb = container_of(browser, struct hist_browser, b);
757 browser->top = rb_first(&hb->hists->entries);
758 }
759}
760
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300761static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300762{
763 unsigned row = 0;
764 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300765 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300766
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300767 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300768
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300769 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300770 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900771 u64 total = hists__total_period(h->hists);
772 float percent = 0.0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300773
774 if (h->filtered)
775 continue;
776
Namhyung Kimf2148332014-01-14 11:52:48 +0900777 if (total)
778 percent = h->stat.period * 100.0 / total;
779
Namhyung Kim064f1982013-05-14 11:09:04 +0900780 if (percent < hb->min_pcnt)
781 continue;
782
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300783 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300784 if (row == browser->height)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300785 break;
786 }
787
788 return row;
789}
790
Namhyung Kim064f1982013-05-14 11:09:04 +0900791static struct rb_node *hists__filter_entries(struct rb_node *nd,
792 struct hists *hists,
793 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300794{
795 while (nd != NULL) {
796 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900797 u64 total = hists__total_period(hists);
798 float percent = 0.0;
799
800 if (total)
801 percent = h->stat.period * 100.0 / total;
Namhyung Kim064f1982013-05-14 11:09:04 +0900802
803 if (percent < min_pcnt)
804 return NULL;
805
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300806 if (!h->filtered)
807 return nd;
808
809 nd = rb_next(nd);
810 }
811
812 return NULL;
813}
814
Namhyung Kim064f1982013-05-14 11:09:04 +0900815static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
816 struct hists *hists,
817 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300818{
819 while (nd != NULL) {
820 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimf2148332014-01-14 11:52:48 +0900821 u64 total = hists__total_period(hists);
822 float percent = 0.0;
823
824 if (total)
825 percent = h->stat.period * 100.0 / total;
Namhyung Kim064f1982013-05-14 11:09:04 +0900826
827 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300828 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;
Namhyung Kim064f1982013-05-14 11:09:04 +0900842 struct hist_browser *hb;
843
844 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300845
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300846 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300847 return;
848
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300849 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300850
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300851 switch (whence) {
852 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900853 nd = hists__filter_entries(rb_first(browser->entries),
854 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300855 break;
856 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300857 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300858 goto do_offset;
859 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900860 nd = hists__filter_prev_entries(rb_last(browser->entries),
861 hb->hists, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300862 first = false;
863 break;
864 default:
865 return;
866 }
867
868 /*
869 * Moves not relative to the first visible entry invalidates its
870 * row_offset:
871 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300872 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300873 h->row_offset = 0;
874
875 /*
876 * Here we have to check if nd is expanded (+), if it is we can't go
877 * the next top level hist_entry, instead we must compute an offset of
878 * what _not_ to show and not change the first visible entry.
879 *
880 * This offset increments when we are going from top to bottom and
881 * decreases when we're going from bottom to top.
882 *
883 * As we don't have backpointers to the top level in the callchains
884 * structure, we need to always print the whole hist_entry callchain,
885 * skipping the first ones that are before the first visible entry
886 * and stop when we printed enough lines to fill the screen.
887 */
888do_offset:
889 if (offset > 0) {
890 do {
891 h = rb_entry(nd, struct hist_entry, rb_node);
892 if (h->ms.unfolded) {
893 u16 remaining = h->nr_rows - h->row_offset;
894 if (offset > remaining) {
895 offset -= remaining;
896 h->row_offset = 0;
897 } else {
898 h->row_offset += offset;
899 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300900 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300901 break;
902 }
903 }
Namhyung Kim064f1982013-05-14 11:09:04 +0900904 nd = hists__filter_entries(rb_next(nd), hb->hists,
905 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300906 if (nd == NULL)
907 break;
908 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300909 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300910 } while (offset != 0);
911 } else if (offset < 0) {
912 while (1) {
913 h = rb_entry(nd, struct hist_entry, rb_node);
914 if (h->ms.unfolded) {
915 if (first) {
916 if (-offset > h->row_offset) {
917 offset += h->row_offset;
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 } else {
926 if (-offset > h->nr_rows) {
927 offset += h->nr_rows;
928 h->row_offset = 0;
929 } else {
930 h->row_offset = h->nr_rows + offset;
931 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300932 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300933 break;
934 }
935 }
936 }
937
Namhyung Kim064f1982013-05-14 11:09:04 +0900938 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
939 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300940 if (nd == NULL)
941 break;
942 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300943 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300944 if (offset == 0) {
945 /*
946 * Last unfiltered hist_entry, check if it is
947 * unfolded, if it is then we should have
948 * row_offset at its last entry.
949 */
950 h = rb_entry(nd, struct hist_entry, rb_node);
951 if (h->ms.unfolded)
952 h->row_offset = h->nr_rows;
953 break;
954 }
955 first = false;
956 }
957 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300958 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300959 h = rb_entry(nd, struct hist_entry, rb_node);
960 h->row_offset = 0;
961 }
962}
963
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300964static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
965 struct callchain_node *chain_node,
966 u64 total, int level,
967 FILE *fp)
968{
969 struct rb_node *node;
970 int offset = level * LEVEL_OFFSET_STEP;
971 u64 new_total, remaining;
972 int printed = 0;
973
974 if (callchain_param.mode == CHAIN_GRAPH_REL)
975 new_total = chain_node->children_hit;
976 else
977 new_total = total;
978
979 remaining = new_total;
980 node = rb_first(&chain_node->rb_root);
981 while (node) {
982 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
983 struct rb_node *next = rb_next(node);
984 u64 cumul = callchain_cumul_hits(child);
985 struct callchain_list *chain;
986 char folded_sign = ' ';
987 int first = true;
988 int extra_offset = 0;
989
990 remaining -= cumul;
991
992 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300993 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300994 const char *str;
995 bool was_first = first;
996
997 if (first)
998 first = false;
999 else
1000 extra_offset = LEVEL_OFFSET_STEP;
1001
1002 folded_sign = callchain_list__folded(chain);
1003
1004 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001005 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1006 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001007 if (was_first) {
1008 double percent = cumul * 100.0 / new_total;
1009
1010 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1011 str = "Not enough memory!";
1012 else
1013 str = alloc_str;
1014 }
1015
1016 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1017 free(alloc_str);
1018 if (folded_sign == '+')
1019 break;
1020 }
1021
1022 if (folded_sign == '-') {
1023 const int new_level = level + (extra_offset ? 2 : 1);
1024 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1025 new_level, fp);
1026 }
1027
1028 node = next;
1029 }
1030
1031 return printed;
1032}
1033
1034static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1035 struct callchain_node *node,
1036 int level, FILE *fp)
1037{
1038 struct callchain_list *chain;
1039 int offset = level * LEVEL_OFFSET_STEP;
1040 char folded_sign = ' ';
1041 int printed = 0;
1042
1043 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001044 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001045
1046 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001047 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001048 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1049 }
1050
1051 if (folded_sign == '-')
1052 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1053 browser->hists->stats.total_period,
1054 level + 1, fp);
1055 return printed;
1056}
1057
1058static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1059 struct rb_root *chain, int level, FILE *fp)
1060{
1061 struct rb_node *nd;
1062 int printed = 0;
1063
1064 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1065 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1066
1067 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1068 }
1069
1070 return printed;
1071}
1072
1073static int hist_browser__fprintf_entry(struct hist_browser *browser,
1074 struct hist_entry *he, FILE *fp)
1075{
1076 char s[8192];
1077 double percent;
1078 int printed = 0;
1079 char folded_sign = ' ';
1080
1081 if (symbol_conf.use_callchain)
1082 folded_sign = hist_entry__folded(he);
1083
Namhyung Kim000078b2012-08-20 13:52:06 +09001084 hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001085 percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001086
1087 if (symbol_conf.use_callchain)
1088 printed += fprintf(fp, "%c ", folded_sign);
1089
1090 printed += fprintf(fp, " %5.2f%%", percent);
1091
1092 if (symbol_conf.show_nr_samples)
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001093 printed += fprintf(fp, " %11u", he->stat.nr_events);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001094
1095 if (symbol_conf.show_total_period)
Namhyung Kimb24c28f2012-10-04 21:49:41 +09001096 printed += fprintf(fp, " %12" PRIu64, he->stat.period);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001097
1098 printed += fprintf(fp, "%s\n", rtrim(s));
1099
1100 if (folded_sign == '-')
1101 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1102
1103 return printed;
1104}
1105
1106static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1107{
Namhyung Kim064f1982013-05-14 11:09:04 +09001108 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1109 browser->hists,
1110 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001111 int printed = 0;
1112
1113 while (nd) {
1114 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1115
1116 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim064f1982013-05-14 11:09:04 +09001117 nd = hists__filter_entries(rb_next(nd), browser->hists,
1118 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001119 }
1120
1121 return printed;
1122}
1123
1124static int hist_browser__dump(struct hist_browser *browser)
1125{
1126 char filename[64];
1127 FILE *fp;
1128
1129 while (1) {
1130 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1131 if (access(filename, F_OK))
1132 break;
1133 /*
1134 * XXX: Just an arbitrary lazy upper limit
1135 */
1136 if (++browser->print_seq == 8192) {
1137 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1138 return -1;
1139 }
1140 }
1141
1142 fp = fopen(filename, "w");
1143 if (fp == NULL) {
1144 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001145 const char *err = strerror_r(errno, bf, sizeof(bf));
1146 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001147 return -1;
1148 }
1149
1150 ++browser->print_seq;
1151 hist_browser__fprintf(browser, fp);
1152 fclose(fp);
1153 ui_helpline__fpush("%s written!", filename);
1154
1155 return 0;
1156}
1157
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001158static struct hist_browser *hist_browser__new(struct hists *hists)
1159{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001160 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001161
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001162 if (browser) {
1163 browser->hists = hists;
1164 browser->b.refresh = hist_browser__refresh;
1165 browser->b.seek = ui_browser__hists_seek;
1166 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001167 }
1168
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001169 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001170}
1171
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001172static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001173{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001174 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001175}
1176
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001177static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001178{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001179 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180}
1181
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001182static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001183{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001184 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001185}
1186
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001187static int hists__browser_title(struct hists *hists, char *bf, size_t size,
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001188 const char *ev_name)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001189{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001190 char unit;
1191 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001192 const struct dso *dso = hists->dso_filter;
1193 const struct thread *thread = hists->thread_filter;
1194 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1195 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001196 struct perf_evsel *evsel = hists_to_evsel(hists);
1197 char buf[512];
1198 size_t buflen = sizeof(buf);
1199
Namhyung Kimf2148332014-01-14 11:52:48 +09001200 if (symbol_conf.filter_relative) {
1201 nr_samples = hists->stats.nr_non_filtered_samples;
1202 nr_events = hists->stats.total_non_filtered_period;
1203 }
1204
Namhyung Kim759ff492013-03-05 14:53:26 +09001205 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001206 struct perf_evsel *pos;
1207
1208 perf_evsel__group_desc(evsel, buf, buflen);
1209 ev_name = buf;
1210
1211 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001212 if (symbol_conf.filter_relative) {
1213 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1214 nr_events += pos->hists.stats.total_non_filtered_period;
1215 } else {
1216 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1217 nr_events += pos->hists.stats.total_period;
1218 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001219 }
1220 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001221
Ashay Ranecc686282012-04-05 21:01:01 -05001222 nr_samples = convert_unit(nr_samples, &unit);
1223 printed = scnprintf(bf, size,
1224 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1225 nr_samples, unit, ev_name, nr_events);
1226
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001227
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001228 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001229 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001230 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001231 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001232 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001233 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001234 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001235 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001236 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001237 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001238 ", DSO: %s", dso->short_name);
1239 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001240}
1241
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001242static inline void free_popup_options(char **options, int n)
1243{
1244 int i;
1245
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001246 for (i = 0; i < n; ++i)
1247 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001248}
1249
Feng Tangc77d8d72012-11-01 00:00:55 +08001250/* Check whether the browser is for 'top' or 'report' */
1251static inline bool is_report_browser(void *timer)
1252{
1253 return timer == NULL;
1254}
1255
Feng Tang341487ab2013-02-03 14:38:20 +08001256/*
1257 * Only runtime switching of perf data file will make "input_name" point
1258 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1259 * whether we need to call free() for current "input_name" during the switch.
1260 */
1261static bool is_input_name_malloced = false;
1262
1263static int switch_data_file(void)
1264{
1265 char *pwd, *options[32], *abs_path[32], *tmp;
1266 DIR *pwd_dir;
1267 int nr_options = 0, choice = -1, ret = -1;
1268 struct dirent *dent;
1269
1270 pwd = getenv("PWD");
1271 if (!pwd)
1272 return ret;
1273
1274 pwd_dir = opendir(pwd);
1275 if (!pwd_dir)
1276 return ret;
1277
1278 memset(options, 0, sizeof(options));
1279 memset(options, 0, sizeof(abs_path));
1280
1281 while ((dent = readdir(pwd_dir))) {
1282 char path[PATH_MAX];
1283 u64 magic;
1284 char *name = dent->d_name;
1285 FILE *file;
1286
1287 if (!(dent->d_type == DT_REG))
1288 continue;
1289
1290 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1291
1292 file = fopen(path, "r");
1293 if (!file)
1294 continue;
1295
1296 if (fread(&magic, 1, 8, file) < 8)
1297 goto close_file_and_continue;
1298
1299 if (is_perf_magic(magic)) {
1300 options[nr_options] = strdup(name);
1301 if (!options[nr_options])
1302 goto close_file_and_continue;
1303
1304 abs_path[nr_options] = strdup(path);
1305 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001306 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001307 ui__warning("Can't search all data files due to memory shortage.\n");
1308 fclose(file);
1309 break;
1310 }
1311
1312 nr_options++;
1313 }
1314
1315close_file_and_continue:
1316 fclose(file);
1317 if (nr_options >= 32) {
1318 ui__warning("Too many perf data files in PWD!\n"
1319 "Only the first 32 files will be listed.\n");
1320 break;
1321 }
1322 }
1323 closedir(pwd_dir);
1324
1325 if (nr_options) {
1326 choice = ui__popup_menu(nr_options, options);
1327 if (choice < nr_options && choice >= 0) {
1328 tmp = strdup(abs_path[choice]);
1329 if (tmp) {
1330 if (is_input_name_malloced)
1331 free((void *)input_name);
1332 input_name = tmp;
1333 is_input_name_malloced = true;
1334 ret = 0;
1335 } else
1336 ui__warning("Data switch failed due to memory shortage!\n");
1337 }
1338 }
1339
1340 free_popup_options(options, nr_options);
1341 free_popup_options(abs_path, nr_options);
1342 return ret;
1343}
1344
Namhyung Kim112f7612014-04-22 14:05:35 +09001345static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001346{
1347 u64 nr_entries = 0;
1348 struct rb_node *nd = rb_first(&hb->hists->entries);
1349
Namhyung Kimc481f932014-04-22 13:56:11 +09001350 while ((nd = hists__filter_entries(nd, hb->hists,
1351 hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001352 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001353 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001354 }
1355
Namhyung Kim112f7612014-04-22 14:05:35 +09001356 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001357}
Feng Tang341487ab2013-02-03 14:38:20 +08001358
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001359static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001360 const char *helpline, const char *ev_name,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001361 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001362 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001363 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001364 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001365{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001366 struct hists *hists = &evsel->hists;
1367 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001368 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001369 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001370 char *options[16];
1371 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001372 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001373 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001374 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001375 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001376
Namhyung Kime8e684a2013-12-26 14:37:58 +09001377#define HIST_BROWSER_HELP_COMMON \
1378 "h/?/F1 Show this window\n" \
1379 "UP/DOWN/PGUP\n" \
1380 "PGDN/SPACE Navigate\n" \
1381 "q/ESC/CTRL+C Exit browser\n\n" \
1382 "For multiple event sessions:\n\n" \
1383 "TAB/UNTAB Switch events\n\n" \
1384 "For symbolic views (--sort has sym):\n\n" \
1385 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1386 "<- Zoom out\n" \
1387 "a Annotate current symbol\n" \
1388 "C Collapse all callchains\n" \
1389 "d Zoom into current DSO\n" \
1390 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001391 "F Toggle percentage of filtered entries\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001392
1393 /* help messages are sorted by lexical order of the hotkey */
1394 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001395 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001396 "P Print histograms to perf.hist.N\n"
1397 "r Run available scripts\n"
1398 "s Switch to another data file in PWD\n"
1399 "t Zoom into current Thread\n"
1400 "V Verbose (DSO names in callchains, etc)\n"
1401 "/ Filter symbol by name";
1402 const char top_help[] = HIST_BROWSER_HELP_COMMON
1403 "P Print histograms to perf.hist.N\n"
1404 "t Zoom into current Thread\n"
1405 "V Verbose (DSO names in callchains, etc)\n"
1406 "/ Filter symbol by name";
1407
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001408 if (browser == NULL)
1409 return -1;
1410
Namhyung Kim064f1982013-05-14 11:09:04 +09001411 if (min_pcnt) {
1412 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001413 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001414 }
1415
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001416 fstack = pstack__new(2);
1417 if (fstack == NULL)
1418 goto out;
1419
1420 ui_helpline__push(helpline);
1421
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001422 memset(options, 0, sizeof(options));
1423
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001424 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001425 const struct thread *thread = NULL;
1426 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001427 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001428 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001429 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001430 int scripts_comm = -2, scripts_symbol = -2,
1431 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001432
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001433 nr_options = 0;
1434
Namhyung Kim9783adf2012-11-02 14:50:05 +09001435 key = hist_browser__run(browser, ev_name, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001436
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001437 if (browser->he_selection != NULL) {
1438 thread = hist_browser__selected_thread(browser);
1439 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1440 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001441 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001442 case K_TAB:
1443 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001444 if (nr_events == 1)
1445 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001446 /*
1447 * Exit the browser, let hists__browser_tree
1448 * go to the next or previous
1449 */
1450 goto out_free_stack;
1451 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001452 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001453 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001454 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001455 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001456 continue;
1457 }
1458
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001459 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001460 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001461 browser->selection->map->dso->annotate_warned)
1462 continue;
1463 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001464 case 'P':
1465 hist_browser__dump(browser);
1466 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001467 case 'd':
1468 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001469 case 'V':
1470 browser->show_dso = !browser->show_dso;
1471 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001472 case 't':
1473 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001474 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001475 if (ui_browser__input_window("Symbol to show",
1476 "Please enter the name of symbol you want to see",
1477 buf, "ENTER: OK, ESC: Cancel",
1478 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001479 hists->symbol_filter_str = *buf ? buf : NULL;
1480 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001481 hist_browser__reset(browser);
1482 }
1483 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001484 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001485 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001486 goto do_scripts;
1487 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001488 case 's':
1489 if (is_report_browser(hbt))
1490 goto do_data_switch;
1491 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001492 case 'i':
1493 /* env->arch is NULL for live-mode (i.e. perf top) */
1494 if (env->arch)
1495 tui__header_window(env);
1496 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001497 case 'F':
1498 symbol_conf.filter_relative ^= 1;
1499 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001500 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001501 case 'h':
1502 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001503 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001504 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001505 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001506 case K_ENTER:
1507 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001508 /* menu */
1509 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001510 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001511 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001512
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001513 if (pstack__empty(fstack)) {
1514 /*
1515 * Go back to the perf_evsel_menu__run or other user
1516 */
1517 if (left_exits)
1518 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001519 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001520 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001521 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001522 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001523 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001524 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001525 goto zoom_out_thread;
1526 continue;
1527 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001528 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001529 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001530 !ui_browser__dialog_yesno(&browser->b,
1531 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001532 continue;
1533 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001534 case 'q':
1535 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001536 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001537 default:
1538 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001539 }
1540
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001541 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001542 goto add_exit_option;
1543
Namhyung Kim55369fc2013-04-01 20:35:20 +09001544 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001545 bi = browser->he_selection->branch_info;
1546 if (browser->selection != NULL &&
1547 bi &&
1548 bi->from.sym != NULL &&
1549 !bi->from.map->dso->annotate_warned &&
1550 asprintf(&options[nr_options], "Annotate %s",
1551 bi->from.sym->name) > 0)
1552 annotate_f = nr_options++;
1553
1554 if (browser->selection != NULL &&
1555 bi &&
1556 bi->to.sym != NULL &&
1557 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001558 (bi->to.sym != bi->from.sym ||
1559 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001560 asprintf(&options[nr_options], "Annotate %s",
1561 bi->to.sym->name) > 0)
1562 annotate_t = nr_options++;
1563 } else {
1564
1565 if (browser->selection != NULL &&
1566 browser->selection->sym != NULL &&
1567 !browser->selection->map->dso->annotate_warned &&
1568 asprintf(&options[nr_options], "Annotate %s",
1569 browser->selection->sym->name) > 0)
1570 annotate = nr_options++;
1571 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001572
1573 if (thread != NULL &&
1574 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001575 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001576 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001577 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001578 zoom_thread = nr_options++;
1579
1580 if (dso != NULL &&
1581 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001582 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001583 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1584 zoom_dso = nr_options++;
1585
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001586 if (browser->selection != NULL &&
1587 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001588 asprintf(&options[nr_options], "Browse map details") > 0)
1589 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001590
1591 /* perf script support */
1592 if (browser->he_selection) {
1593 struct symbol *sym;
1594
1595 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001596 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001597 scripts_comm = nr_options++;
1598
1599 sym = browser->he_selection->ms.sym;
1600 if (sym && sym->namelen &&
1601 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1602 sym->name) > 0)
1603 scripts_symbol = nr_options++;
1604 }
1605
1606 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1607 scripts_all = nr_options++;
1608
Feng Tang341487ab2013-02-03 14:38:20 +08001609 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1610 "Switch to another data file in PWD") > 0)
1611 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001612add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001613 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001614retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001615 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001616
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001617 if (choice == nr_options - 1)
1618 break;
1619
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001620 if (choice == -1) {
1621 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001622 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001623 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001624
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001625 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001626 struct hist_entry *he;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001627 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001628do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001629 if (!objdump_path && perf_session_env__lookup_objdump(env))
1630 continue;
1631
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001632 he = hist_browser__selected_entry(browser);
1633 if (he == NULL)
1634 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001635
1636 /*
1637 * we stash the branch_info symbol + map into the
1638 * the ms so we don't have to rewrite all the annotation
1639 * code to use branch_info.
1640 * in branch mode, the ms struct is not used
1641 */
1642 if (choice == annotate_f) {
1643 he->ms.sym = he->branch_info->from.sym;
1644 he->ms.map = he->branch_info->from.map;
1645 } else if (choice == annotate_t) {
1646 he->ms.sym = he->branch_info->to.sym;
1647 he->ms.map = he->branch_info->to.map;
1648 }
1649
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001650 /*
1651 * Don't let this be freed, say, by hists__decay_entry.
1652 */
1653 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001654 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001655 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001656 /*
1657 * offer option to annotate the other branch source or target
1658 * (if they exists) when returning from annotate
1659 */
1660 if ((err == 'q' || err == CTRL('c'))
1661 && annotate_t != -2 && annotate_f != -2)
1662 goto retry_popup_menu;
1663
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001664 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001665 if (err)
1666 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001667
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001668 } else if (choice == browse_map)
1669 map__browse(browser->selection->map);
1670 else if (choice == zoom_dso) {
1671zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001672 if (browser->hists->dso_filter) {
1673 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001674zoom_out_dso:
1675 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001676 browser->hists->dso_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001677 sort_dso.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001678 } else {
1679 if (dso == NULL)
1680 continue;
1681 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1682 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001683 browser->hists->dso_filter = dso;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001684 sort_dso.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001685 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001686 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001687 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001688 hist_browser__reset(browser);
1689 } else if (choice == zoom_thread) {
1690zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001691 if (browser->hists->thread_filter) {
1692 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001693zoom_out_thread:
1694 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001695 browser->hists->thread_filter = NULL;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001696 sort_thread.elide = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001697 } else {
1698 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001699 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001700 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001701 browser->hists->thread_filter = thread;
Arnaldo Carvalho de Melocc02c922011-10-20 08:02:30 -02001702 sort_thread.elide = true;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001703 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001704 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001705 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001706 hist_browser__reset(browser);
1707 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001708 /* perf scripts support */
1709 else if (choice == scripts_all || choice == scripts_comm ||
1710 choice == scripts_symbol) {
1711do_scripts:
1712 memset(script_opt, 0, 64);
1713
1714 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001715 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001716
1717 if (choice == scripts_symbol)
1718 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1719
1720 script_browse(script_opt);
1721 }
Feng Tang341487ab2013-02-03 14:38:20 +08001722 /* Switch to another data file */
1723 else if (choice == switch_data) {
1724do_data_switch:
1725 if (!switch_data_file()) {
1726 key = K_SWITCH_INPUT_DATA;
1727 break;
1728 } else
1729 ui__warning("Won't switch the data files due to\n"
1730 "no valid data file get selected!\n");
1731 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001732 }
1733out_free_stack:
1734 pstack__delete(fstack);
1735out:
1736 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001737 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001738 return key;
1739}
1740
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001741struct perf_evsel_menu {
1742 struct ui_browser b;
1743 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001744 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001745 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001746 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001747};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001748
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001749static void perf_evsel_menu__write(struct ui_browser *browser,
1750 void *entry, int row)
1751{
1752 struct perf_evsel_menu *menu = container_of(browser,
1753 struct perf_evsel_menu, b);
1754 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1755 bool current_entry = ui_browser__is_current_entry(browser, row);
1756 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001757 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001758 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001759 const char *warn = " ";
1760 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001761
1762 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1763 HE_COLORSET_NORMAL);
1764
Namhyung Kim759ff492013-03-05 14:53:26 +09001765 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001766 struct perf_evsel *pos;
1767
1768 ev_name = perf_evsel__group_name(evsel);
1769
1770 for_each_group_member(pos, evsel) {
1771 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1772 }
1773 }
1774
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001775 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001776 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001777 unit, unit == ' ' ? "" : " ", ev_name);
1778 slsmg_printf("%s", bf);
1779
1780 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1781 if (nr_events != 0) {
1782 menu->lost_events = true;
1783 if (!current_entry)
1784 ui_browser__set_color(browser, HE_COLORSET_TOP);
1785 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001786 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1787 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001788 warn = bf;
1789 }
1790
1791 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001792
1793 if (current_entry)
1794 menu->selection = evsel;
1795}
1796
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001797static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1798 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001799 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001800{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001801 struct perf_evlist *evlist = menu->b.priv;
1802 struct perf_evsel *pos;
1803 const char *ev_name, *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001804 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001805 int key;
1806
1807 if (ui_browser__show(&menu->b, title,
1808 "ESC: exit, ENTER|->: Browse histograms") < 0)
1809 return -1;
1810
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001811 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001812 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001813
1814 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001815 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001816 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001817
1818 if (!menu->lost_events_warned && menu->lost_events) {
1819 ui_browser__warn_lost_events(&menu->b);
1820 menu->lost_events_warned = true;
1821 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001822 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001823 case K_RIGHT:
1824 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001825 if (!menu->selection)
1826 continue;
1827 pos = menu->selection;
1828browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001829 perf_evlist__set_selected(evlist, pos);
1830 /*
1831 * Give the calling tool a chance to populate the non
1832 * default evsel resorted hists tree.
1833 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001834 if (hbt)
1835 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001836 ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001837 key = perf_evsel__hists_browse(pos, nr_events, help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001838 ev_name, true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001839 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001840 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001841 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001842 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001843 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001844 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001845 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001846 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001847 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001848 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001849 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001850 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001851 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001852 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001853 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001854 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001855 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001856 if (!ui_browser__dialog_yesno(&menu->b,
1857 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001858 continue;
1859 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001860 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001861 case 'q':
1862 case CTRL('c'):
1863 goto out;
1864 default:
1865 continue;
1866 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001867 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001868 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001869 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001870 if (!ui_browser__dialog_yesno(&menu->b,
1871 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001872 continue;
1873 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001874 case 'q':
1875 case CTRL('c'):
1876 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001877 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001878 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001879 }
1880 }
1881
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001882out:
1883 ui_browser__hide(&menu->b);
1884 return key;
1885}
1886
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001887static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001888 void *entry)
1889{
1890 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1891
1892 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1893 return true;
1894
1895 return false;
1896}
1897
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001898static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001899 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001900 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001901 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001902 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001903{
1904 struct perf_evsel *pos;
1905 struct perf_evsel_menu menu = {
1906 .b = {
1907 .entries = &evlist->entries,
1908 .refresh = ui_browser__list_head_refresh,
1909 .seek = ui_browser__list_head_seek,
1910 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001911 .filter = filter_group_entries,
1912 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001913 .priv = evlist,
1914 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001915 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001916 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001917 };
1918
1919 ui_helpline__push("Press ESC to exit");
1920
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001921 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001922 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001923 size_t line_len = strlen(ev_name) + 7;
1924
1925 if (menu.b.width < line_len)
1926 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001927 }
1928
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001929 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001930}
1931
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001932int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001933 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001934 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001935 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001936{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001937 int nr_entries = evlist->nr_entries;
1938
1939single_entry:
1940 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001941 struct perf_evsel *first = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001942 const char *ev_name = perf_evsel__name(first);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001943
1944 return perf_evsel__hists_browse(first, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001945 ev_name, false, hbt, min_pcnt,
1946 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001947 }
1948
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001949 if (symbol_conf.event_group) {
1950 struct perf_evsel *pos;
1951
1952 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001953 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001954 if (perf_evsel__is_group_leader(pos))
1955 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001956 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001957
1958 if (nr_entries == 1)
1959 goto single_entry;
1960 }
1961
1962 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09001963 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001964}