blob: ca63564d203a4a2c3fe51a762c84b903197bab97 [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include "../libslang.h"
3#include <stdlib.h>
4#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <linux/rbtree.h>
6
Namhyung Kimaca7a942012-04-04 00:14:26 -07007#include "../../util/evsel.h"
8#include "../../util/evlist.h"
9#include "../../util/hist.h"
10#include "../../util/pstack.h"
11#include "../../util/sort.h"
12#include "../../util/util.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020020#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022struct hist_browser {
23 struct ui_browser b;
24 struct hists *hists;
25 struct hist_entry *he_selection;
26 struct map_symbol *selection;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030027 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030028 bool show_dso;
Namhyung Kim064f1982013-05-14 11:09:04 +090029 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090030 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090031 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030032};
33
Namhyung Kimf5951d52012-09-03 11:53:09 +090034extern void hist_browser__init_hpp(void);
35
Jiri Olsadd00d482014-06-19 13:41:13 +020036static int hists__browser_title(struct hists *hists, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090037static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030038
Namhyung Kimc3b78952014-04-22 15:56:17 +090039static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090040 float min_pcnt);
41
Namhyung Kim268397c2014-04-22 14:49:31 +090042static bool hist_browser__has_filter(struct hist_browser *hb)
43{
44 return hists__has_filter(hb->hists) || hb->min_pcnt;
45}
46
Namhyung Kimc3b78952014-04-22 15:56:17 +090047static u32 hist_browser__nr_entries(struct hist_browser *hb)
48{
49 u32 nr_entries;
50
51 if (hist_browser__has_filter(hb))
52 nr_entries = hb->nr_non_filtered_entries;
53 else
54 nr_entries = hb->hists->nr_entries;
55
56 return nr_entries + hb->nr_callchain_rows;
57}
58
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030059static void hist_browser__refresh_dimensions(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030060{
61 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030062 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030063 sizeof("[k]"));
64}
65
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030066static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
67{
68 ui_browser__gotorc(&browser->b, row, column);
69}
70
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030071static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030072{
Namhyung Kimc3b78952014-04-22 15:56:17 +090073 /*
74 * The hists__remove_entry_filter() already folds non-filtered
75 * entries so we can assume it has 0 callchain rows.
76 */
77 browser->nr_callchain_rows = 0;
78
Namhyung Kim268397c2014-04-22 14:49:31 +090079 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +090080 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030081 hist_browser__refresh_dimensions(browser);
82 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030083}
84
85static char tree__folded_sign(bool unfolded)
86{
87 return unfolded ? '-' : '+';
88}
89
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030090static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030091{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030092 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030093}
94
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030095static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030096{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030097 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030098}
99
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300100static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300102 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300103}
104
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300105static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300106{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300107 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300108}
109
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300110static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300111{
112 int n = 0;
113 struct rb_node *nd;
114
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300115 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300116 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
117 struct callchain_list *chain;
118 char folded_sign = ' '; /* No children */
119
120 list_for_each_entry(chain, &child->val, list) {
121 ++n;
122 /* We need this because we may not have children */
123 folded_sign = callchain_list__folded(chain);
124 if (folded_sign == '+')
125 break;
126 }
127
128 if (folded_sign == '-') /* Have children and they're unfolded */
129 n += callchain_node__count_rows_rb_tree(child);
130 }
131
132 return n;
133}
134
135static int callchain_node__count_rows(struct callchain_node *node)
136{
137 struct callchain_list *chain;
138 bool unfolded = false;
139 int n = 0;
140
141 list_for_each_entry(chain, &node->val, list) {
142 ++n;
143 unfolded = chain->ms.unfolded;
144 }
145
146 if (unfolded)
147 n += callchain_node__count_rows_rb_tree(node);
148
149 return n;
150}
151
152static int callchain__count_rows(struct rb_root *chain)
153{
154 struct rb_node *nd;
155 int n = 0;
156
157 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
158 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
159 n += callchain_node__count_rows(node);
160 }
161
162 return n;
163}
164
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300165static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300166{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300167 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200168 return false;
169
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300170 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300171 return false;
172
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300173 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300174 return true;
175}
176
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300177static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300178{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300179 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300180
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300181 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300182 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
183 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300184 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300185
186 list_for_each_entry(chain, &child->val, list) {
187 if (first) {
188 first = false;
189 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300190 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300191 } else
192 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300193 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300194 }
195
196 callchain_node__init_have_children_rb_tree(child);
197 }
198}
199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300200static void callchain_node__init_have_children(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300201{
202 struct callchain_list *chain;
203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300204 list_for_each_entry(chain, &node->val, list)
205 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300206
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300207 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300208}
209
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300210static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300211{
212 struct rb_node *nd;
213
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300214 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300215 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
216 callchain_node__init_have_children(node);
217 }
218}
219
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300220static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300221{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300222 if (!he->init_have_children) {
223 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
224 callchain__init_have_children(&he->sorted_chain);
225 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300226 }
227}
228
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300229static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300230{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300231 if (map_symbol__toggle_fold(browser->selection)) {
232 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300233
234 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900235 browser->b.nr_entries -= he->nr_rows;
236 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300237
238 if (he->ms.unfolded)
239 he->nr_rows = callchain__count_rows(&he->sorted_chain);
240 else
241 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900242
243 browser->b.nr_entries += he->nr_rows;
244 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300245
246 return true;
247 }
248
249 /* If it doesn't have children, no toggling performed */
250 return false;
251}
252
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300253static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300254{
255 int n = 0;
256 struct rb_node *nd;
257
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300258 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300259 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
260 struct callchain_list *chain;
261 bool has_children = false;
262
263 list_for_each_entry(chain, &child->val, list) {
264 ++n;
265 map_symbol__set_folding(&chain->ms, unfold);
266 has_children = chain->ms.has_children;
267 }
268
269 if (has_children)
270 n += callchain_node__set_folding_rb_tree(child, unfold);
271 }
272
273 return n;
274}
275
276static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
277{
278 struct callchain_list *chain;
279 bool has_children = false;
280 int n = 0;
281
282 list_for_each_entry(chain, &node->val, list) {
283 ++n;
284 map_symbol__set_folding(&chain->ms, unfold);
285 has_children = chain->ms.has_children;
286 }
287
288 if (has_children)
289 n += callchain_node__set_folding_rb_tree(node, unfold);
290
291 return n;
292}
293
294static int callchain__set_folding(struct rb_root *chain, bool unfold)
295{
296 struct rb_node *nd;
297 int n = 0;
298
299 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
300 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
301 n += callchain_node__set_folding(node, unfold);
302 }
303
304 return n;
305}
306
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300307static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300308{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300309 hist_entry__init_have_children(he);
310 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300311
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300312 if (he->ms.has_children) {
313 int n = callchain__set_folding(&he->sorted_chain, unfold);
314 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300315 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300316 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300317}
318
Namhyung Kimc3b78952014-04-22 15:56:17 +0900319static void
320__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300321{
322 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900323 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300324
Namhyung Kimc3b78952014-04-22 15:56:17 +0900325 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900326 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900327 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300328 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
329 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900330 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300331 }
332}
333
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300334static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300335{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900336 browser->nr_callchain_rows = 0;
337 __hist_browser__set_folding(browser, unfold);
338
339 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300340 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300341 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300342}
343
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200344static void ui_browser__warn_lost_events(struct ui_browser *browser)
345{
346 ui_browser__warning(browser, 4,
347 "Events are being lost, check IO/CPU overload!\n\n"
348 "You may want to run 'perf' using a RT scheduler policy:\n\n"
349 " perf top -r 80\n\n"
350 "Or reduce the sampling frequency.");
351}
352
Jiri Olsadd00d482014-06-19 13:41:13 +0200353static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900354 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300355{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300356 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300357 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900358 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300359
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300360 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900361 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300362
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300363 hist_browser__refresh_dimensions(browser);
Jiri Olsadd00d482014-06-19 13:41:13 +0200364 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300365
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300367 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300368 return -1;
369
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300370 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300373 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900374 case K_TIMER: {
375 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900376 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900377
Namhyung Kimc3b78952014-04-22 15:56:17 +0900378 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900379 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900380
Namhyung Kimc3b78952014-04-22 15:56:17 +0900381 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900382 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200383
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300384 if (browser->hists->stats.nr_lost_warned !=
385 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
386 browser->hists->stats.nr_lost_warned =
387 browser->hists->stats.nr_events[PERF_RECORD_LOST];
388 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200389 }
390
Jiri Olsadd00d482014-06-19 13:41:13 +0200391 hists__browser_title(browser->hists, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300392 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300393 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900394 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300395 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300396 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300397 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300398 struct hist_entry, rb_node);
399 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300400 ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300401 seq++, browser->b.nr_entries,
402 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300403 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300404 browser->b.index,
405 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300406 h->row_offset, h->nr_rows);
407 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300408 break;
409 case 'C':
410 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300411 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300412 break;
413 case 'E':
414 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300415 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300416 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200417 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300418 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300419 break;
420 /* fall thru */
421 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300422 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300423 }
424 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300425out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300426 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300427 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428}
429
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300430static char *callchain_list__sym_name(struct callchain_list *cl,
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300431 char *bf, size_t bfsize, bool show_dso)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300432{
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300433 int printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300434
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300435 if (cl->ms.sym)
436 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
437 else
438 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
439
440 if (show_dso)
441 scnprintf(bf + printed, bfsize - printed, " %s",
442 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
443
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300444 return bf;
445}
446
447#define LEVEL_OFFSET_STEP 3
448
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300449static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300450 struct callchain_node *chain_node,
451 u64 total, int level,
452 unsigned short row,
453 off_t *row_offset,
454 bool *is_current_entry)
455{
456 struct rb_node *node;
457 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
458 u64 new_total, remaining;
459
460 if (callchain_param.mode == CHAIN_GRAPH_REL)
461 new_total = chain_node->children_hit;
462 else
463 new_total = total;
464
465 remaining = new_total;
466 node = rb_first(&chain_node->rb_root);
467 while (node) {
468 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
469 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100470 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300471 struct callchain_list *chain;
472 char folded_sign = ' ';
473 int first = true;
474 int extra_offset = 0;
475
476 remaining -= cumul;
477
478 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300479 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300480 const char *str;
481 int color;
482 bool was_first = first;
483
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300484 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300485 first = false;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300486 else
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300487 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300488
489 folded_sign = callchain_list__folded(chain);
490 if (*row_offset != 0) {
491 --*row_offset;
492 goto do_next;
493 }
494
495 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300496 str = callchain_list__sym_name(chain, bf, sizeof(bf),
497 browser->show_dso);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300498 if (was_first) {
499 double percent = cumul * 100.0 / new_total;
500
501 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
502 str = "Not enough memory!";
503 else
504 str = alloc_str;
505 }
506
507 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300508 width = browser->b.width - (offset + extra_offset + 2);
509 if (ui_browser__is_current_entry(&browser->b, row)) {
510 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300511 color = HE_COLORSET_SELECTED;
512 *is_current_entry = true;
513 }
514
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300515 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300516 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300517 slsmg_write_nstring(" ", offset + extra_offset);
518 slsmg_printf("%c ", folded_sign);
519 slsmg_write_nstring(str, width);
520 free(alloc_str);
521
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300522 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300523 goto out;
524do_next:
525 if (folded_sign == '+')
526 break;
527 }
528
529 if (folded_sign == '-') {
530 const int new_level = level + (extra_offset ? 2 : 1);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300531 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300532 new_level, row, row_offset,
533 is_current_entry);
534 }
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300535 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300536 goto out;
537 node = next;
538 }
539out:
540 return row - first_row;
541}
542
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300543static int hist_browser__show_callchain_node(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300544 struct callchain_node *node,
545 int level, unsigned short row,
546 off_t *row_offset,
547 bool *is_current_entry)
548{
549 struct callchain_list *chain;
550 int first_row = row,
551 offset = level * LEVEL_OFFSET_STEP,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300552 width = browser->b.width - offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300553 char folded_sign = ' ';
554
555 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300556 char bf[1024], *s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300557 int color;
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300558
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300559 folded_sign = callchain_list__folded(chain);
560
561 if (*row_offset != 0) {
562 --*row_offset;
563 continue;
564 }
565
566 color = HE_COLORSET_NORMAL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300567 if (ui_browser__is_current_entry(&browser->b, row)) {
568 browser->selection = &chain->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300569 color = HE_COLORSET_SELECTED;
570 *is_current_entry = true;
571 }
572
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300573 s = callchain_list__sym_name(chain, bf, sizeof(bf),
574 browser->show_dso);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300575 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300576 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300577 slsmg_write_nstring(" ", offset);
578 slsmg_printf("%c ", folded_sign);
579 slsmg_write_nstring(s, width - 2);
580
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300581 if (++row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300582 goto out;
583 }
584
585 if (folded_sign == '-')
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300586 row += hist_browser__show_callchain_node_rb_tree(browser, node,
587 browser->hists->stats.total_period,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300588 level + 1, row,
589 row_offset,
590 is_current_entry);
591out:
592 return row - first_row;
593}
594
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300595static int hist_browser__show_callchain(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300596 struct rb_root *chain,
597 int level, unsigned short row,
598 off_t *row_offset,
599 bool *is_current_entry)
600{
601 struct rb_node *nd;
602 int first_row = row;
603
604 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
605 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
606
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300607 row += hist_browser__show_callchain_node(browser, node, level,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300608 row, row_offset,
609 is_current_entry);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300610 if (row == browser->b.rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300611 break;
612 }
613
614 return row - first_row;
615}
616
Namhyung Kim89701462013-01-22 18:09:38 +0900617struct hpp_arg {
618 struct ui_browser *b;
619 char folded_sign;
620 bool current_entry;
621};
622
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900623static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
624{
625 struct hpp_arg *arg = hpp->ptr;
626 int ret;
627 va_list args;
628 double percent;
629
630 va_start(args, fmt);
631 percent = va_arg(args, double);
632 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900633
Namhyung Kim89701462013-01-22 18:09:38 +0900634 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900635
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900636 ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900637 slsmg_printf("%s", hpp->buf);
638
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900639 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900640 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900641}
642
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900643#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900644static u64 __hpp_get_##_field(struct hist_entry *he) \
645{ \
646 return he->stat._field; \
647} \
648 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100649static int \
650hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
651 struct perf_hpp *hpp, \
652 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900653{ \
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900654 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900655 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900656}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900657
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900658#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
659static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
660{ \
661 return he->stat_acc->_field; \
662} \
663 \
664static int \
665hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
666 struct perf_hpp *hpp, \
667 struct hist_entry *he) \
668{ \
669 if (!symbol_conf.cumulate_callchain) { \
670 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
671 slsmg_printf("%s", hpp->buf); \
672 \
673 return ret; \
674 } \
675 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \
676 __hpp__slsmg_color_printf, true); \
677}
678
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900679__HPP_COLOR_PERCENT_FN(overhead, period)
680__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
681__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
682__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
683__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900684__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900685
686#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900687#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900688
689void hist_browser__init_hpp(void)
690{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900691 perf_hpp__format[PERF_HPP__OVERHEAD].color =
692 hist_browser__hpp_color_overhead;
693 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
694 hist_browser__hpp_color_overhead_sys;
695 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
696 hist_browser__hpp_color_overhead_us;
697 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
698 hist_browser__hpp_color_overhead_guest_sys;
699 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
700 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900701 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
702 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900703}
704
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300705static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300706 struct hist_entry *entry,
707 unsigned short row)
708{
709 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200710 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900711 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300712 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300713 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300714 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300715 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200716 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300717
718 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300719 browser->he_selection = entry;
720 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300721 }
722
723 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300724 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300725 folded_sign = hist_entry__folded(entry);
726 }
727
728 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900729 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900730 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900731 .folded_sign = folded_sign,
732 .current_entry = current_entry,
733 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900734 struct perf_hpp hpp = {
735 .buf = s,
736 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900737 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900738 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300739
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300740 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900741
Jiri Olsa12400052012-10-13 00:06:16 +0200742 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900743 if (perf_hpp__should_skip(fmt))
744 continue;
745
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900746 if (current_entry && browser->b.navkeypressed) {
747 ui_browser__set_color(&browser->b,
748 HE_COLORSET_SELECTED);
749 } else {
750 ui_browser__set_color(&browser->b,
751 HE_COLORSET_NORMAL);
752 }
753
754 if (first) {
755 if (symbol_conf.use_callchain) {
756 slsmg_printf("%c ", folded_sign);
757 width -= 2;
758 }
759 first = false;
760 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900761 slsmg_printf(" ");
762 width -= 2;
763 }
764
Jiri Olsa12400052012-10-13 00:06:16 +0200765 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100766 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900767 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100768 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900769 slsmg_printf("%s", s);
770 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300771 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200772
773 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300774 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200775 width += 1;
776
Namhyung Kim26d8b332014-03-03 16:16:20 +0900777 slsmg_write_nstring("", width);
778
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300779 ++row;
780 ++printed;
781 } else
782 --row_offset;
783
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300784 if (folded_sign == '-' && row != browser->b.rows) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300785 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300786 1, row, &row_offset,
787 &current_entry);
788 if (current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300789 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300790 }
791
792 return printed;
793}
794
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300795static void ui_browser__hists_init_top(struct ui_browser *browser)
796{
797 if (browser->top == NULL) {
798 struct hist_browser *hb;
799
800 hb = container_of(browser, struct hist_browser, b);
801 browser->top = rb_first(&hb->hists->entries);
802 }
803}
804
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300805static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300806{
807 unsigned row = 0;
808 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300809 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300810
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300811 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300812
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300813 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300814 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900815 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300816
817 if (h->filtered)
818 continue;
819
Namhyung Kim14135662013-10-31 10:17:39 +0900820 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900821 if (percent < hb->min_pcnt)
822 continue;
823
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300824 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300825 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300826 break;
827 }
828
829 return row;
830}
831
Namhyung Kim064f1982013-05-14 11:09:04 +0900832static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900833 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300834{
835 while (nd != NULL) {
836 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900837 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900838
Namhyung Kimc0f15272014-04-16 11:16:33 +0900839 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300840 return nd;
841
842 nd = rb_next(nd);
843 }
844
845 return NULL;
846}
847
Namhyung Kim064f1982013-05-14 11:09:04 +0900848static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900849 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300850{
851 while (nd != NULL) {
852 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900853 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900854
855 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300856 return nd;
857
858 nd = rb_prev(nd);
859 }
860
861 return NULL;
862}
863
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300864static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300865 off_t offset, int whence)
866{
867 struct hist_entry *h;
868 struct rb_node *nd;
869 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900870 struct hist_browser *hb;
871
872 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300873
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300874 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300875 return;
876
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300877 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300878
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300879 switch (whence) {
880 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900881 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900882 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300883 break;
884 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300885 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300886 goto do_offset;
887 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900888 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900889 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300890 first = false;
891 break;
892 default:
893 return;
894 }
895
896 /*
897 * Moves not relative to the first visible entry invalidates its
898 * row_offset:
899 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300900 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300901 h->row_offset = 0;
902
903 /*
904 * Here we have to check if nd is expanded (+), if it is we can't go
905 * the next top level hist_entry, instead we must compute an offset of
906 * what _not_ to show and not change the first visible entry.
907 *
908 * This offset increments when we are going from top to bottom and
909 * decreases when we're going from bottom to top.
910 *
911 * As we don't have backpointers to the top level in the callchains
912 * structure, we need to always print the whole hist_entry callchain,
913 * skipping the first ones that are before the first visible entry
914 * and stop when we printed enough lines to fill the screen.
915 */
916do_offset:
917 if (offset > 0) {
918 do {
919 h = rb_entry(nd, struct hist_entry, rb_node);
920 if (h->ms.unfolded) {
921 u16 remaining = h->nr_rows - h->row_offset;
922 if (offset > remaining) {
923 offset -= remaining;
924 h->row_offset = 0;
925 } else {
926 h->row_offset += offset;
927 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300928 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300929 break;
930 }
931 }
Namhyung Kim14135662013-10-31 10:17:39 +0900932 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300933 if (nd == NULL)
934 break;
935 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300936 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300937 } while (offset != 0);
938 } else if (offset < 0) {
939 while (1) {
940 h = rb_entry(nd, struct hist_entry, rb_node);
941 if (h->ms.unfolded) {
942 if (first) {
943 if (-offset > h->row_offset) {
944 offset += h->row_offset;
945 h->row_offset = 0;
946 } else {
947 h->row_offset += offset;
948 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300949 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300950 break;
951 }
952 } else {
953 if (-offset > h->nr_rows) {
954 offset += h->nr_rows;
955 h->row_offset = 0;
956 } else {
957 h->row_offset = h->nr_rows + offset;
958 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300959 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300960 break;
961 }
962 }
963 }
964
Namhyung Kim14135662013-10-31 10:17:39 +0900965 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +0900966 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300967 if (nd == NULL)
968 break;
969 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300970 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300971 if (offset == 0) {
972 /*
973 * Last unfiltered hist_entry, check if it is
974 * unfolded, if it is then we should have
975 * row_offset at its last entry.
976 */
977 h = rb_entry(nd, struct hist_entry, rb_node);
978 if (h->ms.unfolded)
979 h->row_offset = h->nr_rows;
980 break;
981 }
982 first = false;
983 }
984 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300985 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300986 h = rb_entry(nd, struct hist_entry, rb_node);
987 h->row_offset = 0;
988 }
989}
990
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -0300991static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
992 struct callchain_node *chain_node,
993 u64 total, int level,
994 FILE *fp)
995{
996 struct rb_node *node;
997 int offset = level * LEVEL_OFFSET_STEP;
998 u64 new_total, remaining;
999 int printed = 0;
1000
1001 if (callchain_param.mode == CHAIN_GRAPH_REL)
1002 new_total = chain_node->children_hit;
1003 else
1004 new_total = total;
1005
1006 remaining = new_total;
1007 node = rb_first(&chain_node->rb_root);
1008 while (node) {
1009 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1010 struct rb_node *next = rb_next(node);
1011 u64 cumul = callchain_cumul_hits(child);
1012 struct callchain_list *chain;
1013 char folded_sign = ' ';
1014 int first = true;
1015 int extra_offset = 0;
1016
1017 remaining -= cumul;
1018
1019 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001020 char bf[1024], *alloc_str;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001021 const char *str;
1022 bool was_first = first;
1023
1024 if (first)
1025 first = false;
1026 else
1027 extra_offset = LEVEL_OFFSET_STEP;
1028
1029 folded_sign = callchain_list__folded(chain);
1030
1031 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001032 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1033 browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001034 if (was_first) {
1035 double percent = cumul * 100.0 / new_total;
1036
1037 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1038 str = "Not enough memory!";
1039 else
1040 str = alloc_str;
1041 }
1042
1043 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1044 free(alloc_str);
1045 if (folded_sign == '+')
1046 break;
1047 }
1048
1049 if (folded_sign == '-') {
1050 const int new_level = level + (extra_offset ? 2 : 1);
1051 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1052 new_level, fp);
1053 }
1054
1055 node = next;
1056 }
1057
1058 return printed;
1059}
1060
1061static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1062 struct callchain_node *node,
1063 int level, FILE *fp)
1064{
1065 struct callchain_list *chain;
1066 int offset = level * LEVEL_OFFSET_STEP;
1067 char folded_sign = ' ';
1068 int printed = 0;
1069
1070 list_for_each_entry(chain, &node->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001071 char bf[1024], *s;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001072
1073 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001074 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001075 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1076 }
1077
1078 if (folded_sign == '-')
1079 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1080 browser->hists->stats.total_period,
1081 level + 1, fp);
1082 return printed;
1083}
1084
1085static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1086 struct rb_root *chain, int level, FILE *fp)
1087{
1088 struct rb_node *nd;
1089 int printed = 0;
1090
1091 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1092 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1093
1094 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
1095 }
1096
1097 return printed;
1098}
1099
1100static int hist_browser__fprintf_entry(struct hist_browser *browser,
1101 struct hist_entry *he, FILE *fp)
1102{
1103 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001104 int printed = 0;
1105 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001106 struct perf_hpp hpp = {
1107 .buf = s,
1108 .size = sizeof(s),
1109 };
1110 struct perf_hpp_fmt *fmt;
1111 bool first = true;
1112 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001113
1114 if (symbol_conf.use_callchain)
1115 folded_sign = hist_entry__folded(he);
1116
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001117 if (symbol_conf.use_callchain)
1118 printed += fprintf(fp, "%c ", folded_sign);
1119
Namhyung Kim26d8b332014-03-03 16:16:20 +09001120 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001121 if (perf_hpp__should_skip(fmt))
1122 continue;
1123
Namhyung Kim26d8b332014-03-03 16:16:20 +09001124 if (!first) {
1125 ret = scnprintf(hpp.buf, hpp.size, " ");
1126 advance_hpp(&hpp, ret);
1127 } else
1128 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001129
Namhyung Kim26d8b332014-03-03 16:16:20 +09001130 ret = fmt->entry(fmt, &hpp, he);
1131 advance_hpp(&hpp, ret);
1132 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001133 printed += fprintf(fp, "%s\n", rtrim(s));
1134
1135 if (folded_sign == '-')
1136 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1137
1138 return printed;
1139}
1140
1141static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1142{
Namhyung Kim064f1982013-05-14 11:09:04 +09001143 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001144 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001145 int printed = 0;
1146
1147 while (nd) {
1148 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1149
1150 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001151 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001152 }
1153
1154 return printed;
1155}
1156
1157static int hist_browser__dump(struct hist_browser *browser)
1158{
1159 char filename[64];
1160 FILE *fp;
1161
1162 while (1) {
1163 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1164 if (access(filename, F_OK))
1165 break;
1166 /*
1167 * XXX: Just an arbitrary lazy upper limit
1168 */
1169 if (++browser->print_seq == 8192) {
1170 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1171 return -1;
1172 }
1173 }
1174
1175 fp = fopen(filename, "w");
1176 if (fp == NULL) {
1177 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001178 const char *err = strerror_r(errno, bf, sizeof(bf));
1179 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001180 return -1;
1181 }
1182
1183 ++browser->print_seq;
1184 hist_browser__fprintf(browser, fp);
1185 fclose(fp);
1186 ui_helpline__fpush("%s written!", filename);
1187
1188 return 0;
1189}
1190
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001191static struct hist_browser *hist_browser__new(struct hists *hists)
1192{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001193 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001194
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001195 if (browser) {
1196 browser->hists = hists;
1197 browser->b.refresh = hist_browser__refresh;
1198 browser->b.seek = ui_browser__hists_seek;
1199 browser->b.use_navkeypressed = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200 }
1201
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001202 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001203}
1204
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001205static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001207 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001208}
1209
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001210static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001211{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001212 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001213}
1214
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001215static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001216{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001217 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218}
1219
Jiri Olsadd00d482014-06-19 13:41:13 +02001220static int hists__browser_title(struct hists *hists, char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001221{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001222 char unit;
1223 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001224 const struct dso *dso = hists->dso_filter;
1225 const struct thread *thread = hists->thread_filter;
1226 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1227 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001228 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001229 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001230 char buf[512];
1231 size_t buflen = sizeof(buf);
1232
Namhyung Kimf2148332014-01-14 11:52:48 +09001233 if (symbol_conf.filter_relative) {
1234 nr_samples = hists->stats.nr_non_filtered_samples;
1235 nr_events = hists->stats.total_non_filtered_period;
1236 }
1237
Namhyung Kim759ff492013-03-05 14:53:26 +09001238 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001239 struct perf_evsel *pos;
1240
1241 perf_evsel__group_desc(evsel, buf, buflen);
1242 ev_name = buf;
1243
1244 for_each_group_member(pos, evsel) {
Namhyung Kimf2148332014-01-14 11:52:48 +09001245 if (symbol_conf.filter_relative) {
1246 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1247 nr_events += pos->hists.stats.total_non_filtered_period;
1248 } else {
1249 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1250 nr_events += pos->hists.stats.total_period;
1251 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001252 }
1253 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001254
Ashay Ranecc686282012-04-05 21:01:01 -05001255 nr_samples = convert_unit(nr_samples, &unit);
1256 printed = scnprintf(bf, size,
1257 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1258 nr_samples, unit, ev_name, nr_events);
1259
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001260
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001261 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001262 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001263 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001264 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001265 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001266 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001267 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001268 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001269 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001270 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001271 ", DSO: %s", dso->short_name);
1272 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001273}
1274
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001275static inline void free_popup_options(char **options, int n)
1276{
1277 int i;
1278
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001279 for (i = 0; i < n; ++i)
1280 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001281}
1282
Feng Tangc77d8d72012-11-01 00:00:55 +08001283/* Check whether the browser is for 'top' or 'report' */
1284static inline bool is_report_browser(void *timer)
1285{
1286 return timer == NULL;
1287}
1288
Feng Tang341487ab2013-02-03 14:38:20 +08001289/*
1290 * Only runtime switching of perf data file will make "input_name" point
1291 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1292 * whether we need to call free() for current "input_name" during the switch.
1293 */
1294static bool is_input_name_malloced = false;
1295
1296static int switch_data_file(void)
1297{
1298 char *pwd, *options[32], *abs_path[32], *tmp;
1299 DIR *pwd_dir;
1300 int nr_options = 0, choice = -1, ret = -1;
1301 struct dirent *dent;
1302
1303 pwd = getenv("PWD");
1304 if (!pwd)
1305 return ret;
1306
1307 pwd_dir = opendir(pwd);
1308 if (!pwd_dir)
1309 return ret;
1310
1311 memset(options, 0, sizeof(options));
1312 memset(options, 0, sizeof(abs_path));
1313
1314 while ((dent = readdir(pwd_dir))) {
1315 char path[PATH_MAX];
1316 u64 magic;
1317 char *name = dent->d_name;
1318 FILE *file;
1319
1320 if (!(dent->d_type == DT_REG))
1321 continue;
1322
1323 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1324
1325 file = fopen(path, "r");
1326 if (!file)
1327 continue;
1328
1329 if (fread(&magic, 1, 8, file) < 8)
1330 goto close_file_and_continue;
1331
1332 if (is_perf_magic(magic)) {
1333 options[nr_options] = strdup(name);
1334 if (!options[nr_options])
1335 goto close_file_and_continue;
1336
1337 abs_path[nr_options] = strdup(path);
1338 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001339 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001340 ui__warning("Can't search all data files due to memory shortage.\n");
1341 fclose(file);
1342 break;
1343 }
1344
1345 nr_options++;
1346 }
1347
1348close_file_and_continue:
1349 fclose(file);
1350 if (nr_options >= 32) {
1351 ui__warning("Too many perf data files in PWD!\n"
1352 "Only the first 32 files will be listed.\n");
1353 break;
1354 }
1355 }
1356 closedir(pwd_dir);
1357
1358 if (nr_options) {
1359 choice = ui__popup_menu(nr_options, options);
1360 if (choice < nr_options && choice >= 0) {
1361 tmp = strdup(abs_path[choice]);
1362 if (tmp) {
1363 if (is_input_name_malloced)
1364 free((void *)input_name);
1365 input_name = tmp;
1366 is_input_name_malloced = true;
1367 ret = 0;
1368 } else
1369 ui__warning("Data switch failed due to memory shortage!\n");
1370 }
1371 }
1372
1373 free_popup_options(options, nr_options);
1374 free_popup_options(abs_path, nr_options);
1375 return ret;
1376}
1377
Namhyung Kim112f7612014-04-22 14:05:35 +09001378static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001379{
1380 u64 nr_entries = 0;
1381 struct rb_node *nd = rb_first(&hb->hists->entries);
1382
Namhyung Kim268397c2014-04-22 14:49:31 +09001383 if (hb->min_pcnt == 0) {
1384 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1385 return;
1386 }
1387
Namhyung Kim14135662013-10-31 10:17:39 +09001388 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001389 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001390 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001391 }
1392
Namhyung Kim112f7612014-04-22 14:05:35 +09001393 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001394}
Feng Tang341487ab2013-02-03 14:38:20 +08001395
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001396static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001397 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001398 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001399 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001400 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001401 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001402{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001403 struct hists *hists = &evsel->hists;
1404 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001405 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001406 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001407 char *options[16];
1408 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001409 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001410 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001411 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001412 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001413
Namhyung Kime8e684a2013-12-26 14:37:58 +09001414#define HIST_BROWSER_HELP_COMMON \
1415 "h/?/F1 Show this window\n" \
1416 "UP/DOWN/PGUP\n" \
1417 "PGDN/SPACE Navigate\n" \
1418 "q/ESC/CTRL+C Exit browser\n\n" \
1419 "For multiple event sessions:\n\n" \
1420 "TAB/UNTAB Switch events\n\n" \
1421 "For symbolic views (--sort has sym):\n\n" \
1422 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1423 "<- Zoom out\n" \
1424 "a Annotate current symbol\n" \
1425 "C Collapse all callchains\n" \
1426 "d Zoom into current DSO\n" \
1427 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001428 "F Toggle percentage of filtered entries\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001429
1430 /* help messages are sorted by lexical order of the hotkey */
1431 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001432 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001433 "P Print histograms to perf.hist.N\n"
1434 "r Run available scripts\n"
1435 "s Switch to another data file in PWD\n"
1436 "t Zoom into current Thread\n"
1437 "V Verbose (DSO names in callchains, etc)\n"
1438 "/ Filter symbol by name";
1439 const char top_help[] = HIST_BROWSER_HELP_COMMON
1440 "P Print histograms to perf.hist.N\n"
1441 "t Zoom into current Thread\n"
1442 "V Verbose (DSO names in callchains, etc)\n"
1443 "/ Filter symbol by name";
1444
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001445 if (browser == NULL)
1446 return -1;
1447
Namhyung Kim064f1982013-05-14 11:09:04 +09001448 if (min_pcnt) {
1449 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001450 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001451 }
1452
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001453 fstack = pstack__new(2);
1454 if (fstack == NULL)
1455 goto out;
1456
1457 ui_helpline__push(helpline);
1458
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001459 memset(options, 0, sizeof(options));
1460
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001461 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001462 const struct thread *thread = NULL;
1463 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001464 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001465 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001466 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001467 int scripts_comm = -2, scripts_symbol = -2,
1468 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001469
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001470 nr_options = 0;
1471
Jiri Olsadd00d482014-06-19 13:41:13 +02001472 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001473
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001474 if (browser->he_selection != NULL) {
1475 thread = hist_browser__selected_thread(browser);
1476 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1477 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001478 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001479 case K_TAB:
1480 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001481 if (nr_events == 1)
1482 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001483 /*
1484 * Exit the browser, let hists__browser_tree
1485 * go to the next or previous
1486 */
1487 goto out_free_stack;
1488 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001489 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001490 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001491 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001492 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001493 continue;
1494 }
1495
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001496 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001497 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001498 browser->selection->map->dso->annotate_warned)
1499 continue;
1500 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001501 case 'P':
1502 hist_browser__dump(browser);
1503 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001504 case 'd':
1505 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001506 case 'V':
1507 browser->show_dso = !browser->show_dso;
1508 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001509 case 't':
1510 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001511 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001512 if (ui_browser__input_window("Symbol to show",
1513 "Please enter the name of symbol you want to see",
1514 buf, "ENTER: OK, ESC: Cancel",
1515 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001516 hists->symbol_filter_str = *buf ? buf : NULL;
1517 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001518 hist_browser__reset(browser);
1519 }
1520 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001521 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001522 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001523 goto do_scripts;
1524 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001525 case 's':
1526 if (is_report_browser(hbt))
1527 goto do_data_switch;
1528 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001529 case 'i':
1530 /* env->arch is NULL for live-mode (i.e. perf top) */
1531 if (env->arch)
1532 tui__header_window(env);
1533 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001534 case 'F':
1535 symbol_conf.filter_relative ^= 1;
1536 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001537 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001538 case 'h':
1539 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001540 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001541 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001542 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001543 case K_ENTER:
1544 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001545 /* menu */
1546 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001547 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001548 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001549
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001550 if (pstack__empty(fstack)) {
1551 /*
1552 * Go back to the perf_evsel_menu__run or other user
1553 */
1554 if (left_exits)
1555 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001556 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001557 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001558 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001559 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001560 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001561 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001562 goto zoom_out_thread;
1563 continue;
1564 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001565 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001566 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001567 !ui_browser__dialog_yesno(&browser->b,
1568 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001569 continue;
1570 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001571 case 'q':
1572 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001573 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001574 default:
1575 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001576 }
1577
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001578 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001579 goto add_exit_option;
1580
Namhyung Kim55369fc2013-04-01 20:35:20 +09001581 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001582 bi = browser->he_selection->branch_info;
1583 if (browser->selection != NULL &&
1584 bi &&
1585 bi->from.sym != NULL &&
1586 !bi->from.map->dso->annotate_warned &&
1587 asprintf(&options[nr_options], "Annotate %s",
1588 bi->from.sym->name) > 0)
1589 annotate_f = nr_options++;
1590
1591 if (browser->selection != NULL &&
1592 bi &&
1593 bi->to.sym != NULL &&
1594 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001595 (bi->to.sym != bi->from.sym ||
1596 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001597 asprintf(&options[nr_options], "Annotate %s",
1598 bi->to.sym->name) > 0)
1599 annotate_t = nr_options++;
1600 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001601 if (browser->selection != NULL &&
1602 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001603 !browser->selection->map->dso->annotate_warned) {
1604 struct annotation *notes;
1605
1606 notes = symbol__annotation(browser->selection->sym);
1607
1608 if (notes->src &&
1609 asprintf(&options[nr_options], "Annotate %s",
1610 browser->selection->sym->name) > 0)
1611 annotate = nr_options++;
1612 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001613 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001614
1615 if (thread != NULL &&
1616 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001617 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001618 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001619 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001620 zoom_thread = nr_options++;
1621
1622 if (dso != NULL &&
1623 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001624 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001625 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1626 zoom_dso = nr_options++;
1627
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001628 if (browser->selection != NULL &&
1629 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001630 asprintf(&options[nr_options], "Browse map details") > 0)
1631 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001632
1633 /* perf script support */
1634 if (browser->he_selection) {
1635 struct symbol *sym;
1636
1637 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001638 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001639 scripts_comm = nr_options++;
1640
1641 sym = browser->he_selection->ms.sym;
1642 if (sym && sym->namelen &&
1643 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1644 sym->name) > 0)
1645 scripts_symbol = nr_options++;
1646 }
1647
1648 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1649 scripts_all = nr_options++;
1650
Feng Tang341487ab2013-02-03 14:38:20 +08001651 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1652 "Switch to another data file in PWD") > 0)
1653 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001654add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001655 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001656retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001657 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001658
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001659 if (choice == nr_options - 1)
1660 break;
1661
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001662 if (choice == -1) {
1663 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001664 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001665 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001666
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001667 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001668 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001669 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001670 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001671do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001672 if (!objdump_path && perf_session_env__lookup_objdump(env))
1673 continue;
1674
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001675 he = hist_browser__selected_entry(browser);
1676 if (he == NULL)
1677 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001678
1679 /*
1680 * we stash the branch_info symbol + map into the
1681 * the ms so we don't have to rewrite all the annotation
1682 * code to use branch_info.
1683 * in branch mode, the ms struct is not used
1684 */
1685 if (choice == annotate_f) {
1686 he->ms.sym = he->branch_info->from.sym;
1687 he->ms.map = he->branch_info->from.map;
1688 } else if (choice == annotate_t) {
1689 he->ms.sym = he->branch_info->to.sym;
1690 he->ms.map = he->branch_info->to.map;
1691 }
1692
Jiri Olsad7553302014-06-15 10:22:15 +02001693 notes = symbol__annotation(he->ms.sym);
1694 if (!notes->src)
1695 continue;
1696
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001697 /*
1698 * Don't let this be freed, say, by hists__decay_entry.
1699 */
1700 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001701 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001702 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001703 /*
1704 * offer option to annotate the other branch source or target
1705 * (if they exists) when returning from annotate
1706 */
1707 if ((err == 'q' || err == CTRL('c'))
1708 && annotate_t != -2 && annotate_f != -2)
1709 goto retry_popup_menu;
1710
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001711 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001712 if (err)
1713 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001714
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001715 } else if (choice == browse_map)
1716 map__browse(browser->selection->map);
1717 else if (choice == zoom_dso) {
1718zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001719 if (browser->hists->dso_filter) {
1720 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001721zoom_out_dso:
1722 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001723 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001724 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001725 } else {
1726 if (dso == NULL)
1727 continue;
1728 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1729 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001730 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001731 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001732 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001733 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001734 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001735 hist_browser__reset(browser);
1736 } else if (choice == zoom_thread) {
1737zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001738 if (browser->hists->thread_filter) {
1739 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001740zoom_out_thread:
1741 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001742 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001743 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001744 } else {
1745 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001746 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001747 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001748 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001749 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001750 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001751 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001752 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001753 hist_browser__reset(browser);
1754 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001755 /* perf scripts support */
1756 else if (choice == scripts_all || choice == scripts_comm ||
1757 choice == scripts_symbol) {
1758do_scripts:
1759 memset(script_opt, 0, 64);
1760
1761 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001762 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001763
1764 if (choice == scripts_symbol)
1765 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1766
1767 script_browse(script_opt);
1768 }
Feng Tang341487ab2013-02-03 14:38:20 +08001769 /* Switch to another data file */
1770 else if (choice == switch_data) {
1771do_data_switch:
1772 if (!switch_data_file()) {
1773 key = K_SWITCH_INPUT_DATA;
1774 break;
1775 } else
1776 ui__warning("Won't switch the data files due to\n"
1777 "no valid data file get selected!\n");
1778 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001779 }
1780out_free_stack:
1781 pstack__delete(fstack);
1782out:
1783 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001784 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001785 return key;
1786}
1787
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001788struct perf_evsel_menu {
1789 struct ui_browser b;
1790 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001791 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001792 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001793 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001794};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001795
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001796static void perf_evsel_menu__write(struct ui_browser *browser,
1797 void *entry, int row)
1798{
1799 struct perf_evsel_menu *menu = container_of(browser,
1800 struct perf_evsel_menu, b);
1801 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1802 bool current_entry = ui_browser__is_current_entry(browser, row);
1803 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001804 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001805 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001806 const char *warn = " ";
1807 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001808
1809 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1810 HE_COLORSET_NORMAL);
1811
Namhyung Kim759ff492013-03-05 14:53:26 +09001812 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001813 struct perf_evsel *pos;
1814
1815 ev_name = perf_evsel__group_name(evsel);
1816
1817 for_each_group_member(pos, evsel) {
1818 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1819 }
1820 }
1821
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001822 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001823 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001824 unit, unit == ' ' ? "" : " ", ev_name);
1825 slsmg_printf("%s", bf);
1826
1827 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1828 if (nr_events != 0) {
1829 menu->lost_events = true;
1830 if (!current_entry)
1831 ui_browser__set_color(browser, HE_COLORSET_TOP);
1832 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001833 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1834 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001835 warn = bf;
1836 }
1837
1838 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001839
1840 if (current_entry)
1841 menu->selection = evsel;
1842}
1843
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001844static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1845 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001846 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001847{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001848 struct perf_evlist *evlist = menu->b.priv;
1849 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001850 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001851 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001852 int key;
1853
1854 if (ui_browser__show(&menu->b, title,
1855 "ESC: exit, ENTER|->: Browse histograms") < 0)
1856 return -1;
1857
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001858 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001859 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001860
1861 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001862 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001863 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001864
1865 if (!menu->lost_events_warned && menu->lost_events) {
1866 ui_browser__warn_lost_events(&menu->b);
1867 menu->lost_events_warned = true;
1868 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001869 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001870 case K_RIGHT:
1871 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001872 if (!menu->selection)
1873 continue;
1874 pos = menu->selection;
1875browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001876 perf_evlist__set_selected(evlist, pos);
1877 /*
1878 * Give the calling tool a chance to populate the non
1879 * default evsel resorted hists tree.
1880 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001881 if (hbt)
1882 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001883 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001884 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001885 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001886 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001887 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001888 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001889 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001890 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001891 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001892 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001893 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001894 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001895 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001896 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001897 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001898 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001899 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001900 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001901 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001902 if (!ui_browser__dialog_yesno(&menu->b,
1903 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001904 continue;
1905 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001906 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001907 case 'q':
1908 case CTRL('c'):
1909 goto out;
1910 default:
1911 continue;
1912 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001913 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001914 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001915 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001916 if (!ui_browser__dialog_yesno(&menu->b,
1917 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001918 continue;
1919 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001920 case 'q':
1921 case CTRL('c'):
1922 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001923 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001924 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001925 }
1926 }
1927
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001928out:
1929 ui_browser__hide(&menu->b);
1930 return key;
1931}
1932
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001933static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001934 void *entry)
1935{
1936 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1937
1938 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1939 return true;
1940
1941 return false;
1942}
1943
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001944static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001945 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001946 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001947 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001948 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001949{
1950 struct perf_evsel *pos;
1951 struct perf_evsel_menu menu = {
1952 .b = {
1953 .entries = &evlist->entries,
1954 .refresh = ui_browser__list_head_refresh,
1955 .seek = ui_browser__list_head_seek,
1956 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001957 .filter = filter_group_entries,
1958 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001959 .priv = evlist,
1960 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001961 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001962 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001963 };
1964
1965 ui_helpline__push("Press ESC to exit");
1966
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001967 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001968 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001969 size_t line_len = strlen(ev_name) + 7;
1970
1971 if (menu.b.width < line_len)
1972 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001973 }
1974
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001975 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001976}
1977
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001978int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001979 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001980 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001981 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001982{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001983 int nr_entries = evlist->nr_entries;
1984
1985single_entry:
1986 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001987 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001988
1989 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001990 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001991 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001992 }
1993
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001994 if (symbol_conf.event_group) {
1995 struct perf_evsel *pos;
1996
1997 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001998 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001999 if (perf_evsel__is_group_leader(pos))
2000 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002001 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002002
2003 if (nr_entries == 1)
2004 goto single_entry;
2005 }
2006
2007 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002008 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002009}