blob: 41dbb79c992e859b78b424e947d5563d127775f8 [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,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900663 u64 parent_total __maybe_unused,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900664 print_callchain_entry_fn print,
665 struct callchain_print_arg *arg,
666 check_output_full_fn is_output_full)
667{
668 struct rb_node *node;
669 int first_row = row, offset = LEVEL_OFFSET_STEP;
670 bool need_percent;
671
672 node = rb_first(root);
673 need_percent = node && rb_next(node);
674
675 while (node) {
676 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
677 struct rb_node *next = rb_next(node);
678 struct callchain_list *chain;
679 char folded_sign = ' ';
680 int first = true;
681 int extra_offset = 0;
682
683 list_for_each_entry(chain, &child->parent_val, list) {
684 bool was_first = first;
685
686 if (first)
687 first = false;
688 else if (need_percent)
689 extra_offset = LEVEL_OFFSET_STEP;
690
691 folded_sign = callchain_list__folded(chain);
692
693 row += hist_browser__show_callchain_list(browser, child,
694 chain, row, total,
695 was_first && need_percent,
696 offset + extra_offset,
697 print, arg);
698
699 if (is_output_full(browser, row))
700 goto out;
701
702 if (folded_sign == '+')
703 goto next;
704 }
705
706 list_for_each_entry(chain, &child->val, list) {
707 bool was_first = first;
708
709 if (first)
710 first = false;
711 else if (need_percent)
712 extra_offset = LEVEL_OFFSET_STEP;
713
714 folded_sign = callchain_list__folded(chain);
715
716 row += hist_browser__show_callchain_list(browser, child,
717 chain, row, total,
718 was_first && need_percent,
719 offset + extra_offset,
720 print, arg);
721
722 if (is_output_full(browser, row))
723 goto out;
724
725 if (folded_sign == '+')
726 break;
727 }
728
729next:
730 if (is_output_full(browser, row))
731 break;
732 node = next;
733 }
734out:
735 return row - first_row;
736}
737
Namhyung Kim8c430a32015-11-09 14:45:44 +0900738static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
739 struct callchain_list *chain,
740 char *value_str, char *old_str)
741{
742 char bf[1024];
743 const char *str;
744 char *new;
745
746 str = callchain_list__sym_name(chain, bf, sizeof(bf),
747 browser->show_dso);
748 if (old_str) {
749 if (asprintf(&new, "%s%s%s", old_str,
750 symbol_conf.field_sep ?: ";", str) < 0)
751 new = NULL;
752 } else {
753 if (value_str) {
754 if (asprintf(&new, "%s %s", value_str, str) < 0)
755 new = NULL;
756 } else {
757 if (asprintf(&new, "%s", str) < 0)
758 new = NULL;
759 }
760 }
761 return new;
762}
763
764static int hist_browser__show_callchain_folded(struct hist_browser *browser,
765 struct rb_root *root,
766 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900767 u64 parent_total __maybe_unused,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900768 print_callchain_entry_fn print,
769 struct callchain_print_arg *arg,
770 check_output_full_fn is_output_full)
771{
772 struct rb_node *node;
773 int first_row = row, offset = LEVEL_OFFSET_STEP;
774 bool need_percent;
775
776 node = rb_first(root);
777 need_percent = node && rb_next(node);
778
779 while (node) {
780 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
781 struct rb_node *next = rb_next(node);
782 struct callchain_list *chain, *first_chain = NULL;
783 int first = true;
784 char *value_str = NULL, *value_str_alloc = NULL;
785 char *chain_str = NULL, *chain_str_alloc = NULL;
786
787 if (arg->row_offset != 0) {
788 arg->row_offset--;
789 goto next;
790 }
791
792 if (need_percent) {
793 char buf[64];
794
795 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
796 if (asprintf(&value_str, "%s", buf) < 0) {
797 value_str = (char *)"<...>";
798 goto do_print;
799 }
800 value_str_alloc = value_str;
801 }
802
803 list_for_each_entry(chain, &child->parent_val, list) {
804 chain_str = hist_browser__folded_callchain_str(browser,
805 chain, value_str, chain_str);
806 if (first) {
807 first = false;
808 first_chain = chain;
809 }
810
811 if (chain_str == NULL) {
812 chain_str = (char *)"Not enough memory!";
813 goto do_print;
814 }
815
816 chain_str_alloc = chain_str;
817 }
818
819 list_for_each_entry(chain, &child->val, list) {
820 chain_str = hist_browser__folded_callchain_str(browser,
821 chain, value_str, chain_str);
822 if (first) {
823 first = false;
824 first_chain = chain;
825 }
826
827 if (chain_str == NULL) {
828 chain_str = (char *)"Not enough memory!";
829 goto do_print;
830 }
831
832 chain_str_alloc = chain_str;
833 }
834
835do_print:
836 print(browser, first_chain, chain_str, offset, row++, arg);
837 free(value_str_alloc);
838 free(chain_str_alloc);
839
840next:
841 if (is_output_full(browser, row))
842 break;
843 node = next;
844 }
845
846 return row - first_row;
847}
848
Namhyung Kim0c841c62016-01-28 00:40:54 +0900849static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900850 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900851 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900852 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900853 print_callchain_entry_fn print,
854 struct callchain_print_arg *arg,
855 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300856{
857 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900858 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +0900859 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +0900860 u64 percent_total = total;
861
862 if (callchain_param.mode == CHAIN_GRAPH_REL)
863 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300864
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900865 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900866 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900867
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300868 while (node) {
869 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
870 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300871 struct callchain_list *chain;
872 char folded_sign = ' ';
873 int first = true;
874 int extra_offset = 0;
875
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300876 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300877 bool was_first = first;
878
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300879 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300880 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900881 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300882 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300883
884 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300885
Namhyung Kim18bb8382015-11-09 14:45:42 +0900886 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900887 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +0900888 was_first && need_percent,
889 offset + extra_offset,
890 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900891
Namhyung Kim18bb8382015-11-09 14:45:42 +0900892 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300893 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900894
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300895 if (folded_sign == '+')
896 break;
897 }
898
899 if (folded_sign == '-') {
900 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900901
Namhyung Kim0c841c62016-01-28 00:40:54 +0900902 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900903 new_level, row, total,
904 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900905 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300906 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900907 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900908 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300909 node = next;
910 }
911out:
912 return row - first_row;
913}
914
Namhyung Kim0c841c62016-01-28 00:40:54 +0900915static int hist_browser__show_callchain(struct hist_browser *browser,
916 struct hist_entry *entry, int level,
917 unsigned short row,
918 print_callchain_entry_fn print,
919 struct callchain_print_arg *arg,
920 check_output_full_fn is_output_full)
921{
922 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +0900923 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +0900924 int printed;
925
Namhyung Kim5eca1042016-01-28 00:40:55 +0900926 if (symbol_conf.cumulate_callchain)
927 parent_total = entry->stat_acc->period;
928 else
929 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +0900930
931 if (callchain_param.mode == CHAIN_FLAT) {
932 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900933 &entry->sorted_chain, row,
934 total, parent_total, print, arg,
935 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +0900936 } else if (callchain_param.mode == CHAIN_FOLDED) {
937 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900938 &entry->sorted_chain, row,
939 total, parent_total, print, arg,
940 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +0900941 } else {
942 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900943 &entry->sorted_chain, level, row,
944 total, parent_total, print, arg,
945 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +0900946 }
947
948 if (arg->is_current_entry)
949 browser->he_selection = entry;
950
951 return printed;
952}
953
Namhyung Kim89701462013-01-22 18:09:38 +0900954struct hpp_arg {
955 struct ui_browser *b;
956 char folded_sign;
957 bool current_entry;
958};
959
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900960static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
961{
962 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900963 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900964 va_list args;
965 double percent;
966
967 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900968 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900969 percent = va_arg(args, double);
970 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900971
Namhyung Kim89701462013-01-22 18:09:38 +0900972 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900973
Namhyung Kimd6751072014-07-31 14:47:36 +0900974 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300975 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +0900976
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900977 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900978 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900979}
980
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900981#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900982static u64 __hpp_get_##_field(struct hist_entry *he) \
983{ \
984 return he->stat._field; \
985} \
986 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100987static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900988hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100989 struct perf_hpp *hpp, \
990 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900991{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900992 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
993 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900994}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900995
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900996#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
997static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
998{ \
999 return he->stat_acc->_field; \
1000} \
1001 \
1002static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001003hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001004 struct perf_hpp *hpp, \
1005 struct hist_entry *he) \
1006{ \
1007 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001008 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001009 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001010 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001011 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001012 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001013 \
1014 return ret; \
1015 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001016 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1017 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001018}
1019
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001020__HPP_COLOR_PERCENT_FN(overhead, period)
1021__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1022__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1023__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1024__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001025__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001026
1027#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001028#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001029
1030void hist_browser__init_hpp(void)
1031{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001032 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1033 hist_browser__hpp_color_overhead;
1034 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1035 hist_browser__hpp_color_overhead_sys;
1036 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1037 hist_browser__hpp_color_overhead_us;
1038 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1039 hist_browser__hpp_color_overhead_guest_sys;
1040 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1041 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001042 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1043 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001044}
1045
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001046static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001047 struct hist_entry *entry,
1048 unsigned short row)
1049{
1050 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +02001051 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001052 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001053 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001054 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001055 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001056 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001057 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001058
1059 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001060 browser->he_selection = entry;
1061 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001062 }
1063
1064 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001065 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001066 folded_sign = hist_entry__folded(entry);
1067 }
1068
1069 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001070 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001071 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001072 .folded_sign = folded_sign,
1073 .current_entry = current_entry,
1074 };
Namhyung Kimf5951d52012-09-03 11:53:09 +09001075 struct perf_hpp hpp = {
1076 .buf = s,
1077 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +09001078 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +09001079 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001080 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001081
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001082 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001083
Jiri Olsa12400052012-10-13 00:06:16 +02001084 perf_hpp__for_each_format(fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001085 if (perf_hpp__should_skip(fmt, entry->hists) ||
1086 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001087 continue;
1088
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001089 if (current_entry && browser->b.navkeypressed) {
1090 ui_browser__set_color(&browser->b,
1091 HE_COLORSET_SELECTED);
1092 } else {
1093 ui_browser__set_color(&browser->b,
1094 HE_COLORSET_NORMAL);
1095 }
1096
1097 if (first) {
1098 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001099 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001100 width -= 2;
1101 }
1102 first = false;
1103 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001104 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001105 width -= 2;
1106 }
1107
Jiri Olsa12400052012-10-13 00:06:16 +02001108 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001109 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001110 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001111 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001112 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001113 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001114 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001115
1116 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001117 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001118 width += 1;
1119
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001120 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001121
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001122 ++row;
1123 ++printed;
1124 } else
1125 --row_offset;
1126
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001127 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001128 struct callchain_print_arg arg = {
1129 .row_offset = row_offset,
1130 .is_current_entry = current_entry,
1131 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001132
Namhyung Kim0c841c62016-01-28 00:40:54 +09001133 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001134 hist_browser__show_callchain_entry, &arg,
1135 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001136 }
1137
1138 return printed;
1139}
1140
Jiri Olsa81a888f2014-06-14 15:44:52 +02001141static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1142{
1143 advance_hpp(hpp, inc);
1144 return hpp->size <= 0;
1145}
1146
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001147static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001148{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001149 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001150 struct perf_hpp dummy_hpp = {
1151 .buf = buf,
1152 .size = size,
1153 };
1154 struct perf_hpp_fmt *fmt;
1155 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001156 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001157
1158 if (symbol_conf.use_callchain) {
1159 ret = scnprintf(buf, size, " ");
1160 if (advance_hpp_check(&dummy_hpp, ret))
1161 return ret;
1162 }
1163
1164 perf_hpp__for_each_format(fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001165 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001166 continue;
1167
Jiri Olsa81a888f2014-06-14 15:44:52 +02001168 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1169 if (advance_hpp_check(&dummy_hpp, ret))
1170 break;
1171
1172 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1173 if (advance_hpp_check(&dummy_hpp, ret))
1174 break;
1175 }
1176
1177 return ret;
1178}
1179
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001180static void hist_browser__show_headers(struct hist_browser *browser)
1181{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001182 char headers[1024];
1183
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001184 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001185 ui_browser__gotorc(&browser->b, 0, 0);
1186 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001187 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001188}
1189
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001190static void ui_browser__hists_init_top(struct ui_browser *browser)
1191{
1192 if (browser->top == NULL) {
1193 struct hist_browser *hb;
1194
1195 hb = container_of(browser, struct hist_browser, b);
1196 browser->top = rb_first(&hb->hists->entries);
1197 }
1198}
1199
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001200static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201{
1202 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001203 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001205 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001207 if (hb->show_headers) {
1208 hist_browser__show_headers(hb);
1209 header_offset = 1;
1210 }
1211
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001212 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001213 hb->he_selection = NULL;
1214 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001216 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001217 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001218 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219
1220 if (h->filtered)
1221 continue;
1222
Namhyung Kim14135662013-10-31 10:17:39 +09001223 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001224 if (percent < hb->min_pcnt)
1225 continue;
1226
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001227 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001228 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001229 break;
1230 }
1231
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001232 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001233}
1234
Namhyung Kim064f1982013-05-14 11:09:04 +09001235static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001236 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001237{
1238 while (nd != NULL) {
1239 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001240 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001241
Namhyung Kimc0f15272014-04-16 11:16:33 +09001242 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001243 return nd;
1244
1245 nd = rb_next(nd);
1246 }
1247
1248 return NULL;
1249}
1250
Namhyung Kim064f1982013-05-14 11:09:04 +09001251static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001252 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253{
1254 while (nd != NULL) {
1255 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001256 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001257
1258 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259 return nd;
1260
1261 nd = rb_prev(nd);
1262 }
1263
1264 return NULL;
1265}
1266
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001267static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001268 off_t offset, int whence)
1269{
1270 struct hist_entry *h;
1271 struct rb_node *nd;
1272 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001273 struct hist_browser *hb;
1274
1275 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001276
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001277 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001278 return;
1279
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001280 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001281
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001282 switch (whence) {
1283 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001284 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001285 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001286 break;
1287 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001288 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001289 goto do_offset;
1290 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001291 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001292 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001293 first = false;
1294 break;
1295 default:
1296 return;
1297 }
1298
1299 /*
1300 * Moves not relative to the first visible entry invalidates its
1301 * row_offset:
1302 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001303 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001304 h->row_offset = 0;
1305
1306 /*
1307 * Here we have to check if nd is expanded (+), if it is we can't go
1308 * the next top level hist_entry, instead we must compute an offset of
1309 * what _not_ to show and not change the first visible entry.
1310 *
1311 * This offset increments when we are going from top to bottom and
1312 * decreases when we're going from bottom to top.
1313 *
1314 * As we don't have backpointers to the top level in the callchains
1315 * structure, we need to always print the whole hist_entry callchain,
1316 * skipping the first ones that are before the first visible entry
1317 * and stop when we printed enough lines to fill the screen.
1318 */
1319do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001320 if (!nd)
1321 return;
1322
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001323 if (offset > 0) {
1324 do {
1325 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001326 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001327 u16 remaining = h->nr_rows - h->row_offset;
1328 if (offset > remaining) {
1329 offset -= remaining;
1330 h->row_offset = 0;
1331 } else {
1332 h->row_offset += offset;
1333 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001334 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001335 break;
1336 }
1337 }
Namhyung Kim14135662013-10-31 10:17:39 +09001338 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001339 if (nd == NULL)
1340 break;
1341 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001342 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001343 } while (offset != 0);
1344 } else if (offset < 0) {
1345 while (1) {
1346 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001347 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001348 if (first) {
1349 if (-offset > h->row_offset) {
1350 offset += h->row_offset;
1351 h->row_offset = 0;
1352 } else {
1353 h->row_offset += offset;
1354 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001355 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001356 break;
1357 }
1358 } else {
1359 if (-offset > h->nr_rows) {
1360 offset += h->nr_rows;
1361 h->row_offset = 0;
1362 } else {
1363 h->row_offset = h->nr_rows + offset;
1364 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001365 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001366 break;
1367 }
1368 }
1369 }
1370
Namhyung Kim14135662013-10-31 10:17:39 +09001371 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001372 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001373 if (nd == NULL)
1374 break;
1375 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001376 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001377 if (offset == 0) {
1378 /*
1379 * Last unfiltered hist_entry, check if it is
1380 * unfolded, if it is then we should have
1381 * row_offset at its last entry.
1382 */
1383 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001384 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001385 h->row_offset = h->nr_rows;
1386 break;
1387 }
1388 first = false;
1389 }
1390 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001391 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001392 h = rb_entry(nd, struct hist_entry, rb_node);
1393 h->row_offset = 0;
1394 }
1395}
1396
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001397static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001398 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001399{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001400 struct callchain_print_arg arg = {
1401 .fp = fp,
1402 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001403
Namhyung Kim0c841c62016-01-28 00:40:54 +09001404 hist_browser__show_callchain(browser, he, 1, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001405 hist_browser__fprintf_callchain_entry, &arg,
1406 hist_browser__check_dump_full);
1407 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001408}
1409
1410static int hist_browser__fprintf_entry(struct hist_browser *browser,
1411 struct hist_entry *he, FILE *fp)
1412{
1413 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001414 int printed = 0;
1415 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001416 struct perf_hpp hpp = {
1417 .buf = s,
1418 .size = sizeof(s),
1419 };
1420 struct perf_hpp_fmt *fmt;
1421 bool first = true;
1422 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001423
1424 if (symbol_conf.use_callchain)
1425 folded_sign = hist_entry__folded(he);
1426
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001427 if (symbol_conf.use_callchain)
1428 printed += fprintf(fp, "%c ", folded_sign);
1429
Namhyung Kim26d8b332014-03-03 16:16:20 +09001430 perf_hpp__for_each_format(fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001431 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001432 continue;
1433
Namhyung Kim26d8b332014-03-03 16:16:20 +09001434 if (!first) {
1435 ret = scnprintf(hpp.buf, hpp.size, " ");
1436 advance_hpp(&hpp, ret);
1437 } else
1438 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001439
Namhyung Kim26d8b332014-03-03 16:16:20 +09001440 ret = fmt->entry(fmt, &hpp, he);
1441 advance_hpp(&hpp, ret);
1442 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001443 printed += fprintf(fp, "%s\n", rtrim(s));
1444
1445 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001446 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001447
1448 return printed;
1449}
1450
1451static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1452{
Namhyung Kim064f1982013-05-14 11:09:04 +09001453 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001454 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001455 int printed = 0;
1456
1457 while (nd) {
1458 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1459
1460 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001461 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001462 }
1463
1464 return printed;
1465}
1466
1467static int hist_browser__dump(struct hist_browser *browser)
1468{
1469 char filename[64];
1470 FILE *fp;
1471
1472 while (1) {
1473 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1474 if (access(filename, F_OK))
1475 break;
1476 /*
1477 * XXX: Just an arbitrary lazy upper limit
1478 */
1479 if (++browser->print_seq == 8192) {
1480 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1481 return -1;
1482 }
1483 }
1484
1485 fp = fopen(filename, "w");
1486 if (fp == NULL) {
1487 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001488 const char *err = strerror_r(errno, bf, sizeof(bf));
1489 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001490 return -1;
1491 }
1492
1493 ++browser->print_seq;
1494 hist_browser__fprintf(browser, fp);
1495 fclose(fp);
1496 ui_helpline__fpush("%s written!", filename);
1497
1498 return 0;
1499}
1500
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001501static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001502 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001503 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001504{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001505 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001506
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001507 if (browser) {
1508 browser->hists = hists;
1509 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001510 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001511 browser->b.seek = ui_browser__hists_seek;
1512 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001513 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001514 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001515 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001516 }
1517
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001518 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001519}
1520
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001521static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001522{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001523 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001524}
1525
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001526static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001527{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001528 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001529}
1530
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001531static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001532{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001533 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001534}
1535
Taeung Song1e378eb2014-10-07 16:13:15 +09001536/* Check whether the browser is for 'top' or 'report' */
1537static inline bool is_report_browser(void *timer)
1538{
1539 return timer == NULL;
1540}
1541
1542static int hists__browser_title(struct hists *hists,
1543 struct hist_browser_timer *hbt,
1544 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001545{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001546 char unit;
1547 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001548 const struct dso *dso = hists->dso_filter;
1549 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001550 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001551 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1552 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001553 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001554 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001555 char buf[512];
1556 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001557 char ref[30] = " show reference callgraph, ";
1558 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001559
Namhyung Kimf2148332014-01-14 11:52:48 +09001560 if (symbol_conf.filter_relative) {
1561 nr_samples = hists->stats.nr_non_filtered_samples;
1562 nr_events = hists->stats.total_non_filtered_period;
1563 }
1564
Namhyung Kim759ff492013-03-05 14:53:26 +09001565 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001566 struct perf_evsel *pos;
1567
1568 perf_evsel__group_desc(evsel, buf, buflen);
1569 ev_name = buf;
1570
1571 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001572 struct hists *pos_hists = evsel__hists(pos);
1573
Namhyung Kimf2148332014-01-14 11:52:48 +09001574 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001575 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1576 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001577 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001578 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1579 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001580 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001581 }
1582 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001583
Kan Liang9e207dd2015-08-11 06:30:49 -04001584 if (symbol_conf.show_ref_callgraph &&
1585 strstr(ev_name, "call-graph=no"))
1586 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05001587 nr_samples = convert_unit(nr_samples, &unit);
1588 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001589 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1590 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05001591
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001592
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001593 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001594 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001595 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001596 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001597 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001598 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001599 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001600 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001601 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001602 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001603 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001604 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001605 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001606 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001607 if (!is_report_browser(hbt)) {
1608 struct perf_top *top = hbt->arg;
1609
1610 if (top->zero)
1611 printed += scnprintf(bf + printed, size - printed, " [z]");
1612 }
1613
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001614 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001615}
1616
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001617static inline void free_popup_options(char **options, int n)
1618{
1619 int i;
1620
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001621 for (i = 0; i < n; ++i)
1622 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001623}
1624
Feng Tang341487ab2013-02-03 14:38:20 +08001625/*
1626 * Only runtime switching of perf data file will make "input_name" point
1627 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1628 * whether we need to call free() for current "input_name" during the switch.
1629 */
1630static bool is_input_name_malloced = false;
1631
1632static int switch_data_file(void)
1633{
1634 char *pwd, *options[32], *abs_path[32], *tmp;
1635 DIR *pwd_dir;
1636 int nr_options = 0, choice = -1, ret = -1;
1637 struct dirent *dent;
1638
1639 pwd = getenv("PWD");
1640 if (!pwd)
1641 return ret;
1642
1643 pwd_dir = opendir(pwd);
1644 if (!pwd_dir)
1645 return ret;
1646
1647 memset(options, 0, sizeof(options));
1648 memset(options, 0, sizeof(abs_path));
1649
1650 while ((dent = readdir(pwd_dir))) {
1651 char path[PATH_MAX];
1652 u64 magic;
1653 char *name = dent->d_name;
1654 FILE *file;
1655
1656 if (!(dent->d_type == DT_REG))
1657 continue;
1658
1659 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1660
1661 file = fopen(path, "r");
1662 if (!file)
1663 continue;
1664
1665 if (fread(&magic, 1, 8, file) < 8)
1666 goto close_file_and_continue;
1667
1668 if (is_perf_magic(magic)) {
1669 options[nr_options] = strdup(name);
1670 if (!options[nr_options])
1671 goto close_file_and_continue;
1672
1673 abs_path[nr_options] = strdup(path);
1674 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001675 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001676 ui__warning("Can't search all data files due to memory shortage.\n");
1677 fclose(file);
1678 break;
1679 }
1680
1681 nr_options++;
1682 }
1683
1684close_file_and_continue:
1685 fclose(file);
1686 if (nr_options >= 32) {
1687 ui__warning("Too many perf data files in PWD!\n"
1688 "Only the first 32 files will be listed.\n");
1689 break;
1690 }
1691 }
1692 closedir(pwd_dir);
1693
1694 if (nr_options) {
1695 choice = ui__popup_menu(nr_options, options);
1696 if (choice < nr_options && choice >= 0) {
1697 tmp = strdup(abs_path[choice]);
1698 if (tmp) {
1699 if (is_input_name_malloced)
1700 free((void *)input_name);
1701 input_name = tmp;
1702 is_input_name_malloced = true;
1703 ret = 0;
1704 } else
1705 ui__warning("Data switch failed due to memory shortage!\n");
1706 }
1707 }
1708
1709 free_popup_options(options, nr_options);
1710 free_popup_options(abs_path, nr_options);
1711 return ret;
1712}
1713
Namhyung Kimea7cd592015-04-22 16:18:19 +09001714struct popup_action {
1715 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001716 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001717 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001718
1719 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1720};
1721
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001722static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001723do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001724{
1725 struct perf_evsel *evsel;
1726 struct annotation *notes;
1727 struct hist_entry *he;
1728 int err;
1729
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001730 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001731 return 0;
1732
Namhyung Kimea7cd592015-04-22 16:18:19 +09001733 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001734 if (!notes->src)
1735 return 0;
1736
1737 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001738 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001739 he = hist_browser__selected_entry(browser);
1740 /*
1741 * offer option to annotate the other branch source or target
1742 * (if they exists) when returning from annotate
1743 */
1744 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1745 return 1;
1746
1747 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1748 if (err)
1749 ui_browser__handle_resize(&browser->b);
1750 return 0;
1751}
1752
1753static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001754add_annotate_opt(struct hist_browser *browser __maybe_unused,
1755 struct popup_action *act, char **optstr,
1756 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001757{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001758 if (sym == NULL || map->dso->annotate_warned)
1759 return 0;
1760
1761 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1762 return 0;
1763
1764 act->ms.map = map;
1765 act->ms.sym = sym;
1766 act->fn = do_annotate;
1767 return 1;
1768}
1769
1770static int
1771do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1772{
1773 struct thread *thread = act->thread;
1774
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001775 if (browser->hists->thread_filter) {
1776 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1777 perf_hpp__set_elide(HISTC_THREAD, false);
1778 thread__zput(browser->hists->thread_filter);
1779 ui_helpline__pop();
1780 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001781 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001782 thread->comm_set ? thread__comm_str(thread) : "",
1783 thread->tid);
1784 browser->hists->thread_filter = thread__get(thread);
1785 perf_hpp__set_elide(HISTC_THREAD, false);
1786 pstack__push(browser->pstack, &browser->hists->thread_filter);
1787 }
1788
1789 hists__filter_by_thread(browser->hists);
1790 hist_browser__reset(browser);
1791 return 0;
1792}
1793
1794static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001795add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1796 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001797{
Namhyung Kim2eafd412016-01-21 19:13:24 -03001798 if (!sort__has_thread || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001799 return 0;
1800
1801 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1802 browser->hists->thread_filter ? "out of" : "into",
1803 thread->comm_set ? thread__comm_str(thread) : "",
1804 thread->tid) < 0)
1805 return 0;
1806
1807 act->thread = thread;
1808 act->fn = do_zoom_thread;
1809 return 1;
1810}
1811
1812static int
1813do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1814{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001815 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001816
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001817 if (browser->hists->dso_filter) {
1818 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1819 perf_hpp__set_elide(HISTC_DSO, false);
1820 browser->hists->dso_filter = NULL;
1821 ui_helpline__pop();
1822 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001823 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001824 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001825 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001826 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1827 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001828 perf_hpp__set_elide(HISTC_DSO, true);
1829 pstack__push(browser->pstack, &browser->hists->dso_filter);
1830 }
1831
1832 hists__filter_by_dso(browser->hists);
1833 hist_browser__reset(browser);
1834 return 0;
1835}
1836
1837static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001838add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001839 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001840{
Namhyung Kimb1447a542016-01-22 11:22:41 -03001841 if (!sort__has_dso || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001842 return 0;
1843
1844 if (asprintf(optstr, "Zoom %s %s DSO",
1845 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001846 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001847 return 0;
1848
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001849 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001850 act->fn = do_zoom_dso;
1851 return 1;
1852}
1853
1854static int
1855do_browse_map(struct hist_browser *browser __maybe_unused,
1856 struct popup_action *act)
1857{
1858 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001859 return 0;
1860}
1861
1862static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001863add_map_opt(struct hist_browser *browser __maybe_unused,
1864 struct popup_action *act, char **optstr, struct map *map)
1865{
Namhyung Kimb1447a542016-01-22 11:22:41 -03001866 if (!sort__has_dso || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001867 return 0;
1868
1869 if (asprintf(optstr, "Browse map details") < 0)
1870 return 0;
1871
1872 act->ms.map = map;
1873 act->fn = do_browse_map;
1874 return 1;
1875}
1876
1877static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001878do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001879 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001880{
1881 char script_opt[64];
1882 memset(script_opt, 0, sizeof(script_opt));
1883
Namhyung Kimea7cd592015-04-22 16:18:19 +09001884 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001885 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001886 thread__comm_str(act->thread));
1887 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001888 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001889 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001890 }
1891
1892 script_browse(script_opt);
1893 return 0;
1894}
1895
1896static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001897add_script_opt(struct hist_browser *browser __maybe_unused,
1898 struct popup_action *act, char **optstr,
1899 struct thread *thread, struct symbol *sym)
1900{
1901 if (thread) {
1902 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1903 thread__comm_str(thread)) < 0)
1904 return 0;
1905 } else if (sym) {
1906 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1907 sym->name) < 0)
1908 return 0;
1909 } else {
1910 if (asprintf(optstr, "Run scripts for all samples") < 0)
1911 return 0;
1912 }
1913
1914 act->thread = thread;
1915 act->ms.sym = sym;
1916 act->fn = do_run_script;
1917 return 1;
1918}
1919
1920static int
1921do_switch_data(struct hist_browser *browser __maybe_unused,
1922 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001923{
1924 if (switch_data_file()) {
1925 ui__warning("Won't switch the data files due to\n"
1926 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001927 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001928 }
1929
1930 return K_SWITCH_INPUT_DATA;
1931}
1932
Namhyung Kimea7cd592015-04-22 16:18:19 +09001933static int
1934add_switch_opt(struct hist_browser *browser,
1935 struct popup_action *act, char **optstr)
1936{
1937 if (!is_report_browser(browser->hbt))
1938 return 0;
1939
1940 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1941 return 0;
1942
1943 act->fn = do_switch_data;
1944 return 1;
1945}
1946
1947static int
1948do_exit_browser(struct hist_browser *browser __maybe_unused,
1949 struct popup_action *act __maybe_unused)
1950{
1951 return 0;
1952}
1953
1954static int
1955add_exit_opt(struct hist_browser *browser __maybe_unused,
1956 struct popup_action *act, char **optstr)
1957{
1958 if (asprintf(optstr, "Exit") < 0)
1959 return 0;
1960
1961 act->fn = do_exit_browser;
1962 return 1;
1963}
1964
Kan Liang84734b02015-09-04 10:45:45 -04001965static int
1966do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1967{
1968 if (browser->hists->socket_filter > -1) {
1969 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1970 browser->hists->socket_filter = -1;
1971 perf_hpp__set_elide(HISTC_SOCKET, false);
1972 } else {
1973 browser->hists->socket_filter = act->socket;
1974 perf_hpp__set_elide(HISTC_SOCKET, true);
1975 pstack__push(browser->pstack, &browser->hists->socket_filter);
1976 }
1977
1978 hists__filter_by_socket(browser->hists);
1979 hist_browser__reset(browser);
1980 return 0;
1981}
1982
1983static int
1984add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1985 char **optstr, int socket_id)
1986{
Namhyung Kimd9695d92016-01-22 12:20:18 -03001987 if (!sort__has_socket || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04001988 return 0;
1989
1990 if (asprintf(optstr, "Zoom %s Processor Socket %d",
1991 (browser->hists->socket_filter > -1) ? "out of" : "into",
1992 socket_id) < 0)
1993 return 0;
1994
1995 act->socket = socket_id;
1996 act->fn = do_zoom_socket;
1997 return 1;
1998}
1999
Namhyung Kim112f7612014-04-22 14:05:35 +09002000static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002001{
2002 u64 nr_entries = 0;
2003 struct rb_node *nd = rb_first(&hb->hists->entries);
2004
Namhyung Kim268397c2014-04-22 14:49:31 +09002005 if (hb->min_pcnt == 0) {
2006 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2007 return;
2008 }
2009
Namhyung Kim14135662013-10-31 10:17:39 +09002010 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002011 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09002012 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002013 }
2014
Namhyung Kim112f7612014-04-22 14:05:35 +09002015 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002016}
Feng Tang341487ab2013-02-03 14:38:20 +08002017
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002018static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002019 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002020 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002021 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002022 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002023 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002024{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002025 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09002026 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002027 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002028#define MAX_OPTIONS 16
2029 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002030 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002031 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002032 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002033 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002034 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002035 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002036
Namhyung Kime8e684a2013-12-26 14:37:58 +09002037#define HIST_BROWSER_HELP_COMMON \
2038 "h/?/F1 Show this window\n" \
2039 "UP/DOWN/PGUP\n" \
2040 "PGDN/SPACE Navigate\n" \
2041 "q/ESC/CTRL+C Exit browser\n\n" \
2042 "For multiple event sessions:\n\n" \
2043 "TAB/UNTAB Switch events\n\n" \
2044 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002045 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2046 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002047 "a Annotate current symbol\n" \
2048 "C Collapse all callchains\n" \
2049 "d Zoom into current DSO\n" \
2050 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002051 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002052 "H Display column headers\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002053 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002054 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002055
2056 /* help messages are sorted by lexical order of the hotkey */
2057 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002058 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002059 "P Print histograms to perf.hist.N\n"
2060 "r Run available scripts\n"
2061 "s Switch to another data file in PWD\n"
2062 "t Zoom into current Thread\n"
2063 "V Verbose (DSO names in callchains, etc)\n"
2064 "/ Filter symbol by name";
2065 const char top_help[] = HIST_BROWSER_HELP_COMMON
2066 "P Print histograms to perf.hist.N\n"
2067 "t Zoom into current Thread\n"
2068 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002069 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002070 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002071 "/ Filter symbol by name";
2072
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002073 if (browser == NULL)
2074 return -1;
2075
Namhyung Kimed426912015-05-29 21:53:44 +09002076 /* reset abort key so that it can get Ctrl-C as a key */
2077 SLang_reset_tty();
2078 SLang_init_tty(0, 0, 0);
2079
Namhyung Kim03905042015-11-28 02:32:39 +09002080 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002081 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002082 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002083
Kan Liang84734b02015-09-04 10:45:45 -04002084 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002085 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002086 goto out;
2087
2088 ui_helpline__push(helpline);
2089
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002090 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002091 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002092
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002093 perf_hpp__for_each_format(fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002094 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002095 /*
2096 * This is done just once, and activates the horizontal scrolling
2097 * code in the ui_browser code, it would be better to have a the
2098 * counter in the perf_hpp code, but I couldn't find doing it here
2099 * works, FIXME by setting this in hist_browser__new, for now, be
2100 * clever 8-)
2101 */
2102 ++browser->b.columns;
2103 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002104
Namhyung Kim5b591662014-07-31 14:47:38 +09002105 if (symbol_conf.col_width_list_str)
2106 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2107
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002108 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002109 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002110 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002111 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002112 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002113
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002114 nr_options = 0;
2115
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002116 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002117
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002118 if (browser->he_selection != NULL) {
2119 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002120 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002121 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002122 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002123 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002124 case K_TAB:
2125 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002126 if (nr_events == 1)
2127 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002128 /*
2129 * Exit the browser, let hists__browser_tree
2130 * go to the next or previous
2131 */
2132 goto out_free_stack;
2133 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002134 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002135 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002136 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002137 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002138 continue;
2139 }
2140
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002141 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002142 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002143 browser->selection->map->dso->annotate_warned)
2144 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002145
Namhyung Kimea7cd592015-04-22 16:18:19 +09002146 actions->ms.map = browser->selection->map;
2147 actions->ms.sym = browser->selection->sym;
2148 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002149 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002150 case 'P':
2151 hist_browser__dump(browser);
2152 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002153 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002154 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002155 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002156 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002157 case 'V':
2158 browser->show_dso = !browser->show_dso;
2159 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002160 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002161 actions->thread = thread;
2162 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002163 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002164 case 'S':
2165 actions->socket = socked_id;
2166 do_zoom_socket(browser, actions);
2167 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002168 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002169 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002170 "Please enter the name of symbol you want to see.\n"
2171 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002172 buf, "ENTER: OK, ESC: Cancel",
2173 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002174 hists->symbol_filter_str = *buf ? buf : NULL;
2175 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002176 hist_browser__reset(browser);
2177 }
2178 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002179 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002180 if (is_report_browser(hbt)) {
2181 actions->thread = NULL;
2182 actions->ms.sym = NULL;
2183 do_run_script(browser, actions);
2184 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002185 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002186 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002187 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002188 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002189 if (key == K_SWITCH_INPUT_DATA)
2190 goto out_free_stack;
2191 }
Feng Tang341487ab2013-02-03 14:38:20 +08002192 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002193 case 'i':
2194 /* env->arch is NULL for live-mode (i.e. perf top) */
2195 if (env->arch)
2196 tui__header_window(env);
2197 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002198 case 'F':
2199 symbol_conf.filter_relative ^= 1;
2200 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002201 case 'z':
2202 if (!is_report_browser(hbt)) {
2203 struct perf_top *top = hbt->arg;
2204
2205 top->zero = !top->zero;
2206 }
2207 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002208 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002209 case 'h':
2210 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002211 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002212 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002213 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002214 case K_ENTER:
2215 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002216 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002217 /* menu */
2218 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002219 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002220 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002221 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002222
Namhyung Kim01f00a12015-04-22 16:18:16 +09002223 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002224 /*
2225 * Go back to the perf_evsel_menu__run or other user
2226 */
2227 if (left_exits)
2228 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002229
2230 if (key == K_ESC &&
2231 ui_browser__dialog_yesno(&browser->b,
2232 "Do you really want to exit?"))
2233 goto out_free_stack;
2234
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002235 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002236 }
Namhyung Kim64221842015-04-24 10:15:33 +09002237 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002238 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002239 /*
2240 * No need to set actions->dso here since
2241 * it's just to remove the current filter.
2242 * Ditto for thread below.
2243 */
2244 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002245 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002246 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002247 } else if (top == &browser->hists->socket_filter) {
2248 do_zoom_socket(browser, actions);
2249 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002250 continue;
2251 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002252 case 'q':
2253 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002254 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002255 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002256 if (!is_report_browser(hbt)) {
2257 struct perf_top *top = hbt->arg;
2258
2259 perf_evlist__toggle_enable(top->evlist);
2260 /*
2261 * No need to refresh, resort/decay histogram
2262 * entries if we are not collecting samples:
2263 */
2264 if (top->evlist->enabled) {
2265 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2266 hbt->refresh = delay_secs;
2267 } else {
2268 helpline = "Press 'f' again to re-enable the events";
2269 hbt->refresh = 0;
2270 }
2271 continue;
2272 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002273 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002274 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002275 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002276 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002277 }
2278
Namhyung Kim40561322016-01-22 12:26:06 -03002279 if (!sort__has_sym || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002280 goto skip_annotation;
2281
Namhyung Kim55369fc2013-04-01 20:35:20 +09002282 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002283 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002284
2285 if (bi == NULL)
2286 goto skip_annotation;
2287
Namhyung Kimea7cd592015-04-22 16:18:19 +09002288 nr_options += add_annotate_opt(browser,
2289 &actions[nr_options],
2290 &options[nr_options],
2291 bi->from.map,
2292 bi->from.sym);
2293 if (bi->to.sym != bi->from.sym)
2294 nr_options += add_annotate_opt(browser,
2295 &actions[nr_options],
2296 &options[nr_options],
2297 bi->to.map,
2298 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002299 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002300 nr_options += add_annotate_opt(browser,
2301 &actions[nr_options],
2302 &options[nr_options],
2303 browser->selection->map,
2304 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002305 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002306skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002307 nr_options += add_thread_opt(browser, &actions[nr_options],
2308 &options[nr_options], thread);
2309 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002310 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002311 nr_options += add_map_opt(browser, &actions[nr_options],
2312 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002313 browser->selection ?
2314 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002315 nr_options += add_socket_opt(browser, &actions[nr_options],
2316 &options[nr_options],
2317 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002318 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002319 if (!is_report_browser(hbt))
2320 goto skip_scripting;
2321
Feng Tangcdbab7c2012-10-30 11:56:06 +08002322 if (browser->he_selection) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002323 if (sort__has_thread && thread) {
2324 nr_options += add_script_opt(browser,
2325 &actions[nr_options],
2326 &options[nr_options],
2327 thread, NULL);
2328 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002329 /*
2330 * Note that browser->selection != NULL
2331 * when browser->he_selection is not NULL,
2332 * so we don't need to check browser->selection
2333 * before fetching browser->selection->sym like what
2334 * we do before fetching browser->selection->map.
2335 *
2336 * See hist_browser__show_entry.
2337 */
Namhyung Kimc221acb2016-01-21 19:50:09 -03002338 if (sort__has_sym && browser->selection->sym) {
2339 nr_options += add_script_opt(browser,
2340 &actions[nr_options],
2341 &options[nr_options],
2342 NULL, browser->selection->sym);
2343 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08002344 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002345 nr_options += add_script_opt(browser, &actions[nr_options],
2346 &options[nr_options], NULL, NULL);
2347 nr_options += add_switch_opt(browser, &actions[nr_options],
2348 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03002349skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002350 nr_options += add_exit_opt(browser, &actions[nr_options],
2351 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002352
Namhyung Kimea7cd592015-04-22 16:18:19 +09002353 do {
2354 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002355
Namhyung Kimea7cd592015-04-22 16:18:19 +09002356 choice = ui__popup_menu(nr_options, options);
2357 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002358 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002359
2360 act = &actions[choice];
2361 key = act->fn(browser, act);
2362 } while (key == 1);
2363
2364 if (key == K_SWITCH_INPUT_DATA)
2365 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002366 }
2367out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002368 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002369out:
2370 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002371 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002372 return key;
2373}
2374
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002375struct perf_evsel_menu {
2376 struct ui_browser b;
2377 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002378 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002379 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002380 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002381};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002382
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002383static void perf_evsel_menu__write(struct ui_browser *browser,
2384 void *entry, int row)
2385{
2386 struct perf_evsel_menu *menu = container_of(browser,
2387 struct perf_evsel_menu, b);
2388 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002389 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002390 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002391 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002392 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002393 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002394 const char *warn = " ";
2395 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002396
2397 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2398 HE_COLORSET_NORMAL);
2399
Namhyung Kim759ff492013-03-05 14:53:26 +09002400 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002401 struct perf_evsel *pos;
2402
2403 ev_name = perf_evsel__group_name(evsel);
2404
2405 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002406 struct hists *pos_hists = evsel__hists(pos);
2407 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002408 }
2409 }
2410
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002411 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002412 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002413 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002414 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002415
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002416 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002417 if (nr_events != 0) {
2418 menu->lost_events = true;
2419 if (!current_entry)
2420 ui_browser__set_color(browser, HE_COLORSET_TOP);
2421 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002422 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2423 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002424 warn = bf;
2425 }
2426
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002427 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002428
2429 if (current_entry)
2430 menu->selection = evsel;
2431}
2432
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002433static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2434 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002435 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002436{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002437 struct perf_evlist *evlist = menu->b.priv;
2438 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002439 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002440 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002441 int key;
2442
2443 if (ui_browser__show(&menu->b, title,
2444 "ESC: exit, ENTER|->: Browse histograms") < 0)
2445 return -1;
2446
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002447 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002448 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002449
2450 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002451 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002452 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002453
2454 if (!menu->lost_events_warned && menu->lost_events) {
2455 ui_browser__warn_lost_events(&menu->b);
2456 menu->lost_events_warned = true;
2457 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002458 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002459 case K_RIGHT:
2460 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002461 if (!menu->selection)
2462 continue;
2463 pos = menu->selection;
2464browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002465 perf_evlist__set_selected(evlist, pos);
2466 /*
2467 * Give the calling tool a chance to populate the non
2468 * default evsel resorted hists tree.
2469 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002470 if (hbt)
2471 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002472 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002473 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002474 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002475 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002476 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002477 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002478 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002479 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002480 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002481 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002482 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002483 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002484 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002485 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002486 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002487 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002488 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002489 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002490 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002491 case 'q':
2492 case CTRL('c'):
2493 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002494 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002495 default:
2496 continue;
2497 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002498 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002499 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002500 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002501 if (!ui_browser__dialog_yesno(&menu->b,
2502 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002503 continue;
2504 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002505 case 'q':
2506 case CTRL('c'):
2507 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002508 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002509 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002510 }
2511 }
2512
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002513out:
2514 ui_browser__hide(&menu->b);
2515 return key;
2516}
2517
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002518static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002519 void *entry)
2520{
2521 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2522
2523 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2524 return true;
2525
2526 return false;
2527}
2528
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002529static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002530 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002531 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002532 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002533 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002534{
2535 struct perf_evsel *pos;
2536 struct perf_evsel_menu menu = {
2537 .b = {
2538 .entries = &evlist->entries,
2539 .refresh = ui_browser__list_head_refresh,
2540 .seek = ui_browser__list_head_seek,
2541 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002542 .filter = filter_group_entries,
2543 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002544 .priv = evlist,
2545 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002546 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002547 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002548 };
2549
2550 ui_helpline__push("Press ESC to exit");
2551
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002552 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002553 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002554 size_t line_len = strlen(ev_name) + 7;
2555
2556 if (menu.b.width < line_len)
2557 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002558 }
2559
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002560 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002561}
2562
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002563int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002564 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002565 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002566 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002567{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002568 int nr_entries = evlist->nr_entries;
2569
2570single_entry:
2571 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002572 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002573
2574 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002575 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002576 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002577 }
2578
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002579 if (symbol_conf.event_group) {
2580 struct perf_evsel *pos;
2581
2582 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002583 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002584 if (perf_evsel__is_group_leader(pos))
2585 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002586 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002587
2588 if (nr_entries == 1)
2589 goto single_entry;
2590 }
2591
2592 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002593 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002594}