blob: e6bb04b5b09b863013e4d361120269d59f6207c6 [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;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030028 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030029 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020030 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090031 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090032 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090033 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030034};
35
Namhyung Kimf5951d52012-09-03 11:53:09 +090036extern void hist_browser__init_hpp(void);
37
Taeung Song1e378eb2014-10-07 16:13:15 +090038static int hists__browser_title(struct hists *hists,
39 struct hist_browser_timer *hbt,
40 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090041static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030042
Namhyung Kimc3b78952014-04-22 15:56:17 +090043static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090044 float min_pcnt);
45
Namhyung Kim268397c2014-04-22 14:49:31 +090046static bool hist_browser__has_filter(struct hist_browser *hb)
47{
48 return hists__has_filter(hb->hists) || hb->min_pcnt;
49}
50
Namhyung Kimc3b78952014-04-22 15:56:17 +090051static u32 hist_browser__nr_entries(struct hist_browser *hb)
52{
53 u32 nr_entries;
54
55 if (hist_browser__has_filter(hb))
56 nr_entries = hb->nr_non_filtered_entries;
57 else
58 nr_entries = hb->hists->nr_entries;
59
60 return nr_entries + hb->nr_callchain_rows;
61}
62
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020063static void hist_browser__update_rows(struct hist_browser *hb)
64{
65 struct ui_browser *browser = &hb->b;
66 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
67
68 browser->rows = browser->height - header_offset;
69 /*
70 * Verify if we were at the last line and that line isn't
71 * visibe because we now show the header line(s).
72 */
73 index_row = browser->index - browser->top_idx;
74 if (index_row >= browser->rows)
75 browser->index -= index_row - browser->rows + 1;
76}
77
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030078static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030079{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030080 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
81
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030082 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030083 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
84 /*
85 * FIXME: Just keeping existing behaviour, but this really should be
86 * before updating browser->width, as it will invalidate the
87 * calculation above. Fix this and the fallout in another
88 * changeset.
89 */
90 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020091 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030092}
93
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030094static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
95{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020096 u16 header_offset = browser->show_headers ? 1 : 0;
97
98 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -030099}
100
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300101static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300102{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900103 /*
104 * The hists__remove_entry_filter() already folds non-filtered
105 * entries so we can assume it has 0 callchain rows.
106 */
107 browser->nr_callchain_rows = 0;
108
Namhyung Kim268397c2014-04-22 14:49:31 +0900109 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900110 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300111 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300112 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300113}
114
115static char tree__folded_sign(bool unfolded)
116{
117 return unfolded ? '-' : '+';
118}
119
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300120static char map_symbol__folded(const struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300121{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300122 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300123}
124
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300125static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300126{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300127 return map_symbol__folded(&he->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300128}
129
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300130static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300131{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132 return map_symbol__folded(&cl->ms);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133}
134
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300135static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300136{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137 ms->unfolded = unfold ? ms->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300138}
139
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300140static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300141{
142 int n = 0;
143 struct rb_node *nd;
144
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300145 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300146 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
147 struct callchain_list *chain;
148 char folded_sign = ' '; /* No children */
149
150 list_for_each_entry(chain, &child->val, list) {
151 ++n;
152 /* We need this because we may not have children */
153 folded_sign = callchain_list__folded(chain);
154 if (folded_sign == '+')
155 break;
156 }
157
158 if (folded_sign == '-') /* Have children and they're unfolded */
159 n += callchain_node__count_rows_rb_tree(child);
160 }
161
162 return n;
163}
164
165static int callchain_node__count_rows(struct callchain_node *node)
166{
167 struct callchain_list *chain;
168 bool unfolded = false;
169 int n = 0;
170
171 list_for_each_entry(chain, &node->val, list) {
172 ++n;
173 unfolded = chain->ms.unfolded;
174 }
175
176 if (unfolded)
177 n += callchain_node__count_rows_rb_tree(node);
178
179 return n;
180}
181
182static int callchain__count_rows(struct rb_root *chain)
183{
184 struct rb_node *nd;
185 int n = 0;
186
187 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
188 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
189 n += callchain_node__count_rows(node);
190 }
191
192 return n;
193}
194
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300195static bool map_symbol__toggle_fold(struct map_symbol *ms)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300196{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300197 if (!ms)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200198 return false;
199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300200 if (!ms->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300201 return false;
202
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300203 ms->unfolded = !ms->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300204 return true;
205}
206
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300207static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300208{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300209 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300210
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300211 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300212 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
213 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300214 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300215
216 list_for_each_entry(chain, &child->val, list) {
217 if (first) {
218 first = false;
219 chain->ms.has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300220 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300221 } else
222 chain->ms.has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300223 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300224 }
225
226 callchain_node__init_have_children_rb_tree(child);
227 }
228}
229
Namhyung Kima7444af2014-11-24 17:13:27 +0900230static void callchain_node__init_have_children(struct callchain_node *node,
231 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300232{
233 struct callchain_list *chain;
234
Namhyung Kima7444af2014-11-24 17:13:27 +0900235 chain = list_entry(node->val.next, struct callchain_list, list);
236 chain->ms.has_children = has_sibling;
237
Namhyung Kim82162b52014-08-13 15:02:41 +0900238 if (!list_empty(&node->val)) {
239 chain = list_entry(node->val.prev, struct callchain_list, list);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300240 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900241 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300242
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300243 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300244}
245
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300246static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300247{
Namhyung Kima7444af2014-11-24 17:13:27 +0900248 struct rb_node *nd = rb_first(root);
249 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300250
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300251 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300252 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900253 callchain_node__init_have_children(node, has_sibling);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300254 }
255}
256
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300257static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300258{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300259 if (!he->init_have_children) {
260 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
261 callchain__init_have_children(&he->sorted_chain);
262 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300263 }
264}
265
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300266static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300267{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300268 if (map_symbol__toggle_fold(browser->selection)) {
269 struct hist_entry *he = browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300270
271 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900272 browser->b.nr_entries -= he->nr_rows;
273 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300274
275 if (he->ms.unfolded)
276 he->nr_rows = callchain__count_rows(&he->sorted_chain);
277 else
278 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900279
280 browser->b.nr_entries += he->nr_rows;
281 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300282
283 return true;
284 }
285
286 /* If it doesn't have children, no toggling performed */
287 return false;
288}
289
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300290static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300291{
292 int n = 0;
293 struct rb_node *nd;
294
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300295 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300296 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
297 struct callchain_list *chain;
298 bool has_children = false;
299
300 list_for_each_entry(chain, &child->val, list) {
301 ++n;
302 map_symbol__set_folding(&chain->ms, unfold);
303 has_children = chain->ms.has_children;
304 }
305
306 if (has_children)
307 n += callchain_node__set_folding_rb_tree(child, unfold);
308 }
309
310 return n;
311}
312
313static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
314{
315 struct callchain_list *chain;
316 bool has_children = false;
317 int n = 0;
318
319 list_for_each_entry(chain, &node->val, list) {
320 ++n;
321 map_symbol__set_folding(&chain->ms, unfold);
322 has_children = chain->ms.has_children;
323 }
324
325 if (has_children)
326 n += callchain_node__set_folding_rb_tree(node, unfold);
327
328 return n;
329}
330
331static int callchain__set_folding(struct rb_root *chain, bool unfold)
332{
333 struct rb_node *nd;
334 int n = 0;
335
336 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
337 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
338 n += callchain_node__set_folding(node, unfold);
339 }
340
341 return n;
342}
343
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300344static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300345{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300346 hist_entry__init_have_children(he);
347 map_symbol__set_folding(&he->ms, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300348
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300349 if (he->ms.has_children) {
350 int n = callchain__set_folding(&he->sorted_chain, unfold);
351 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300352 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300353 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300354}
355
Namhyung Kimc3b78952014-04-22 15:56:17 +0900356static void
357__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300358{
359 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900360 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300361
Namhyung Kimc3b78952014-04-22 15:56:17 +0900362 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900363 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900364 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300365 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
366 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900367 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300368 }
369}
370
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300372{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900373 browser->nr_callchain_rows = 0;
374 __hist_browser__set_folding(browser, unfold);
375
376 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300377 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300378 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300379}
380
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200381static void ui_browser__warn_lost_events(struct ui_browser *browser)
382{
383 ui_browser__warning(browser, 4,
384 "Events are being lost, check IO/CPU overload!\n\n"
385 "You may want to run 'perf' using a RT scheduler policy:\n\n"
386 " perf top -r 80\n\n"
387 "Or reduce the sampling frequency.");
388}
389
Jiri Olsadd00d482014-06-19 13:41:13 +0200390static int hist_browser__run(struct hist_browser *browser,
Namhyung Kim9783adf2012-11-02 14:50:05 +0900391 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300393 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300394 char title[160];
Namhyung Kim9783adf2012-11-02 14:50:05 +0900395 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300396
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300397 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900398 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300399
Taeung Song1e378eb2014-10-07 16:13:15 +0900400 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300402 if (ui_browser__show(&browser->b, title,
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300403 "Press '?' for help on key bindings") < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300404 return -1;
405
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300406 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300407 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300408
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300409 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900410 case K_TIMER: {
411 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900412 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900413
Namhyung Kimc3b78952014-04-22 15:56:17 +0900414 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900415 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900416
Namhyung Kimc3b78952014-04-22 15:56:17 +0900417 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900418 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200419
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300420 if (browser->hists->stats.nr_lost_warned !=
421 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
422 browser->hists->stats.nr_lost_warned =
423 browser->hists->stats.nr_events[PERF_RECORD_LOST];
424 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200425 }
426
Taeung Song1e378eb2014-10-07 16:13:15 +0900427 hists__browser_title(browser->hists,
428 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300429 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300430 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900431 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300432 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300433 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300434 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300435 struct hist_entry, rb_node);
436 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300437 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 -0300438 seq++, browser->b.nr_entries,
439 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300440 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300441 browser->b.index,
442 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300443 h->row_offset, h->nr_rows);
444 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300445 break;
446 case 'C':
447 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300448 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300449 break;
450 case 'E':
451 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300452 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300453 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200454 case 'H':
455 browser->show_headers = !browser->show_headers;
456 hist_browser__update_rows(browser);
457 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200458 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300459 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300460 break;
461 /* fall thru */
462 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300463 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300464 }
465 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300466out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300467 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300468 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300469}
470
Namhyung Kim39ee5332014-08-22 09:13:21 +0900471struct callchain_print_arg {
472 /* for hists browser */
473 off_t row_offset;
474 bool is_current_entry;
475
476 /* for file dump */
477 FILE *fp;
478 int printed;
479};
480
481typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
482 struct callchain_list *chain,
483 const char *str, int offset,
484 unsigned short row,
485 struct callchain_print_arg *arg);
486
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900487static void hist_browser__show_callchain_entry(struct hist_browser *browser,
488 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900489 const char *str, int offset,
490 unsigned short row,
491 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900492{
493 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900494 char folded_sign = callchain_list__folded(chain);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900495
496 color = HE_COLORSET_NORMAL;
497 width = browser->b.width - (offset + 2);
498 if (ui_browser__is_current_entry(&browser->b, row)) {
499 browser->selection = &chain->ms;
500 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900501 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900502 }
503
504 ui_browser__set_color(&browser->b, color);
505 hist_browser__gotorc(browser, row, 0);
506 slsmg_write_nstring(" ", offset);
507 slsmg_printf("%c ", folded_sign);
508 slsmg_write_nstring(str, width);
509}
510
Namhyung Kim39ee5332014-08-22 09:13:21 +0900511static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
512 struct callchain_list *chain,
513 const char *str, int offset,
514 unsigned short row __maybe_unused,
515 struct callchain_print_arg *arg)
516{
517 char folded_sign = callchain_list__folded(chain);
518
519 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
520 folded_sign, str);
521}
522
523typedef bool (*check_output_full_fn)(struct hist_browser *browser,
524 unsigned short row);
525
526static bool hist_browser__check_output_full(struct hist_browser *browser,
527 unsigned short row)
528{
529 return browser->b.rows == row;
530}
531
532static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
533 unsigned short row __maybe_unused)
534{
535 return false;
536}
537
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300538#define LEVEL_OFFSET_STEP 3
539
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900540static int hist_browser__show_callchain(struct hist_browser *browser,
541 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900542 unsigned short row, u64 total,
543 print_callchain_entry_fn print,
544 struct callchain_print_arg *arg,
545 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300546{
547 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900548 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900549 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900550 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300551
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900552 node = rb_first(root);
Namhyung Kim4087d112014-11-24 17:13:26 +0900553 need_percent = !!rb_next(node);
554
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300555 while (node) {
556 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
557 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100558 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300559 struct callchain_list *chain;
560 char folded_sign = ' ';
561 int first = true;
562 int extra_offset = 0;
563
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300564 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300565 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300566 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300567 bool was_first = first;
568
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300569 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300570 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900571 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300572 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300573
574 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900575 if (arg->row_offset != 0) {
576 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300577 goto do_next;
578 }
579
580 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300581 str = callchain_list__sym_name(chain, bf, sizeof(bf),
582 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900583
Namhyung Kim4087d112014-11-24 17:13:26 +0900584 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900585 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300586
587 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
588 str = "Not enough memory!";
589 else
590 str = alloc_str;
591 }
592
Namhyung Kim39ee5332014-08-22 09:13:21 +0900593 print(browser, chain, str, offset + extra_offset, row, arg);
594
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300595 free(alloc_str);
596
Namhyung Kim39ee5332014-08-22 09:13:21 +0900597 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300598 goto out;
599do_next:
600 if (folded_sign == '+')
601 break;
602 }
603
604 if (folded_sign == '-') {
605 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900606
607 if (callchain_param.mode == CHAIN_GRAPH_REL)
608 new_total = child->children_hit;
609 else
610 new_total = total;
611
612 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900613 new_level, row, new_total,
614 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300615 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900616 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900617 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300618 node = next;
619 }
620out:
621 return row - first_row;
622}
623
Namhyung Kim89701462013-01-22 18:09:38 +0900624struct hpp_arg {
625 struct ui_browser *b;
626 char folded_sign;
627 bool current_entry;
628};
629
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900630static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
631{
632 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900633 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900634 va_list args;
635 double percent;
636
637 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900638 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900639 percent = va_arg(args, double);
640 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900641
Namhyung Kim89701462013-01-22 18:09:38 +0900642 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900643
Namhyung Kimd6751072014-07-31 14:47:36 +0900644 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Namhyung Kim89701462013-01-22 18:09:38 +0900645 slsmg_printf("%s", hpp->buf);
646
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900647 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900648 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900649}
650
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900651#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900652static u64 __hpp_get_##_field(struct hist_entry *he) \
653{ \
654 return he->stat._field; \
655} \
656 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100657static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900658hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100659 struct perf_hpp *hpp, \
660 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900661{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900662 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
663 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900664}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900665
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900666#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
667static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
668{ \
669 return he->stat_acc->_field; \
670} \
671 \
672static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900673hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900674 struct perf_hpp *hpp, \
675 struct hist_entry *he) \
676{ \
677 if (!symbol_conf.cumulate_callchain) { \
Namhyung Kim5b591662014-07-31 14:47:38 +0900678 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900679 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900680 "%*s", len, "N/A"); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900681 slsmg_printf("%s", hpp->buf); \
682 \
683 return ret; \
684 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900685 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
686 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900687}
688
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900689__HPP_COLOR_PERCENT_FN(overhead, period)
690__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
691__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
692__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
693__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900694__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900695
696#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900697#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900698
699void hist_browser__init_hpp(void)
700{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900701 perf_hpp__format[PERF_HPP__OVERHEAD].color =
702 hist_browser__hpp_color_overhead;
703 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
704 hist_browser__hpp_color_overhead_sys;
705 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
706 hist_browser__hpp_color_overhead_us;
707 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
708 hist_browser__hpp_color_overhead_guest_sys;
709 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
710 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900711 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
712 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900713}
714
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300715static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300716 struct hist_entry *entry,
717 unsigned short row)
718{
719 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200720 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900721 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300722 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300723 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300724 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300725 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200726 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300727
728 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300729 browser->he_selection = entry;
730 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300731 }
732
733 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300734 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300735 folded_sign = hist_entry__folded(entry);
736 }
737
738 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900739 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900740 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900741 .folded_sign = folded_sign,
742 .current_entry = current_entry,
743 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900744 struct perf_hpp hpp = {
745 .buf = s,
746 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900747 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900748 };
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300749
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300750 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900751
Jiri Olsa12400052012-10-13 00:06:16 +0200752 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900753 if (perf_hpp__should_skip(fmt))
754 continue;
755
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900756 if (current_entry && browser->b.navkeypressed) {
757 ui_browser__set_color(&browser->b,
758 HE_COLORSET_SELECTED);
759 } else {
760 ui_browser__set_color(&browser->b,
761 HE_COLORSET_NORMAL);
762 }
763
764 if (first) {
765 if (symbol_conf.use_callchain) {
766 slsmg_printf("%c ", folded_sign);
767 width -= 2;
768 }
769 first = false;
770 } else {
Namhyung Kimf5951d52012-09-03 11:53:09 +0900771 slsmg_printf(" ");
772 width -= 2;
773 }
774
Jiri Olsa12400052012-10-13 00:06:16 +0200775 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100776 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900777 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100778 width -= fmt->entry(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900779 slsmg_printf("%s", s);
780 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300781 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200782
783 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300784 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200785 width += 1;
786
Namhyung Kim26d8b332014-03-03 16:16:20 +0900787 slsmg_write_nstring("", width);
788
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300789 ++row;
790 ++printed;
791 } else
792 --row_offset;
793
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300794 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900795 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900796 struct callchain_print_arg arg = {
797 .row_offset = row_offset,
798 .is_current_entry = current_entry,
799 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900800
Namhyung Kim4087d112014-11-24 17:13:26 +0900801 if (callchain_param.mode == CHAIN_GRAPH_REL) {
802 if (symbol_conf.cumulate_callchain)
803 total = entry->stat_acc->period;
804 else
805 total = entry->stat.period;
806 }
807
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900808 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900809 &entry->sorted_chain, 1, row, total,
810 hist_browser__show_callchain_entry, &arg,
811 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900812
Namhyung Kim39ee5332014-08-22 09:13:21 +0900813 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300814 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300815 }
816
817 return printed;
818}
819
Jiri Olsa81a888f2014-06-14 15:44:52 +0200820static int advance_hpp_check(struct perf_hpp *hpp, int inc)
821{
822 advance_hpp(hpp, inc);
823 return hpp->size <= 0;
824}
825
826static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
827{
828 struct perf_hpp dummy_hpp = {
829 .buf = buf,
830 .size = size,
831 };
832 struct perf_hpp_fmt *fmt;
833 size_t ret = 0;
834
835 if (symbol_conf.use_callchain) {
836 ret = scnprintf(buf, size, " ");
837 if (advance_hpp_check(&dummy_hpp, ret))
838 return ret;
839 }
840
841 perf_hpp__for_each_format(fmt) {
842 if (perf_hpp__should_skip(fmt))
843 continue;
844
Jiri Olsa81a888f2014-06-14 15:44:52 +0200845 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
846 if (advance_hpp_check(&dummy_hpp, ret))
847 break;
848
849 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
850 if (advance_hpp_check(&dummy_hpp, ret))
851 break;
852 }
853
854 return ret;
855}
856
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200857static void hist_browser__show_headers(struct hist_browser *browser)
858{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200859 char headers[1024];
860
861 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200862 ui_browser__gotorc(&browser->b, 0, 0);
863 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Jiri Olsa81a888f2014-06-14 15:44:52 +0200864 slsmg_write_nstring(headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200865}
866
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300867static void ui_browser__hists_init_top(struct ui_browser *browser)
868{
869 if (browser->top == NULL) {
870 struct hist_browser *hb;
871
872 hb = container_of(browser, struct hist_browser, b);
873 browser->top = rb_first(&hb->hists->entries);
874 }
875}
876
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300877static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300878{
879 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200880 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300881 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300882 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300883
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200884 if (hb->show_headers) {
885 hist_browser__show_headers(hb);
886 header_offset = 1;
887 }
888
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300889 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300890
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300891 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300892 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900893 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300894
895 if (h->filtered)
896 continue;
897
Namhyung Kim14135662013-10-31 10:17:39 +0900898 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900899 if (percent < hb->min_pcnt)
900 continue;
901
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300902 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300903 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904 break;
905 }
906
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200907 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300908}
909
Namhyung Kim064f1982013-05-14 11:09:04 +0900910static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900911 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300912{
913 while (nd != NULL) {
914 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900915 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900916
Namhyung Kimc0f15272014-04-16 11:16:33 +0900917 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300918 return nd;
919
920 nd = rb_next(nd);
921 }
922
923 return NULL;
924}
925
Namhyung Kim064f1982013-05-14 11:09:04 +0900926static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900927 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300928{
929 while (nd != NULL) {
930 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900931 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900932
933 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300934 return nd;
935
936 nd = rb_prev(nd);
937 }
938
939 return NULL;
940}
941
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300942static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300943 off_t offset, int whence)
944{
945 struct hist_entry *h;
946 struct rb_node *nd;
947 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900948 struct hist_browser *hb;
949
950 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300951
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300952 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300953 return;
954
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300955 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300956
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300957 switch (whence) {
958 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900959 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900960 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300961 break;
962 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300963 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300964 goto do_offset;
965 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +0900966 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900967 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300968 first = false;
969 break;
970 default:
971 return;
972 }
973
974 /*
975 * Moves not relative to the first visible entry invalidates its
976 * row_offset:
977 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300978 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300979 h->row_offset = 0;
980
981 /*
982 * Here we have to check if nd is expanded (+), if it is we can't go
983 * the next top level hist_entry, instead we must compute an offset of
984 * what _not_ to show and not change the first visible entry.
985 *
986 * This offset increments when we are going from top to bottom and
987 * decreases when we're going from bottom to top.
988 *
989 * As we don't have backpointers to the top level in the callchains
990 * structure, we need to always print the whole hist_entry callchain,
991 * skipping the first ones that are before the first visible entry
992 * and stop when we printed enough lines to fill the screen.
993 */
994do_offset:
995 if (offset > 0) {
996 do {
997 h = rb_entry(nd, struct hist_entry, rb_node);
998 if (h->ms.unfolded) {
999 u16 remaining = h->nr_rows - h->row_offset;
1000 if (offset > remaining) {
1001 offset -= remaining;
1002 h->row_offset = 0;
1003 } else {
1004 h->row_offset += offset;
1005 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001006 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001007 break;
1008 }
1009 }
Namhyung Kim14135662013-10-31 10:17:39 +09001010 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001011 if (nd == NULL)
1012 break;
1013 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001014 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001015 } while (offset != 0);
1016 } else if (offset < 0) {
1017 while (1) {
1018 h = rb_entry(nd, struct hist_entry, rb_node);
1019 if (h->ms.unfolded) {
1020 if (first) {
1021 if (-offset > h->row_offset) {
1022 offset += h->row_offset;
1023 h->row_offset = 0;
1024 } else {
1025 h->row_offset += offset;
1026 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001027 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001028 break;
1029 }
1030 } else {
1031 if (-offset > h->nr_rows) {
1032 offset += h->nr_rows;
1033 h->row_offset = 0;
1034 } else {
1035 h->row_offset = h->nr_rows + offset;
1036 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001037 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001038 break;
1039 }
1040 }
1041 }
1042
Namhyung Kim14135662013-10-31 10:17:39 +09001043 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001044 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001045 if (nd == NULL)
1046 break;
1047 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001048 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001049 if (offset == 0) {
1050 /*
1051 * Last unfiltered hist_entry, check if it is
1052 * unfolded, if it is then we should have
1053 * row_offset at its last entry.
1054 */
1055 h = rb_entry(nd, struct hist_entry, rb_node);
1056 if (h->ms.unfolded)
1057 h->row_offset = h->nr_rows;
1058 break;
1059 }
1060 first = false;
1061 }
1062 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001063 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001064 h = rb_entry(nd, struct hist_entry, rb_node);
1065 h->row_offset = 0;
1066 }
1067}
1068
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001069static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001070 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001071{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001072 u64 total = hists__total_period(he->hists);
1073 struct callchain_print_arg arg = {
1074 .fp = fp,
1075 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001076
Namhyung Kim39ee5332014-08-22 09:13:21 +09001077 if (symbol_conf.cumulate_callchain)
1078 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001079
Namhyung Kim39ee5332014-08-22 09:13:21 +09001080 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1081 hist_browser__fprintf_callchain_entry, &arg,
1082 hist_browser__check_dump_full);
1083 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001084}
1085
1086static int hist_browser__fprintf_entry(struct hist_browser *browser,
1087 struct hist_entry *he, FILE *fp)
1088{
1089 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001090 int printed = 0;
1091 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001092 struct perf_hpp hpp = {
1093 .buf = s,
1094 .size = sizeof(s),
1095 };
1096 struct perf_hpp_fmt *fmt;
1097 bool first = true;
1098 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001099
1100 if (symbol_conf.use_callchain)
1101 folded_sign = hist_entry__folded(he);
1102
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001103 if (symbol_conf.use_callchain)
1104 printed += fprintf(fp, "%c ", folded_sign);
1105
Namhyung Kim26d8b332014-03-03 16:16:20 +09001106 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001107 if (perf_hpp__should_skip(fmt))
1108 continue;
1109
Namhyung Kim26d8b332014-03-03 16:16:20 +09001110 if (!first) {
1111 ret = scnprintf(hpp.buf, hpp.size, " ");
1112 advance_hpp(&hpp, ret);
1113 } else
1114 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001115
Namhyung Kim26d8b332014-03-03 16:16:20 +09001116 ret = fmt->entry(fmt, &hpp, he);
1117 advance_hpp(&hpp, ret);
1118 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001119 printed += fprintf(fp, "%s\n", rtrim(s));
1120
1121 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001122 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001123
1124 return printed;
1125}
1126
1127static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1128{
Namhyung Kim064f1982013-05-14 11:09:04 +09001129 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001130 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001131 int printed = 0;
1132
1133 while (nd) {
1134 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1135
1136 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001137 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001138 }
1139
1140 return printed;
1141}
1142
1143static int hist_browser__dump(struct hist_browser *browser)
1144{
1145 char filename[64];
1146 FILE *fp;
1147
1148 while (1) {
1149 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1150 if (access(filename, F_OK))
1151 break;
1152 /*
1153 * XXX: Just an arbitrary lazy upper limit
1154 */
1155 if (++browser->print_seq == 8192) {
1156 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1157 return -1;
1158 }
1159 }
1160
1161 fp = fopen(filename, "w");
1162 if (fp == NULL) {
1163 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001164 const char *err = strerror_r(errno, bf, sizeof(bf));
1165 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001166 return -1;
1167 }
1168
1169 ++browser->print_seq;
1170 hist_browser__fprintf(browser, fp);
1171 fclose(fp);
1172 ui_helpline__fpush("%s written!", filename);
1173
1174 return 0;
1175}
1176
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001177static struct hist_browser *hist_browser__new(struct hists *hists)
1178{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001179 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001181 if (browser) {
1182 browser->hists = hists;
1183 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001184 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001185 browser->b.seek = ui_browser__hists_seek;
1186 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001187 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001188 }
1189
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001190 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001191}
1192
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001193static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001194{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001195 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196}
1197
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001198static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001200 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201}
1202
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001203static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001205 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206}
1207
Taeung Song1e378eb2014-10-07 16:13:15 +09001208/* Check whether the browser is for 'top' or 'report' */
1209static inline bool is_report_browser(void *timer)
1210{
1211 return timer == NULL;
1212}
1213
1214static int hists__browser_title(struct hists *hists,
1215 struct hist_browser_timer *hbt,
1216 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001217{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001218 char unit;
1219 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001220 const struct dso *dso = hists->dso_filter;
1221 const struct thread *thread = hists->thread_filter;
1222 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1223 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001224 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001225 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001226 char buf[512];
1227 size_t buflen = sizeof(buf);
1228
Namhyung Kimf2148332014-01-14 11:52:48 +09001229 if (symbol_conf.filter_relative) {
1230 nr_samples = hists->stats.nr_non_filtered_samples;
1231 nr_events = hists->stats.total_non_filtered_period;
1232 }
1233
Namhyung Kim759ff492013-03-05 14:53:26 +09001234 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001235 struct perf_evsel *pos;
1236
1237 perf_evsel__group_desc(evsel, buf, buflen);
1238 ev_name = buf;
1239
1240 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001241 struct hists *pos_hists = evsel__hists(pos);
1242
Namhyung Kimf2148332014-01-14 11:52:48 +09001243 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001244 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1245 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001246 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001247 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1248 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001249 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001250 }
1251 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001252
Ashay Ranecc686282012-04-05 21:01:01 -05001253 nr_samples = convert_unit(nr_samples, &unit);
1254 printed = scnprintf(bf, size,
Tom Huynhe641f692014-12-02 11:37:22 -06001255 "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
Ashay Ranecc686282012-04-05 21:01:01 -05001256 nr_samples, unit, ev_name, nr_events);
1257
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001258
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001259 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001260 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001261 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001262 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001263 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001264 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001265 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001266 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001267 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001268 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001269 ", DSO: %s", dso->short_name);
Taeung Song1e378eb2014-10-07 16:13:15 +09001270 if (!is_report_browser(hbt)) {
1271 struct perf_top *top = hbt->arg;
1272
1273 if (top->zero)
1274 printed += scnprintf(bf + printed, size - printed, " [z]");
1275 }
1276
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001277 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001278}
1279
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001280static inline void free_popup_options(char **options, int n)
1281{
1282 int i;
1283
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001284 for (i = 0; i < n; ++i)
1285 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001286}
1287
Feng Tang341487ab2013-02-03 14:38:20 +08001288/*
1289 * Only runtime switching of perf data file will make "input_name" point
1290 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1291 * whether we need to call free() for current "input_name" during the switch.
1292 */
1293static bool is_input_name_malloced = false;
1294
1295static int switch_data_file(void)
1296{
1297 char *pwd, *options[32], *abs_path[32], *tmp;
1298 DIR *pwd_dir;
1299 int nr_options = 0, choice = -1, ret = -1;
1300 struct dirent *dent;
1301
1302 pwd = getenv("PWD");
1303 if (!pwd)
1304 return ret;
1305
1306 pwd_dir = opendir(pwd);
1307 if (!pwd_dir)
1308 return ret;
1309
1310 memset(options, 0, sizeof(options));
1311 memset(options, 0, sizeof(abs_path));
1312
1313 while ((dent = readdir(pwd_dir))) {
1314 char path[PATH_MAX];
1315 u64 magic;
1316 char *name = dent->d_name;
1317 FILE *file;
1318
1319 if (!(dent->d_type == DT_REG))
1320 continue;
1321
1322 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1323
1324 file = fopen(path, "r");
1325 if (!file)
1326 continue;
1327
1328 if (fread(&magic, 1, 8, file) < 8)
1329 goto close_file_and_continue;
1330
1331 if (is_perf_magic(magic)) {
1332 options[nr_options] = strdup(name);
1333 if (!options[nr_options])
1334 goto close_file_and_continue;
1335
1336 abs_path[nr_options] = strdup(path);
1337 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001338 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001339 ui__warning("Can't search all data files due to memory shortage.\n");
1340 fclose(file);
1341 break;
1342 }
1343
1344 nr_options++;
1345 }
1346
1347close_file_and_continue:
1348 fclose(file);
1349 if (nr_options >= 32) {
1350 ui__warning("Too many perf data files in PWD!\n"
1351 "Only the first 32 files will be listed.\n");
1352 break;
1353 }
1354 }
1355 closedir(pwd_dir);
1356
1357 if (nr_options) {
1358 choice = ui__popup_menu(nr_options, options);
1359 if (choice < nr_options && choice >= 0) {
1360 tmp = strdup(abs_path[choice]);
1361 if (tmp) {
1362 if (is_input_name_malloced)
1363 free((void *)input_name);
1364 input_name = tmp;
1365 is_input_name_malloced = true;
1366 ret = 0;
1367 } else
1368 ui__warning("Data switch failed due to memory shortage!\n");
1369 }
1370 }
1371
1372 free_popup_options(options, nr_options);
1373 free_popup_options(abs_path, nr_options);
1374 return ret;
1375}
1376
Namhyung Kim112f7612014-04-22 14:05:35 +09001377static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001378{
1379 u64 nr_entries = 0;
1380 struct rb_node *nd = rb_first(&hb->hists->entries);
1381
Namhyung Kim268397c2014-04-22 14:49:31 +09001382 if (hb->min_pcnt == 0) {
1383 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1384 return;
1385 }
1386
Namhyung Kim14135662013-10-31 10:17:39 +09001387 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001388 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001389 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001390 }
1391
Namhyung Kim112f7612014-04-22 14:05:35 +09001392 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001393}
Feng Tang341487ab2013-02-03 14:38:20 +08001394
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001395static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001396 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001397 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001398 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001399 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001400 struct perf_session_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001401{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001402 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001403 struct hist_browser *browser = hist_browser__new(hists);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001404 struct branch_info *bi;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001405 struct pstack *fstack;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001406 char *options[16];
1407 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001408 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001409 char buf[64];
Feng Tangcdbab7c2012-10-30 11:56:06 +08001410 char script_opt[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001411 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001412 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001413
Namhyung Kime8e684a2013-12-26 14:37:58 +09001414#define HIST_BROWSER_HELP_COMMON \
1415 "h/?/F1 Show this window\n" \
1416 "UP/DOWN/PGUP\n" \
1417 "PGDN/SPACE Navigate\n" \
1418 "q/ESC/CTRL+C Exit browser\n\n" \
1419 "For multiple event sessions:\n\n" \
1420 "TAB/UNTAB Switch events\n\n" \
1421 "For symbolic views (--sort has sym):\n\n" \
1422 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1423 "<- Zoom out\n" \
1424 "a Annotate current symbol\n" \
1425 "C Collapse all callchains\n" \
1426 "d Zoom into current DSO\n" \
1427 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001428 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001429 "H Display column headers\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001430
1431 /* help messages are sorted by lexical order of the hotkey */
1432 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001433 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001434 "P Print histograms to perf.hist.N\n"
1435 "r Run available scripts\n"
1436 "s Switch to another data file in PWD\n"
1437 "t Zoom into current Thread\n"
1438 "V Verbose (DSO names in callchains, etc)\n"
1439 "/ Filter symbol by name";
1440 const char top_help[] = HIST_BROWSER_HELP_COMMON
1441 "P Print histograms to perf.hist.N\n"
1442 "t Zoom into current Thread\n"
1443 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001444 "z Toggle zeroing of samples\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001445 "/ Filter symbol by name";
1446
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001447 if (browser == NULL)
1448 return -1;
1449
Namhyung Kim064f1982013-05-14 11:09:04 +09001450 if (min_pcnt) {
1451 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001452 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001453 }
1454
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001455 fstack = pstack__new(2);
1456 if (fstack == NULL)
1457 goto out;
1458
1459 ui_helpline__push(helpline);
1460
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001461 memset(options, 0, sizeof(options));
1462
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001463 perf_hpp__for_each_format(fmt)
1464 perf_hpp__reset_width(fmt, hists);
1465
Namhyung Kim5b591662014-07-31 14:47:38 +09001466 if (symbol_conf.col_width_list_str)
1467 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1468
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001469 while (1) {
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001470 const struct thread *thread = NULL;
1471 const struct dso *dso = NULL;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001472 int choice = 0,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001473 annotate = -2, zoom_dso = -2, zoom_thread = -2,
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001474 annotate_f = -2, annotate_t = -2, browse_map = -2;
Feng Tang341487ab2013-02-03 14:38:20 +08001475 int scripts_comm = -2, scripts_symbol = -2,
1476 scripts_all = -2, switch_data = -2;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001477
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001478 nr_options = 0;
1479
Jiri Olsadd00d482014-06-19 13:41:13 +02001480 key = hist_browser__run(browser, hbt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001481
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001482 if (browser->he_selection != NULL) {
1483 thread = hist_browser__selected_thread(browser);
1484 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1485 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001486 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001487 case K_TAB:
1488 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001489 if (nr_events == 1)
1490 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001491 /*
1492 * Exit the browser, let hists__browser_tree
1493 * go to the next or previous
1494 */
1495 goto out_free_stack;
1496 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001497 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001498 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001499 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001500 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001501 continue;
1502 }
1503
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001504 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001505 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001506 browser->selection->map->dso->annotate_warned)
1507 continue;
1508 goto do_annotate;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001509 case 'P':
1510 hist_browser__dump(browser);
1511 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001512 case 'd':
1513 goto zoom_dso;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001514 case 'V':
1515 browser->show_dso = !browser->show_dso;
1516 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001517 case 't':
1518 goto zoom_thread;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001519 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001520 if (ui_browser__input_window("Symbol to show",
1521 "Please enter the name of symbol you want to see",
1522 buf, "ENTER: OK, ESC: Cancel",
1523 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001524 hists->symbol_filter_str = *buf ? buf : NULL;
1525 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001526 hist_browser__reset(browser);
1527 }
1528 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001529 case 'r':
Namhyung Kim9783adf2012-11-02 14:50:05 +09001530 if (is_report_browser(hbt))
Feng Tangc77d8d72012-11-01 00:00:55 +08001531 goto do_scripts;
1532 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001533 case 's':
1534 if (is_report_browser(hbt))
1535 goto do_data_switch;
1536 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001537 case 'i':
1538 /* env->arch is NULL for live-mode (i.e. perf top) */
1539 if (env->arch)
1540 tui__header_window(env);
1541 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001542 case 'F':
1543 symbol_conf.filter_relative ^= 1;
1544 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001545 case 'z':
1546 if (!is_report_browser(hbt)) {
1547 struct perf_top *top = hbt->arg;
1548
1549 top->zero = !top->zero;
1550 }
1551 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001552 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001553 case 'h':
1554 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001555 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001556 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001557 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001558 case K_ENTER:
1559 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001560 /* menu */
1561 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001562 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001563 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001564
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001565 if (pstack__empty(fstack)) {
1566 /*
1567 * Go back to the perf_evsel_menu__run or other user
1568 */
1569 if (left_exits)
1570 goto out_free_stack;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001571 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001572 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001573 top = pstack__pop(fstack);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001574 if (top == &browser->hists->dso_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001575 goto zoom_out_dso;
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001576 if (top == &browser->hists->thread_filter)
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001577 goto zoom_out_thread;
1578 continue;
1579 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001580 case K_ESC:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001581 if (!left_exits &&
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001582 !ui_browser__dialog_yesno(&browser->b,
1583 "Do you really want to exit?"))
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001584 continue;
1585 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001586 case 'q':
1587 case CTRL('c'):
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001588 goto out_free_stack;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001589 default:
1590 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001591 }
1592
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001593 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001594 goto add_exit_option;
1595
Namhyung Kim55369fc2013-04-01 20:35:20 +09001596 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001597 bi = browser->he_selection->branch_info;
1598 if (browser->selection != NULL &&
1599 bi &&
1600 bi->from.sym != NULL &&
1601 !bi->from.map->dso->annotate_warned &&
1602 asprintf(&options[nr_options], "Annotate %s",
1603 bi->from.sym->name) > 0)
1604 annotate_f = nr_options++;
1605
1606 if (browser->selection != NULL &&
1607 bi &&
1608 bi->to.sym != NULL &&
1609 !bi->to.map->dso->annotate_warned &&
Stephane Eranian8bcd65f2012-03-12 16:13:29 +01001610 (bi->to.sym != bi->from.sym ||
1611 bi->to.map->dso != bi->from.map->dso) &&
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001612 asprintf(&options[nr_options], "Annotate %s",
1613 bi->to.sym->name) > 0)
1614 annotate_t = nr_options++;
1615 } else {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001616 if (browser->selection != NULL &&
1617 browser->selection->sym != NULL &&
Jiri Olsad7553302014-06-15 10:22:15 +02001618 !browser->selection->map->dso->annotate_warned) {
1619 struct annotation *notes;
1620
1621 notes = symbol__annotation(browser->selection->sym);
1622
1623 if (notes->src &&
1624 asprintf(&options[nr_options], "Annotate %s",
1625 browser->selection->sym->name) > 0)
1626 annotate = nr_options++;
1627 }
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001628 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001629
1630 if (thread != NULL &&
1631 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001632 (browser->hists->thread_filter ? "out of" : "into"),
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001633 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001634 thread->tid) > 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001635 zoom_thread = nr_options++;
1636
1637 if (dso != NULL &&
1638 asprintf(&options[nr_options], "Zoom %s %s DSO",
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001639 (browser->hists->dso_filter ? "out of" : "into"),
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001640 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1641 zoom_dso = nr_options++;
1642
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001643 if (browser->selection != NULL &&
1644 browser->selection->map != NULL &&
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001645 asprintf(&options[nr_options], "Browse map details") > 0)
1646 browse_map = nr_options++;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001647
1648 /* perf script support */
1649 if (browser->he_selection) {
1650 struct symbol *sym;
1651
1652 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001653 thread__comm_str(browser->he_selection->thread)) > 0)
Feng Tangcdbab7c2012-10-30 11:56:06 +08001654 scripts_comm = nr_options++;
1655
1656 sym = browser->he_selection->ms.sym;
1657 if (sym && sym->namelen &&
1658 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1659 sym->name) > 0)
1660 scripts_symbol = nr_options++;
1661 }
1662
1663 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1664 scripts_all = nr_options++;
1665
Feng Tang341487ab2013-02-03 14:38:20 +08001666 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1667 "Switch to another data file in PWD") > 0)
1668 switch_data = nr_options++;
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001669add_exit_option:
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001670 options[nr_options++] = (char *)"Exit";
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001671retry_popup_menu:
Arnaldo Carvalho de Melo1e6dd072010-08-10 15:58:50 -03001672 choice = ui__popup_menu(nr_options, options);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001673
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001674 if (choice == nr_options - 1)
1675 break;
1676
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001677 if (choice == -1) {
1678 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001679 continue;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001680 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001681
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001682 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001683 struct hist_entry *he;
Jiri Olsad7553302014-06-15 10:22:15 +02001684 struct annotation *notes;
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001685 int err;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001686do_annotate:
Namhyung Kim68d80752012-11-02 14:50:06 +09001687 if (!objdump_path && perf_session_env__lookup_objdump(env))
1688 continue;
1689
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001690 he = hist_browser__selected_entry(browser);
1691 if (he == NULL)
1692 continue;
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001693
1694 /*
1695 * we stash the branch_info symbol + map into the
1696 * the ms so we don't have to rewrite all the annotation
1697 * code to use branch_info.
1698 * in branch mode, the ms struct is not used
1699 */
1700 if (choice == annotate_f) {
1701 he->ms.sym = he->branch_info->from.sym;
1702 he->ms.map = he->branch_info->from.map;
1703 } else if (choice == annotate_t) {
1704 he->ms.sym = he->branch_info->to.sym;
1705 he->ms.map = he->branch_info->to.map;
1706 }
1707
Jiri Olsad7553302014-06-15 10:22:15 +02001708 notes = symbol__annotation(he->ms.sym);
1709 if (!notes->src)
1710 continue;
1711
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001712 /*
1713 * Don't let this be freed, say, by hists__decay_entry.
1714 */
1715 he->used = true;
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001716 err = hist_entry__tui_annotate(he, evsel, hbt);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -03001717 he->used = false;
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001718 /*
1719 * offer option to annotate the other branch source or target
1720 * (if they exists) when returning from annotate
1721 */
1722 if ((err == 'q' || err == CTRL('c'))
1723 && annotate_t != -2 && annotate_f != -2)
1724 goto retry_popup_menu;
1725
Arnaldo Carvalho de Melo900e14a2011-10-11 16:15:39 -03001726 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001727 if (err)
1728 ui_browser__handle_resize(&browser->b);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001729
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001730 } else if (choice == browse_map)
1731 map__browse(browser->selection->map);
1732 else if (choice == zoom_dso) {
1733zoom_dso:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001734 if (browser->hists->dso_filter) {
1735 pstack__remove(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001736zoom_out_dso:
1737 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001738 browser->hists->dso_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001739 perf_hpp__set_elide(HISTC_DSO, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001740 } else {
1741 if (dso == NULL)
1742 continue;
1743 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1744 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001745 browser->hists->dso_filter = dso;
Jiri Olsaf2998422014-05-23 17:15:47 +02001746 perf_hpp__set_elide(HISTC_DSO, true);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001747 pstack__push(fstack, &browser->hists->dso_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001748 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001749 hists__filter_by_dso(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001750 hist_browser__reset(browser);
1751 } else if (choice == zoom_thread) {
1752zoom_thread:
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001753 if (browser->hists->thread_filter) {
1754 pstack__remove(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001755zoom_out_thread:
1756 ui_helpline__pop();
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001757 browser->hists->thread_filter = NULL;
Jiri Olsaf2998422014-05-23 17:15:47 +02001758 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001759 } else {
1760 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001761 thread->comm_set ? thread__comm_str(thread) : "",
Adrian Hunter38051232013-07-04 16:20:31 +03001762 thread->tid);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001763 browser->hists->thread_filter = thread;
Jiri Olsaf2998422014-05-23 17:15:47 +02001764 perf_hpp__set_elide(HISTC_THREAD, false);
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001765 pstack__push(fstack, &browser->hists->thread_filter);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766 }
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001767 hists__filter_by_thread(hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001768 hist_browser__reset(browser);
1769 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08001770 /* perf scripts support */
1771 else if (choice == scripts_all || choice == scripts_comm ||
1772 choice == scripts_symbol) {
1773do_scripts:
1774 memset(script_opt, 0, 64);
1775
1776 if (choice == scripts_comm)
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001777 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
Feng Tangcdbab7c2012-10-30 11:56:06 +08001778
1779 if (choice == scripts_symbol)
1780 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1781
1782 script_browse(script_opt);
1783 }
Feng Tang341487ab2013-02-03 14:38:20 +08001784 /* Switch to another data file */
1785 else if (choice == switch_data) {
1786do_data_switch:
1787 if (!switch_data_file()) {
1788 key = K_SWITCH_INPUT_DATA;
1789 break;
1790 } else
1791 ui__warning("Won't switch the data files due to\n"
1792 "no valid data file get selected!\n");
1793 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001794 }
1795out_free_stack:
1796 pstack__delete(fstack);
1797out:
1798 hist_browser__delete(browser);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001799 free_popup_options(options, nr_options - 1);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001800 return key;
1801}
1802
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001803struct perf_evsel_menu {
1804 struct ui_browser b;
1805 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001806 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09001807 float min_pcnt;
Namhyung Kim68d80752012-11-02 14:50:06 +09001808 struct perf_session_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001809};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001810
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001811static void perf_evsel_menu__write(struct ui_browser *browser,
1812 void *entry, int row)
1813{
1814 struct perf_evsel_menu *menu = container_of(browser,
1815 struct perf_evsel_menu, b);
1816 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001817 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001818 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001819 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001820 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001821 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001822 const char *warn = " ";
1823 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001824
1825 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1826 HE_COLORSET_NORMAL);
1827
Namhyung Kim759ff492013-03-05 14:53:26 +09001828 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001829 struct perf_evsel *pos;
1830
1831 ev_name = perf_evsel__group_name(evsel);
1832
1833 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001834 struct hists *pos_hists = evsel__hists(pos);
1835 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09001836 }
1837 }
1838
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001839 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001840 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001841 unit, unit == ' ' ? "" : " ", ev_name);
1842 slsmg_printf("%s", bf);
1843
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001844 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001845 if (nr_events != 0) {
1846 menu->lost_events = true;
1847 if (!current_entry)
1848 ui_browser__set_color(browser, HE_COLORSET_TOP);
1849 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001850 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1851 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001852 warn = bf;
1853 }
1854
1855 slsmg_write_nstring(warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001856
1857 if (current_entry)
1858 menu->selection = evsel;
1859}
1860
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001861static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1862 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09001863 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001864{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001865 struct perf_evlist *evlist = menu->b.priv;
1866 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02001867 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09001868 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001869 int key;
1870
1871 if (ui_browser__show(&menu->b, title,
1872 "ESC: exit, ENTER|->: Browse histograms") < 0)
1873 return -1;
1874
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001875 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03001876 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001877
1878 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001879 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09001880 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001881
1882 if (!menu->lost_events_warned && menu->lost_events) {
1883 ui_browser__warn_lost_events(&menu->b);
1884 menu->lost_events_warned = true;
1885 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001886 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001887 case K_RIGHT:
1888 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001889 if (!menu->selection)
1890 continue;
1891 pos = menu->selection;
1892browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001893 perf_evlist__set_selected(evlist, pos);
1894 /*
1895 * Give the calling tool a chance to populate the non
1896 * default evsel resorted hists tree.
1897 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09001898 if (hbt)
1899 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001900 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02001901 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001902 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001903 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001904 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001905 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001906 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001907 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001908 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001909 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001910 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001911 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001912 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001913 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03001914 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001915 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03001916 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001917 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001918 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001919 if (!ui_browser__dialog_yesno(&menu->b,
1920 "Do you really want to exit?"))
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001921 continue;
1922 /* Fall thru */
Feng Tang341487ab2013-02-03 14:38:20 +08001923 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001924 case 'q':
1925 case CTRL('c'):
1926 goto out;
1927 default:
1928 continue;
1929 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001930 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001931 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001932 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001933 if (!ui_browser__dialog_yesno(&menu->b,
1934 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001935 continue;
1936 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001937 case 'q':
1938 case CTRL('c'):
1939 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001940 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03001941 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001942 }
1943 }
1944
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001945out:
1946 ui_browser__hide(&menu->b);
1947 return key;
1948}
1949
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001950static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001951 void *entry)
1952{
1953 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1954
1955 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1956 return true;
1957
1958 return false;
1959}
1960
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001961static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001962 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001963 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001964 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001965 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001966{
1967 struct perf_evsel *pos;
1968 struct perf_evsel_menu menu = {
1969 .b = {
1970 .entries = &evlist->entries,
1971 .refresh = ui_browser__list_head_refresh,
1972 .seek = ui_browser__list_head_seek,
1973 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001974 .filter = filter_group_entries,
1975 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001976 .priv = evlist,
1977 },
Namhyung Kim064f1982013-05-14 11:09:04 +09001978 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001979 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001980 };
1981
1982 ui_helpline__push("Press ESC to exit");
1983
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03001984 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03001985 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001986 size_t line_len = strlen(ev_name) + 7;
1987
1988 if (menu.b.width < line_len)
1989 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001990 }
1991
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09001992 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001993}
1994
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001995int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09001996 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001997 float min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09001998 struct perf_session_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001999{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002000 int nr_entries = evlist->nr_entries;
2001
2002single_entry:
2003 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002004 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002005
2006 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002007 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002008 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002009 }
2010
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002011 if (symbol_conf.event_group) {
2012 struct perf_evsel *pos;
2013
2014 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002015 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002016 if (perf_evsel__is_group_leader(pos))
2017 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002018 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002019
2020 if (nr_entries == 1)
2021 goto single_entry;
2022 }
2023
2024 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002025 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002026}