blob: 08c09ad755d2d2f8dd55be06b258e16fb2c8335f [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
Wang Nan4938cf02015-12-07 02:35:44 +0000343 if (!he || !ms)
344 return false;
345
Namhyung Kim3698dab2015-05-05 23:55:46 +0900346 if (ms == &he->ms)
347 has_children = hist_entry__toggle_fold(he);
348 else
349 has_children = callchain_list__toggle_fold(cl);
350
351 if (has_children) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300352 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900353 browser->b.nr_entries -= he->nr_rows;
354 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300355
Namhyung Kim3698dab2015-05-05 23:55:46 +0900356 if (he->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300357 he->nr_rows = callchain__count_rows(&he->sorted_chain);
358 else
359 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900360
361 browser->b.nr_entries += he->nr_rows;
362 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363
364 return true;
365 }
366
367 /* If it doesn't have children, no toggling performed */
368 return false;
369}
370
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300372{
373 int n = 0;
374 struct rb_node *nd;
375
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300376 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300377 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
378 struct callchain_list *chain;
379 bool has_children = false;
380
381 list_for_each_entry(chain, &child->val, list) {
382 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900383 callchain_list__set_folding(chain, unfold);
384 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300385 }
386
387 if (has_children)
388 n += callchain_node__set_folding_rb_tree(child, unfold);
389 }
390
391 return n;
392}
393
394static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
395{
396 struct callchain_list *chain;
397 bool has_children = false;
398 int n = 0;
399
400 list_for_each_entry(chain, &node->val, list) {
401 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900402 callchain_list__set_folding(chain, unfold);
403 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300404 }
405
406 if (has_children)
407 n += callchain_node__set_folding_rb_tree(node, unfold);
408
409 return n;
410}
411
412static int callchain__set_folding(struct rb_root *chain, bool unfold)
413{
414 struct rb_node *nd;
415 int n = 0;
416
417 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
418 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
419 n += callchain_node__set_folding(node, unfold);
420 }
421
422 return n;
423}
424
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300425static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300426{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300427 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900428 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300429
Namhyung Kim3698dab2015-05-05 23:55:46 +0900430 if (he->has_children) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300431 int n = callchain__set_folding(&he->sorted_chain, unfold);
432 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300433 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300434 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300435}
436
Namhyung Kimc3b78952014-04-22 15:56:17 +0900437static void
438__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300439{
440 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900441 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300442
Namhyung Kimc3b78952014-04-22 15:56:17 +0900443 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900444 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900445 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300446 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
447 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900448 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300449 }
450}
451
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300452static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300453{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900454 browser->nr_callchain_rows = 0;
455 __hist_browser__set_folding(browser, unfold);
456
457 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300458 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300459 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300460}
461
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200462static void ui_browser__warn_lost_events(struct ui_browser *browser)
463{
464 ui_browser__warning(browser, 4,
465 "Events are being lost, check IO/CPU overload!\n\n"
466 "You may want to run 'perf' using a RT scheduler policy:\n\n"
467 " perf top -r 80\n\n"
468 "Or reduce the sampling frequency.");
469}
470
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300471static int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300472{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300473 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300474 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900475 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900476 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300477
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300478 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900479 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300480
Taeung Song1e378eb2014-10-07 16:13:15 +0900481 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300482
Namhyung Kim090cff32016-01-11 19:53:14 +0900483 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300484 return -1;
485
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300486 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300487 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300488
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300489 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900490 case K_TIMER: {
491 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900492 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900493
Namhyung Kimc3b78952014-04-22 15:56:17 +0900494 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900495 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900496
Namhyung Kimc3b78952014-04-22 15:56:17 +0900497 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900498 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200499
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300500 if (browser->hists->stats.nr_lost_warned !=
501 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
502 browser->hists->stats.nr_lost_warned =
503 browser->hists->stats.nr_events[PERF_RECORD_LOST];
504 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200505 }
506
Taeung Song1e378eb2014-10-07 16:13:15 +0900507 hists__browser_title(browser->hists,
508 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300509 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300510 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900511 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300512 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300513 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300514 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300515 struct hist_entry, rb_node);
516 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300517 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 -0300518 seq++, browser->b.nr_entries,
519 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300520 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300521 browser->b.index,
522 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300523 h->row_offset, h->nr_rows);
524 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300525 break;
526 case 'C':
527 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300528 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300529 break;
530 case 'E':
531 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300532 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300533 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200534 case 'H':
535 browser->show_headers = !browser->show_headers;
536 hist_browser__update_rows(browser);
537 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200538 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300539 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300540 break;
541 /* fall thru */
542 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300543 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300544 }
545 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300546out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300547 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300548 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300549}
550
Namhyung Kim39ee5332014-08-22 09:13:21 +0900551struct callchain_print_arg {
552 /* for hists browser */
553 off_t row_offset;
554 bool is_current_entry;
555
556 /* for file dump */
557 FILE *fp;
558 int printed;
559};
560
561typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
562 struct callchain_list *chain,
563 const char *str, int offset,
564 unsigned short row,
565 struct callchain_print_arg *arg);
566
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900567static void hist_browser__show_callchain_entry(struct hist_browser *browser,
568 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900569 const char *str, int offset,
570 unsigned short row,
571 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900572{
573 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900574 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300575 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900576
577 color = HE_COLORSET_NORMAL;
578 width = browser->b.width - (offset + 2);
579 if (ui_browser__is_current_entry(&browser->b, row)) {
580 browser->selection = &chain->ms;
581 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900582 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900583 }
584
585 ui_browser__set_color(&browser->b, color);
586 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300587 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300588 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300589 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300590 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900591}
592
Namhyung Kim39ee5332014-08-22 09:13:21 +0900593static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
594 struct callchain_list *chain,
595 const char *str, int offset,
596 unsigned short row __maybe_unused,
597 struct callchain_print_arg *arg)
598{
599 char folded_sign = callchain_list__folded(chain);
600
601 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
602 folded_sign, str);
603}
604
605typedef bool (*check_output_full_fn)(struct hist_browser *browser,
606 unsigned short row);
607
608static bool hist_browser__check_output_full(struct hist_browser *browser,
609 unsigned short row)
610{
611 return browser->b.rows == row;
612}
613
614static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
615 unsigned short row __maybe_unused)
616{
617 return false;
618}
619
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300620#define LEVEL_OFFSET_STEP 3
621
Namhyung Kim18bb8382015-11-09 14:45:42 +0900622static int hist_browser__show_callchain_list(struct hist_browser *browser,
623 struct callchain_node *node,
624 struct callchain_list *chain,
625 unsigned short row, u64 total,
626 bool need_percent, int offset,
627 print_callchain_entry_fn print,
628 struct callchain_print_arg *arg)
629{
630 char bf[1024], *alloc_str;
631 const char *str;
632
633 if (arg->row_offset != 0) {
634 arg->row_offset--;
635 return 0;
636 }
637
638 alloc_str = NULL;
639 str = callchain_list__sym_name(chain, bf, sizeof(bf),
640 browser->show_dso);
641
642 if (need_percent) {
643 char buf[64];
644
645 callchain_node__scnprintf_value(node, buf, sizeof(buf),
646 total);
647
648 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
649 str = "Not enough memory!";
650 else
651 str = alloc_str;
652 }
653
654 print(browser, chain, str, offset, row, arg);
655
656 free(alloc_str);
657 return 1;
658}
659
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900660static int hist_browser__show_callchain_flat(struct hist_browser *browser,
661 struct rb_root *root,
662 unsigned short row, u64 total,
663 print_callchain_entry_fn print,
664 struct callchain_print_arg *arg,
665 check_output_full_fn is_output_full)
666{
667 struct rb_node *node;
668 int first_row = row, offset = LEVEL_OFFSET_STEP;
669 bool need_percent;
670
671 node = rb_first(root);
672 need_percent = node && rb_next(node);
673
674 while (node) {
675 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
676 struct rb_node *next = rb_next(node);
677 struct callchain_list *chain;
678 char folded_sign = ' ';
679 int first = true;
680 int extra_offset = 0;
681
682 list_for_each_entry(chain, &child->parent_val, list) {
683 bool was_first = first;
684
685 if (first)
686 first = false;
687 else if (need_percent)
688 extra_offset = LEVEL_OFFSET_STEP;
689
690 folded_sign = callchain_list__folded(chain);
691
692 row += hist_browser__show_callchain_list(browser, child,
693 chain, row, total,
694 was_first && need_percent,
695 offset + extra_offset,
696 print, arg);
697
698 if (is_output_full(browser, row))
699 goto out;
700
701 if (folded_sign == '+')
702 goto next;
703 }
704
705 list_for_each_entry(chain, &child->val, list) {
706 bool was_first = first;
707
708 if (first)
709 first = false;
710 else if (need_percent)
711 extra_offset = LEVEL_OFFSET_STEP;
712
713 folded_sign = callchain_list__folded(chain);
714
715 row += hist_browser__show_callchain_list(browser, child,
716 chain, row, total,
717 was_first && need_percent,
718 offset + extra_offset,
719 print, arg);
720
721 if (is_output_full(browser, row))
722 goto out;
723
724 if (folded_sign == '+')
725 break;
726 }
727
728next:
729 if (is_output_full(browser, row))
730 break;
731 node = next;
732 }
733out:
734 return row - first_row;
735}
736
Namhyung Kim8c430a32015-11-09 14:45:44 +0900737static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
738 struct callchain_list *chain,
739 char *value_str, char *old_str)
740{
741 char bf[1024];
742 const char *str;
743 char *new;
744
745 str = callchain_list__sym_name(chain, bf, sizeof(bf),
746 browser->show_dso);
747 if (old_str) {
748 if (asprintf(&new, "%s%s%s", old_str,
749 symbol_conf.field_sep ?: ";", str) < 0)
750 new = NULL;
751 } else {
752 if (value_str) {
753 if (asprintf(&new, "%s %s", value_str, str) < 0)
754 new = NULL;
755 } else {
756 if (asprintf(&new, "%s", str) < 0)
757 new = NULL;
758 }
759 }
760 return new;
761}
762
763static int hist_browser__show_callchain_folded(struct hist_browser *browser,
764 struct rb_root *root,
765 unsigned short row, u64 total,
766 print_callchain_entry_fn print,
767 struct callchain_print_arg *arg,
768 check_output_full_fn is_output_full)
769{
770 struct rb_node *node;
771 int first_row = row, offset = LEVEL_OFFSET_STEP;
772 bool need_percent;
773
774 node = rb_first(root);
775 need_percent = node && rb_next(node);
776
777 while (node) {
778 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
779 struct rb_node *next = rb_next(node);
780 struct callchain_list *chain, *first_chain = NULL;
781 int first = true;
782 char *value_str = NULL, *value_str_alloc = NULL;
783 char *chain_str = NULL, *chain_str_alloc = NULL;
784
785 if (arg->row_offset != 0) {
786 arg->row_offset--;
787 goto next;
788 }
789
790 if (need_percent) {
791 char buf[64];
792
793 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
794 if (asprintf(&value_str, "%s", buf) < 0) {
795 value_str = (char *)"<...>";
796 goto do_print;
797 }
798 value_str_alloc = value_str;
799 }
800
801 list_for_each_entry(chain, &child->parent_val, list) {
802 chain_str = hist_browser__folded_callchain_str(browser,
803 chain, value_str, chain_str);
804 if (first) {
805 first = false;
806 first_chain = chain;
807 }
808
809 if (chain_str == NULL) {
810 chain_str = (char *)"Not enough memory!";
811 goto do_print;
812 }
813
814 chain_str_alloc = chain_str;
815 }
816
817 list_for_each_entry(chain, &child->val, list) {
818 chain_str = hist_browser__folded_callchain_str(browser,
819 chain, value_str, chain_str);
820 if (first) {
821 first = false;
822 first_chain = chain;
823 }
824
825 if (chain_str == NULL) {
826 chain_str = (char *)"Not enough memory!";
827 goto do_print;
828 }
829
830 chain_str_alloc = chain_str;
831 }
832
833do_print:
834 print(browser, first_chain, chain_str, offset, row++, arg);
835 free(value_str_alloc);
836 free(chain_str_alloc);
837
838next:
839 if (is_output_full(browser, row))
840 break;
841 node = next;
842 }
843
844 return row - first_row;
845}
846
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900847static int hist_browser__show_callchain(struct hist_browser *browser,
848 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900849 unsigned short row, u64 total,
850 print_callchain_entry_fn print,
851 struct callchain_print_arg *arg,
852 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300853{
854 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900855 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900856 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900857 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300858
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900859 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900860 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900861
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300862 while (node) {
863 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
864 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300865 struct callchain_list *chain;
866 char folded_sign = ' ';
867 int first = true;
868 int extra_offset = 0;
869
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300870 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300871 bool was_first = first;
872
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300873 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300874 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900875 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300876 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300877
878 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300879
Namhyung Kim18bb8382015-11-09 14:45:42 +0900880 row += hist_browser__show_callchain_list(browser, child,
881 chain, row, total,
882 was_first && need_percent,
883 offset + extra_offset,
884 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900885
Namhyung Kim18bb8382015-11-09 14:45:42 +0900886 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300887 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900888
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300889 if (folded_sign == '+')
890 break;
891 }
892
893 if (folded_sign == '-') {
894 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900895
896 if (callchain_param.mode == CHAIN_GRAPH_REL)
897 new_total = child->children_hit;
898 else
899 new_total = total;
900
901 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900902 new_level, row, new_total,
903 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300904 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900905 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900906 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300907 node = next;
908 }
909out:
910 return row - first_row;
911}
912
Namhyung Kim89701462013-01-22 18:09:38 +0900913struct hpp_arg {
914 struct ui_browser *b;
915 char folded_sign;
916 bool current_entry;
917};
918
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900919static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
920{
921 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900922 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900923 va_list args;
924 double percent;
925
926 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900927 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900928 percent = va_arg(args, double);
929 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900930
Namhyung Kim89701462013-01-22 18:09:38 +0900931 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900932
Namhyung Kimd6751072014-07-31 14:47:36 +0900933 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300934 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +0900935
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900936 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900937 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900938}
939
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900940#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900941static u64 __hpp_get_##_field(struct hist_entry *he) \
942{ \
943 return he->stat._field; \
944} \
945 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100946static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900947hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100948 struct perf_hpp *hpp, \
949 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900950{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900951 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
952 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900953}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900954
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900955#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
956static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
957{ \
958 return he->stat_acc->_field; \
959} \
960 \
961static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900962hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900963 struct perf_hpp *hpp, \
964 struct hist_entry *he) \
965{ \
966 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300967 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +0900968 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900969 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900970 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300971 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900972 \
973 return ret; \
974 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900975 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
976 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900977}
978
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900979__HPP_COLOR_PERCENT_FN(overhead, period)
980__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
981__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
982__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
983__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900984__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900985
986#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900987#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900988
989void hist_browser__init_hpp(void)
990{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900991 perf_hpp__format[PERF_HPP__OVERHEAD].color =
992 hist_browser__hpp_color_overhead;
993 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
994 hist_browser__hpp_color_overhead_sys;
995 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
996 hist_browser__hpp_color_overhead_us;
997 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
998 hist_browser__hpp_color_overhead_guest_sys;
999 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1000 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001001 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1002 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001003}
1004
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001005static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001006 struct hist_entry *entry,
1007 unsigned short row)
1008{
1009 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +02001010 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001011 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001012 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001013 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001014 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001015 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001016 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001017
1018 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001019 browser->he_selection = entry;
1020 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001021 }
1022
1023 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001024 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001025 folded_sign = hist_entry__folded(entry);
1026 }
1027
1028 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001029 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001030 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001031 .folded_sign = folded_sign,
1032 .current_entry = current_entry,
1033 };
Namhyung Kimf5951d52012-09-03 11:53:09 +09001034 struct perf_hpp hpp = {
1035 .buf = s,
1036 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +09001037 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +09001038 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001039 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001040
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001041 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001042
Jiri Olsa12400052012-10-13 00:06:16 +02001043 perf_hpp__for_each_format(fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001044 if (perf_hpp__should_skip(fmt, entry->hists) ||
1045 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001046 continue;
1047
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001048 if (current_entry && browser->b.navkeypressed) {
1049 ui_browser__set_color(&browser->b,
1050 HE_COLORSET_SELECTED);
1051 } else {
1052 ui_browser__set_color(&browser->b,
1053 HE_COLORSET_NORMAL);
1054 }
1055
1056 if (first) {
1057 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001058 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001059 width -= 2;
1060 }
1061 first = false;
1062 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001063 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001064 width -= 2;
1065 }
1066
Jiri Olsa12400052012-10-13 00:06:16 +02001067 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001068 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001069 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001070 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001071 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001072 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001073 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001074
1075 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001076 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001077 width += 1;
1078
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001079 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001080
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001081 ++row;
1082 ++printed;
1083 } else
1084 --row_offset;
1085
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001086 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001087 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +09001088 struct callchain_print_arg arg = {
1089 .row_offset = row_offset,
1090 .is_current_entry = current_entry,
1091 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001092
Namhyung Kim4087d112014-11-24 17:13:26 +09001093 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1094 if (symbol_conf.cumulate_callchain)
1095 total = entry->stat_acc->period;
1096 else
1097 total = entry->stat.period;
1098 }
1099
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001100 if (callchain_param.mode == CHAIN_FLAT) {
1101 printed += hist_browser__show_callchain_flat(browser,
1102 &entry->sorted_chain, row, total,
1103 hist_browser__show_callchain_entry, &arg,
1104 hist_browser__check_output_full);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001105 } else if (callchain_param.mode == CHAIN_FOLDED) {
1106 printed += hist_browser__show_callchain_folded(browser,
1107 &entry->sorted_chain, row, total,
1108 hist_browser__show_callchain_entry, &arg,
1109 hist_browser__check_output_full);
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001110 } else {
1111 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001112 &entry->sorted_chain, 1, row, total,
1113 hist_browser__show_callchain_entry, &arg,
1114 hist_browser__check_output_full);
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001115 }
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001116
Namhyung Kim39ee5332014-08-22 09:13:21 +09001117 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001118 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001119 }
1120
1121 return printed;
1122}
1123
Jiri Olsa81a888f2014-06-14 15:44:52 +02001124static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1125{
1126 advance_hpp(hpp, inc);
1127 return hpp->size <= 0;
1128}
1129
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001130static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001131{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001132 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001133 struct perf_hpp dummy_hpp = {
1134 .buf = buf,
1135 .size = size,
1136 };
1137 struct perf_hpp_fmt *fmt;
1138 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001139 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001140
1141 if (symbol_conf.use_callchain) {
1142 ret = scnprintf(buf, size, " ");
1143 if (advance_hpp_check(&dummy_hpp, ret))
1144 return ret;
1145 }
1146
1147 perf_hpp__for_each_format(fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001148 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001149 continue;
1150
Jiri Olsa81a888f2014-06-14 15:44:52 +02001151 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1152 if (advance_hpp_check(&dummy_hpp, ret))
1153 break;
1154
1155 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1156 if (advance_hpp_check(&dummy_hpp, ret))
1157 break;
1158 }
1159
1160 return ret;
1161}
1162
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001163static void hist_browser__show_headers(struct hist_browser *browser)
1164{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001165 char headers[1024];
1166
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001167 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001168 ui_browser__gotorc(&browser->b, 0, 0);
1169 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001170 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001171}
1172
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001173static void ui_browser__hists_init_top(struct ui_browser *browser)
1174{
1175 if (browser->top == NULL) {
1176 struct hist_browser *hb;
1177
1178 hb = container_of(browser, struct hist_browser, b);
1179 browser->top = rb_first(&hb->hists->entries);
1180 }
1181}
1182
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001183static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001184{
1185 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001186 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001187 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001188 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001189
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001190 if (hb->show_headers) {
1191 hist_browser__show_headers(hb);
1192 header_offset = 1;
1193 }
1194
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001195 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001196 hb->he_selection = NULL;
1197 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001199 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001201 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202
1203 if (h->filtered)
1204 continue;
1205
Namhyung Kim14135662013-10-31 10:17:39 +09001206 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001207 if (percent < hb->min_pcnt)
1208 continue;
1209
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001210 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001211 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001212 break;
1213 }
1214
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001215 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001216}
1217
Namhyung Kim064f1982013-05-14 11:09:04 +09001218static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001219 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220{
1221 while (nd != NULL) {
1222 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001223 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001224
Namhyung Kimc0f15272014-04-16 11:16:33 +09001225 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001226 return nd;
1227
1228 nd = rb_next(nd);
1229 }
1230
1231 return NULL;
1232}
1233
Namhyung Kim064f1982013-05-14 11:09:04 +09001234static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001235 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001236{
1237 while (nd != NULL) {
1238 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001239 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001240
1241 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001242 return nd;
1243
1244 nd = rb_prev(nd);
1245 }
1246
1247 return NULL;
1248}
1249
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001250static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001251 off_t offset, int whence)
1252{
1253 struct hist_entry *h;
1254 struct rb_node *nd;
1255 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001256 struct hist_browser *hb;
1257
1258 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001260 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001261 return;
1262
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001263 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001264
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001265 switch (whence) {
1266 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001267 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001268 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001269 break;
1270 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001271 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001272 goto do_offset;
1273 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001274 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001275 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001276 first = false;
1277 break;
1278 default:
1279 return;
1280 }
1281
1282 /*
1283 * Moves not relative to the first visible entry invalidates its
1284 * row_offset:
1285 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001286 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001287 h->row_offset = 0;
1288
1289 /*
1290 * Here we have to check if nd is expanded (+), if it is we can't go
1291 * the next top level hist_entry, instead we must compute an offset of
1292 * what _not_ to show and not change the first visible entry.
1293 *
1294 * This offset increments when we are going from top to bottom and
1295 * decreases when we're going from bottom to top.
1296 *
1297 * As we don't have backpointers to the top level in the callchains
1298 * structure, we need to always print the whole hist_entry callchain,
1299 * skipping the first ones that are before the first visible entry
1300 * and stop when we printed enough lines to fill the screen.
1301 */
1302do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001303 if (!nd)
1304 return;
1305
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001306 if (offset > 0) {
1307 do {
1308 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001309 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001310 u16 remaining = h->nr_rows - h->row_offset;
1311 if (offset > remaining) {
1312 offset -= remaining;
1313 h->row_offset = 0;
1314 } else {
1315 h->row_offset += offset;
1316 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001317 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001318 break;
1319 }
1320 }
Namhyung Kim14135662013-10-31 10:17:39 +09001321 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001322 if (nd == NULL)
1323 break;
1324 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001325 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001326 } while (offset != 0);
1327 } else if (offset < 0) {
1328 while (1) {
1329 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001330 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001331 if (first) {
1332 if (-offset > h->row_offset) {
1333 offset += h->row_offset;
1334 h->row_offset = 0;
1335 } else {
1336 h->row_offset += offset;
1337 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001338 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001339 break;
1340 }
1341 } else {
1342 if (-offset > h->nr_rows) {
1343 offset += h->nr_rows;
1344 h->row_offset = 0;
1345 } else {
1346 h->row_offset = h->nr_rows + offset;
1347 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001348 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001349 break;
1350 }
1351 }
1352 }
1353
Namhyung Kim14135662013-10-31 10:17:39 +09001354 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001355 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001356 if (nd == NULL)
1357 break;
1358 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001359 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001360 if (offset == 0) {
1361 /*
1362 * Last unfiltered hist_entry, check if it is
1363 * unfolded, if it is then we should have
1364 * row_offset at its last entry.
1365 */
1366 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001367 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001368 h->row_offset = h->nr_rows;
1369 break;
1370 }
1371 first = false;
1372 }
1373 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001374 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001375 h = rb_entry(nd, struct hist_entry, rb_node);
1376 h->row_offset = 0;
1377 }
1378}
1379
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001380static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001381 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001382{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001383 u64 total = hists__total_period(he->hists);
1384 struct callchain_print_arg arg = {
1385 .fp = fp,
1386 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001387
Namhyung Kim39ee5332014-08-22 09:13:21 +09001388 if (symbol_conf.cumulate_callchain)
1389 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001390
Namhyung Kim39ee5332014-08-22 09:13:21 +09001391 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1392 hist_browser__fprintf_callchain_entry, &arg,
1393 hist_browser__check_dump_full);
1394 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001395}
1396
1397static int hist_browser__fprintf_entry(struct hist_browser *browser,
1398 struct hist_entry *he, FILE *fp)
1399{
1400 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001401 int printed = 0;
1402 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001403 struct perf_hpp hpp = {
1404 .buf = s,
1405 .size = sizeof(s),
1406 };
1407 struct perf_hpp_fmt *fmt;
1408 bool first = true;
1409 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001410
1411 if (symbol_conf.use_callchain)
1412 folded_sign = hist_entry__folded(he);
1413
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001414 if (symbol_conf.use_callchain)
1415 printed += fprintf(fp, "%c ", folded_sign);
1416
Namhyung Kim26d8b332014-03-03 16:16:20 +09001417 perf_hpp__for_each_format(fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001418 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001419 continue;
1420
Namhyung Kim26d8b332014-03-03 16:16:20 +09001421 if (!first) {
1422 ret = scnprintf(hpp.buf, hpp.size, " ");
1423 advance_hpp(&hpp, ret);
1424 } else
1425 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001426
Namhyung Kim26d8b332014-03-03 16:16:20 +09001427 ret = fmt->entry(fmt, &hpp, he);
1428 advance_hpp(&hpp, ret);
1429 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001430 printed += fprintf(fp, "%s\n", rtrim(s));
1431
1432 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001433 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001434
1435 return printed;
1436}
1437
1438static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1439{
Namhyung Kim064f1982013-05-14 11:09:04 +09001440 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001441 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001442 int printed = 0;
1443
1444 while (nd) {
1445 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1446
1447 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001448 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001449 }
1450
1451 return printed;
1452}
1453
1454static int hist_browser__dump(struct hist_browser *browser)
1455{
1456 char filename[64];
1457 FILE *fp;
1458
1459 while (1) {
1460 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1461 if (access(filename, F_OK))
1462 break;
1463 /*
1464 * XXX: Just an arbitrary lazy upper limit
1465 */
1466 if (++browser->print_seq == 8192) {
1467 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1468 return -1;
1469 }
1470 }
1471
1472 fp = fopen(filename, "w");
1473 if (fp == NULL) {
1474 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001475 const char *err = strerror_r(errno, bf, sizeof(bf));
1476 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001477 return -1;
1478 }
1479
1480 ++browser->print_seq;
1481 hist_browser__fprintf(browser, fp);
1482 fclose(fp);
1483 ui_helpline__fpush("%s written!", filename);
1484
1485 return 0;
1486}
1487
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001488static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001489 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001490 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001491{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001492 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001493
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001494 if (browser) {
1495 browser->hists = hists;
1496 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001497 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001498 browser->b.seek = ui_browser__hists_seek;
1499 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001500 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001501 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001502 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001503 }
1504
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001505 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001506}
1507
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001508static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001509{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001510 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001511}
1512
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001513static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001514{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001515 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001516}
1517
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001518static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001519{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001520 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001521}
1522
Taeung Song1e378eb2014-10-07 16:13:15 +09001523/* Check whether the browser is for 'top' or 'report' */
1524static inline bool is_report_browser(void *timer)
1525{
1526 return timer == NULL;
1527}
1528
1529static int hists__browser_title(struct hists *hists,
1530 struct hist_browser_timer *hbt,
1531 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001532{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001533 char unit;
1534 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001535 const struct dso *dso = hists->dso_filter;
1536 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001537 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001538 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1539 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001540 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001541 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001542 char buf[512];
1543 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001544 char ref[30] = " show reference callgraph, ";
1545 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001546
Namhyung Kimf2148332014-01-14 11:52:48 +09001547 if (symbol_conf.filter_relative) {
1548 nr_samples = hists->stats.nr_non_filtered_samples;
1549 nr_events = hists->stats.total_non_filtered_period;
1550 }
1551
Namhyung Kim759ff492013-03-05 14:53:26 +09001552 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001553 struct perf_evsel *pos;
1554
1555 perf_evsel__group_desc(evsel, buf, buflen);
1556 ev_name = buf;
1557
1558 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001559 struct hists *pos_hists = evsel__hists(pos);
1560
Namhyung Kimf2148332014-01-14 11:52:48 +09001561 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001562 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1563 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001564 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001565 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1566 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001567 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001568 }
1569 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001570
Kan Liang9e207dd2015-08-11 06:30:49 -04001571 if (symbol_conf.show_ref_callgraph &&
1572 strstr(ev_name, "call-graph=no"))
1573 enable_ref = true;
Ashay Ranecc686282012-04-05 21:01:01 -05001574 nr_samples = convert_unit(nr_samples, &unit);
1575 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001576 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1577 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc686282012-04-05 21:01:01 -05001578
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001579
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001580 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001581 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001582 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001583 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001584 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001585 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001586 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001587 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001588 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001589 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001590 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001591 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001592 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001593 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001594 if (!is_report_browser(hbt)) {
1595 struct perf_top *top = hbt->arg;
1596
1597 if (top->zero)
1598 printed += scnprintf(bf + printed, size - printed, " [z]");
1599 }
1600
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001601 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001602}
1603
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001604static inline void free_popup_options(char **options, int n)
1605{
1606 int i;
1607
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001608 for (i = 0; i < n; ++i)
1609 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001610}
1611
Feng Tang341487ab2013-02-03 14:38:20 +08001612/*
1613 * Only runtime switching of perf data file will make "input_name" point
1614 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1615 * whether we need to call free() for current "input_name" during the switch.
1616 */
1617static bool is_input_name_malloced = false;
1618
1619static int switch_data_file(void)
1620{
1621 char *pwd, *options[32], *abs_path[32], *tmp;
1622 DIR *pwd_dir;
1623 int nr_options = 0, choice = -1, ret = -1;
1624 struct dirent *dent;
1625
1626 pwd = getenv("PWD");
1627 if (!pwd)
1628 return ret;
1629
1630 pwd_dir = opendir(pwd);
1631 if (!pwd_dir)
1632 return ret;
1633
1634 memset(options, 0, sizeof(options));
1635 memset(options, 0, sizeof(abs_path));
1636
1637 while ((dent = readdir(pwd_dir))) {
1638 char path[PATH_MAX];
1639 u64 magic;
1640 char *name = dent->d_name;
1641 FILE *file;
1642
1643 if (!(dent->d_type == DT_REG))
1644 continue;
1645
1646 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1647
1648 file = fopen(path, "r");
1649 if (!file)
1650 continue;
1651
1652 if (fread(&magic, 1, 8, file) < 8)
1653 goto close_file_and_continue;
1654
1655 if (is_perf_magic(magic)) {
1656 options[nr_options] = strdup(name);
1657 if (!options[nr_options])
1658 goto close_file_and_continue;
1659
1660 abs_path[nr_options] = strdup(path);
1661 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001662 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001663 ui__warning("Can't search all data files due to memory shortage.\n");
1664 fclose(file);
1665 break;
1666 }
1667
1668 nr_options++;
1669 }
1670
1671close_file_and_continue:
1672 fclose(file);
1673 if (nr_options >= 32) {
1674 ui__warning("Too many perf data files in PWD!\n"
1675 "Only the first 32 files will be listed.\n");
1676 break;
1677 }
1678 }
1679 closedir(pwd_dir);
1680
1681 if (nr_options) {
1682 choice = ui__popup_menu(nr_options, options);
1683 if (choice < nr_options && choice >= 0) {
1684 tmp = strdup(abs_path[choice]);
1685 if (tmp) {
1686 if (is_input_name_malloced)
1687 free((void *)input_name);
1688 input_name = tmp;
1689 is_input_name_malloced = true;
1690 ret = 0;
1691 } else
1692 ui__warning("Data switch failed due to memory shortage!\n");
1693 }
1694 }
1695
1696 free_popup_options(options, nr_options);
1697 free_popup_options(abs_path, nr_options);
1698 return ret;
1699}
1700
Namhyung Kimea7cd592015-04-22 16:18:19 +09001701struct popup_action {
1702 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001703 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001704 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001705
1706 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1707};
1708
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001709static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001710do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001711{
1712 struct perf_evsel *evsel;
1713 struct annotation *notes;
1714 struct hist_entry *he;
1715 int err;
1716
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001717 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001718 return 0;
1719
Namhyung Kimea7cd592015-04-22 16:18:19 +09001720 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001721 if (!notes->src)
1722 return 0;
1723
1724 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001725 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001726 he = hist_browser__selected_entry(browser);
1727 /*
1728 * offer option to annotate the other branch source or target
1729 * (if they exists) when returning from annotate
1730 */
1731 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1732 return 1;
1733
1734 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1735 if (err)
1736 ui_browser__handle_resize(&browser->b);
1737 return 0;
1738}
1739
1740static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001741add_annotate_opt(struct hist_browser *browser __maybe_unused,
1742 struct popup_action *act, char **optstr,
1743 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001744{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001745 if (sym == NULL || map->dso->annotate_warned)
1746 return 0;
1747
1748 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1749 return 0;
1750
1751 act->ms.map = map;
1752 act->ms.sym = sym;
1753 act->fn = do_annotate;
1754 return 1;
1755}
1756
1757static int
1758do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1759{
1760 struct thread *thread = act->thread;
1761
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001762 if (browser->hists->thread_filter) {
1763 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1764 perf_hpp__set_elide(HISTC_THREAD, false);
1765 thread__zput(browser->hists->thread_filter);
1766 ui_helpline__pop();
1767 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001768 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001769 thread->comm_set ? thread__comm_str(thread) : "",
1770 thread->tid);
1771 browser->hists->thread_filter = thread__get(thread);
1772 perf_hpp__set_elide(HISTC_THREAD, false);
1773 pstack__push(browser->pstack, &browser->hists->thread_filter);
1774 }
1775
1776 hists__filter_by_thread(browser->hists);
1777 hist_browser__reset(browser);
1778 return 0;
1779}
1780
1781static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001782add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1783 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001784{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001785 if (thread == NULL)
1786 return 0;
1787
1788 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1789 browser->hists->thread_filter ? "out of" : "into",
1790 thread->comm_set ? thread__comm_str(thread) : "",
1791 thread->tid) < 0)
1792 return 0;
1793
1794 act->thread = thread;
1795 act->fn = do_zoom_thread;
1796 return 1;
1797}
1798
1799static int
1800do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1801{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001802 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001803
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001804 if (browser->hists->dso_filter) {
1805 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1806 perf_hpp__set_elide(HISTC_DSO, false);
1807 browser->hists->dso_filter = NULL;
1808 ui_helpline__pop();
1809 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001810 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001811 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001812 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001813 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1814 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001815 perf_hpp__set_elide(HISTC_DSO, true);
1816 pstack__push(browser->pstack, &browser->hists->dso_filter);
1817 }
1818
1819 hists__filter_by_dso(browser->hists);
1820 hist_browser__reset(browser);
1821 return 0;
1822}
1823
1824static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001825add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001826 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001827{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001828 if (map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001829 return 0;
1830
1831 if (asprintf(optstr, "Zoom %s %s DSO",
1832 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001833 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001834 return 0;
1835
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001836 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001837 act->fn = do_zoom_dso;
1838 return 1;
1839}
1840
1841static int
1842do_browse_map(struct hist_browser *browser __maybe_unused,
1843 struct popup_action *act)
1844{
1845 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001846 return 0;
1847}
1848
1849static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001850add_map_opt(struct hist_browser *browser __maybe_unused,
1851 struct popup_action *act, char **optstr, struct map *map)
1852{
1853 if (map == NULL)
1854 return 0;
1855
1856 if (asprintf(optstr, "Browse map details") < 0)
1857 return 0;
1858
1859 act->ms.map = map;
1860 act->fn = do_browse_map;
1861 return 1;
1862}
1863
1864static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001865do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001866 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001867{
1868 char script_opt[64];
1869 memset(script_opt, 0, sizeof(script_opt));
1870
Namhyung Kimea7cd592015-04-22 16:18:19 +09001871 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001872 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001873 thread__comm_str(act->thread));
1874 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001875 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001876 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001877 }
1878
1879 script_browse(script_opt);
1880 return 0;
1881}
1882
1883static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001884add_script_opt(struct hist_browser *browser __maybe_unused,
1885 struct popup_action *act, char **optstr,
1886 struct thread *thread, struct symbol *sym)
1887{
1888 if (thread) {
1889 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1890 thread__comm_str(thread)) < 0)
1891 return 0;
1892 } else if (sym) {
1893 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1894 sym->name) < 0)
1895 return 0;
1896 } else {
1897 if (asprintf(optstr, "Run scripts for all samples") < 0)
1898 return 0;
1899 }
1900
1901 act->thread = thread;
1902 act->ms.sym = sym;
1903 act->fn = do_run_script;
1904 return 1;
1905}
1906
1907static int
1908do_switch_data(struct hist_browser *browser __maybe_unused,
1909 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001910{
1911 if (switch_data_file()) {
1912 ui__warning("Won't switch the data files due to\n"
1913 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001914 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001915 }
1916
1917 return K_SWITCH_INPUT_DATA;
1918}
1919
Namhyung Kimea7cd592015-04-22 16:18:19 +09001920static int
1921add_switch_opt(struct hist_browser *browser,
1922 struct popup_action *act, char **optstr)
1923{
1924 if (!is_report_browser(browser->hbt))
1925 return 0;
1926
1927 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1928 return 0;
1929
1930 act->fn = do_switch_data;
1931 return 1;
1932}
1933
1934static int
1935do_exit_browser(struct hist_browser *browser __maybe_unused,
1936 struct popup_action *act __maybe_unused)
1937{
1938 return 0;
1939}
1940
1941static int
1942add_exit_opt(struct hist_browser *browser __maybe_unused,
1943 struct popup_action *act, char **optstr)
1944{
1945 if (asprintf(optstr, "Exit") < 0)
1946 return 0;
1947
1948 act->fn = do_exit_browser;
1949 return 1;
1950}
1951
Kan Liang84734b02015-09-04 10:45:45 -04001952static int
1953do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1954{
1955 if (browser->hists->socket_filter > -1) {
1956 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1957 browser->hists->socket_filter = -1;
1958 perf_hpp__set_elide(HISTC_SOCKET, false);
1959 } else {
1960 browser->hists->socket_filter = act->socket;
1961 perf_hpp__set_elide(HISTC_SOCKET, true);
1962 pstack__push(browser->pstack, &browser->hists->socket_filter);
1963 }
1964
1965 hists__filter_by_socket(browser->hists);
1966 hist_browser__reset(browser);
1967 return 0;
1968}
1969
1970static int
1971add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1972 char **optstr, int socket_id)
1973{
1974 if (socket_id < 0)
1975 return 0;
1976
1977 if (asprintf(optstr, "Zoom %s Processor Socket %d",
1978 (browser->hists->socket_filter > -1) ? "out of" : "into",
1979 socket_id) < 0)
1980 return 0;
1981
1982 act->socket = socket_id;
1983 act->fn = do_zoom_socket;
1984 return 1;
1985}
1986
Namhyung Kim112f7612014-04-22 14:05:35 +09001987static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001988{
1989 u64 nr_entries = 0;
1990 struct rb_node *nd = rb_first(&hb->hists->entries);
1991
Namhyung Kim268397c2014-04-22 14:49:31 +09001992 if (hb->min_pcnt == 0) {
1993 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1994 return;
1995 }
1996
Namhyung Kim14135662013-10-31 10:17:39 +09001997 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001998 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001999 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002000 }
2001
Namhyung Kim112f7612014-04-22 14:05:35 +09002002 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002003}
Feng Tang341487ab2013-02-03 14:38:20 +08002004
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002005static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002006 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002007 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002008 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002009 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002010 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002011{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002012 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09002013 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002014 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002015#define MAX_OPTIONS 16
2016 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002017 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002018 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002019 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002020 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002021 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002022 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002023
Namhyung Kime8e684a2013-12-26 14:37:58 +09002024#define HIST_BROWSER_HELP_COMMON \
2025 "h/?/F1 Show this window\n" \
2026 "UP/DOWN/PGUP\n" \
2027 "PGDN/SPACE Navigate\n" \
2028 "q/ESC/CTRL+C Exit browser\n\n" \
2029 "For multiple event sessions:\n\n" \
2030 "TAB/UNTAB Switch events\n\n" \
2031 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002032 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2033 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002034 "a Annotate current symbol\n" \
2035 "C Collapse all callchains\n" \
2036 "d Zoom into current DSO\n" \
2037 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002038 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002039 "H Display column headers\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002040 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002041 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002042
2043 /* help messages are sorted by lexical order of the hotkey */
2044 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002045 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002046 "P Print histograms to perf.hist.N\n"
2047 "r Run available scripts\n"
2048 "s Switch to another data file in PWD\n"
2049 "t Zoom into current Thread\n"
2050 "V Verbose (DSO names in callchains, etc)\n"
2051 "/ Filter symbol by name";
2052 const char top_help[] = HIST_BROWSER_HELP_COMMON
2053 "P Print histograms to perf.hist.N\n"
2054 "t Zoom into current Thread\n"
2055 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002056 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002057 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002058 "/ Filter symbol by name";
2059
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002060 if (browser == NULL)
2061 return -1;
2062
Namhyung Kimed426912015-05-29 21:53:44 +09002063 /* reset abort key so that it can get Ctrl-C as a key */
2064 SLang_reset_tty();
2065 SLang_init_tty(0, 0, 0);
2066
Namhyung Kim03905042015-11-28 02:32:39 +09002067 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002068 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002069 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002070
Kan Liang84734b02015-09-04 10:45:45 -04002071 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002072 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002073 goto out;
2074
2075 ui_helpline__push(helpline);
2076
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002077 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002078 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002079
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002080 perf_hpp__for_each_format(fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002081 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002082 /*
2083 * This is done just once, and activates the horizontal scrolling
2084 * code in the ui_browser code, it would be better to have a the
2085 * counter in the perf_hpp code, but I couldn't find doing it here
2086 * works, FIXME by setting this in hist_browser__new, for now, be
2087 * clever 8-)
2088 */
2089 ++browser->b.columns;
2090 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002091
Namhyung Kim5b591662014-07-31 14:47:38 +09002092 if (symbol_conf.col_width_list_str)
2093 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2094
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002095 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002096 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002097 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002098 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002099 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002100
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002101 nr_options = 0;
2102
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002103 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002104
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002105 if (browser->he_selection != NULL) {
2106 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002107 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002108 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002109 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002110 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002111 case K_TAB:
2112 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002113 if (nr_events == 1)
2114 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002115 /*
2116 * Exit the browser, let hists__browser_tree
2117 * go to the next or previous
2118 */
2119 goto out_free_stack;
2120 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002121 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002122 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002123 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002124 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002125 continue;
2126 }
2127
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002128 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002129 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002130 browser->selection->map->dso->annotate_warned)
2131 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002132
Namhyung Kimea7cd592015-04-22 16:18:19 +09002133 actions->ms.map = browser->selection->map;
2134 actions->ms.sym = browser->selection->sym;
2135 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002136 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002137 case 'P':
2138 hist_browser__dump(browser);
2139 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002140 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002141 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002142 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002143 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002144 case 'V':
2145 browser->show_dso = !browser->show_dso;
2146 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002147 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002148 actions->thread = thread;
2149 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002150 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002151 case 'S':
2152 actions->socket = socked_id;
2153 do_zoom_socket(browser, actions);
2154 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002155 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002156 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e452015-10-12 14:02:29 -03002157 "Please enter the name of symbol you want to see.\n"
2158 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002159 buf, "ENTER: OK, ESC: Cancel",
2160 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002161 hists->symbol_filter_str = *buf ? buf : NULL;
2162 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002163 hist_browser__reset(browser);
2164 }
2165 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002166 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002167 if (is_report_browser(hbt)) {
2168 actions->thread = NULL;
2169 actions->ms.sym = NULL;
2170 do_run_script(browser, actions);
2171 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002172 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002173 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002174 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002175 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002176 if (key == K_SWITCH_INPUT_DATA)
2177 goto out_free_stack;
2178 }
Feng Tang341487ab2013-02-03 14:38:20 +08002179 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002180 case 'i':
2181 /* env->arch is NULL for live-mode (i.e. perf top) */
2182 if (env->arch)
2183 tui__header_window(env);
2184 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002185 case 'F':
2186 symbol_conf.filter_relative ^= 1;
2187 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002188 case 'z':
2189 if (!is_report_browser(hbt)) {
2190 struct perf_top *top = hbt->arg;
2191
2192 top->zero = !top->zero;
2193 }
2194 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002195 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002196 case 'h':
2197 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002198 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002199 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002200 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002201 case K_ENTER:
2202 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002203 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002204 /* menu */
2205 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002206 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002207 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002208 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002209
Namhyung Kim01f00a12015-04-22 16:18:16 +09002210 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002211 /*
2212 * Go back to the perf_evsel_menu__run or other user
2213 */
2214 if (left_exits)
2215 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002216
2217 if (key == K_ESC &&
2218 ui_browser__dialog_yesno(&browser->b,
2219 "Do you really want to exit?"))
2220 goto out_free_stack;
2221
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002222 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002223 }
Namhyung Kim64221842015-04-24 10:15:33 +09002224 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002225 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002226 /*
2227 * No need to set actions->dso here since
2228 * it's just to remove the current filter.
2229 * Ditto for thread below.
2230 */
2231 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002232 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002233 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002234 } else if (top == &browser->hists->socket_filter) {
2235 do_zoom_socket(browser, actions);
2236 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002237 continue;
2238 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002239 case 'q':
2240 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002241 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002242 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002243 if (!is_report_browser(hbt)) {
2244 struct perf_top *top = hbt->arg;
2245
2246 perf_evlist__toggle_enable(top->evlist);
2247 /*
2248 * No need to refresh, resort/decay histogram
2249 * entries if we are not collecting samples:
2250 */
2251 if (top->evlist->enabled) {
2252 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2253 hbt->refresh = delay_secs;
2254 } else {
2255 helpline = "Press 'f' again to re-enable the events";
2256 hbt->refresh = 0;
2257 }
2258 continue;
2259 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002260 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002261 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002262 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002263 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002264 }
2265
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002266 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002267 goto add_exit_option;
2268
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002269 if (browser->selection == NULL)
2270 goto skip_annotation;
2271
Namhyung Kim55369fc2013-04-01 20:35:20 +09002272 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002273 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002274
2275 if (bi == NULL)
2276 goto skip_annotation;
2277
Namhyung Kimea7cd592015-04-22 16:18:19 +09002278 nr_options += add_annotate_opt(browser,
2279 &actions[nr_options],
2280 &options[nr_options],
2281 bi->from.map,
2282 bi->from.sym);
2283 if (bi->to.sym != bi->from.sym)
2284 nr_options += add_annotate_opt(browser,
2285 &actions[nr_options],
2286 &options[nr_options],
2287 bi->to.map,
2288 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002289 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002290 nr_options += add_annotate_opt(browser,
2291 &actions[nr_options],
2292 &options[nr_options],
2293 browser->selection->map,
2294 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002295 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002296skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002297 nr_options += add_thread_opt(browser, &actions[nr_options],
2298 &options[nr_options], thread);
2299 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002300 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002301 nr_options += add_map_opt(browser, &actions[nr_options],
2302 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002303 browser->selection ?
2304 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002305 nr_options += add_socket_opt(browser, &actions[nr_options],
2306 &options[nr_options],
2307 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002308 /* perf script support */
2309 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002310 nr_options += add_script_opt(browser,
2311 &actions[nr_options],
2312 &options[nr_options],
2313 thread, NULL);
Wang Nanbd315aa2015-09-14 10:23:55 +00002314 /*
2315 * Note that browser->selection != NULL
2316 * when browser->he_selection is not NULL,
2317 * so we don't need to check browser->selection
2318 * before fetching browser->selection->sym like what
2319 * we do before fetching browser->selection->map.
2320 *
2321 * See hist_browser__show_entry.
2322 */
Namhyung Kimea7cd592015-04-22 16:18:19 +09002323 nr_options += add_script_opt(browser,
2324 &actions[nr_options],
2325 &options[nr_options],
2326 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002327 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002328 nr_options += add_script_opt(browser, &actions[nr_options],
2329 &options[nr_options], NULL, NULL);
2330 nr_options += add_switch_opt(browser, &actions[nr_options],
2331 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002332add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002333 nr_options += add_exit_opt(browser, &actions[nr_options],
2334 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002335
Namhyung Kimea7cd592015-04-22 16:18:19 +09002336 do {
2337 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002338
Namhyung Kimea7cd592015-04-22 16:18:19 +09002339 choice = ui__popup_menu(nr_options, options);
2340 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002341 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002342
2343 act = &actions[choice];
2344 key = act->fn(browser, act);
2345 } while (key == 1);
2346
2347 if (key == K_SWITCH_INPUT_DATA)
2348 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002349 }
2350out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002351 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002352out:
2353 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002354 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002355 return key;
2356}
2357
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002358struct perf_evsel_menu {
2359 struct ui_browser b;
2360 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002361 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002362 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002363 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002364};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002365
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002366static void perf_evsel_menu__write(struct ui_browser *browser,
2367 void *entry, int row)
2368{
2369 struct perf_evsel_menu *menu = container_of(browser,
2370 struct perf_evsel_menu, b);
2371 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002372 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002373 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002374 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002375 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002376 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002377 const char *warn = " ";
2378 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002379
2380 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2381 HE_COLORSET_NORMAL);
2382
Namhyung Kim759ff492013-03-05 14:53:26 +09002383 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002384 struct perf_evsel *pos;
2385
2386 ev_name = perf_evsel__group_name(evsel);
2387
2388 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002389 struct hists *pos_hists = evsel__hists(pos);
2390 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002391 }
2392 }
2393
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002394 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002395 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002396 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002397 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002398
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002399 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002400 if (nr_events != 0) {
2401 menu->lost_events = true;
2402 if (!current_entry)
2403 ui_browser__set_color(browser, HE_COLORSET_TOP);
2404 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002405 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2406 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002407 warn = bf;
2408 }
2409
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002410 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002411
2412 if (current_entry)
2413 menu->selection = evsel;
2414}
2415
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002416static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2417 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002418 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002419{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002420 struct perf_evlist *evlist = menu->b.priv;
2421 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002422 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002423 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002424 int key;
2425
2426 if (ui_browser__show(&menu->b, title,
2427 "ESC: exit, ENTER|->: Browse histograms") < 0)
2428 return -1;
2429
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002430 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002431 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002432
2433 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002434 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002435 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002436
2437 if (!menu->lost_events_warned && menu->lost_events) {
2438 ui_browser__warn_lost_events(&menu->b);
2439 menu->lost_events_warned = true;
2440 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002441 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002442 case K_RIGHT:
2443 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002444 if (!menu->selection)
2445 continue;
2446 pos = menu->selection;
2447browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002448 perf_evlist__set_selected(evlist, pos);
2449 /*
2450 * Give the calling tool a chance to populate the non
2451 * default evsel resorted hists tree.
2452 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002453 if (hbt)
2454 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002455 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002456 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002457 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002458 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002459 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002460 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002461 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002462 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002463 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002464 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002465 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002466 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002467 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002468 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002469 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002470 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002471 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002472 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002473 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002474 case 'q':
2475 case CTRL('c'):
2476 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002477 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002478 default:
2479 continue;
2480 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002481 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002482 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002483 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002484 if (!ui_browser__dialog_yesno(&menu->b,
2485 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002486 continue;
2487 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002488 case 'q':
2489 case CTRL('c'):
2490 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002491 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002492 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002493 }
2494 }
2495
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002496out:
2497 ui_browser__hide(&menu->b);
2498 return key;
2499}
2500
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002501static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002502 void *entry)
2503{
2504 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2505
2506 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2507 return true;
2508
2509 return false;
2510}
2511
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002512static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002513 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002514 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002515 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002516 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002517{
2518 struct perf_evsel *pos;
2519 struct perf_evsel_menu menu = {
2520 .b = {
2521 .entries = &evlist->entries,
2522 .refresh = ui_browser__list_head_refresh,
2523 .seek = ui_browser__list_head_seek,
2524 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002525 .filter = filter_group_entries,
2526 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002527 .priv = evlist,
2528 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002529 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002530 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002531 };
2532
2533 ui_helpline__push("Press ESC to exit");
2534
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002535 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002536 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002537 size_t line_len = strlen(ev_name) + 7;
2538
2539 if (menu.b.width < line_len)
2540 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002541 }
2542
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002543 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002544}
2545
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002546int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002547 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002548 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002549 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002550{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002551 int nr_entries = evlist->nr_entries;
2552
2553single_entry:
2554 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002555 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002556
2557 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002558 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002559 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002560 }
2561
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002562 if (symbol_conf.event_group) {
2563 struct perf_evsel *pos;
2564
2565 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002566 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002567 if (perf_evsel__is_group_leader(pos))
2568 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002569 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002570
2571 if (nr_entries == 1)
2572 goto single_entry;
2573 }
2574
2575 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002576 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002577}