blob: 0847623f42e08c1e2ee8d5922dadc8c400da6e48 [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;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030029 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030030 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020031 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090032 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090033 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090034 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030035};
36
Namhyung Kimf5951d52012-09-03 11:53:09 +090037extern void hist_browser__init_hpp(void);
38
Taeung Song1e378eb2014-10-07 16:13:15 +090039static int hists__browser_title(struct hists *hists,
40 struct hist_browser_timer *hbt,
41 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090042static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030043
Namhyung Kimc3b78952014-04-22 15:56:17 +090044static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090045 float min_pcnt);
46
Namhyung Kim268397c2014-04-22 14:49:31 +090047static bool hist_browser__has_filter(struct hist_browser *hb)
48{
49 return hists__has_filter(hb->hists) || hb->min_pcnt;
50}
51
He Kuang4fabf3d2015-03-12 15:21:49 +080052static int hist_browser__get_folding(struct hist_browser *browser)
53{
54 struct rb_node *nd;
55 struct hists *hists = browser->hists;
56 int unfolded_rows = 0;
57
58 for (nd = rb_first(&hists->entries);
59 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
60 nd = rb_next(nd)) {
61 struct hist_entry *he =
62 rb_entry(nd, struct hist_entry, rb_node);
63
64 if (he->ms.unfolded)
65 unfolded_rows += he->nr_rows;
66 }
67 return unfolded_rows;
68}
69
Namhyung Kimc3b78952014-04-22 15:56:17 +090070static u32 hist_browser__nr_entries(struct hist_browser *hb)
71{
72 u32 nr_entries;
73
74 if (hist_browser__has_filter(hb))
75 nr_entries = hb->nr_non_filtered_entries;
76 else
77 nr_entries = hb->hists->nr_entries;
78
He Kuang4fabf3d2015-03-12 15:21:49 +080079 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090080 return nr_entries + hb->nr_callchain_rows;
81}
82
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020083static void hist_browser__update_rows(struct hist_browser *hb)
84{
85 struct ui_browser *browser = &hb->b;
86 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
87
88 browser->rows = browser->height - header_offset;
89 /*
90 * Verify if we were at the last line and that line isn't
91 * visibe because we now show the header line(s).
92 */
93 index_row = browser->index - browser->top_idx;
94 if (index_row >= browser->rows)
95 browser->index -= index_row - browser->rows + 1;
96}
97
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030098static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030099{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300100 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
101
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300102 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300103 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
104 /*
105 * FIXME: Just keeping existing behaviour, but this really should be
106 * before updating browser->width, as it will invalidate the
107 * calculation above. Fix this and the fallout in another
108 * changeset.
109 */
110 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200111 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300112}
113
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300114static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
115{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200116 u16 header_offset = browser->show_headers ? 1 : 0;
117
118 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300119}
120
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300121static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300122{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900123 /*
124 * The hists__remove_entry_filter() already folds non-filtered
125 * entries so we can assume it has 0 callchain rows.
126 */
127 browser->nr_callchain_rows = 0;
128
Namhyung Kim268397c2014-04-22 14:49:31 +0900129 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900130 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300131 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133}
134
135static char tree__folded_sign(bool unfolded)
136{
137 return unfolded ? '-' : '+';
138}
139
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300140static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300141{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300142 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143}
144
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300145static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300146{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148}
149
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300150static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300151{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300152 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300153}
154
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300155static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300156{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300157 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300158}
159
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300160static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300161{
162 int n = 0;
163 struct rb_node *nd;
164
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300165 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300166 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
167 struct callchain_list *chain;
168 char folded_sign = ' '; /* No children */
169
170 list_for_each_entry(chain, &child->val, list) {
171 ++n;
172 /* We need this because we may not have children */
173 folded_sign = callchain_list__folded(chain);
174 if (folded_sign == '+')
175 break;
176 }
177
178 if (folded_sign == '-') /* Have children and they're unfolded */
179 n += callchain_node__count_rows_rb_tree(child);
180 }
181
182 return n;
183}
184
185static int callchain_node__count_rows(struct callchain_node *node)
186{
187 struct callchain_list *chain;
188 bool unfolded = false;
189 int n = 0;
190
191 list_for_each_entry(chain, &node->val, list) {
192 ++n;
193 unfolded = chain->ms.unfolded;
194 }
195
196 if (unfolded)
197 n += callchain_node__count_rows_rb_tree(node);
198
199 return n;
200}
201
202static int callchain__count_rows(struct rb_root *chain)
203{
204 struct rb_node *nd;
205 int n = 0;
206
207 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
208 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
209 n += callchain_node__count_rows(node);
210 }
211
212 return n;
213}
214
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300215static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300216{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300217 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200218 return false;
219
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300220 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300221 return false;
222
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300223 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300224 return true;
225}
226
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300227static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300228{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300229 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300230
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300231 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300232 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
233 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300234 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300235
236 list_for_each_entry(chain, &child->val, list) {
237 if (first) {
238 first = false;
239 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300240 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300241 } else
242 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300243 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300244 }
245
246 callchain_node__init_have_children_rb_tree(child);
247 }
248}
249
Namhyung Kima7444af2014-11-24 17:13:27 +0900250static void callchain_node__init_have_children(struct callchain_node *node,
251 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300252{
253 struct callchain_list *chain;
254
Namhyung Kima7444af2014-11-24 17:13:27 +0900255 chain = list_entry(node->val.next, struct callchain_list, list);
256 chain->ms.has_children = has_sibling;
257
Namhyung Kim82162b52014-08-13 15:02:41 +0900258 if (!list_empty(&node->val)) {
259 chain = list_entry(node->val.prev, struct callchain_list, list);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300260 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900261 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300262
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300263 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300264}
265
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300266static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300267{
Namhyung Kima7444af2014-11-24 17:13:27 +0900268 struct rb_node *nd = rb_first(root);
269 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300270
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300271 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300272 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900273 callchain_node__init_have_children(node, has_sibling);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300274 }
275}
276
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300277static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300278{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300279 if (!he->init_have_children) {
280 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
281 callchain__init_have_children(&he->sorted_chain);
282 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300283 }
284}
285
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300286static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300287{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300288 if (map_symbol__toggle_fold(browser->selection)) {
289 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300290
291 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900292 browser->b.nr_entries -= he->nr_rows;
293 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300294
295 if (he->ms.unfolded)
296 he->nr_rows = callchain__count_rows(&he->sorted_chain);
297 else
298 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900299
300 browser->b.nr_entries += he->nr_rows;
301 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300302
303 return true;
304 }
305
306 /* If it doesn't have children, no toggling performed */
307 return false;
308}
309
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300310static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300311{
312 int n = 0;
313 struct rb_node *nd;
314
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300315 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300316 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
317 struct callchain_list *chain;
318 bool has_children = false;
319
320 list_for_each_entry(chain, &child->val, list) {
321 ++n;
322 map_symbol__set_folding(&chain->ms, unfold);
323 has_children = chain->ms.has_children;
324 }
325
326 if (has_children)
327 n += callchain_node__set_folding_rb_tree(child, unfold);
328 }
329
330 return n;
331}
332
333static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
334{
335 struct callchain_list *chain;
336 bool has_children = false;
337 int n = 0;
338
339 list_for_each_entry(chain, &node->val, list) {
340 ++n;
341 map_symbol__set_folding(&chain->ms, unfold);
342 has_children = chain->ms.has_children;
343 }
344
345 if (has_children)
346 n += callchain_node__set_folding_rb_tree(node, unfold);
347
348 return n;
349}
350
351static int callchain__set_folding(struct rb_root *chain, bool unfold)
352{
353 struct rb_node *nd;
354 int n = 0;
355
356 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
357 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
358 n += callchain_node__set_folding(node, unfold);
359 }
360
361 return n;
362}
363
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300364static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300365{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366 hist_entry__init_have_children(he);
367 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300368
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300369 if (he->ms.has_children) {
370 int n = callchain__set_folding(&he->sorted_chain, unfold);
371 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300372 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300373 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300374}
375
Namhyung Kimc3b78952014-04-22 15:56:17 +0900376static void
377__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300378{
379 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900380 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300381
Namhyung Kimc3b78952014-04-22 15:56:17 +0900382 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900383 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900384 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300385 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
386 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900387 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300388 }
389}
390
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300391static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300392{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900393 browser->nr_callchain_rows = 0;
394 __hist_browser__set_folding(browser, unfold);
395
396 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300397 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300398 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300399}
400
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200401static void ui_browser__warn_lost_events(struct ui_browser *browser)
402{
403 ui_browser__warning(browser, 4,
404 "Events are being lost, check IO/CPU overload!\n\n"
405 "You may want to run 'perf' using a RT scheduler policy:\n\n"
406 " perf top -r 80\n\n"
407 "Or reduce the sampling frequency.");
408}
409
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900410static int hist_browser__run(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300411{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300412 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300413 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900414 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900415 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300416
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300417 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900418 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300419
Taeung Song1e378eb2014-10-07 16:13:15 +0900420 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300421
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300422 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300423 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300424 return -1;
425
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300426 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300427 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300429 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900430 case K_TIMER: {
431 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900432 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900433
Namhyung Kimc3b78952014-04-22 15:56:17 +0900434 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900435 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900436
Namhyung Kimc3b78952014-04-22 15:56:17 +0900437 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900438 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200439
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300440 if (browser->hists->stats.nr_lost_warned !=
441 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
442 browser->hists->stats.nr_lost_warned =
443 browser->hists->stats.nr_events[PERF_RECORD_LOST];
444 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200445 }
446
Taeung Song1e378eb2014-10-07 16:13:15 +0900447 hists__browser_title(browser->hists,
448 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300449 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300450 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900451 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300452 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300453 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300454 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300455 struct hist_entry, rb_node);
456 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300457 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 -0300458 seq++, browser->b.nr_entries,
459 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300460 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300461 browser->b.index,
462 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300463 h->row_offset, h->nr_rows);
464 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300465 break;
466 case 'C':
467 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300468 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300469 break;
470 case 'E':
471 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300472 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300473 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200474 case 'H':
475 browser->show_headers = !browser->show_headers;
476 hist_browser__update_rows(browser);
477 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200478 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300479 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300480 break;
481 /* fall thru */
482 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300483 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300484 }
485 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300486out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300487 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300488 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300489}
490
Namhyung Kim39ee5332014-08-22 09:13:21 +0900491struct callchain_print_arg {
492 /* for hists browser */
493 off_t row_offset;
494 bool is_current_entry;
495
496 /* for file dump */
497 FILE *fp;
498 int printed;
499};
500
501typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
502 struct callchain_list *chain,
503 const char *str, int offset,
504 unsigned short row,
505 struct callchain_print_arg *arg);
506
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900507static void hist_browser__show_callchain_entry(struct hist_browser *browser,
508 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900509 const char *str, int offset,
510 unsigned short row,
511 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900512{
513 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900514 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300515 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900516
517 color = HE_COLORSET_NORMAL;
518 width = browser->b.width - (offset + 2);
519 if (ui_browser__is_current_entry(&browser->b, row)) {
520 browser->selection = &chain->ms;
521 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900522 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900523 }
524
525 ui_browser__set_color(&browser->b, color);
526 hist_browser__gotorc(browser, row, 0);
527 slsmg_write_nstring(" ", offset);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300528 slsmg_printf("%c", folded_sign);
529 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900530 slsmg_write_nstring(str, width);
531}
532
Namhyung Kim39ee5332014-08-22 09:13:21 +0900533static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
534 struct callchain_list *chain,
535 const char *str, int offset,
536 unsigned short row __maybe_unused,
537 struct callchain_print_arg *arg)
538{
539 char folded_sign = callchain_list__folded(chain);
540
541 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
542 folded_sign, str);
543}
544
545typedef bool (*check_output_full_fn)(struct hist_browser *browser,
546 unsigned short row);
547
548static bool hist_browser__check_output_full(struct hist_browser *browser,
549 unsigned short row)
550{
551 return browser->b.rows == row;
552}
553
554static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
555 unsigned short row __maybe_unused)
556{
557 return false;
558}
559
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300560#define LEVEL_OFFSET_STEP 3
561
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900562static int hist_browser__show_callchain(struct hist_browser *browser,
563 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900564 unsigned short row, u64 total,
565 print_callchain_entry_fn print,
566 struct callchain_print_arg *arg,
567 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300568{
569 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900570 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900571 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900572 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300573
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900574 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900575 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900576
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300577 while (node) {
578 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
579 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100580 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300581 struct callchain_list *chain;
582 char folded_sign = ' ';
583 int first = true;
584 int extra_offset = 0;
585
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300586 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300587 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300588 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300589 bool was_first = first;
590
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300591 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900593 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300594 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300595
596 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900597 if (arg->row_offset != 0) {
598 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300599 goto do_next;
600 }
601
602 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300603 str = callchain_list__sym_name(chain, bf, sizeof(bf),
604 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900605
Namhyung Kim4087d112014-11-24 17:13:26 +0900606 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900607 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300608
609 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
610 str = "Not enough memory!";
611 else
612 str = alloc_str;
613 }
614
Namhyung Kim39ee5332014-08-22 09:13:21 +0900615 print(browser, chain, str, offset + extra_offset, row, arg);
616
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300617 free(alloc_str);
618
Namhyung Kim39ee5332014-08-22 09:13:21 +0900619 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300620 goto out;
621do_next:
622 if (folded_sign == '+')
623 break;
624 }
625
626 if (folded_sign == '-') {
627 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900628
629 if (callchain_param.mode == CHAIN_GRAPH_REL)
630 new_total = child->children_hit;
631 else
632 new_total = total;
633
634 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900635 new_level, row, new_total,
636 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300637 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900638 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900639 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300640 node = next;
641 }
642out:
643 return row - first_row;
644}
645
Namhyung Kim89701462013-01-22 18:09:38 +0900646struct hpp_arg {
647 struct ui_browser *b;
648 char folded_sign;
649 bool current_entry;
650};
651
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900652static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
653{
654 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900655 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900656 va_list args;
657 double percent;
658
659 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900660 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900661 percent = va_arg(args, double);
662 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900663
Namhyung Kim89701462013-01-22 18:09:38 +0900664 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900665
Namhyung Kimd6751072014-07-31 14:47:36 +0900666 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900667 slsmg_printf("%s", hpp->buf);
668
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900669 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900670 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900671}
672
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900673#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900674static u64 __hpp_get_##_field(struct hist_entry *he) \
675{ \
676 return he->stat._field; \
677} \
678 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100679static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900680hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100681 struct perf_hpp *hpp, \
682 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900683{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900684 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
685 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900686}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900687
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900688#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
689static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
690{ \
691 return he->stat_acc->_field; \
692} \
693 \
694static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900695hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900696 struct perf_hpp *hpp, \
697 struct hist_entry *he) \
698{ \
699 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900700 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900701 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900702 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900703 slsmg_printf("%s", hpp->buf); \
704 \
705 return ret; \
706 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900707 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
708 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900709}
710
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900711__HPP_COLOR_PERCENT_FN(overhead, period)
712__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
713__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
714__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
715__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900716__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900717
718#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900719#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900720
721void hist_browser__init_hpp(void)
722{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900723 perf_hpp__format[PERF_HPP__OVERHEAD].color =
724 hist_browser__hpp_color_overhead;
725 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
726 hist_browser__hpp_color_overhead_sys;
727 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
728 hist_browser__hpp_color_overhead_us;
729 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
730 hist_browser__hpp_color_overhead_guest_sys;
731 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
732 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900733 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
734 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900735}
736
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300737static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300738 struct hist_entry *entry,
739 unsigned short row)
740{
741 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200742 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900743 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300744 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300745 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300746 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300747 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200748 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300749
750 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300751 browser->he_selection = entry;
752 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300753 }
754
755 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300756 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300757 folded_sign = hist_entry__folded(entry);
758 }
759
760 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900761 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900762 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900763 .folded_sign = folded_sign,
764 .current_entry = current_entry,
765 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900766 struct perf_hpp hpp = {
767 .buf = s,
768 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900769 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900770 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300771
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300772 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900773
Jiri Olsa12400052012-10-13 00:06:16 +0200774 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900775 if (perf_hpp__should_skip(fmt))
776 continue;
777
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900778 if (current_entry && browser->b.navkeypressed) {
779 ui_browser__set_color(&browser->b,
780 HE_COLORSET_SELECTED);
781 } else {
782 ui_browser__set_color(&browser->b,
783 HE_COLORSET_NORMAL);
784 }
785
786 if (first) {
787 if (symbol_conf.use_callchain) {
788 slsmg_printf("%c ", folded_sign);
789 width -= 2;
790 }
791 first = false;
792 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900793 slsmg_printf(" ");
794 width -= 2;
795 }
796
Jiri Olsa12400052012-10-13 00:06:16 +0200797 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100798 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900799 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100800 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900801 slsmg_printf("%s", s);
802 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300803 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200804
805 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300806 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200807 width += 1;
808
Namhyung Kim26d8b332014-03-03 16:16:20 +0900809 slsmg_write_nstring("", width);
810
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300811 ++row;
812 ++printed;
813 } else
814 --row_offset;
815
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300816 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900817 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900818 struct callchain_print_arg arg = {
819 .row_offset = row_offset,
820 .is_current_entry = current_entry,
821 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900822
Namhyung Kim4087d112014-11-24 17:13:26 +0900823 if (callchain_param.mode == CHAIN_GRAPH_REL) {
824 if (symbol_conf.cumulate_callchain)
825 total = entry->stat_acc->period;
826 else
827 total = entry->stat.period;
828 }
829
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900830 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900831 &entry->sorted_chain, 1, row, total,
832 hist_browser__show_callchain_entry, &arg,
833 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900834
Namhyung Kim39ee5332014-08-22 09:13:21 +0900835 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300836 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300837 }
838
839 return printed;
840}
841
Jiri Olsa81a888f2014-06-14 15:44:52 +0200842static int advance_hpp_check(struct perf_hpp *hpp, int inc)
843{
844 advance_hpp(hpp, inc);
845 return hpp->size <= 0;
846}
847
848static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
849{
850 struct perf_hpp dummy_hpp = {
851 .buf = buf,
852 .size = size,
853 };
854 struct perf_hpp_fmt *fmt;
855 size_t ret = 0;
856
857 if (symbol_conf.use_callchain) {
858 ret = scnprintf(buf, size, " ");
859 if (advance_hpp_check(&dummy_hpp, ret))
860 return ret;
861 }
862
863 perf_hpp__for_each_format(fmt) {
864 if (perf_hpp__should_skip(fmt))
865 continue;
866
Jiri Olsa81a888f2014-06-14 15:44:52 +0200867 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
868 if (advance_hpp_check(&dummy_hpp, ret))
869 break;
870
871 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
872 if (advance_hpp_check(&dummy_hpp, ret))
873 break;
874 }
875
876 return ret;
877}
878
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200879static void hist_browser__show_headers(struct hist_browser *browser)
880{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200881 char headers[1024];
882
883 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200884 ui_browser__gotorc(&browser->b, 0, 0);
885 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200886 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200887}
888
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300889static void ui_browser__hists_init_top(struct ui_browser *browser)
890{
891 if (browser->top == NULL) {
892 struct hist_browser *hb;
893
894 hb = container_of(browser, struct hist_browser, b);
895 browser->top = rb_first(&hb->hists->entries);
896 }
897}
898
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300899static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300900{
901 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200902 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300903 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300904 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300905
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200906 if (hb->show_headers) {
907 hist_browser__show_headers(hb);
908 header_offset = 1;
909 }
910
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300911 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300912
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300913 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300914 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900915 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300916
917 if (h->filtered)
918 continue;
919
Namhyung Kim14135662013-10-31 10:17:39 +0900920 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900921 if (percent < hb->min_pcnt)
922 continue;
923
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300924 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300925 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300926 break;
927 }
928
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200929 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300930}
931
Namhyung Kim064f1982013-05-14 11:09:04 +0900932static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900933 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300934{
935 while (nd != NULL) {
936 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900937 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900938
Namhyung Kimc0f15272014-04-16 11:16:33 +0900939 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300940 return nd;
941
942 nd = rb_next(nd);
943 }
944
945 return NULL;
946}
947
Namhyung Kim064f1982013-05-14 11:09:04 +0900948static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900949 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300950{
951 while (nd != NULL) {
952 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900953 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900954
955 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300956 return nd;
957
958 nd = rb_prev(nd);
959 }
960
961 return NULL;
962}
963
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300964static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300965 off_t offset, int whence)
966{
967 struct hist_entry *h;
968 struct rb_node *nd;
969 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900970 struct hist_browser *hb;
971
972 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300973
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300974 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300975 return;
976
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300977 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300978
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300979 switch (whence) {
980 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900981 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900982 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300983 break;
984 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300985 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300986 goto do_offset;
987 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900988 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900989 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300990 first = false;
991 break;
992 default:
993 return;
994 }
995
996 /*
997 * Moves not relative to the first visible entry invalidates its
998 * row_offset:
999 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001000 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001001 h->row_offset = 0;
1002
1003 /*
1004 * Here we have to check if nd is expanded (+), if it is we can't go
1005 * the next top level hist_entry, instead we must compute an offset of
1006 * what _not_ to show and not change the first visible entry.
1007 *
1008 * This offset increments when we are going from top to bottom and
1009 * decreases when we're going from bottom to top.
1010 *
1011 * As we don't have backpointers to the top level in the callchains
1012 * structure, we need to always print the whole hist_entry callchain,
1013 * skipping the first ones that are before the first visible entry
1014 * and stop when we printed enough lines to fill the screen.
1015 */
1016do_offset:
1017 if (offset > 0) {
1018 do {
1019 h = rb_entry(nd, struct hist_entry, rb_node);
1020 if (h->ms.unfolded) {
1021 u16 remaining = h->nr_rows - h->row_offset;
1022 if (offset > remaining) {
1023 offset -= remaining;
1024 h->row_offset = 0;
1025 } else {
1026 h->row_offset += offset;
1027 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001028 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001029 break;
1030 }
1031 }
Namhyung Kim14135662013-10-31 10:17:39 +09001032 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001033 if (nd == NULL)
1034 break;
1035 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001036 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001037 } while (offset != 0);
1038 } else if (offset < 0) {
1039 while (1) {
1040 h = rb_entry(nd, struct hist_entry, rb_node);
1041 if (h->ms.unfolded) {
1042 if (first) {
1043 if (-offset > h->row_offset) {
1044 offset += h->row_offset;
1045 h->row_offset = 0;
1046 } else {
1047 h->row_offset += offset;
1048 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001049 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001050 break;
1051 }
1052 } else {
1053 if (-offset > h->nr_rows) {
1054 offset += h->nr_rows;
1055 h->row_offset = 0;
1056 } else {
1057 h->row_offset = h->nr_rows + offset;
1058 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001059 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001060 break;
1061 }
1062 }
1063 }
1064
Namhyung Kim14135662013-10-31 10:17:39 +09001065 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001066 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001067 if (nd == NULL)
1068 break;
1069 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001070 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001071 if (offset == 0) {
1072 /*
1073 * Last unfiltered hist_entry, check if it is
1074 * unfolded, if it is then we should have
1075 * row_offset at its last entry.
1076 */
1077 h = rb_entry(nd, struct hist_entry, rb_node);
1078 if (h->ms.unfolded)
1079 h->row_offset = h->nr_rows;
1080 break;
1081 }
1082 first = false;
1083 }
1084 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001085 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001086 h = rb_entry(nd, struct hist_entry, rb_node);
1087 h->row_offset = 0;
1088 }
1089}
1090
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001091static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001092 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001093{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001094 u64 total = hists__total_period(he->hists);
1095 struct callchain_print_arg arg = {
1096 .fp = fp,
1097 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001098
Namhyung Kim39ee5332014-08-22 09:13:21 +09001099 if (symbol_conf.cumulate_callchain)
1100 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001101
Namhyung Kim39ee5332014-08-22 09:13:21 +09001102 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1103 hist_browser__fprintf_callchain_entry, &arg,
1104 hist_browser__check_dump_full);
1105 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001106}
1107
1108static int hist_browser__fprintf_entry(struct hist_browser *browser,
1109 struct hist_entry *he, FILE *fp)
1110{
1111 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001112 int printed = 0;
1113 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001114 struct perf_hpp hpp = {
1115 .buf = s,
1116 .size = sizeof(s),
1117 };
1118 struct perf_hpp_fmt *fmt;
1119 bool first = true;
1120 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001121
1122 if (symbol_conf.use_callchain)
1123 folded_sign = hist_entry__folded(he);
1124
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001125 if (symbol_conf.use_callchain)
1126 printed += fprintf(fp, "%c ", folded_sign);
1127
Namhyung Kim26d8b332014-03-03 16:16:20 +09001128 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001129 if (perf_hpp__should_skip(fmt))
1130 continue;
1131
Namhyung Kim26d8b332014-03-03 16:16:20 +09001132 if (!first) {
1133 ret = scnprintf(hpp.buf, hpp.size, " ");
1134 advance_hpp(&hpp, ret);
1135 } else
1136 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001137
Namhyung Kim26d8b332014-03-03 16:16:20 +09001138 ret = fmt->entry(fmt, &hpp, he);
1139 advance_hpp(&hpp, ret);
1140 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001141 printed += fprintf(fp, "%s\n", rtrim(s));
1142
1143 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001144 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001145
1146 return printed;
1147}
1148
1149static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1150{
Namhyung Kim064f1982013-05-14 11:09:04 +09001151 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001152 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001153 int printed = 0;
1154
1155 while (nd) {
1156 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1157
1158 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001159 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001160 }
1161
1162 return printed;
1163}
1164
1165static int hist_browser__dump(struct hist_browser *browser)
1166{
1167 char filename[64];
1168 FILE *fp;
1169
1170 while (1) {
1171 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1172 if (access(filename, F_OK))
1173 break;
1174 /*
1175 * XXX: Just an arbitrary lazy upper limit
1176 */
1177 if (++browser->print_seq == 8192) {
1178 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1179 return -1;
1180 }
1181 }
1182
1183 fp = fopen(filename, "w");
1184 if (fp == NULL) {
1185 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001186 const char *err = strerror_r(errno, bf, sizeof(bf));
1187 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001188 return -1;
1189 }
1190
1191 ++browser->print_seq;
1192 hist_browser__fprintf(browser, fp);
1193 fclose(fp);
1194 ui_helpline__fpush("%s written!", filename);
1195
1196 return 0;
1197}
1198
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001199static struct hist_browser *hist_browser__new(struct hists *hists,
1200 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001202 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001204 if (browser) {
1205 browser->hists = hists;
1206 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001207 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001208 browser->b.seek = ui_browser__hists_seek;
1209 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001210 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001211 browser->hbt = hbt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001212 }
1213
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001214 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215}
1216
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001217static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001219 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220}
1221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001222static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001223{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001224 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001225}
1226
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001227static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001228{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001229 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001230}
1231
Taeung Song1e378eb2014-10-07 16:13:15 +09001232/* Check whether the browser is for 'top' or 'report' */
1233static inline bool is_report_browser(void *timer)
1234{
1235 return timer == NULL;
1236}
1237
1238static int hists__browser_title(struct hists *hists,
1239 struct hist_browser_timer *hbt,
1240 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001242 char unit;
1243 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001244 const struct dso *dso = hists->dso_filter;
1245 const struct thread *thread = hists->thread_filter;
1246 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1247 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001248 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001249 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001250 char buf[512];
1251 size_t buflen = sizeof(buf);
1252
Namhyung Kimf2148332014-01-14 11:52:48 +09001253 if (symbol_conf.filter_relative) {
1254 nr_samples = hists->stats.nr_non_filtered_samples;
1255 nr_events = hists->stats.total_non_filtered_period;
1256 }
1257
Namhyung Kim759ff492013-03-05 14:53:26 +09001258 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001259 struct perf_evsel *pos;
1260
1261 perf_evsel__group_desc(evsel, buf, buflen);
1262 ev_name = buf;
1263
1264 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001265 struct hists *pos_hists = evsel__hists(pos);
1266
Namhyung Kimf2148332014-01-14 11:52:48 +09001267 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001268 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1269 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001270 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001271 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1272 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001273 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001274 }
1275 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001276
Ashay Ranecc6862802012-04-05 21:01:01 -05001277 nr_samples = convert_unit(nr_samples, &unit);
1278 printed = scnprintf(bf, size,
Tom Huynhe641f692014-12-02 11:37:22 -06001279 "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
Ashay Ranecc6862802012-04-05 21:01:01 -05001280 nr_samples, unit, ev_name, nr_events);
1281
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001282
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001283 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001284 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001285 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001286 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001287 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001288 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001289 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001290 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001291 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001292 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001293 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001294 if (!is_report_browser(hbt)) {
1295 struct perf_top *top = hbt->arg;
1296
1297 if (top->zero)
1298 printed += scnprintf(bf + printed, size - printed, " [z]");
1299 }
1300
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001301 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001302}
1303
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001304static inline void free_popup_options(char **options, int n)
1305{
1306 int i;
1307
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001308 for (i = 0; i < n; ++i)
1309 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001310}
1311
Feng Tang341487ab2013-02-03 14:38:20 +08001312/*
1313 * Only runtime switching of perf data file will make "input_name" point
1314 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1315 * whether we need to call free() for current "input_name" during the switch.
1316 */
1317static bool is_input_name_malloced = false;
1318
1319static int switch_data_file(void)
1320{
1321 char *pwd, *options[32], *abs_path[32], *tmp;
1322 DIR *pwd_dir;
1323 int nr_options = 0, choice = -1, ret = -1;
1324 struct dirent *dent;
1325
1326 pwd = getenv("PWD");
1327 if (!pwd)
1328 return ret;
1329
1330 pwd_dir = opendir(pwd);
1331 if (!pwd_dir)
1332 return ret;
1333
1334 memset(options, 0, sizeof(options));
1335 memset(options, 0, sizeof(abs_path));
1336
1337 while ((dent = readdir(pwd_dir))) {
1338 char path[PATH_MAX];
1339 u64 magic;
1340 char *name = dent->d_name;
1341 FILE *file;
1342
1343 if (!(dent->d_type == DT_REG))
1344 continue;
1345
1346 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1347
1348 file = fopen(path, "r");
1349 if (!file)
1350 continue;
1351
1352 if (fread(&magic, 1, 8, file) < 8)
1353 goto close_file_and_continue;
1354
1355 if (is_perf_magic(magic)) {
1356 options[nr_options] = strdup(name);
1357 if (!options[nr_options])
1358 goto close_file_and_continue;
1359
1360 abs_path[nr_options] = strdup(path);
1361 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001362 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001363 ui__warning("Can't search all data files due to memory shortage.\n");
1364 fclose(file);
1365 break;
1366 }
1367
1368 nr_options++;
1369 }
1370
1371close_file_and_continue:
1372 fclose(file);
1373 if (nr_options >= 32) {
1374 ui__warning("Too many perf data files in PWD!\n"
1375 "Only the first 32 files will be listed.\n");
1376 break;
1377 }
1378 }
1379 closedir(pwd_dir);
1380
1381 if (nr_options) {
1382 choice = ui__popup_menu(nr_options, options);
1383 if (choice < nr_options && choice >= 0) {
1384 tmp = strdup(abs_path[choice]);
1385 if (tmp) {
1386 if (is_input_name_malloced)
1387 free((void *)input_name);
1388 input_name = tmp;
1389 is_input_name_malloced = true;
1390 ret = 0;
1391 } else
1392 ui__warning("Data switch failed due to memory shortage!\n");
1393 }
1394 }
1395
1396 free_popup_options(options, nr_options);
1397 free_popup_options(abs_path, nr_options);
1398 return ret;
1399}
1400
Namhyung Kim112f7612014-04-22 14:05:35 +09001401static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001402{
1403 u64 nr_entries = 0;
1404 struct rb_node *nd = rb_first(&hb->hists->entries);
1405
Namhyung Kim268397c2014-04-22 14:49:31 +09001406 if (hb->min_pcnt == 0) {
1407 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1408 return;
1409 }
1410
Namhyung Kim14135662013-10-31 10:17:39 +09001411 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001412 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001413 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001414 }
1415
Namhyung Kim112f7612014-04-22 14:05:35 +09001416 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001417}
Feng Tang341487ab2013-02-03 14:38:20 +08001418
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001419static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001420 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001421 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001422 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001423 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001424 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001425{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001426 struct hists *hists = evsel__hists(evsel);
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001427 struct hist_browser *browser = hist_browser__new(hists, hbt);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001428 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001429 struct pstack *fstack;
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
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001480 fstack = pstack__new(2);
1481 if (fstack == NULL)
1482 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
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001590 if (pstack__empty(fstack)) {
1591 /*
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 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001598 top = pstack__pop(fstack);
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) {
1756 pstack__remove(fstack, &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);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001768 pstack__push(fstack, &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) {
1775 pstack__remove(fstack, &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);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001786 pstack__push(fstack, &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:
1817 pstack__delete(fstack);
1818out:
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}