blob: dcdcbafb078ba4b66c397645f7151f6d27bcec09 [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 <stdlib.h>
3#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <linux/rbtree.h>
5
Namhyung Kimaca7a942012-04-04 00:14:26 -07006#include "../../util/evsel.h"
7#include "../../util/evlist.h"
8#include "../../util/hist.h"
9#include "../../util/pstack.h"
10#include "../../util/sort.h"
11#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090012#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020020#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022struct hist_browser {
23 struct ui_browser b;
24 struct hists *hists;
25 struct hist_entry *he_selection;
26 struct map_symbol *selection;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +090027 struct hist_browser_timer *hbt;
Namhyung Kim01f00a12015-04-22 16:18:16 +090028 struct pstack *pstack;
Kan Liangce80d3b2015-08-28 05:48:04 -040029 struct perf_env *env;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -030030 int print_seq;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -030031 bool show_dso;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020032 bool show_headers;
Namhyung Kim064f1982013-05-14 11:09:04 +090033 float min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +090034 u64 nr_non_filtered_entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +090035 u64 nr_callchain_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030036};
37
Namhyung Kimf5951d52012-09-03 11:53:09 +090038extern void hist_browser__init_hpp(void);
39
Taeung Song1e378eb2014-10-07 16:13:15 +090040static int hists__browser_title(struct hists *hists,
41 struct hist_browser_timer *hbt,
42 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090043static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030044
Namhyung Kimc3b78952014-04-22 15:56:17 +090045static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090046 float min_pcnt);
47
Namhyung Kim268397c2014-04-22 14:49:31 +090048static bool hist_browser__has_filter(struct hist_browser *hb)
49{
Arnaldo Carvalho de Melo9c0fa8d2015-07-13 08:26:35 -030050 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090051}
52
He Kuang4fabf3d2015-03-12 15:21:49 +080053static int hist_browser__get_folding(struct hist_browser *browser)
54{
55 struct rb_node *nd;
56 struct hists *hists = browser->hists;
57 int unfolded_rows = 0;
58
59 for (nd = rb_first(&hists->entries);
60 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
61 nd = rb_next(nd)) {
62 struct hist_entry *he =
63 rb_entry(nd, struct hist_entry, rb_node);
64
Namhyung Kim3698dab2015-05-05 23:55:46 +090065 if (he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080066 unfolded_rows += he->nr_rows;
67 }
68 return unfolded_rows;
69}
70
Namhyung Kimc3b78952014-04-22 15:56:17 +090071static u32 hist_browser__nr_entries(struct hist_browser *hb)
72{
73 u32 nr_entries;
74
75 if (hist_browser__has_filter(hb))
76 nr_entries = hb->nr_non_filtered_entries;
77 else
78 nr_entries = hb->hists->nr_entries;
79
He Kuang4fabf3d2015-03-12 15:21:49 +080080 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090081 return nr_entries + hb->nr_callchain_rows;
82}
83
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020084static void hist_browser__update_rows(struct hist_browser *hb)
85{
86 struct ui_browser *browser = &hb->b;
87 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
88
89 browser->rows = browser->height - header_offset;
90 /*
91 * Verify if we were at the last line and that line isn't
92 * visibe because we now show the header line(s).
93 */
94 index_row = browser->index - browser->top_idx;
95 if (index_row >= browser->rows)
96 browser->index -= index_row - browser->rows + 1;
97}
98
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030099static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300100{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300101 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
102
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300103 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300104 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
105 /*
106 * FIXME: Just keeping existing behaviour, but this really should be
107 * before updating browser->width, as it will invalidate the
108 * calculation above. Fix this and the fallout in another
109 * changeset.
110 */
111 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200112 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300113}
114
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300115static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
116{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200117 u16 header_offset = browser->show_headers ? 1 : 0;
118
119 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300120}
121
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300122static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300123{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900124 /*
125 * The hists__remove_entry_filter() already folds non-filtered
126 * entries so we can assume it has 0 callchain rows.
127 */
128 browser->nr_callchain_rows = 0;
129
Namhyung Kim268397c2014-04-22 14:49:31 +0900130 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900131 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300132 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300133 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300134}
135
136static char tree__folded_sign(bool unfolded)
137{
138 return unfolded ? '-' : '+';
139}
140
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300141static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300142{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900143 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144}
145
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300146static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300147{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900148 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300149}
150
Namhyung Kim3698dab2015-05-05 23:55:46 +0900151static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300152{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900153 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300154}
155
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300156static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300157{
158 int n = 0;
159 struct rb_node *nd;
160
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300161 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300162 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
163 struct callchain_list *chain;
164 char folded_sign = ' '; /* No children */
165
166 list_for_each_entry(chain, &child->val, list) {
167 ++n;
168 /* We need this because we may not have children */
169 folded_sign = callchain_list__folded(chain);
170 if (folded_sign == '+')
171 break;
172 }
173
174 if (folded_sign == '-') /* Have children and they're unfolded */
175 n += callchain_node__count_rows_rb_tree(child);
176 }
177
178 return n;
179}
180
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900181static int callchain_node__count_flat_rows(struct callchain_node *node)
182{
183 struct callchain_list *chain;
184 char folded_sign = 0;
185 int n = 0;
186
187 list_for_each_entry(chain, &node->parent_val, list) {
188 if (!folded_sign) {
189 /* only check first chain list entry */
190 folded_sign = callchain_list__folded(chain);
191 if (folded_sign == '+')
192 return 1;
193 }
194 n++;
195 }
196
197 list_for_each_entry(chain, &node->val, list) {
198 if (!folded_sign) {
199 /* node->parent_val list might be empty */
200 folded_sign = callchain_list__folded(chain);
201 if (folded_sign == '+')
202 return 1;
203 }
204 n++;
205 }
206
207 return n;
208}
209
Namhyung Kim8c430a32015-11-09 14:45:44 +0900210static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
211{
212 return 1;
213}
214
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300215static int callchain_node__count_rows(struct callchain_node *node)
216{
217 struct callchain_list *chain;
218 bool unfolded = false;
219 int n = 0;
220
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900221 if (callchain_param.mode == CHAIN_FLAT)
222 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900223 else if (callchain_param.mode == CHAIN_FOLDED)
224 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900225
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300226 list_for_each_entry(chain, &node->val, list) {
227 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900228 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229 }
230
231 if (unfolded)
232 n += callchain_node__count_rows_rb_tree(node);
233
234 return n;
235}
236
237static int callchain__count_rows(struct rb_root *chain)
238{
239 struct rb_node *nd;
240 int n = 0;
241
242 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
243 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
244 n += callchain_node__count_rows(node);
245 }
246
247 return n;
248}
249
Namhyung Kim3698dab2015-05-05 23:55:46 +0900250static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300251{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900252 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200253 return false;
254
Namhyung Kim3698dab2015-05-05 23:55:46 +0900255 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300256 return false;
257
Namhyung Kim3698dab2015-05-05 23:55:46 +0900258 he->unfolded = !he->unfolded;
259 return true;
260}
261
262static bool callchain_list__toggle_fold(struct callchain_list *cl)
263{
264 if (!cl)
265 return false;
266
267 if (!cl->has_children)
268 return false;
269
270 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300271 return true;
272}
273
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300274static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300275{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300276 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300277
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300278 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300279 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
280 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300281 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300282
283 list_for_each_entry(chain, &child->val, list) {
284 if (first) {
285 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900286 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300287 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300288 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900289 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300290 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300291 }
292
293 callchain_node__init_have_children_rb_tree(child);
294 }
295}
296
Namhyung Kima7444af2014-11-24 17:13:27 +0900297static void callchain_node__init_have_children(struct callchain_node *node,
298 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300299{
300 struct callchain_list *chain;
301
Namhyung Kima7444af2014-11-24 17:13:27 +0900302 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900303 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900304
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900305 if (node->val.next != node->val.prev) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900306 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900307 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900308 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300309
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300310 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300311}
312
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300313static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300314{
Namhyung Kima7444af2014-11-24 17:13:27 +0900315 struct rb_node *nd = rb_first(root);
316 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300317
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300318 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300319 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900320 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900321 if (callchain_param.mode == CHAIN_FLAT ||
322 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900323 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300324 }
325}
326
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300327static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300328{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300329 if (!he->init_have_children) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900330 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300331 callchain__init_have_children(&he->sorted_chain);
332 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300333 }
334}
335
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300336static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300337{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900338 struct hist_entry *he = browser->he_selection;
339 struct map_symbol *ms = browser->selection;
340 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
341 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300342
Namhyung Kim3698dab2015-05-05 23:55:46 +0900343 if (ms == &he->ms)
344 has_children = hist_entry__toggle_fold(he);
345 else
346 has_children = callchain_list__toggle_fold(cl);
347
348 if (has_children) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300349 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900350 browser->b.nr_entries -= he->nr_rows;
351 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300352
Namhyung Kim3698dab2015-05-05 23:55:46 +0900353 if (he->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300354 he->nr_rows = callchain__count_rows(&he->sorted_chain);
355 else
356 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900357
358 browser->b.nr_entries += he->nr_rows;
359 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300360
361 return true;
362 }
363
364 /* If it doesn't have children, no toggling performed */
365 return false;
366}
367
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300369{
370 int n = 0;
371 struct rb_node *nd;
372
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300373 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300374 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
375 struct callchain_list *chain;
376 bool has_children = false;
377
378 list_for_each_entry(chain, &child->val, list) {
379 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900380 callchain_list__set_folding(chain, unfold);
381 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300382 }
383
384 if (has_children)
385 n += callchain_node__set_folding_rb_tree(child, unfold);
386 }
387
388 return n;
389}
390
391static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
392{
393 struct callchain_list *chain;
394 bool has_children = false;
395 int n = 0;
396
397 list_for_each_entry(chain, &node->val, list) {
398 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900399 callchain_list__set_folding(chain, unfold);
400 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300401 }
402
403 if (has_children)
404 n += callchain_node__set_folding_rb_tree(node, unfold);
405
406 return n;
407}
408
409static int callchain__set_folding(struct rb_root *chain, bool unfold)
410{
411 struct rb_node *nd;
412 int n = 0;
413
414 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
415 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
416 n += callchain_node__set_folding(node, unfold);
417 }
418
419 return n;
420}
421
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300422static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300423{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300424 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900425 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300426
Namhyung Kim3698dab2015-05-05 23:55:46 +0900427 if (he->has_children) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300428 int n = callchain__set_folding(&he->sorted_chain, unfold);
429 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300430 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300431 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300432}
433
Namhyung Kimc3b78952014-04-22 15:56:17 +0900434static void
435__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300436{
437 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900438 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300439
Namhyung Kimc3b78952014-04-22 15:56:17 +0900440 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900441 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900442 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300443 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
444 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900445 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300446 }
447}
448
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300449static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300450{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900451 browser->nr_callchain_rows = 0;
452 __hist_browser__set_folding(browser, unfold);
453
454 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300455 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300456 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300457}
458
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200459static void ui_browser__warn_lost_events(struct ui_browser *browser)
460{
461 ui_browser__warning(browser, 4,
462 "Events are being lost, check IO/CPU overload!\n\n"
463 "You may want to run 'perf' using a RT scheduler policy:\n\n"
464 " perf top -r 80\n\n"
465 "Or reduce the sampling frequency.");
466}
467
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300468static int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300469{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300470 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300471 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900472 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900473 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300474
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300475 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900476 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300477
Taeung Song1e378eb2014-10-07 16:13:15 +0900478 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300479
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300480 if (ui_browser__show(&browser->b, title, help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300481 return -1;
482
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300483 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300484 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300485
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300486 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900487 case K_TIMER: {
488 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900489 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900490
Namhyung Kimc3b78952014-04-22 15:56:17 +0900491 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900492 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900493
Namhyung Kimc3b78952014-04-22 15:56:17 +0900494 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900495 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200496
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300497 if (browser->hists->stats.nr_lost_warned !=
498 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
499 browser->hists->stats.nr_lost_warned =
500 browser->hists->stats.nr_events[PERF_RECORD_LOST];
501 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200502 }
503
Taeung Song1e378eb2014-10-07 16:13:15 +0900504 hists__browser_title(browser->hists,
505 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300506 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300507 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900508 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300509 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300510 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300511 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300512 struct hist_entry, rb_node);
513 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300514 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 -0300515 seq++, browser->b.nr_entries,
516 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300517 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518 browser->b.index,
519 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300520 h->row_offset, h->nr_rows);
521 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300522 break;
523 case 'C':
524 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300525 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300526 break;
527 case 'E':
528 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300529 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300530 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200531 case 'H':
532 browser->show_headers = !browser->show_headers;
533 hist_browser__update_rows(browser);
534 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200535 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300536 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300537 break;
538 /* fall thru */
539 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300540 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300541 }
542 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300543out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300544 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300545 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300546}
547
Namhyung Kim39ee5332014-08-22 09:13:21 +0900548struct callchain_print_arg {
549 /* for hists browser */
550 off_t row_offset;
551 bool is_current_entry;
552
553 /* for file dump */
554 FILE *fp;
555 int printed;
556};
557
558typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
559 struct callchain_list *chain,
560 const char *str, int offset,
561 unsigned short row,
562 struct callchain_print_arg *arg);
563
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900564static void hist_browser__show_callchain_entry(struct hist_browser *browser,
565 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900566 const char *str, int offset,
567 unsigned short row,
568 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900569{
570 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900571 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300572 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900573
574 color = HE_COLORSET_NORMAL;
575 width = browser->b.width - (offset + 2);
576 if (ui_browser__is_current_entry(&browser->b, row)) {
577 browser->selection = &chain->ms;
578 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900579 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900580 }
581
582 ui_browser__set_color(&browser->b, color);
583 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300584 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300585 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300586 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300587 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900588}
589
Namhyung Kim39ee5332014-08-22 09:13:21 +0900590static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
591 struct callchain_list *chain,
592 const char *str, int offset,
593 unsigned short row __maybe_unused,
594 struct callchain_print_arg *arg)
595{
596 char folded_sign = callchain_list__folded(chain);
597
598 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
599 folded_sign, str);
600}
601
602typedef bool (*check_output_full_fn)(struct hist_browser *browser,
603 unsigned short row);
604
605static bool hist_browser__check_output_full(struct hist_browser *browser,
606 unsigned short row)
607{
608 return browser->b.rows == row;
609}
610
611static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
612 unsigned short row __maybe_unused)
613{
614 return false;
615}
616
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300617#define LEVEL_OFFSET_STEP 3
618
Namhyung Kim18bb8382015-11-09 14:45:42 +0900619static int hist_browser__show_callchain_list(struct hist_browser *browser,
620 struct callchain_node *node,
621 struct callchain_list *chain,
622 unsigned short row, u64 total,
623 bool need_percent, int offset,
624 print_callchain_entry_fn print,
625 struct callchain_print_arg *arg)
626{
627 char bf[1024], *alloc_str;
628 const char *str;
629
630 if (arg->row_offset != 0) {
631 arg->row_offset--;
632 return 0;
633 }
634
635 alloc_str = NULL;
636 str = callchain_list__sym_name(chain, bf, sizeof(bf),
637 browser->show_dso);
638
639 if (need_percent) {
640 char buf[64];
641
642 callchain_node__scnprintf_value(node, buf, sizeof(buf),
643 total);
644
645 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
646 str = "Not enough memory!";
647 else
648 str = alloc_str;
649 }
650
651 print(browser, chain, str, offset, row, arg);
652
653 free(alloc_str);
654 return 1;
655}
656
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900657static int hist_browser__show_callchain_flat(struct hist_browser *browser,
658 struct rb_root *root,
659 unsigned short row, u64 total,
660 print_callchain_entry_fn print,
661 struct callchain_print_arg *arg,
662 check_output_full_fn is_output_full)
663{
664 struct rb_node *node;
665 int first_row = row, offset = LEVEL_OFFSET_STEP;
666 bool need_percent;
667
668 node = rb_first(root);
669 need_percent = node && rb_next(node);
670
671 while (node) {
672 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
673 struct rb_node *next = rb_next(node);
674 struct callchain_list *chain;
675 char folded_sign = ' ';
676 int first = true;
677 int extra_offset = 0;
678
679 list_for_each_entry(chain, &child->parent_val, list) {
680 bool was_first = first;
681
682 if (first)
683 first = false;
684 else if (need_percent)
685 extra_offset = LEVEL_OFFSET_STEP;
686
687 folded_sign = callchain_list__folded(chain);
688
689 row += hist_browser__show_callchain_list(browser, child,
690 chain, row, total,
691 was_first && need_percent,
692 offset + extra_offset,
693 print, arg);
694
695 if (is_output_full(browser, row))
696 goto out;
697
698 if (folded_sign == '+')
699 goto next;
700 }
701
702 list_for_each_entry(chain, &child->val, list) {
703 bool was_first = first;
704
705 if (first)
706 first = false;
707 else if (need_percent)
708 extra_offset = LEVEL_OFFSET_STEP;
709
710 folded_sign = callchain_list__folded(chain);
711
712 row += hist_browser__show_callchain_list(browser, child,
713 chain, row, total,
714 was_first && need_percent,
715 offset + extra_offset,
716 print, arg);
717
718 if (is_output_full(browser, row))
719 goto out;
720
721 if (folded_sign == '+')
722 break;
723 }
724
725next:
726 if (is_output_full(browser, row))
727 break;
728 node = next;
729 }
730out:
731 return row - first_row;
732}
733
Namhyung Kim8c430a32015-11-09 14:45:44 +0900734static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
735 struct callchain_list *chain,
736 char *value_str, char *old_str)
737{
738 char bf[1024];
739 const char *str;
740 char *new;
741
742 str = callchain_list__sym_name(chain, bf, sizeof(bf),
743 browser->show_dso);
744 if (old_str) {
745 if (asprintf(&new, "%s%s%s", old_str,
746 symbol_conf.field_sep ?: ";", str) < 0)
747 new = NULL;
748 } else {
749 if (value_str) {
750 if (asprintf(&new, "%s %s", value_str, str) < 0)
751 new = NULL;
752 } else {
753 if (asprintf(&new, "%s", str) < 0)
754 new = NULL;
755 }
756 }
757 return new;
758}
759
760static int hist_browser__show_callchain_folded(struct hist_browser *browser,
761 struct rb_root *root,
762 unsigned short row, u64 total,
763 print_callchain_entry_fn print,
764 struct callchain_print_arg *arg,
765 check_output_full_fn is_output_full)
766{
767 struct rb_node *node;
768 int first_row = row, offset = LEVEL_OFFSET_STEP;
769 bool need_percent;
770
771 node = rb_first(root);
772 need_percent = node && rb_next(node);
773
774 while (node) {
775 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
776 struct rb_node *next = rb_next(node);
777 struct callchain_list *chain, *first_chain = NULL;
778 int first = true;
779 char *value_str = NULL, *value_str_alloc = NULL;
780 char *chain_str = NULL, *chain_str_alloc = NULL;
781
782 if (arg->row_offset != 0) {
783 arg->row_offset--;
784 goto next;
785 }
786
787 if (need_percent) {
788 char buf[64];
789
790 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
791 if (asprintf(&value_str, "%s", buf) < 0) {
792 value_str = (char *)"<...>";
793 goto do_print;
794 }
795 value_str_alloc = value_str;
796 }
797
798 list_for_each_entry(chain, &child->parent_val, list) {
799 chain_str = hist_browser__folded_callchain_str(browser,
800 chain, value_str, chain_str);
801 if (first) {
802 first = false;
803 first_chain = chain;
804 }
805
806 if (chain_str == NULL) {
807 chain_str = (char *)"Not enough memory!";
808 goto do_print;
809 }
810
811 chain_str_alloc = chain_str;
812 }
813
814 list_for_each_entry(chain, &child->val, list) {
815 chain_str = hist_browser__folded_callchain_str(browser,
816 chain, value_str, chain_str);
817 if (first) {
818 first = false;
819 first_chain = chain;
820 }
821
822 if (chain_str == NULL) {
823 chain_str = (char *)"Not enough memory!";
824 goto do_print;
825 }
826
827 chain_str_alloc = chain_str;
828 }
829
830do_print:
831 print(browser, first_chain, chain_str, offset, row++, arg);
832 free(value_str_alloc);
833 free(chain_str_alloc);
834
835next:
836 if (is_output_full(browser, row))
837 break;
838 node = next;
839 }
840
841 return row - first_row;
842}
843
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900844static int hist_browser__show_callchain(struct hist_browser *browser,
845 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900846 unsigned short row, u64 total,
847 print_callchain_entry_fn print,
848 struct callchain_print_arg *arg,
849 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300850{
851 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900852 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900853 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900854 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300855
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900856 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900857 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900858
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300859 while (node) {
860 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
861 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300862 struct callchain_list *chain;
863 char folded_sign = ' ';
864 int first = true;
865 int extra_offset = 0;
866
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300867 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300868 bool was_first = first;
869
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300870 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300871 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900872 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300873 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300874
875 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300876
Namhyung Kim18bb8382015-11-09 14:45:42 +0900877 row += hist_browser__show_callchain_list(browser, child,
878 chain, row, total,
879 was_first && need_percent,
880 offset + extra_offset,
881 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900882
Namhyung Kim18bb8382015-11-09 14:45:42 +0900883 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300884 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900885
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300886 if (folded_sign == '+')
887 break;
888 }
889
890 if (folded_sign == '-') {
891 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900892
893 if (callchain_param.mode == CHAIN_GRAPH_REL)
894 new_total = child->children_hit;
895 else
896 new_total = total;
897
898 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900899 new_level, row, new_total,
900 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300901 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900902 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900903 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904 node = next;
905 }
906out:
907 return row - first_row;
908}
909
Namhyung Kim89701462013-01-22 18:09:38 +0900910struct hpp_arg {
911 struct ui_browser *b;
912 char folded_sign;
913 bool current_entry;
914};
915
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900916static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
917{
918 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900919 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900920 va_list args;
921 double percent;
922
923 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900924 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900925 percent = va_arg(args, double);
926 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900927
Namhyung Kim89701462013-01-22 18:09:38 +0900928 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900929
Namhyung Kimd6751072014-07-31 14:47:36 +0900930 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300931 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +0900932
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900933 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900934 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900935}
936
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900937#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900938static u64 __hpp_get_##_field(struct hist_entry *he) \
939{ \
940 return he->stat._field; \
941} \
942 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100943static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900944hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100945 struct perf_hpp *hpp, \
946 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900947{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900948 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
949 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900950}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900951
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900952#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
953static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
954{ \
955 return he->stat_acc->_field; \
956} \
957 \
958static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900959hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900960 struct perf_hpp *hpp, \
961 struct hist_entry *he) \
962{ \
963 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300964 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +0900965 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900966 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900967 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300968 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900969 \
970 return ret; \
971 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900972 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
973 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900974}
975
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900976__HPP_COLOR_PERCENT_FN(overhead, period)
977__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
978__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
979__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
980__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900981__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900982
983#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900984#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900985
986void hist_browser__init_hpp(void)
987{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900988 perf_hpp__format[PERF_HPP__OVERHEAD].color =
989 hist_browser__hpp_color_overhead;
990 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
991 hist_browser__hpp_color_overhead_sys;
992 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
993 hist_browser__hpp_color_overhead_us;
994 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
995 hist_browser__hpp_color_overhead_guest_sys;
996 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
997 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900998 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
999 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001000}
1001
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001002static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001003 struct hist_entry *entry,
1004 unsigned short row)
1005{
1006 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +02001007 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001008 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001009 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001010 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001011 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001012 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001013 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001014
1015 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001016 browser->he_selection = entry;
1017 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001018 }
1019
1020 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001021 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001022 folded_sign = hist_entry__folded(entry);
1023 }
1024
1025 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001026 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001027 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001028 .folded_sign = folded_sign,
1029 .current_entry = current_entry,
1030 };
Namhyung Kimf5951d52012-09-03 11:53:09 +09001031 struct perf_hpp hpp = {
1032 .buf = s,
1033 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +09001034 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +09001035 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001036 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001037
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001038 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001039
Jiri Olsa12400052012-10-13 00:06:16 +02001040 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001041 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001042 continue;
1043
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001044 if (current_entry && browser->b.navkeypressed) {
1045 ui_browser__set_color(&browser->b,
1046 HE_COLORSET_SELECTED);
1047 } else {
1048 ui_browser__set_color(&browser->b,
1049 HE_COLORSET_NORMAL);
1050 }
1051
1052 if (first) {
1053 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001054 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001055 width -= 2;
1056 }
1057 first = false;
1058 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001059 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001060 width -= 2;
1061 }
1062
Jiri Olsa12400052012-10-13 00:06:16 +02001063 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001064 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001065 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001066 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001067 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001068 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001069 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001070
1071 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001072 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001073 width += 1;
1074
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001075 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001076
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001077 ++row;
1078 ++printed;
1079 } else
1080 --row_offset;
1081
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001082 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001083 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +09001084 struct callchain_print_arg arg = {
1085 .row_offset = row_offset,
1086 .is_current_entry = current_entry,
1087 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001088
Namhyung Kim4087d112014-11-24 17:13:26 +09001089 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1090 if (symbol_conf.cumulate_callchain)
1091 total = entry->stat_acc->period;
1092 else
1093 total = entry->stat.period;
1094 }
1095
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001096 if (callchain_param.mode == CHAIN_FLAT) {
1097 printed += hist_browser__show_callchain_flat(browser,
1098 &entry->sorted_chain, row, total,
1099 hist_browser__show_callchain_entry, &arg,
1100 hist_browser__check_output_full);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001101 } else if (callchain_param.mode == CHAIN_FOLDED) {
1102 printed += hist_browser__show_callchain_folded(browser,
1103 &entry->sorted_chain, row, total,
1104 hist_browser__show_callchain_entry, &arg,
1105 hist_browser__check_output_full);
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001106 } else {
1107 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001108 &entry->sorted_chain, 1, row, total,
1109 hist_browser__show_callchain_entry, &arg,
1110 hist_browser__check_output_full);
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001111 }
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001112
Namhyung Kim39ee5332014-08-22 09:13:21 +09001113 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001114 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001115 }
1116
1117 return printed;
1118}
1119
Jiri Olsa81a888f2014-06-14 15:44:52 +02001120static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1121{
1122 advance_hpp(hpp, inc);
1123 return hpp->size <= 0;
1124}
1125
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001126static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001127{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001128 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001129 struct perf_hpp dummy_hpp = {
1130 .buf = buf,
1131 .size = size,
1132 };
1133 struct perf_hpp_fmt *fmt;
1134 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001135 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001136
1137 if (symbol_conf.use_callchain) {
1138 ret = scnprintf(buf, size, " ");
1139 if (advance_hpp_check(&dummy_hpp, ret))
1140 return ret;
1141 }
1142
1143 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001144 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001145 continue;
1146
Jiri Olsa81a888f2014-06-14 15:44:52 +02001147 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1148 if (advance_hpp_check(&dummy_hpp, ret))
1149 break;
1150
1151 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1152 if (advance_hpp_check(&dummy_hpp, ret))
1153 break;
1154 }
1155
1156 return ret;
1157}
1158
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001159static void hist_browser__show_headers(struct hist_browser *browser)
1160{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001161 char headers[1024];
1162
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001163 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001164 ui_browser__gotorc(&browser->b, 0, 0);
1165 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001166 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001167}
1168
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001169static void ui_browser__hists_init_top(struct ui_browser *browser)
1170{
1171 if (browser->top == NULL) {
1172 struct hist_browser *hb;
1173
1174 hb = container_of(browser, struct hist_browser, b);
1175 browser->top = rb_first(&hb->hists->entries);
1176 }
1177}
1178
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001179static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180{
1181 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001182 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001183 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001184 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001185
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001186 if (hb->show_headers) {
1187 hist_browser__show_headers(hb);
1188 header_offset = 1;
1189 }
1190
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001191 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001192
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001193 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001194 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001195 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196
1197 if (h->filtered)
1198 continue;
1199
Namhyung Kim14135662013-10-31 10:17:39 +09001200 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001201 if (percent < hb->min_pcnt)
1202 continue;
1203
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001205 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206 break;
1207 }
1208
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001209 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001210}
1211
Namhyung Kim064f1982013-05-14 11:09:04 +09001212static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001213 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001214{
1215 while (nd != NULL) {
1216 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001217 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001218
Namhyung Kimc0f15272014-04-16 11:16:33 +09001219 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220 return nd;
1221
1222 nd = rb_next(nd);
1223 }
1224
1225 return NULL;
1226}
1227
Namhyung Kim064f1982013-05-14 11:09:04 +09001228static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001229 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001230{
1231 while (nd != NULL) {
1232 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001233 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001234
1235 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001236 return nd;
1237
1238 nd = rb_prev(nd);
1239 }
1240
1241 return NULL;
1242}
1243
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001244static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001245 off_t offset, int whence)
1246{
1247 struct hist_entry *h;
1248 struct rb_node *nd;
1249 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001250 struct hist_browser *hb;
1251
1252 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001254 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001255 return;
1256
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001257 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001258
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259 switch (whence) {
1260 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001261 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001262 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001263 break;
1264 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001265 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001266 goto do_offset;
1267 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001268 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001269 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001270 first = false;
1271 break;
1272 default:
1273 return;
1274 }
1275
1276 /*
1277 * Moves not relative to the first visible entry invalidates its
1278 * row_offset:
1279 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001280 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001281 h->row_offset = 0;
1282
1283 /*
1284 * Here we have to check if nd is expanded (+), if it is we can't go
1285 * the next top level hist_entry, instead we must compute an offset of
1286 * what _not_ to show and not change the first visible entry.
1287 *
1288 * This offset increments when we are going from top to bottom and
1289 * decreases when we're going from bottom to top.
1290 *
1291 * As we don't have backpointers to the top level in the callchains
1292 * structure, we need to always print the whole hist_entry callchain,
1293 * skipping the first ones that are before the first visible entry
1294 * and stop when we printed enough lines to fill the screen.
1295 */
1296do_offset:
1297 if (offset > 0) {
1298 do {
1299 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001300 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001301 u16 remaining = h->nr_rows - h->row_offset;
1302 if (offset > remaining) {
1303 offset -= remaining;
1304 h->row_offset = 0;
1305 } else {
1306 h->row_offset += offset;
1307 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001308 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001309 break;
1310 }
1311 }
Namhyung Kim14135662013-10-31 10:17:39 +09001312 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001313 if (nd == NULL)
1314 break;
1315 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001316 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001317 } while (offset != 0);
1318 } else if (offset < 0) {
1319 while (1) {
1320 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001321 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001322 if (first) {
1323 if (-offset > h->row_offset) {
1324 offset += h->row_offset;
1325 h->row_offset = 0;
1326 } else {
1327 h->row_offset += offset;
1328 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001329 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001330 break;
1331 }
1332 } else {
1333 if (-offset > h->nr_rows) {
1334 offset += h->nr_rows;
1335 h->row_offset = 0;
1336 } else {
1337 h->row_offset = h->nr_rows + offset;
1338 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001339 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001340 break;
1341 }
1342 }
1343 }
1344
Namhyung Kim14135662013-10-31 10:17:39 +09001345 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001346 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001347 if (nd == NULL)
1348 break;
1349 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001350 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001351 if (offset == 0) {
1352 /*
1353 * Last unfiltered hist_entry, check if it is
1354 * unfolded, if it is then we should have
1355 * row_offset at its last entry.
1356 */
1357 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001358 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001359 h->row_offset = h->nr_rows;
1360 break;
1361 }
1362 first = false;
1363 }
1364 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001365 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001366 h = rb_entry(nd, struct hist_entry, rb_node);
1367 h->row_offset = 0;
1368 }
1369}
1370
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001371static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001372 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001373{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001374 u64 total = hists__total_period(he->hists);
1375 struct callchain_print_arg arg = {
1376 .fp = fp,
1377 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001378
Namhyung Kim39ee5332014-08-22 09:13:21 +09001379 if (symbol_conf.cumulate_callchain)
1380 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001381
Namhyung Kim39ee5332014-08-22 09:13:21 +09001382 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1383 hist_browser__fprintf_callchain_entry, &arg,
1384 hist_browser__check_dump_full);
1385 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001386}
1387
1388static int hist_browser__fprintf_entry(struct hist_browser *browser,
1389 struct hist_entry *he, FILE *fp)
1390{
1391 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001392 int printed = 0;
1393 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001394 struct perf_hpp hpp = {
1395 .buf = s,
1396 .size = sizeof(s),
1397 };
1398 struct perf_hpp_fmt *fmt;
1399 bool first = true;
1400 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001401
1402 if (symbol_conf.use_callchain)
1403 folded_sign = hist_entry__folded(he);
1404
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001405 if (symbol_conf.use_callchain)
1406 printed += fprintf(fp, "%c ", folded_sign);
1407
Namhyung Kim26d8b332014-03-03 16:16:20 +09001408 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001409 if (perf_hpp__should_skip(fmt))
1410 continue;
1411
Namhyung Kim26d8b332014-03-03 16:16:20 +09001412 if (!first) {
1413 ret = scnprintf(hpp.buf, hpp.size, " ");
1414 advance_hpp(&hpp, ret);
1415 } else
1416 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001417
Namhyung Kim26d8b332014-03-03 16:16:20 +09001418 ret = fmt->entry(fmt, &hpp, he);
1419 advance_hpp(&hpp, ret);
1420 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001421 printed += fprintf(fp, "%s\n", rtrim(s));
1422
1423 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001424 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001425
1426 return printed;
1427}
1428
1429static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1430{
Namhyung Kim064f1982013-05-14 11:09:04 +09001431 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001432 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001433 int printed = 0;
1434
1435 while (nd) {
1436 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1437
1438 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001439 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001440 }
1441
1442 return printed;
1443}
1444
1445static int hist_browser__dump(struct hist_browser *browser)
1446{
1447 char filename[64];
1448 FILE *fp;
1449
1450 while (1) {
1451 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1452 if (access(filename, F_OK))
1453 break;
1454 /*
1455 * XXX: Just an arbitrary lazy upper limit
1456 */
1457 if (++browser->print_seq == 8192) {
1458 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1459 return -1;
1460 }
1461 }
1462
1463 fp = fopen(filename, "w");
1464 if (fp == NULL) {
1465 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001466 const char *err = strerror_r(errno, bf, sizeof(bf));
1467 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001468 return -1;
1469 }
1470
1471 ++browser->print_seq;
1472 hist_browser__fprintf(browser, fp);
1473 fclose(fp);
1474 ui_helpline__fpush("%s written!", filename);
1475
1476 return 0;
1477}
1478
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001479static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001480 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001481 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001482{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001483 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001484
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001485 if (browser) {
1486 browser->hists = hists;
1487 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001488 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001489 browser->b.seek = ui_browser__hists_seek;
1490 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001491 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001492 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001493 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001494 }
1495
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001496 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001497}
1498
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001499static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001500{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001501 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001502}
1503
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001504static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001505{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001506 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001507}
1508
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001509static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001510{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001511 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001512}
1513
Taeung Song1e378eb2014-10-07 16:13:15 +09001514/* Check whether the browser is for 'top' or 'report' */
1515static inline bool is_report_browser(void *timer)
1516{
1517 return timer == NULL;
1518}
1519
1520static int hists__browser_title(struct hists *hists,
1521 struct hist_browser_timer *hbt,
1522 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001523{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001524 char unit;
1525 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001526 const struct dso *dso = hists->dso_filter;
1527 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001528 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001529 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1530 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001531 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001532 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001533 char buf[512];
1534 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001535 char ref[30] = " show reference callgraph, ";
1536 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001537
Namhyung Kimf2148332014-01-14 11:52:48 +09001538 if (symbol_conf.filter_relative) {
1539 nr_samples = hists->stats.nr_non_filtered_samples;
1540 nr_events = hists->stats.total_non_filtered_period;
1541 }
1542
Namhyung Kim759ff492013-03-05 14:53:26 +09001543 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001544 struct perf_evsel *pos;
1545
1546 perf_evsel__group_desc(evsel, buf, buflen);
1547 ev_name = buf;
1548
1549 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001550 struct hists *pos_hists = evsel__hists(pos);
1551
Namhyung Kimf2148332014-01-14 11:52:48 +09001552 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001553 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1554 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001555 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001556 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1557 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001558 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001559 }
1560 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001561
Kan Liang9e207dd2015-08-11 06:30:49 -04001562 if (symbol_conf.show_ref_callgraph &&
1563 strstr(ev_name, "call-graph=no"))
1564 enable_ref = true;
Ashay Ranecc686282012-04-05 21:01:01 -05001565 nr_samples = convert_unit(nr_samples, &unit);
1566 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001567 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1568 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc686282012-04-05 21:01:01 -05001569
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001570
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001571 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001572 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001573 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001574 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001575 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001576 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001577 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001578 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001579 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001580 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001581 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001582 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001583 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001584 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001585 if (!is_report_browser(hbt)) {
1586 struct perf_top *top = hbt->arg;
1587
1588 if (top->zero)
1589 printed += scnprintf(bf + printed, size - printed, " [z]");
1590 }
1591
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001592 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001593}
1594
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001595static inline void free_popup_options(char **options, int n)
1596{
1597 int i;
1598
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001599 for (i = 0; i < n; ++i)
1600 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001601}
1602
Feng Tang341487ab2013-02-03 14:38:20 +08001603/*
1604 * Only runtime switching of perf data file will make "input_name" point
1605 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1606 * whether we need to call free() for current "input_name" during the switch.
1607 */
1608static bool is_input_name_malloced = false;
1609
1610static int switch_data_file(void)
1611{
1612 char *pwd, *options[32], *abs_path[32], *tmp;
1613 DIR *pwd_dir;
1614 int nr_options = 0, choice = -1, ret = -1;
1615 struct dirent *dent;
1616
1617 pwd = getenv("PWD");
1618 if (!pwd)
1619 return ret;
1620
1621 pwd_dir = opendir(pwd);
1622 if (!pwd_dir)
1623 return ret;
1624
1625 memset(options, 0, sizeof(options));
1626 memset(options, 0, sizeof(abs_path));
1627
1628 while ((dent = readdir(pwd_dir))) {
1629 char path[PATH_MAX];
1630 u64 magic;
1631 char *name = dent->d_name;
1632 FILE *file;
1633
1634 if (!(dent->d_type == DT_REG))
1635 continue;
1636
1637 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1638
1639 file = fopen(path, "r");
1640 if (!file)
1641 continue;
1642
1643 if (fread(&magic, 1, 8, file) < 8)
1644 goto close_file_and_continue;
1645
1646 if (is_perf_magic(magic)) {
1647 options[nr_options] = strdup(name);
1648 if (!options[nr_options])
1649 goto close_file_and_continue;
1650
1651 abs_path[nr_options] = strdup(path);
1652 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001653 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001654 ui__warning("Can't search all data files due to memory shortage.\n");
1655 fclose(file);
1656 break;
1657 }
1658
1659 nr_options++;
1660 }
1661
1662close_file_and_continue:
1663 fclose(file);
1664 if (nr_options >= 32) {
1665 ui__warning("Too many perf data files in PWD!\n"
1666 "Only the first 32 files will be listed.\n");
1667 break;
1668 }
1669 }
1670 closedir(pwd_dir);
1671
1672 if (nr_options) {
1673 choice = ui__popup_menu(nr_options, options);
1674 if (choice < nr_options && choice >= 0) {
1675 tmp = strdup(abs_path[choice]);
1676 if (tmp) {
1677 if (is_input_name_malloced)
1678 free((void *)input_name);
1679 input_name = tmp;
1680 is_input_name_malloced = true;
1681 ret = 0;
1682 } else
1683 ui__warning("Data switch failed due to memory shortage!\n");
1684 }
1685 }
1686
1687 free_popup_options(options, nr_options);
1688 free_popup_options(abs_path, nr_options);
1689 return ret;
1690}
1691
Namhyung Kimea7cd592015-04-22 16:18:19 +09001692struct popup_action {
1693 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001694 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001695 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001696
1697 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1698};
1699
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001700static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001701do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001702{
1703 struct perf_evsel *evsel;
1704 struct annotation *notes;
1705 struct hist_entry *he;
1706 int err;
1707
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001708 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001709 return 0;
1710
Namhyung Kimea7cd592015-04-22 16:18:19 +09001711 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001712 if (!notes->src)
1713 return 0;
1714
1715 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001716 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001717 he = hist_browser__selected_entry(browser);
1718 /*
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')) && he->branch_info)
1723 return 1;
1724
1725 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1726 if (err)
1727 ui_browser__handle_resize(&browser->b);
1728 return 0;
1729}
1730
1731static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001732add_annotate_opt(struct hist_browser *browser __maybe_unused,
1733 struct popup_action *act, char **optstr,
1734 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001735{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001736 if (sym == NULL || map->dso->annotate_warned)
1737 return 0;
1738
1739 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1740 return 0;
1741
1742 act->ms.map = map;
1743 act->ms.sym = sym;
1744 act->fn = do_annotate;
1745 return 1;
1746}
1747
1748static int
1749do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1750{
1751 struct thread *thread = act->thread;
1752
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001753 if (browser->hists->thread_filter) {
1754 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1755 perf_hpp__set_elide(HISTC_THREAD, false);
1756 thread__zput(browser->hists->thread_filter);
1757 ui_helpline__pop();
1758 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001759 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001760 thread->comm_set ? thread__comm_str(thread) : "",
1761 thread->tid);
1762 browser->hists->thread_filter = thread__get(thread);
1763 perf_hpp__set_elide(HISTC_THREAD, false);
1764 pstack__push(browser->pstack, &browser->hists->thread_filter);
1765 }
1766
1767 hists__filter_by_thread(browser->hists);
1768 hist_browser__reset(browser);
1769 return 0;
1770}
1771
1772static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001773add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1774 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001775{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001776 if (thread == NULL)
1777 return 0;
1778
1779 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1780 browser->hists->thread_filter ? "out of" : "into",
1781 thread->comm_set ? thread__comm_str(thread) : "",
1782 thread->tid) < 0)
1783 return 0;
1784
1785 act->thread = thread;
1786 act->fn = do_zoom_thread;
1787 return 1;
1788}
1789
1790static int
1791do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1792{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001793 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001794
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001795 if (browser->hists->dso_filter) {
1796 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1797 perf_hpp__set_elide(HISTC_DSO, false);
1798 browser->hists->dso_filter = NULL;
1799 ui_helpline__pop();
1800 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001801 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001802 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001803 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001804 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1805 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001806 perf_hpp__set_elide(HISTC_DSO, true);
1807 pstack__push(browser->pstack, &browser->hists->dso_filter);
1808 }
1809
1810 hists__filter_by_dso(browser->hists);
1811 hist_browser__reset(browser);
1812 return 0;
1813}
1814
1815static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001816add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001817 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001818{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001819 if (map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001820 return 0;
1821
1822 if (asprintf(optstr, "Zoom %s %s DSO",
1823 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001824 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001825 return 0;
1826
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001827 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001828 act->fn = do_zoom_dso;
1829 return 1;
1830}
1831
1832static int
1833do_browse_map(struct hist_browser *browser __maybe_unused,
1834 struct popup_action *act)
1835{
1836 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001837 return 0;
1838}
1839
1840static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001841add_map_opt(struct hist_browser *browser __maybe_unused,
1842 struct popup_action *act, char **optstr, struct map *map)
1843{
1844 if (map == NULL)
1845 return 0;
1846
1847 if (asprintf(optstr, "Browse map details") < 0)
1848 return 0;
1849
1850 act->ms.map = map;
1851 act->fn = do_browse_map;
1852 return 1;
1853}
1854
1855static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001856do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001857 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001858{
1859 char script_opt[64];
1860 memset(script_opt, 0, sizeof(script_opt));
1861
Namhyung Kimea7cd592015-04-22 16:18:19 +09001862 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001863 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001864 thread__comm_str(act->thread));
1865 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001866 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001867 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001868 }
1869
1870 script_browse(script_opt);
1871 return 0;
1872}
1873
1874static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001875add_script_opt(struct hist_browser *browser __maybe_unused,
1876 struct popup_action *act, char **optstr,
1877 struct thread *thread, struct symbol *sym)
1878{
1879 if (thread) {
1880 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1881 thread__comm_str(thread)) < 0)
1882 return 0;
1883 } else if (sym) {
1884 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1885 sym->name) < 0)
1886 return 0;
1887 } else {
1888 if (asprintf(optstr, "Run scripts for all samples") < 0)
1889 return 0;
1890 }
1891
1892 act->thread = thread;
1893 act->ms.sym = sym;
1894 act->fn = do_run_script;
1895 return 1;
1896}
1897
1898static int
1899do_switch_data(struct hist_browser *browser __maybe_unused,
1900 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001901{
1902 if (switch_data_file()) {
1903 ui__warning("Won't switch the data files due to\n"
1904 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001905 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001906 }
1907
1908 return K_SWITCH_INPUT_DATA;
1909}
1910
Namhyung Kimea7cd592015-04-22 16:18:19 +09001911static int
1912add_switch_opt(struct hist_browser *browser,
1913 struct popup_action *act, char **optstr)
1914{
1915 if (!is_report_browser(browser->hbt))
1916 return 0;
1917
1918 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1919 return 0;
1920
1921 act->fn = do_switch_data;
1922 return 1;
1923}
1924
1925static int
1926do_exit_browser(struct hist_browser *browser __maybe_unused,
1927 struct popup_action *act __maybe_unused)
1928{
1929 return 0;
1930}
1931
1932static int
1933add_exit_opt(struct hist_browser *browser __maybe_unused,
1934 struct popup_action *act, char **optstr)
1935{
1936 if (asprintf(optstr, "Exit") < 0)
1937 return 0;
1938
1939 act->fn = do_exit_browser;
1940 return 1;
1941}
1942
Kan Liang84734b02015-09-04 10:45:45 -04001943static int
1944do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1945{
1946 if (browser->hists->socket_filter > -1) {
1947 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1948 browser->hists->socket_filter = -1;
1949 perf_hpp__set_elide(HISTC_SOCKET, false);
1950 } else {
1951 browser->hists->socket_filter = act->socket;
1952 perf_hpp__set_elide(HISTC_SOCKET, true);
1953 pstack__push(browser->pstack, &browser->hists->socket_filter);
1954 }
1955
1956 hists__filter_by_socket(browser->hists);
1957 hist_browser__reset(browser);
1958 return 0;
1959}
1960
1961static int
1962add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1963 char **optstr, int socket_id)
1964{
1965 if (socket_id < 0)
1966 return 0;
1967
1968 if (asprintf(optstr, "Zoom %s Processor Socket %d",
1969 (browser->hists->socket_filter > -1) ? "out of" : "into",
1970 socket_id) < 0)
1971 return 0;
1972
1973 act->socket = socket_id;
1974 act->fn = do_zoom_socket;
1975 return 1;
1976}
1977
Namhyung Kim112f7612014-04-22 14:05:35 +09001978static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001979{
1980 u64 nr_entries = 0;
1981 struct rb_node *nd = rb_first(&hb->hists->entries);
1982
Namhyung Kim268397c2014-04-22 14:49:31 +09001983 if (hb->min_pcnt == 0) {
1984 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1985 return;
1986 }
1987
Namhyung Kim14135662013-10-31 10:17:39 +09001988 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001989 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001990 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001991 }
1992
Namhyung Kim112f7612014-04-22 14:05:35 +09001993 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001994}
Feng Tang341487ab2013-02-03 14:38:20 +08001995
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001996static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001997 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001998 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001999 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002000 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002001 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002002{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002003 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09002004 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002005 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002006#define MAX_OPTIONS 16
2007 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002008 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002009 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002010 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002011 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002012 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002013 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002014
Namhyung Kime8e684a2013-12-26 14:37:58 +09002015#define HIST_BROWSER_HELP_COMMON \
2016 "h/?/F1 Show this window\n" \
2017 "UP/DOWN/PGUP\n" \
2018 "PGDN/SPACE Navigate\n" \
2019 "q/ESC/CTRL+C Exit browser\n\n" \
2020 "For multiple event sessions:\n\n" \
2021 "TAB/UNTAB Switch events\n\n" \
2022 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002023 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2024 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002025 "a Annotate current symbol\n" \
2026 "C Collapse all callchains\n" \
2027 "d Zoom into current DSO\n" \
2028 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002029 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002030 "H Display column headers\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002031 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002032 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002033
2034 /* help messages are sorted by lexical order of the hotkey */
2035 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002036 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002037 "P Print histograms to perf.hist.N\n"
2038 "r Run available scripts\n"
2039 "s Switch to another data file in PWD\n"
2040 "t Zoom into current Thread\n"
2041 "V Verbose (DSO names in callchains, etc)\n"
2042 "/ Filter symbol by name";
2043 const char top_help[] = HIST_BROWSER_HELP_COMMON
2044 "P Print histograms to perf.hist.N\n"
2045 "t Zoom into current Thread\n"
2046 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002047 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002048 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002049 "/ Filter symbol by name";
2050
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002051 if (browser == NULL)
2052 return -1;
2053
Namhyung Kimed426912015-05-29 21:53:44 +09002054 /* reset abort key so that it can get Ctrl-C as a key */
2055 SLang_reset_tty();
2056 SLang_init_tty(0, 0, 0);
2057
Namhyung Kim03905042015-11-28 02:32:39 +09002058 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002059 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002060 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002061
Kan Liang84734b02015-09-04 10:45:45 -04002062 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002063 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002064 goto out;
2065
2066 ui_helpline__push(helpline);
2067
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002068 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002069 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002070
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002071 perf_hpp__for_each_format(fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002072 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002073 /*
2074 * This is done just once, and activates the horizontal scrolling
2075 * code in the ui_browser code, it would be better to have a the
2076 * counter in the perf_hpp code, but I couldn't find doing it here
2077 * works, FIXME by setting this in hist_browser__new, for now, be
2078 * clever 8-)
2079 */
2080 ++browser->b.columns;
2081 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002082
Namhyung Kim5b591662014-07-31 14:47:38 +09002083 if (symbol_conf.col_width_list_str)
2084 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2085
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002086 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002087 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002088 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002089 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002090 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002091
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002092 nr_options = 0;
2093
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002094 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002095
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002096 if (browser->he_selection != NULL) {
2097 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002098 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002099 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002100 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002101 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002102 case K_TAB:
2103 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002104 if (nr_events == 1)
2105 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002106 /*
2107 * Exit the browser, let hists__browser_tree
2108 * go to the next or previous
2109 */
2110 goto out_free_stack;
2111 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002112 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002113 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002114 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002115 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002116 continue;
2117 }
2118
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002119 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002120 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002121 browser->selection->map->dso->annotate_warned)
2122 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002123
Namhyung Kimea7cd592015-04-22 16:18:19 +09002124 actions->ms.map = browser->selection->map;
2125 actions->ms.sym = browser->selection->sym;
2126 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002127 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002128 case 'P':
2129 hist_browser__dump(browser);
2130 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002131 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002132 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002133 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002134 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002135 case 'V':
2136 browser->show_dso = !browser->show_dso;
2137 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002138 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002139 actions->thread = thread;
2140 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002141 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002142 case 'S':
2143 actions->socket = socked_id;
2144 do_zoom_socket(browser, actions);
2145 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002146 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002147 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e452015-10-12 14:02:29 -03002148 "Please enter the name of symbol you want to see.\n"
2149 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002150 buf, "ENTER: OK, ESC: Cancel",
2151 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002152 hists->symbol_filter_str = *buf ? buf : NULL;
2153 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002154 hist_browser__reset(browser);
2155 }
2156 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002157 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002158 if (is_report_browser(hbt)) {
2159 actions->thread = NULL;
2160 actions->ms.sym = NULL;
2161 do_run_script(browser, actions);
2162 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002163 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002164 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002165 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002166 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002167 if (key == K_SWITCH_INPUT_DATA)
2168 goto out_free_stack;
2169 }
Feng Tang341487ab2013-02-03 14:38:20 +08002170 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002171 case 'i':
2172 /* env->arch is NULL for live-mode (i.e. perf top) */
2173 if (env->arch)
2174 tui__header_window(env);
2175 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002176 case 'F':
2177 symbol_conf.filter_relative ^= 1;
2178 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002179 case 'z':
2180 if (!is_report_browser(hbt)) {
2181 struct perf_top *top = hbt->arg;
2182
2183 top->zero = !top->zero;
2184 }
2185 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002186 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002187 case 'h':
2188 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002189 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002190 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002191 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002192 case K_ENTER:
2193 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002194 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002195 /* menu */
2196 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002197 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002198 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002199 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002200
Namhyung Kim01f00a12015-04-22 16:18:16 +09002201 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002202 /*
2203 * Go back to the perf_evsel_menu__run or other user
2204 */
2205 if (left_exits)
2206 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002207
2208 if (key == K_ESC &&
2209 ui_browser__dialog_yesno(&browser->b,
2210 "Do you really want to exit?"))
2211 goto out_free_stack;
2212
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002213 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002214 }
Namhyung Kim64221842015-04-24 10:15:33 +09002215 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002216 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002217 /*
2218 * No need to set actions->dso here since
2219 * it's just to remove the current filter.
2220 * Ditto for thread below.
2221 */
2222 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002223 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002224 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002225 } else if (top == &browser->hists->socket_filter) {
2226 do_zoom_socket(browser, actions);
2227 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002228 continue;
2229 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002230 case 'q':
2231 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002232 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002233 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002234 if (!is_report_browser(hbt)) {
2235 struct perf_top *top = hbt->arg;
2236
2237 perf_evlist__toggle_enable(top->evlist);
2238 /*
2239 * No need to refresh, resort/decay histogram
2240 * entries if we are not collecting samples:
2241 */
2242 if (top->evlist->enabled) {
2243 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2244 hbt->refresh = delay_secs;
2245 } else {
2246 helpline = "Press 'f' again to re-enable the events";
2247 hbt->refresh = 0;
2248 }
2249 continue;
2250 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002251 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002252 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002253 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002254 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002255 }
2256
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002257 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002258 goto add_exit_option;
2259
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002260 if (browser->selection == NULL)
2261 goto skip_annotation;
2262
Namhyung Kim55369fc2013-04-01 20:35:20 +09002263 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002264 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002265
2266 if (bi == NULL)
2267 goto skip_annotation;
2268
Namhyung Kimea7cd592015-04-22 16:18:19 +09002269 nr_options += add_annotate_opt(browser,
2270 &actions[nr_options],
2271 &options[nr_options],
2272 bi->from.map,
2273 bi->from.sym);
2274 if (bi->to.sym != bi->from.sym)
2275 nr_options += add_annotate_opt(browser,
2276 &actions[nr_options],
2277 &options[nr_options],
2278 bi->to.map,
2279 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002280 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002281 nr_options += add_annotate_opt(browser,
2282 &actions[nr_options],
2283 &options[nr_options],
2284 browser->selection->map,
2285 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002286 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002287skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002288 nr_options += add_thread_opt(browser, &actions[nr_options],
2289 &options[nr_options], thread);
2290 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002291 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002292 nr_options += add_map_opt(browser, &actions[nr_options],
2293 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002294 browser->selection ?
2295 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002296 nr_options += add_socket_opt(browser, &actions[nr_options],
2297 &options[nr_options],
2298 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002299 /* perf script support */
2300 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002301 nr_options += add_script_opt(browser,
2302 &actions[nr_options],
2303 &options[nr_options],
2304 thread, NULL);
Wang Nanbd315aa2015-09-14 10:23:55 +00002305 /*
2306 * Note that browser->selection != NULL
2307 * when browser->he_selection is not NULL,
2308 * so we don't need to check browser->selection
2309 * before fetching browser->selection->sym like what
2310 * we do before fetching browser->selection->map.
2311 *
2312 * See hist_browser__show_entry.
2313 */
Namhyung Kimea7cd592015-04-22 16:18:19 +09002314 nr_options += add_script_opt(browser,
2315 &actions[nr_options],
2316 &options[nr_options],
2317 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002318 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002319 nr_options += add_script_opt(browser, &actions[nr_options],
2320 &options[nr_options], NULL, NULL);
2321 nr_options += add_switch_opt(browser, &actions[nr_options],
2322 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002323add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002324 nr_options += add_exit_opt(browser, &actions[nr_options],
2325 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002326
Namhyung Kimea7cd592015-04-22 16:18:19 +09002327 do {
2328 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002329
Namhyung Kimea7cd592015-04-22 16:18:19 +09002330 choice = ui__popup_menu(nr_options, options);
2331 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002332 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002333
2334 act = &actions[choice];
2335 key = act->fn(browser, act);
2336 } while (key == 1);
2337
2338 if (key == K_SWITCH_INPUT_DATA)
2339 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002340 }
2341out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002342 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002343out:
2344 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002345 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002346 return key;
2347}
2348
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002349struct perf_evsel_menu {
2350 struct ui_browser b;
2351 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002352 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002353 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002354 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002355};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002356
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002357static void perf_evsel_menu__write(struct ui_browser *browser,
2358 void *entry, int row)
2359{
2360 struct perf_evsel_menu *menu = container_of(browser,
2361 struct perf_evsel_menu, b);
2362 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002363 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002364 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002365 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002366 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002367 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002368 const char *warn = " ";
2369 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002370
2371 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2372 HE_COLORSET_NORMAL);
2373
Namhyung Kim759ff492013-03-05 14:53:26 +09002374 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002375 struct perf_evsel *pos;
2376
2377 ev_name = perf_evsel__group_name(evsel);
2378
2379 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002380 struct hists *pos_hists = evsel__hists(pos);
2381 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002382 }
2383 }
2384
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002385 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002386 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002387 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002388 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002389
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002390 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002391 if (nr_events != 0) {
2392 menu->lost_events = true;
2393 if (!current_entry)
2394 ui_browser__set_color(browser, HE_COLORSET_TOP);
2395 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002396 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2397 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002398 warn = bf;
2399 }
2400
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002401 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002402
2403 if (current_entry)
2404 menu->selection = evsel;
2405}
2406
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002407static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2408 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002409 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002410{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002411 struct perf_evlist *evlist = menu->b.priv;
2412 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002413 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002414 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002415 int key;
2416
2417 if (ui_browser__show(&menu->b, title,
2418 "ESC: exit, ENTER|->: Browse histograms") < 0)
2419 return -1;
2420
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002421 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002422 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002423
2424 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002425 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002426 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002427
2428 if (!menu->lost_events_warned && menu->lost_events) {
2429 ui_browser__warn_lost_events(&menu->b);
2430 menu->lost_events_warned = true;
2431 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002432 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002433 case K_RIGHT:
2434 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002435 if (!menu->selection)
2436 continue;
2437 pos = menu->selection;
2438browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002439 perf_evlist__set_selected(evlist, pos);
2440 /*
2441 * Give the calling tool a chance to populate the non
2442 * default evsel resorted hists tree.
2443 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002444 if (hbt)
2445 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002446 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002447 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002448 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002449 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002450 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002451 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002452 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002453 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002454 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002455 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002456 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002457 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002458 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002459 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002460 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002461 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002462 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002463 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002464 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002465 case 'q':
2466 case CTRL('c'):
2467 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002468 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002469 default:
2470 continue;
2471 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002472 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002473 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002474 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002475 if (!ui_browser__dialog_yesno(&menu->b,
2476 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002477 continue;
2478 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002479 case 'q':
2480 case CTRL('c'):
2481 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002482 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002483 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002484 }
2485 }
2486
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002487out:
2488 ui_browser__hide(&menu->b);
2489 return key;
2490}
2491
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002492static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002493 void *entry)
2494{
2495 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2496
2497 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2498 return true;
2499
2500 return false;
2501}
2502
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002503static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002504 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002505 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002506 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002507 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002508{
2509 struct perf_evsel *pos;
2510 struct perf_evsel_menu menu = {
2511 .b = {
2512 .entries = &evlist->entries,
2513 .refresh = ui_browser__list_head_refresh,
2514 .seek = ui_browser__list_head_seek,
2515 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002516 .filter = filter_group_entries,
2517 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002518 .priv = evlist,
2519 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002520 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002521 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002522 };
2523
2524 ui_helpline__push("Press ESC to exit");
2525
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002526 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002527 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002528 size_t line_len = strlen(ev_name) + 7;
2529
2530 if (menu.b.width < line_len)
2531 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002532 }
2533
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002534 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002535}
2536
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002537int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002538 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002539 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002540 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002541{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002542 int nr_entries = evlist->nr_entries;
2543
2544single_entry:
2545 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002546 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002547
2548 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002549 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002550 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002551 }
2552
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002553 if (symbol_conf.event_group) {
2554 struct perf_evsel *pos;
2555
2556 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002557 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002558 if (perf_evsel__is_group_leader(pos))
2559 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002560 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002561
2562 if (nr_entries == 1)
2563 goto single_entry;
2564 }
2565
2566 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002567 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002568}