blob: 26d5548b796e504a5525c372c191e067888c23ff [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 Kim42337a22014-08-12 17:16:06 +090013#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090014#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030015
16#include "../browser.h"
17#include "../helpline.h"
18#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020019#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030020#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020021#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030023struct hist_browser {
24 struct ui_browser b;
25 struct hists *hists;
26 struct hist_entry *he_selection;
27 struct map_symbol *selection;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +090028 struct hist_browser_timer *hbt;
Namhyung Kim01f00a12015-04-22 16:18:16 +090029 struct pstack *pstack;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030030 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030031 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020032 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090033 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090034 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090035 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030036};
37
Namhyung Kimf5951d52012-09-03 11:53:09 +090038extern void hist_browser__init_hpp(void);
39
Taeung Song1e378eb2014-10-07 16:13:15 +090040static int hists__browser_title(struct hists *hists,
41 struct hist_browser_timer *hbt,
42 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090043static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030044
Namhyung Kimc3b78952014-04-22 15:56:17 +090045static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090046 float min_pcnt);
47
Namhyung Kim268397c2014-04-22 14:49:31 +090048static bool hist_browser__has_filter(struct hist_browser *hb)
49{
50 return hists__has_filter(hb->hists) || hb->min_pcnt;
51}
52
He Kuang4fabf3d2015-03-12 15:21:49 +080053static int hist_browser__get_folding(struct hist_browser *browser)
54{
55 struct rb_node *nd;
56 struct hists *hists = browser->hists;
57 int unfolded_rows = 0;
58
59 for (nd = rb_first(&hists->entries);
60 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
61 nd = rb_next(nd)) {
62 struct hist_entry *he =
63 rb_entry(nd, struct hist_entry, rb_node);
64
65 if (he->ms.unfolded)
66 unfolded_rows += he->nr_rows;
67 }
68 return unfolded_rows;
69}
70
Namhyung Kimc3b78952014-04-22 15:56:17 +090071static u32 hist_browser__nr_entries(struct hist_browser *hb)
72{
73 u32 nr_entries;
74
75 if (hist_browser__has_filter(hb))
76 nr_entries = hb->nr_non_filtered_entries;
77 else
78 nr_entries = hb->hists->nr_entries;
79
He Kuang4fabf3d2015-03-12 15:21:49 +080080 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090081 return nr_entries + hb->nr_callchain_rows;
82}
83
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020084static void hist_browser__update_rows(struct hist_browser *hb)
85{
86 struct ui_browser *browser = &hb->b;
87 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
88
89 browser->rows = browser->height - header_offset;
90 /*
91 * Verify if we were at the last line and that line isn't
92 * visibe because we now show the header line(s).
93 */
94 index_row = browser->index - browser->top_idx;
95 if (index_row >= browser->rows)
96 browser->index -= index_row - browser->rows + 1;
97}
98
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030099static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300100{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300101 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
102
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300103 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300104 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
105 /*
106 * FIXME: Just keeping existing behaviour, but this really should be
107 * before updating browser->width, as it will invalidate the
108 * calculation above. Fix this and the fallout in another
109 * changeset.
110 */
111 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200112 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300113}
114
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300115static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
116{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200117 u16 header_offset = browser->show_headers ? 1 : 0;
118
119 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300120}
121
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300122static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300123{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900124 /*
125 * The hists__remove_entry_filter() already folds non-filtered
126 * entries so we can assume it has 0 callchain rows.
127 */
128 browser->nr_callchain_rows = 0;
129
Namhyung Kim268397c2014-04-22 14:49:31 +0900130 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900131 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300132 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300133 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300134}
135
136static char tree__folded_sign(bool unfolded)
137{
138 return unfolded ? '-' : '+';
139}
140
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300141static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300142{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300143 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144}
145
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300146static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300147{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300148 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300149}
150
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300151static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300152{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300153 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300154}
155
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300156static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300157{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300158 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300159}
160
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300161static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300162{
163 int n = 0;
164 struct rb_node *nd;
165
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300166 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300167 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
168 struct callchain_list *chain;
169 char folded_sign = ' '; /* No children */
170
171 list_for_each_entry(chain, &child->val, list) {
172 ++n;
173 /* We need this because we may not have children */
174 folded_sign = callchain_list__folded(chain);
175 if (folded_sign == '+')
176 break;
177 }
178
179 if (folded_sign == '-') /* Have children and they're unfolded */
180 n += callchain_node__count_rows_rb_tree(child);
181 }
182
183 return n;
184}
185
186static int callchain_node__count_rows(struct callchain_node *node)
187{
188 struct callchain_list *chain;
189 bool unfolded = false;
190 int n = 0;
191
192 list_for_each_entry(chain, &node->val, list) {
193 ++n;
194 unfolded = chain->ms.unfolded;
195 }
196
197 if (unfolded)
198 n += callchain_node__count_rows_rb_tree(node);
199
200 return n;
201}
202
203static int callchain__count_rows(struct rb_root *chain)
204{
205 struct rb_node *nd;
206 int n = 0;
207
208 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
209 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
210 n += callchain_node__count_rows(node);
211 }
212
213 return n;
214}
215
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300216static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300217{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300218 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200219 return false;
220
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300221 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300222 return false;
223
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300224 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300225 return true;
226}
227
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300228static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300230 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300231
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300232 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300233 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
234 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300235 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300236
237 list_for_each_entry(chain, &child->val, list) {
238 if (first) {
239 first = false;
240 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300241 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300242 } else
243 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300244 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300245 }
246
247 callchain_node__init_have_children_rb_tree(child);
248 }
249}
250
Namhyung Kima7444af2014-11-24 17:13:27 +0900251static void callchain_node__init_have_children(struct callchain_node *node,
252 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300253{
254 struct callchain_list *chain;
255
Namhyung Kima7444af2014-11-24 17:13:27 +0900256 chain = list_entry(node->val.next, struct callchain_list, list);
257 chain->ms.has_children = has_sibling;
258
Namhyung Kim82162b52014-08-13 15:02:41 +0900259 if (!list_empty(&node->val)) {
260 chain = list_entry(node->val.prev, struct callchain_list, list);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300261 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900262 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300263
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300264 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300265}
266
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300267static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300268{
Namhyung Kima7444af2014-11-24 17:13:27 +0900269 struct rb_node *nd = rb_first(root);
270 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300271
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300272 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300273 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900274 callchain_node__init_have_children(node, has_sibling);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300275 }
276}
277
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300278static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300279{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300280 if (!he->init_have_children) {
281 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
282 callchain__init_have_children(&he->sorted_chain);
283 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300284 }
285}
286
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300287static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300288{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300289 if (map_symbol__toggle_fold(browser->selection)) {
290 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300291
292 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900293 browser->b.nr_entries -= he->nr_rows;
294 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300295
296 if (he->ms.unfolded)
297 he->nr_rows = callchain__count_rows(&he->sorted_chain);
298 else
299 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900300
301 browser->b.nr_entries += he->nr_rows;
302 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300303
304 return true;
305 }
306
307 /* If it doesn't have children, no toggling performed */
308 return false;
309}
310
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300311static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300312{
313 int n = 0;
314 struct rb_node *nd;
315
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300316 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300317 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
318 struct callchain_list *chain;
319 bool has_children = false;
320
321 list_for_each_entry(chain, &child->val, list) {
322 ++n;
323 map_symbol__set_folding(&chain->ms, unfold);
324 has_children = chain->ms.has_children;
325 }
326
327 if (has_children)
328 n += callchain_node__set_folding_rb_tree(child, unfold);
329 }
330
331 return n;
332}
333
334static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
335{
336 struct callchain_list *chain;
337 bool has_children = false;
338 int n = 0;
339
340 list_for_each_entry(chain, &node->val, list) {
341 ++n;
342 map_symbol__set_folding(&chain->ms, unfold);
343 has_children = chain->ms.has_children;
344 }
345
346 if (has_children)
347 n += callchain_node__set_folding_rb_tree(node, unfold);
348
349 return n;
350}
351
352static int callchain__set_folding(struct rb_root *chain, bool unfold)
353{
354 struct rb_node *nd;
355 int n = 0;
356
357 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
358 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
359 n += callchain_node__set_folding(node, unfold);
360 }
361
362 return n;
363}
364
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300365static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300366{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300367 hist_entry__init_have_children(he);
368 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300369
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300370 if (he->ms.has_children) {
371 int n = callchain__set_folding(&he->sorted_chain, unfold);
372 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300373 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300374 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300375}
376
Namhyung Kimc3b78952014-04-22 15:56:17 +0900377static void
378__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300379{
380 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900381 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300382
Namhyung Kimc3b78952014-04-22 15:56:17 +0900383 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900384 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900385 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300386 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
387 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900388 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300389 }
390}
391
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300392static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300393{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900394 browser->nr_callchain_rows = 0;
395 __hist_browser__set_folding(browser, unfold);
396
397 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300398 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300399 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300400}
401
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200402static void ui_browser__warn_lost_events(struct ui_browser *browser)
403{
404 ui_browser__warning(browser, 4,
405 "Events are being lost, check IO/CPU overload!\n\n"
406 "You may want to run 'perf' using a RT scheduler policy:\n\n"
407 " perf top -r 80\n\n"
408 "Or reduce the sampling frequency.");
409}
410
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900411static int hist_browser__run(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300412{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300413 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300414 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900415 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900416 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300417
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300418 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900419 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300420
Taeung Song1e378eb2014-10-07 16:13:15 +0900421 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300422
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300423 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300424 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300425 return -1;
426
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300427 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300428 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300429
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300430 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900431 case K_TIMER: {
432 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900433 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900434
Namhyung Kimc3b78952014-04-22 15:56:17 +0900435 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900436 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900437
Namhyung Kimc3b78952014-04-22 15:56:17 +0900438 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900439 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200440
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300441 if (browser->hists->stats.nr_lost_warned !=
442 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
443 browser->hists->stats.nr_lost_warned =
444 browser->hists->stats.nr_events[PERF_RECORD_LOST];
445 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200446 }
447
Taeung Song1e378eb2014-10-07 16:13:15 +0900448 hists__browser_title(browser->hists,
449 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300450 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300451 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900452 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300453 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300454 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300455 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300456 struct hist_entry, rb_node);
457 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300458 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 -0300459 seq++, browser->b.nr_entries,
460 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300461 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300462 browser->b.index,
463 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300464 h->row_offset, h->nr_rows);
465 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300466 break;
467 case 'C':
468 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300469 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300470 break;
471 case 'E':
472 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300473 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300474 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200475 case 'H':
476 browser->show_headers = !browser->show_headers;
477 hist_browser__update_rows(browser);
478 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200479 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300480 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300481 break;
482 /* fall thru */
483 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300484 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300485 }
486 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300487out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300488 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300489 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300490}
491
Namhyung Kim39ee5332014-08-22 09:13:21 +0900492struct callchain_print_arg {
493 /* for hists browser */
494 off_t row_offset;
495 bool is_current_entry;
496
497 /* for file dump */
498 FILE *fp;
499 int printed;
500};
501
502typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
503 struct callchain_list *chain,
504 const char *str, int offset,
505 unsigned short row,
506 struct callchain_print_arg *arg);
507
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900508static void hist_browser__show_callchain_entry(struct hist_browser *browser,
509 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900510 const char *str, int offset,
511 unsigned short row,
512 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900513{
514 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900515 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300516 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900517
518 color = HE_COLORSET_NORMAL;
519 width = browser->b.width - (offset + 2);
520 if (ui_browser__is_current_entry(&browser->b, row)) {
521 browser->selection = &chain->ms;
522 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900523 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900524 }
525
526 ui_browser__set_color(&browser->b, color);
527 hist_browser__gotorc(browser, row, 0);
528 slsmg_write_nstring(" ", offset);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300529 slsmg_printf("%c", folded_sign);
530 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900531 slsmg_write_nstring(str, width);
532}
533
Namhyung Kim39ee5332014-08-22 09:13:21 +0900534static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
535 struct callchain_list *chain,
536 const char *str, int offset,
537 unsigned short row __maybe_unused,
538 struct callchain_print_arg *arg)
539{
540 char folded_sign = callchain_list__folded(chain);
541
542 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
543 folded_sign, str);
544}
545
546typedef bool (*check_output_full_fn)(struct hist_browser *browser,
547 unsigned short row);
548
549static bool hist_browser__check_output_full(struct hist_browser *browser,
550 unsigned short row)
551{
552 return browser->b.rows == row;
553}
554
555static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
556 unsigned short row __maybe_unused)
557{
558 return false;
559}
560
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300561#define LEVEL_OFFSET_STEP 3
562
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900563static int hist_browser__show_callchain(struct hist_browser *browser,
564 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900565 unsigned short row, u64 total,
566 print_callchain_entry_fn print,
567 struct callchain_print_arg *arg,
568 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300569{
570 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900571 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900572 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900573 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300574
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900575 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900576 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900577
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300578 while (node) {
579 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
580 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100581 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300582 struct callchain_list *chain;
583 char folded_sign = ' ';
584 int first = true;
585 int extra_offset = 0;
586
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300587 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300588 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300589 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590 bool was_first = first;
591
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300592 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300593 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900594 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300595 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300596
597 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900598 if (arg->row_offset != 0) {
599 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300600 goto do_next;
601 }
602
603 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300604 str = callchain_list__sym_name(chain, bf, sizeof(bf),
605 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900606
Namhyung Kim4087d112014-11-24 17:13:26 +0900607 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900608 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300609
610 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
611 str = "Not enough memory!";
612 else
613 str = alloc_str;
614 }
615
Namhyung Kim39ee5332014-08-22 09:13:21 +0900616 print(browser, chain, str, offset + extra_offset, row, arg);
617
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300618 free(alloc_str);
619
Namhyung Kim39ee5332014-08-22 09:13:21 +0900620 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300621 goto out;
622do_next:
623 if (folded_sign == '+')
624 break;
625 }
626
627 if (folded_sign == '-') {
628 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900629
630 if (callchain_param.mode == CHAIN_GRAPH_REL)
631 new_total = child->children_hit;
632 else
633 new_total = total;
634
635 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900636 new_level, row, new_total,
637 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300638 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900639 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900640 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300641 node = next;
642 }
643out:
644 return row - first_row;
645}
646
Namhyung Kim89701462013-01-22 18:09:38 +0900647struct hpp_arg {
648 struct ui_browser *b;
649 char folded_sign;
650 bool current_entry;
651};
652
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900653static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
654{
655 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900656 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900657 va_list args;
658 double percent;
659
660 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900661 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900662 percent = va_arg(args, double);
663 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900664
Namhyung Kim89701462013-01-22 18:09:38 +0900665 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900666
Namhyung Kimd6751072014-07-31 14:47:36 +0900667 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900668 slsmg_printf("%s", hpp->buf);
669
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900670 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900671 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900672}
673
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900674#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900675static u64 __hpp_get_##_field(struct hist_entry *he) \
676{ \
677 return he->stat._field; \
678} \
679 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100680static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900681hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100682 struct perf_hpp *hpp, \
683 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900684{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900685 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
686 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900687}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900688
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900689#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
690static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
691{ \
692 return he->stat_acc->_field; \
693} \
694 \
695static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900696hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900697 struct perf_hpp *hpp, \
698 struct hist_entry *he) \
699{ \
700 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900701 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900702 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900703 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900704 slsmg_printf("%s", hpp->buf); \
705 \
706 return ret; \
707 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900708 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
709 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900710}
711
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900712__HPP_COLOR_PERCENT_FN(overhead, period)
713__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
714__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
715__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
716__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900717__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900718
719#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900720#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900721
722void hist_browser__init_hpp(void)
723{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900724 perf_hpp__format[PERF_HPP__OVERHEAD].color =
725 hist_browser__hpp_color_overhead;
726 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
727 hist_browser__hpp_color_overhead_sys;
728 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
729 hist_browser__hpp_color_overhead_us;
730 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
731 hist_browser__hpp_color_overhead_guest_sys;
732 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
733 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900734 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
735 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900736}
737
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300738static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300739 struct hist_entry *entry,
740 unsigned short row)
741{
742 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200743 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900744 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300745 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300746 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300747 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300748 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200749 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300750
751 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300752 browser->he_selection = entry;
753 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300754 }
755
756 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300757 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300758 folded_sign = hist_entry__folded(entry);
759 }
760
761 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900762 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900763 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900764 .folded_sign = folded_sign,
765 .current_entry = current_entry,
766 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900767 struct perf_hpp hpp = {
768 .buf = s,
769 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900770 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900771 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300772
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300773 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900774
Jiri Olsa12400052012-10-13 00:06:16 +0200775 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900776 if (perf_hpp__should_skip(fmt))
777 continue;
778
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900779 if (current_entry && browser->b.navkeypressed) {
780 ui_browser__set_color(&browser->b,
781 HE_COLORSET_SELECTED);
782 } else {
783 ui_browser__set_color(&browser->b,
784 HE_COLORSET_NORMAL);
785 }
786
787 if (first) {
788 if (symbol_conf.use_callchain) {
789 slsmg_printf("%c ", folded_sign);
790 width -= 2;
791 }
792 first = false;
793 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900794 slsmg_printf(" ");
795 width -= 2;
796 }
797
Jiri Olsa12400052012-10-13 00:06:16 +0200798 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100799 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900800 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100801 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900802 slsmg_printf("%s", s);
803 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300804 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200805
806 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300807 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200808 width += 1;
809
Namhyung Kim26d8b332014-03-03 16:16:20 +0900810 slsmg_write_nstring("", width);
811
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300812 ++row;
813 ++printed;
814 } else
815 --row_offset;
816
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300817 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900818 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900819 struct callchain_print_arg arg = {
820 .row_offset = row_offset,
821 .is_current_entry = current_entry,
822 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900823
Namhyung Kim4087d112014-11-24 17:13:26 +0900824 if (callchain_param.mode == CHAIN_GRAPH_REL) {
825 if (symbol_conf.cumulate_callchain)
826 total = entry->stat_acc->period;
827 else
828 total = entry->stat.period;
829 }
830
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900831 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900832 &entry->sorted_chain, 1, row, total,
833 hist_browser__show_callchain_entry, &arg,
834 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900835
Namhyung Kim39ee5332014-08-22 09:13:21 +0900836 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300837 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300838 }
839
840 return printed;
841}
842
Jiri Olsa81a888f2014-06-14 15:44:52 +0200843static int advance_hpp_check(struct perf_hpp *hpp, int inc)
844{
845 advance_hpp(hpp, inc);
846 return hpp->size <= 0;
847}
848
849static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
850{
851 struct perf_hpp dummy_hpp = {
852 .buf = buf,
853 .size = size,
854 };
855 struct perf_hpp_fmt *fmt;
856 size_t ret = 0;
857
858 if (symbol_conf.use_callchain) {
859 ret = scnprintf(buf, size, " ");
860 if (advance_hpp_check(&dummy_hpp, ret))
861 return ret;
862 }
863
864 perf_hpp__for_each_format(fmt) {
865 if (perf_hpp__should_skip(fmt))
866 continue;
867
Jiri Olsa81a888f2014-06-14 15:44:52 +0200868 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
869 if (advance_hpp_check(&dummy_hpp, ret))
870 break;
871
872 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
873 if (advance_hpp_check(&dummy_hpp, ret))
874 break;
875 }
876
877 return ret;
878}
879
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200880static void hist_browser__show_headers(struct hist_browser *browser)
881{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200882 char headers[1024];
883
884 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200885 ui_browser__gotorc(&browser->b, 0, 0);
886 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200887 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200888}
889
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300890static void ui_browser__hists_init_top(struct ui_browser *browser)
891{
892 if (browser->top == NULL) {
893 struct hist_browser *hb;
894
895 hb = container_of(browser, struct hist_browser, b);
896 browser->top = rb_first(&hb->hists->entries);
897 }
898}
899
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300900static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300901{
902 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200903 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300905 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300906
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200907 if (hb->show_headers) {
908 hist_browser__show_headers(hb);
909 header_offset = 1;
910 }
911
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300912 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300913
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300914 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300915 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900916 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300917
918 if (h->filtered)
919 continue;
920
Namhyung Kim14135662013-10-31 10:17:39 +0900921 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900922 if (percent < hb->min_pcnt)
923 continue;
924
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300925 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300926 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300927 break;
928 }
929
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200930 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300931}
932
Namhyung Kim064f1982013-05-14 11:09:04 +0900933static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900934 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300935{
936 while (nd != NULL) {
937 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900938 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900939
Namhyung Kimc0f15272014-04-16 11:16:33 +0900940 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300941 return nd;
942
943 nd = rb_next(nd);
944 }
945
946 return NULL;
947}
948
Namhyung Kim064f1982013-05-14 11:09:04 +0900949static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900950 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300951{
952 while (nd != NULL) {
953 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900954 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900955
956 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300957 return nd;
958
959 nd = rb_prev(nd);
960 }
961
962 return NULL;
963}
964
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300965static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300966 off_t offset, int whence)
967{
968 struct hist_entry *h;
969 struct rb_node *nd;
970 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900971 struct hist_browser *hb;
972
973 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300974
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300975 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300976 return;
977
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300978 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300979
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300980 switch (whence) {
981 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900982 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900983 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300984 break;
985 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300986 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300987 goto do_offset;
988 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900989 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900990 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300991 first = false;
992 break;
993 default:
994 return;
995 }
996
997 /*
998 * Moves not relative to the first visible entry invalidates its
999 * row_offset:
1000 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001001 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001002 h->row_offset = 0;
1003
1004 /*
1005 * Here we have to check if nd is expanded (+), if it is we can't go
1006 * the next top level hist_entry, instead we must compute an offset of
1007 * what _not_ to show and not change the first visible entry.
1008 *
1009 * This offset increments when we are going from top to bottom and
1010 * decreases when we're going from bottom to top.
1011 *
1012 * As we don't have backpointers to the top level in the callchains
1013 * structure, we need to always print the whole hist_entry callchain,
1014 * skipping the first ones that are before the first visible entry
1015 * and stop when we printed enough lines to fill the screen.
1016 */
1017do_offset:
1018 if (offset > 0) {
1019 do {
1020 h = rb_entry(nd, struct hist_entry, rb_node);
1021 if (h->ms.unfolded) {
1022 u16 remaining = h->nr_rows - h->row_offset;
1023 if (offset > remaining) {
1024 offset -= remaining;
1025 h->row_offset = 0;
1026 } else {
1027 h->row_offset += offset;
1028 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001029 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001030 break;
1031 }
1032 }
Namhyung Kim14135662013-10-31 10:17:39 +09001033 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001034 if (nd == NULL)
1035 break;
1036 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001037 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001038 } while (offset != 0);
1039 } else if (offset < 0) {
1040 while (1) {
1041 h = rb_entry(nd, struct hist_entry, rb_node);
1042 if (h->ms.unfolded) {
1043 if (first) {
1044 if (-offset > h->row_offset) {
1045 offset += h->row_offset;
1046 h->row_offset = 0;
1047 } else {
1048 h->row_offset += offset;
1049 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001050 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001051 break;
1052 }
1053 } else {
1054 if (-offset > h->nr_rows) {
1055 offset += h->nr_rows;
1056 h->row_offset = 0;
1057 } else {
1058 h->row_offset = h->nr_rows + offset;
1059 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001060 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001061 break;
1062 }
1063 }
1064 }
1065
Namhyung Kim14135662013-10-31 10:17:39 +09001066 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001067 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001068 if (nd == NULL)
1069 break;
1070 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001071 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001072 if (offset == 0) {
1073 /*
1074 * Last unfiltered hist_entry, check if it is
1075 * unfolded, if it is then we should have
1076 * row_offset at its last entry.
1077 */
1078 h = rb_entry(nd, struct hist_entry, rb_node);
1079 if (h->ms.unfolded)
1080 h->row_offset = h->nr_rows;
1081 break;
1082 }
1083 first = false;
1084 }
1085 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001086 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001087 h = rb_entry(nd, struct hist_entry, rb_node);
1088 h->row_offset = 0;
1089 }
1090}
1091
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001092static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001093 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001094{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001095 u64 total = hists__total_period(he->hists);
1096 struct callchain_print_arg arg = {
1097 .fp = fp,
1098 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001099
Namhyung Kim39ee5332014-08-22 09:13:21 +09001100 if (symbol_conf.cumulate_callchain)
1101 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001102
Namhyung Kim39ee5332014-08-22 09:13:21 +09001103 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1104 hist_browser__fprintf_callchain_entry, &arg,
1105 hist_browser__check_dump_full);
1106 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001107}
1108
1109static int hist_browser__fprintf_entry(struct hist_browser *browser,
1110 struct hist_entry *he, FILE *fp)
1111{
1112 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001113 int printed = 0;
1114 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001115 struct perf_hpp hpp = {
1116 .buf = s,
1117 .size = sizeof(s),
1118 };
1119 struct perf_hpp_fmt *fmt;
1120 bool first = true;
1121 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001122
1123 if (symbol_conf.use_callchain)
1124 folded_sign = hist_entry__folded(he);
1125
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001126 if (symbol_conf.use_callchain)
1127 printed += fprintf(fp, "%c ", folded_sign);
1128
Namhyung Kim26d8b332014-03-03 16:16:20 +09001129 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001130 if (perf_hpp__should_skip(fmt))
1131 continue;
1132
Namhyung Kim26d8b332014-03-03 16:16:20 +09001133 if (!first) {
1134 ret = scnprintf(hpp.buf, hpp.size, " ");
1135 advance_hpp(&hpp, ret);
1136 } else
1137 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001138
Namhyung Kim26d8b332014-03-03 16:16:20 +09001139 ret = fmt->entry(fmt, &hpp, he);
1140 advance_hpp(&hpp, ret);
1141 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001142 printed += fprintf(fp, "%s\n", rtrim(s));
1143
1144 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001145 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001146
1147 return printed;
1148}
1149
1150static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1151{
Namhyung Kim064f1982013-05-14 11:09:04 +09001152 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001153 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001154 int printed = 0;
1155
1156 while (nd) {
1157 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1158
1159 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001160 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001161 }
1162
1163 return printed;
1164}
1165
1166static int hist_browser__dump(struct hist_browser *browser)
1167{
1168 char filename[64];
1169 FILE *fp;
1170
1171 while (1) {
1172 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1173 if (access(filename, F_OK))
1174 break;
1175 /*
1176 * XXX: Just an arbitrary lazy upper limit
1177 */
1178 if (++browser->print_seq == 8192) {
1179 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1180 return -1;
1181 }
1182 }
1183
1184 fp = fopen(filename, "w");
1185 if (fp == NULL) {
1186 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001187 const char *err = strerror_r(errno, bf, sizeof(bf));
1188 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001189 return -1;
1190 }
1191
1192 ++browser->print_seq;
1193 hist_browser__fprintf(browser, fp);
1194 fclose(fp);
1195 ui_helpline__fpush("%s written!", filename);
1196
1197 return 0;
1198}
1199
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001200static struct hist_browser *hist_browser__new(struct hists *hists,
1201 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001203 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001205 if (browser) {
1206 browser->hists = hists;
1207 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001208 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001209 browser->b.seek = ui_browser__hists_seek;
1210 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001211 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001212 browser->hbt = hbt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001213 }
1214
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001215 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001216}
1217
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001218static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001220 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001221}
1222
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001223static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001224{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001225 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001226}
1227
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001228static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001229{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001230 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001231}
1232
Taeung Song1e378eb2014-10-07 16:13:15 +09001233/* Check whether the browser is for 'top' or 'report' */
1234static inline bool is_report_browser(void *timer)
1235{
1236 return timer == NULL;
1237}
1238
1239static int hists__browser_title(struct hists *hists,
1240 struct hist_browser_timer *hbt,
1241 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001242{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001243 char unit;
1244 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001245 const struct dso *dso = hists->dso_filter;
1246 const struct thread *thread = hists->thread_filter;
1247 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1248 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001249 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001250 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001251 char buf[512];
1252 size_t buflen = sizeof(buf);
1253
Namhyung Kimf2148332014-01-14 11:52:48 +09001254 if (symbol_conf.filter_relative) {
1255 nr_samples = hists->stats.nr_non_filtered_samples;
1256 nr_events = hists->stats.total_non_filtered_period;
1257 }
1258
Namhyung Kim759ff492013-03-05 14:53:26 +09001259 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001260 struct perf_evsel *pos;
1261
1262 perf_evsel__group_desc(evsel, buf, buflen);
1263 ev_name = buf;
1264
1265 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001266 struct hists *pos_hists = evsel__hists(pos);
1267
Namhyung Kimf2148332014-01-14 11:52:48 +09001268 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001269 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1270 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001271 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001272 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1273 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001274 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001275 }
1276 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001277
Ashay Ranecc6862802012-04-05 21:01:01 -05001278 nr_samples = convert_unit(nr_samples, &unit);
1279 printed = scnprintf(bf, size,
Tom Huynhe641f692014-12-02 11:37:22 -06001280 "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
Ashay Ranecc6862802012-04-05 21:01:01 -05001281 nr_samples, unit, ev_name, nr_events);
1282
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001283
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001284 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001285 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001286 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001287 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001288 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001289 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001290 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001291 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001292 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001293 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001294 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001295 if (!is_report_browser(hbt)) {
1296 struct perf_top *top = hbt->arg;
1297
1298 if (top->zero)
1299 printed += scnprintf(bf + printed, size - printed, " [z]");
1300 }
1301
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001302 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001303}
1304
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001305static inline void free_popup_options(char **options, int n)
1306{
1307 int i;
1308
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001309 for (i = 0; i < n; ++i)
1310 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001311}
1312
Feng Tang341487ab2013-02-03 14:38:20 +08001313/*
1314 * Only runtime switching of perf data file will make "input_name" point
1315 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1316 * whether we need to call free() for current "input_name" during the switch.
1317 */
1318static bool is_input_name_malloced = false;
1319
1320static int switch_data_file(void)
1321{
1322 char *pwd, *options[32], *abs_path[32], *tmp;
1323 DIR *pwd_dir;
1324 int nr_options = 0, choice = -1, ret = -1;
1325 struct dirent *dent;
1326
1327 pwd = getenv("PWD");
1328 if (!pwd)
1329 return ret;
1330
1331 pwd_dir = opendir(pwd);
1332 if (!pwd_dir)
1333 return ret;
1334
1335 memset(options, 0, sizeof(options));
1336 memset(options, 0, sizeof(abs_path));
1337
1338 while ((dent = readdir(pwd_dir))) {
1339 char path[PATH_MAX];
1340 u64 magic;
1341 char *name = dent->d_name;
1342 FILE *file;
1343
1344 if (!(dent->d_type == DT_REG))
1345 continue;
1346
1347 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1348
1349 file = fopen(path, "r");
1350 if (!file)
1351 continue;
1352
1353 if (fread(&magic, 1, 8, file) < 8)
1354 goto close_file_and_continue;
1355
1356 if (is_perf_magic(magic)) {
1357 options[nr_options] = strdup(name);
1358 if (!options[nr_options])
1359 goto close_file_and_continue;
1360
1361 abs_path[nr_options] = strdup(path);
1362 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001363 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001364 ui__warning("Can't search all data files due to memory shortage.\n");
1365 fclose(file);
1366 break;
1367 }
1368
1369 nr_options++;
1370 }
1371
1372close_file_and_continue:
1373 fclose(file);
1374 if (nr_options >= 32) {
1375 ui__warning("Too many perf data files in PWD!\n"
1376 "Only the first 32 files will be listed.\n");
1377 break;
1378 }
1379 }
1380 closedir(pwd_dir);
1381
1382 if (nr_options) {
1383 choice = ui__popup_menu(nr_options, options);
1384 if (choice < nr_options && choice >= 0) {
1385 tmp = strdup(abs_path[choice]);
1386 if (tmp) {
1387 if (is_input_name_malloced)
1388 free((void *)input_name);
1389 input_name = tmp;
1390 is_input_name_malloced = true;
1391 ret = 0;
1392 } else
1393 ui__warning("Data switch failed due to memory shortage!\n");
1394 }
1395 }
1396
1397 free_popup_options(options, nr_options);
1398 free_popup_options(abs_path, nr_options);
1399 return ret;
1400}
1401
Namhyung Kim112f7612014-04-22 14:05:35 +09001402static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001403{
1404 u64 nr_entries = 0;
1405 struct rb_node *nd = rb_first(&hb->hists->entries);
1406
Namhyung Kim268397c2014-04-22 14:49:31 +09001407 if (hb->min_pcnt == 0) {
1408 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1409 return;
1410 }
1411
Namhyung Kim14135662013-10-31 10:17:39 +09001412 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001413 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001414 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001415 }
1416
Namhyung Kim112f7612014-04-22 14:05:35 +09001417 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001418}
Feng Tang341487ab2013-02-03 14:38:20 +08001419
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001420static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001421 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001422 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001423 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001424 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001425 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001426{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001427 struct hists *hists = evsel__hists(evsel);
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001428 struct hist_browser *browser = hist_browser__new(hists, hbt);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001429 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001430#define MAX_OPTIONS 16
1431 char *options[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001432 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001433 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001434 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001435 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001436 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001437 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001438
Namhyung Kime8e684a2013-12-26 14:37:58 +09001439#define HIST_BROWSER_HELP_COMMON \
1440 "h/?/F1 Show this window\n" \
1441 "UP/DOWN/PGUP\n" \
1442 "PGDN/SPACE Navigate\n" \
1443 "q/ESC/CTRL+C Exit browser\n\n" \
1444 "For multiple event sessions:\n\n" \
1445 "TAB/UNTAB Switch events\n\n" \
1446 "For symbolic views (--sort has sym):\n\n" \
1447 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1448 "<- Zoom out\n" \
1449 "a Annotate current symbol\n" \
1450 "C Collapse all callchains\n" \
1451 "d Zoom into current DSO\n" \
1452 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001453 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001454 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001455
1456 /* help messages are sorted by lexical order of the hotkey */
1457 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001458 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001459 "P Print histograms to perf.hist.N\n"
1460 "r Run available scripts\n"
1461 "s Switch to another data file in PWD\n"
1462 "t Zoom into current Thread\n"
1463 "V Verbose (DSO names in callchains, etc)\n"
1464 "/ Filter symbol by name";
1465 const char top_help[] = HIST_BROWSER_HELP_COMMON
1466 "P Print histograms to perf.hist.N\n"
1467 "t Zoom into current Thread\n"
1468 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001469 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001470 "/ Filter symbol by name";
1471
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001472 if (browser == NULL)
1473 return -1;
1474
Namhyung Kim064f1982013-05-14 11:09:04 +09001475 if (min_pcnt) {
1476 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001477 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001478 }
1479
Namhyung Kim01f00a12015-04-22 16:18:16 +09001480 browser->pstack = pstack__new(2);
1481 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001482 goto out;
1483
1484 ui_helpline__push(helpline);
1485
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001486 memset(options, 0, sizeof(options));
1487
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001488 perf_hpp__for_each_format(fmt)
1489 perf_hpp__reset_width(fmt, hists);
1490
Namhyung Kim5b591662014-07-31 14:47:38 +09001491 if (symbol_conf.col_width_list_str)
1492 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1493
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001494 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001495 struct thread *thread = NULL;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001496 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001497 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001498 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001499 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001500 int scripts_comm = -2, scripts_symbol = -2,
1501 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001502
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001503 nr_options = 0;
1504
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001505 key = hist_browser__run(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001506
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001507 if (browser->he_selection != NULL) {
1508 thread = hist_browser__selected_thread(browser);
1509 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1510 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001511 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001512 case K_TAB:
1513 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001514 if (nr_events == 1)
1515 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001516 /*
1517 * Exit the browser, let hists__browser_tree
1518 * go to the next or previous
1519 */
1520 goto out_free_stack;
1521 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001522 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001523 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001524 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001525 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001526 continue;
1527 }
1528
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001529 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001530 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001531 browser->selection->map->dso->annotate_warned)
1532 continue;
1533 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001534 case 'P':
1535 hist_browser__dump(browser);
1536 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001537 case 'd':
1538 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001539 case 'V':
1540 browser->show_dso = !browser->show_dso;
1541 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001542 case 't':
1543 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001544 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001545 if (ui_browser__input_window("Symbol to show",
1546 "Please enter the name of symbol you want to see",
1547 buf, "ENTER: OK, ESC: Cancel",
1548 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001549 hists->symbol_filter_str = *buf ? buf : NULL;
1550 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001551 hist_browser__reset(browser);
1552 }
1553 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001554 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001555 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001556 goto do_scripts;
1557 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001558 case 's':
1559 if (is_report_browser(hbt))
1560 goto do_data_switch;
1561 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001562 case 'i':
1563 /* env->arch is NULL for live-mode (i.e. perf top) */
1564 if (env->arch)
1565 tui__header_window(env);
1566 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001567 case 'F':
1568 symbol_conf.filter_relative ^= 1;
1569 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001570 case 'z':
1571 if (!is_report_browser(hbt)) {
1572 struct perf_top *top = hbt->arg;
1573
1574 top->zero = !top->zero;
1575 }
1576 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001577 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001578 case 'h':
1579 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001580 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001581 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001582 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001583 case K_ENTER:
1584 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001585 /* menu */
1586 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001587 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001588 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001589
Namhyung Kim01f00a12015-04-22 16:18:16 +09001590 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001591 /*
1592 * Go back to the perf_evsel_menu__run or other user
1593 */
1594 if (left_exits)
1595 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001596 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001597 }
Namhyung Kim01f00a12015-04-22 16:18:16 +09001598 top = pstack__pop(browser->pstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001599 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001600 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001601 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001602 goto zoom_out_thread;
1603 continue;
1604 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001605 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001606 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001607 !ui_browser__dialog_yesno(&browser->b,
1608 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001609 continue;
1610 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001611 case 'q':
1612 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001613 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001614 default:
1615 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001616 }
1617
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001618 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001619 goto add_exit_option;
1620
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001621 if (browser->selection == NULL)
1622 goto skip_annotation;
1623
Namhyung Kim55369fc2013-04-01 20:35:20 +09001624 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001625 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001626
1627 if (bi == NULL)
1628 goto skip_annotation;
1629
1630 if (bi->from.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001631 !bi->from.map->dso->annotate_warned &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001632 asprintf(&options[nr_options], "Annotate %s", bi->from.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001633 annotate_f = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001634 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001635
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001636 if (bi->to.sym != NULL &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001637 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001638 (bi->to.sym != bi->from.sym ||
1639 bi->to.map->dso != bi->from.map->dso) &&
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001640 asprintf(&options[nr_options], "Annotate %s", bi->to.sym->name) > 0) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001641 annotate_t = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001642 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001643 } else {
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001644 if (browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001645 !browser->selection->map->dso->annotate_warned) {
1646 struct annotation *notes;
1647
1648 notes = symbol__annotation(browser->selection->sym);
1649
1650 if (notes->src &&
1651 asprintf(&options[nr_options], "Annotate %s",
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001652 browser->selection->sym->name) > 0) {
Jiri Olsad7553302014-06-15 10:22:15 +02001653 annotate = nr_options++;
Arnaldo Carvalho de Melo446fb962015-03-16 17:46:57 -03001654 }
Jiri Olsad7553302014-06-15 10:22:15 +02001655 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001656 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001657skip_annotation:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001658 if (thread != NULL &&
1659 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001660 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001661 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001662 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001663 zoom_thread = nr_options++;
1664
1665 if (dso != NULL &&
1666 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001667 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001668 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1669 zoom_dso = nr_options++;
1670
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001671 if (browser->selection != NULL &&
1672 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001673 asprintf(&options[nr_options], "Browse map details") > 0)
1674 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001675
1676 /* perf script support */
1677 if (browser->he_selection) {
1678 struct symbol *sym;
1679
1680 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001681 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001682 scripts_comm = nr_options++;
1683
1684 sym = browser->he_selection->ms.sym;
1685 if (sym && sym->namelen &&
1686 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1687 sym->name) > 0)
1688 scripts_symbol = nr_options++;
1689 }
1690
1691 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1692 scripts_all = nr_options++;
1693
Feng Tang341487ab2013-02-03 14:38:20 +08001694 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1695 "Switch to another data file in PWD") > 0)
1696 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001697add_exit_option:
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001698 if (asprintf(&options[nr_options], "Exit") > 0)
1699 nr_options++;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001700retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001701 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001702
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001703 if (choice == nr_options - 1)
1704 break;
1705
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001706 if (choice == -1) {
1707 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001708 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001709 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001710
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001711 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001712 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001713 struct annotation *notes;
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001714 struct map_symbol ms;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001715 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001716do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001717 if (!objdump_path && perf_session_env__lookup_objdump(env))
1718 continue;
1719
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001720 he = hist_browser__selected_entry(browser);
1721 if (he == NULL)
1722 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001723
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001724 if (choice == annotate_f) {
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001725 ms.map = he->branch_info->from.map;
1726 ms.sym = he->branch_info->from.sym;
1727 } else if (choice == annotate_t) {
1728 ms.map = he->branch_info->to.map;
1729 ms.sym = he->branch_info->to.sym;
1730 } else {
1731 ms = *browser->selection;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001732 }
1733
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001734 notes = symbol__annotation(ms.sym);
Jiri Olsad7553302014-06-15 10:22:15 +02001735 if (!notes->src)
1736 continue;
1737
Arnaldo Carvalho de Melod5dbc512015-03-17 18:27:28 -03001738 err = map_symbol__tui_annotate(&ms, evsel, hbt);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001739 /*
1740 * offer option to annotate the other branch source or target
1741 * (if they exists) when returning from annotate
1742 */
1743 if ((err == 'q' || err == CTRL('c'))
1744 && annotate_t != -2 && annotate_f != -2)
1745 goto retry_popup_menu;
1746
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001747 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001748 if (err)
1749 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001750
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001751 } else if (choice == browse_map)
1752 map__browse(browser->selection->map);
1753 else if (choice == zoom_dso) {
1754zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001755 if (browser->hists->dso_filter) {
Namhyung Kim01f00a12015-04-22 16:18:16 +09001756 pstack__remove(browser->pstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757zoom_out_dso:
1758 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001759 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001760 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761 } else {
1762 if (dso == NULL)
1763 continue;
1764 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1765 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001766 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001767 perf_hpp__set_elide(HISTC_DSO, true);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001768 pstack__push(browser->pstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001770 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001771 hist_browser__reset(browser);
1772 } else if (choice == zoom_thread) {
1773zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001774 if (browser->hists->thread_filter) {
Namhyung Kim01f00a12015-04-22 16:18:16 +09001775 pstack__remove(browser->pstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001776zoom_out_thread:
1777 ui_helpline__pop();
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001778 thread__zput(browser->hists->thread_filter);
Jiri Olsaf2998422014-05-23 17:15:47 +02001779 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001780 } else {
1781 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001782 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001783 thread->tid);
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001784 browser->hists->thread_filter = thread__get(thread);
Jiri Olsaf2998422014-05-23 17:15:47 +02001785 perf_hpp__set_elide(HISTC_THREAD, false);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001786 pstack__push(browser->pstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001787 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001788 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001789 hist_browser__reset(browser);
1790 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001791 /* perf scripts support */
1792 else if (choice == scripts_all || choice == scripts_comm ||
1793 choice == scripts_symbol) {
1794do_scripts:
1795 memset(script_opt, 0, 64);
1796
1797 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001798 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001799
1800 if (choice == scripts_symbol)
1801 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1802
1803 script_browse(script_opt);
1804 }
Feng Tang341487ab2013-02-03 14:38:20 +08001805 /* Switch to another data file */
1806 else if (choice == switch_data) {
1807do_data_switch:
1808 if (!switch_data_file()) {
1809 key = K_SWITCH_INPUT_DATA;
1810 break;
1811 } else
1812 ui__warning("Won't switch the data files due to\n"
1813 "no valid data file get selected!\n");
1814 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001815 }
1816out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09001817 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001818out:
1819 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001820 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001821 return key;
1822}
1823
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001824struct perf_evsel_menu {
1825 struct ui_browser b;
1826 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001827 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001828 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001829 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001830};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001831
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001832static void perf_evsel_menu__write(struct ui_browser *browser,
1833 void *entry, int row)
1834{
1835 struct perf_evsel_menu *menu = container_of(browser,
1836 struct perf_evsel_menu, b);
1837 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001838 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001839 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001840 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001841 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001842 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001843 const char *warn = " ";
1844 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001845
1846 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1847 HE_COLORSET_NORMAL);
1848
Namhyung Kim759ff492013-03-05 14:53:26 +09001849 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001850 struct perf_evsel *pos;
1851
1852 ev_name = perf_evsel__group_name(evsel);
1853
1854 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001855 struct hists *pos_hists = evsel__hists(pos);
1856 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001857 }
1858 }
1859
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001860 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001861 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001862 unit, unit == ' ' ? "" : " ", ev_name);
1863 slsmg_printf("%s", bf);
1864
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001865 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001866 if (nr_events != 0) {
1867 menu->lost_events = true;
1868 if (!current_entry)
1869 ui_browser__set_color(browser, HE_COLORSET_TOP);
1870 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001871 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1872 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001873 warn = bf;
1874 }
1875
1876 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001877
1878 if (current_entry)
1879 menu->selection = evsel;
1880}
1881
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001882static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1883 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001884 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001885{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001886 struct perf_evlist *evlist = menu->b.priv;
1887 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001888 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001889 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001890 int key;
1891
1892 if (ui_browser__show(&menu->b, title,
1893 "ESC: exit, ENTER|->: Browse histograms") < 0)
1894 return -1;
1895
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001896 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001897 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001898
1899 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001900 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001901 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001902
1903 if (!menu->lost_events_warned && menu->lost_events) {
1904 ui_browser__warn_lost_events(&menu->b);
1905 menu->lost_events_warned = true;
1906 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001907 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001908 case K_RIGHT:
1909 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001910 if (!menu->selection)
1911 continue;
1912 pos = menu->selection;
1913browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001914 perf_evlist__set_selected(evlist, pos);
1915 /*
1916 * Give the calling tool a chance to populate the non
1917 * default evsel resorted hists tree.
1918 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001919 if (hbt)
1920 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001921 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001922 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001923 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001924 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001925 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001926 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001927 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001928 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001929 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001930 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001931 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001932 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001933 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001934 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001935 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001936 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001937 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001938 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001939 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001940 if (!ui_browser__dialog_yesno(&menu->b,
1941 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001942 continue;
1943 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001944 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001945 case 'q':
1946 case CTRL('c'):
1947 goto out;
1948 default:
1949 continue;
1950 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001951 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001952 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001953 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001954 if (!ui_browser__dialog_yesno(&menu->b,
1955 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001956 continue;
1957 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001958 case 'q':
1959 case CTRL('c'):
1960 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001961 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001962 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001963 }
1964 }
1965
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001966out:
1967 ui_browser__hide(&menu->b);
1968 return key;
1969}
1970
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001971static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001972 void *entry)
1973{
1974 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1975
1976 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1977 return true;
1978
1979 return false;
1980}
1981
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001982static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001983 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001984 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001985 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001986 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001987{
1988 struct perf_evsel *pos;
1989 struct perf_evsel_menu menu = {
1990 .b = {
1991 .entries = &evlist->entries,
1992 .refresh = ui_browser__list_head_refresh,
1993 .seek = ui_browser__list_head_seek,
1994 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001995 .filter = filter_group_entries,
1996 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001997 .priv = evlist,
1998 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001999 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002000 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002001 };
2002
2003 ui_helpline__push("Press ESC to exit");
2004
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002005 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002006 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002007 size_t line_len = strlen(ev_name) + 7;
2008
2009 if (menu.b.width < line_len)
2010 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002011 }
2012
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002013 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002014}
2015
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002016int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002017 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002018 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002019 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002020{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002021 int nr_entries = evlist->nr_entries;
2022
2023single_entry:
2024 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002025 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002026
2027 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002028 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002029 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002030 }
2031
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002032 if (symbol_conf.event_group) {
2033 struct perf_evsel *pos;
2034
2035 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002036 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002037 if (perf_evsel__is_group_leader(pos))
2038 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002039 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002040
2041 if (nr_entries == 1)
2042 goto single_entry;
2043 }
2044
2045 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002046 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002047}