blob: 3a1e0965a8fdde52abb14474a8e8f095dac9ef7b [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 Kim59c624e2016-01-28 00:40:56 +0900660static bool check_percent_display(struct rb_node *node, u64 parent_total)
661{
662 struct callchain_node *child;
663
664 if (node == NULL)
665 return false;
666
667 if (rb_next(node))
668 return true;
669
670 child = rb_entry(node, struct callchain_node, rb_node);
671 return callchain_cumul_hits(child) != parent_total;
672}
673
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900674static int hist_browser__show_callchain_flat(struct hist_browser *browser,
675 struct rb_root *root,
676 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900677 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900678 print_callchain_entry_fn print,
679 struct callchain_print_arg *arg,
680 check_output_full_fn is_output_full)
681{
682 struct rb_node *node;
683 int first_row = row, offset = LEVEL_OFFSET_STEP;
684 bool need_percent;
685
686 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900687 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900688
689 while (node) {
690 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
691 struct rb_node *next = rb_next(node);
692 struct callchain_list *chain;
693 char folded_sign = ' ';
694 int first = true;
695 int extra_offset = 0;
696
697 list_for_each_entry(chain, &child->parent_val, list) {
698 bool was_first = first;
699
700 if (first)
701 first = false;
702 else if (need_percent)
703 extra_offset = LEVEL_OFFSET_STEP;
704
705 folded_sign = callchain_list__folded(chain);
706
707 row += hist_browser__show_callchain_list(browser, child,
708 chain, row, total,
709 was_first && need_percent,
710 offset + extra_offset,
711 print, arg);
712
713 if (is_output_full(browser, row))
714 goto out;
715
716 if (folded_sign == '+')
717 goto next;
718 }
719
720 list_for_each_entry(chain, &child->val, list) {
721 bool was_first = first;
722
723 if (first)
724 first = false;
725 else if (need_percent)
726 extra_offset = LEVEL_OFFSET_STEP;
727
728 folded_sign = callchain_list__folded(chain);
729
730 row += hist_browser__show_callchain_list(browser, child,
731 chain, row, total,
732 was_first && need_percent,
733 offset + extra_offset,
734 print, arg);
735
736 if (is_output_full(browser, row))
737 goto out;
738
739 if (folded_sign == '+')
740 break;
741 }
742
743next:
744 if (is_output_full(browser, row))
745 break;
746 node = next;
747 }
748out:
749 return row - first_row;
750}
751
Namhyung Kim8c430a32015-11-09 14:45:44 +0900752static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
753 struct callchain_list *chain,
754 char *value_str, char *old_str)
755{
756 char bf[1024];
757 const char *str;
758 char *new;
759
760 str = callchain_list__sym_name(chain, bf, sizeof(bf),
761 browser->show_dso);
762 if (old_str) {
763 if (asprintf(&new, "%s%s%s", old_str,
764 symbol_conf.field_sep ?: ";", str) < 0)
765 new = NULL;
766 } else {
767 if (value_str) {
768 if (asprintf(&new, "%s %s", value_str, str) < 0)
769 new = NULL;
770 } else {
771 if (asprintf(&new, "%s", str) < 0)
772 new = NULL;
773 }
774 }
775 return new;
776}
777
778static int hist_browser__show_callchain_folded(struct hist_browser *browser,
779 struct rb_root *root,
780 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900781 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900782 print_callchain_entry_fn print,
783 struct callchain_print_arg *arg,
784 check_output_full_fn is_output_full)
785{
786 struct rb_node *node;
787 int first_row = row, offset = LEVEL_OFFSET_STEP;
788 bool need_percent;
789
790 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900791 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900792
793 while (node) {
794 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
795 struct rb_node *next = rb_next(node);
796 struct callchain_list *chain, *first_chain = NULL;
797 int first = true;
798 char *value_str = NULL, *value_str_alloc = NULL;
799 char *chain_str = NULL, *chain_str_alloc = NULL;
800
801 if (arg->row_offset != 0) {
802 arg->row_offset--;
803 goto next;
804 }
805
806 if (need_percent) {
807 char buf[64];
808
809 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
810 if (asprintf(&value_str, "%s", buf) < 0) {
811 value_str = (char *)"<...>";
812 goto do_print;
813 }
814 value_str_alloc = value_str;
815 }
816
817 list_for_each_entry(chain, &child->parent_val, list) {
818 chain_str = hist_browser__folded_callchain_str(browser,
819 chain, value_str, chain_str);
820 if (first) {
821 first = false;
822 first_chain = chain;
823 }
824
825 if (chain_str == NULL) {
826 chain_str = (char *)"Not enough memory!";
827 goto do_print;
828 }
829
830 chain_str_alloc = chain_str;
831 }
832
833 list_for_each_entry(chain, &child->val, list) {
834 chain_str = hist_browser__folded_callchain_str(browser,
835 chain, value_str, chain_str);
836 if (first) {
837 first = false;
838 first_chain = chain;
839 }
840
841 if (chain_str == NULL) {
842 chain_str = (char *)"Not enough memory!";
843 goto do_print;
844 }
845
846 chain_str_alloc = chain_str;
847 }
848
849do_print:
850 print(browser, first_chain, chain_str, offset, row++, arg);
851 free(value_str_alloc);
852 free(chain_str_alloc);
853
854next:
855 if (is_output_full(browser, row))
856 break;
857 node = next;
858 }
859
860 return row - first_row;
861}
862
Namhyung Kim0c841c62016-01-28 00:40:54 +0900863static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900864 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900865 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900866 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900867 print_callchain_entry_fn print,
868 struct callchain_print_arg *arg,
869 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300870{
871 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900872 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +0900873 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +0900874 u64 percent_total = total;
875
876 if (callchain_param.mode == CHAIN_GRAPH_REL)
877 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300878
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900879 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900880 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +0900881
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300882 while (node) {
883 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
884 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300885 struct callchain_list *chain;
886 char folded_sign = ' ';
887 int first = true;
888 int extra_offset = 0;
889
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300890 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300891 bool was_first = first;
892
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300893 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300894 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900895 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300896 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300897
898 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300899
Namhyung Kim18bb8382015-11-09 14:45:42 +0900900 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900901 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +0900902 was_first && need_percent,
903 offset + extra_offset,
904 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900905
Namhyung Kim18bb8382015-11-09 14:45:42 +0900906 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300907 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900908
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300909 if (folded_sign == '+')
910 break;
911 }
912
913 if (folded_sign == '-') {
914 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900915
Namhyung Kim0c841c62016-01-28 00:40:54 +0900916 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900917 new_level, row, total,
918 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900919 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300920 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900921 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900922 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300923 node = next;
924 }
925out:
926 return row - first_row;
927}
928
Namhyung Kim0c841c62016-01-28 00:40:54 +0900929static int hist_browser__show_callchain(struct hist_browser *browser,
930 struct hist_entry *entry, int level,
931 unsigned short row,
932 print_callchain_entry_fn print,
933 struct callchain_print_arg *arg,
934 check_output_full_fn is_output_full)
935{
936 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +0900937 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +0900938 int printed;
939
Namhyung Kim5eca1042016-01-28 00:40:55 +0900940 if (symbol_conf.cumulate_callchain)
941 parent_total = entry->stat_acc->period;
942 else
943 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +0900944
945 if (callchain_param.mode == CHAIN_FLAT) {
946 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900947 &entry->sorted_chain, row,
948 total, parent_total, print, arg,
949 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +0900950 } else if (callchain_param.mode == CHAIN_FOLDED) {
951 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900952 &entry->sorted_chain, row,
953 total, parent_total, print, arg,
954 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +0900955 } else {
956 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900957 &entry->sorted_chain, level, row,
958 total, parent_total, print, arg,
959 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +0900960 }
961
962 if (arg->is_current_entry)
963 browser->he_selection = entry;
964
965 return printed;
966}
967
Namhyung Kim89701462013-01-22 18:09:38 +0900968struct hpp_arg {
969 struct ui_browser *b;
970 char folded_sign;
971 bool current_entry;
972};
973
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900974static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
975{
976 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900977 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900978 va_list args;
979 double percent;
980
981 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900982 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900983 percent = va_arg(args, double);
984 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900985
Namhyung Kim89701462013-01-22 18:09:38 +0900986 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900987
Namhyung Kimd6751072014-07-31 14:47:36 +0900988 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300989 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +0900990
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900991 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900992 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900993}
994
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900995#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900996static u64 __hpp_get_##_field(struct hist_entry *he) \
997{ \
998 return he->stat._field; \
999} \
1000 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001001static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001002hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001003 struct perf_hpp *hpp, \
1004 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001005{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001006 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1007 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001008}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001009
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001010#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1011static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1012{ \
1013 return he->stat_acc->_field; \
1014} \
1015 \
1016static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001017hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001018 struct perf_hpp *hpp, \
1019 struct hist_entry *he) \
1020{ \
1021 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001022 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001023 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001024 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001025 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001026 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001027 \
1028 return ret; \
1029 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001030 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1031 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001032}
1033
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001034__HPP_COLOR_PERCENT_FN(overhead, period)
1035__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1036__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1037__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1038__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001039__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001040
1041#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001042#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001043
1044void hist_browser__init_hpp(void)
1045{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001046 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1047 hist_browser__hpp_color_overhead;
1048 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1049 hist_browser__hpp_color_overhead_sys;
1050 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1051 hist_browser__hpp_color_overhead_us;
1052 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1053 hist_browser__hpp_color_overhead_guest_sys;
1054 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1055 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001056 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1057 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001058}
1059
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001060static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001061 struct hist_entry *entry,
1062 unsigned short row)
1063{
1064 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +02001065 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001066 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001067 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001068 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001069 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001070 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001071 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001072
1073 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001074 browser->he_selection = entry;
1075 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001076 }
1077
1078 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001079 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001080 folded_sign = hist_entry__folded(entry);
1081 }
1082
1083 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001084 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001085 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001086 .folded_sign = folded_sign,
1087 .current_entry = current_entry,
1088 };
Namhyung Kimf5951d52012-09-03 11:53:09 +09001089 struct perf_hpp hpp = {
1090 .buf = s,
1091 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +09001092 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +09001093 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001094 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001095
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001096 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001097
Jiri Olsaf0786af2016-01-18 10:24:23 +01001098 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001099 if (perf_hpp__should_skip(fmt, entry->hists) ||
1100 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001101 continue;
1102
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001103 if (current_entry && browser->b.navkeypressed) {
1104 ui_browser__set_color(&browser->b,
1105 HE_COLORSET_SELECTED);
1106 } else {
1107 ui_browser__set_color(&browser->b,
1108 HE_COLORSET_NORMAL);
1109 }
1110
1111 if (first) {
1112 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001113 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001114 width -= 2;
1115 }
1116 first = false;
1117 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001118 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001119 width -= 2;
1120 }
1121
Jiri Olsa12400052012-10-13 00:06:16 +02001122 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001123 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001124 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001125 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001126 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001127 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001128 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001129
1130 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001131 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001132 width += 1;
1133
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001134 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001135
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001136 ++row;
1137 ++printed;
1138 } else
1139 --row_offset;
1140
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001141 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001142 struct callchain_print_arg arg = {
1143 .row_offset = row_offset,
1144 .is_current_entry = current_entry,
1145 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001146
Namhyung Kim0c841c62016-01-28 00:40:54 +09001147 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001148 hist_browser__show_callchain_entry, &arg,
1149 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001150 }
1151
1152 return printed;
1153}
1154
Jiri Olsa81a888f2014-06-14 15:44:52 +02001155static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1156{
1157 advance_hpp(hpp, inc);
1158 return hpp->size <= 0;
1159}
1160
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001161static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001162{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001163 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001164 struct perf_hpp dummy_hpp = {
1165 .buf = buf,
1166 .size = size,
1167 };
1168 struct perf_hpp_fmt *fmt;
1169 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001170 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001171
1172 if (symbol_conf.use_callchain) {
1173 ret = scnprintf(buf, size, " ");
1174 if (advance_hpp_check(&dummy_hpp, ret))
1175 return ret;
1176 }
1177
Jiri Olsaf0786af2016-01-18 10:24:23 +01001178 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001179 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001180 continue;
1181
Jiri Olsa81a888f2014-06-14 15:44:52 +02001182 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1183 if (advance_hpp_check(&dummy_hpp, ret))
1184 break;
1185
1186 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1187 if (advance_hpp_check(&dummy_hpp, ret))
1188 break;
1189 }
1190
1191 return ret;
1192}
1193
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001194static void hist_browser__show_headers(struct hist_browser *browser)
1195{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001196 char headers[1024];
1197
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001198 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001199 ui_browser__gotorc(&browser->b, 0, 0);
1200 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001201 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001202}
1203
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001204static void ui_browser__hists_init_top(struct ui_browser *browser)
1205{
1206 if (browser->top == NULL) {
1207 struct hist_browser *hb;
1208
1209 hb = container_of(browser, struct hist_browser, b);
1210 browser->top = rb_first(&hb->hists->entries);
1211 }
1212}
1213
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001214static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215{
1216 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001217 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001219 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001221 if (hb->show_headers) {
1222 hist_browser__show_headers(hb);
1223 header_offset = 1;
1224 }
1225
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001226 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001227 hb->he_selection = NULL;
1228 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001229
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001230 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001231 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001232 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001233
1234 if (h->filtered)
1235 continue;
1236
Namhyung Kim14135662013-10-31 10:17:39 +09001237 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001238 if (percent < hb->min_pcnt)
1239 continue;
1240
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001242 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001243 break;
1244 }
1245
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001246 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001247}
1248
Namhyung Kim064f1982013-05-14 11:09:04 +09001249static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001250 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001251{
1252 while (nd != NULL) {
1253 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001254 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001255
Namhyung Kimc0f15272014-04-16 11:16:33 +09001256 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001257 return nd;
1258
1259 nd = rb_next(nd);
1260 }
1261
1262 return NULL;
1263}
1264
Namhyung Kim064f1982013-05-14 11:09:04 +09001265static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001266 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001267{
1268 while (nd != NULL) {
1269 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001270 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001271
1272 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001273 return nd;
1274
1275 nd = rb_prev(nd);
1276 }
1277
1278 return NULL;
1279}
1280
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001281static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001282 off_t offset, int whence)
1283{
1284 struct hist_entry *h;
1285 struct rb_node *nd;
1286 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001287 struct hist_browser *hb;
1288
1289 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001290
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001291 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001292 return;
1293
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001294 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001295
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001296 switch (whence) {
1297 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001298 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001299 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001300 break;
1301 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001302 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001303 goto do_offset;
1304 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001305 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001306 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001307 first = false;
1308 break;
1309 default:
1310 return;
1311 }
1312
1313 /*
1314 * Moves not relative to the first visible entry invalidates its
1315 * row_offset:
1316 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001317 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001318 h->row_offset = 0;
1319
1320 /*
1321 * Here we have to check if nd is expanded (+), if it is we can't go
1322 * the next top level hist_entry, instead we must compute an offset of
1323 * what _not_ to show and not change the first visible entry.
1324 *
1325 * This offset increments when we are going from top to bottom and
1326 * decreases when we're going from bottom to top.
1327 *
1328 * As we don't have backpointers to the top level in the callchains
1329 * structure, we need to always print the whole hist_entry callchain,
1330 * skipping the first ones that are before the first visible entry
1331 * and stop when we printed enough lines to fill the screen.
1332 */
1333do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001334 if (!nd)
1335 return;
1336
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001337 if (offset > 0) {
1338 do {
1339 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001340 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001341 u16 remaining = h->nr_rows - h->row_offset;
1342 if (offset > remaining) {
1343 offset -= remaining;
1344 h->row_offset = 0;
1345 } else {
1346 h->row_offset += offset;
1347 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001348 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001349 break;
1350 }
1351 }
Namhyung Kim14135662013-10-31 10:17:39 +09001352 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001353 if (nd == NULL)
1354 break;
1355 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001356 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001357 } while (offset != 0);
1358 } else if (offset < 0) {
1359 while (1) {
1360 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001361 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001362 if (first) {
1363 if (-offset > h->row_offset) {
1364 offset += h->row_offset;
1365 h->row_offset = 0;
1366 } else {
1367 h->row_offset += offset;
1368 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001369 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001370 break;
1371 }
1372 } else {
1373 if (-offset > h->nr_rows) {
1374 offset += h->nr_rows;
1375 h->row_offset = 0;
1376 } else {
1377 h->row_offset = h->nr_rows + offset;
1378 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001379 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001380 break;
1381 }
1382 }
1383 }
1384
Namhyung Kim14135662013-10-31 10:17:39 +09001385 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001386 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001387 if (nd == NULL)
1388 break;
1389 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001390 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001391 if (offset == 0) {
1392 /*
1393 * Last unfiltered hist_entry, check if it is
1394 * unfolded, if it is then we should have
1395 * row_offset at its last entry.
1396 */
1397 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001398 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001399 h->row_offset = h->nr_rows;
1400 break;
1401 }
1402 first = false;
1403 }
1404 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001405 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001406 h = rb_entry(nd, struct hist_entry, rb_node);
1407 h->row_offset = 0;
1408 }
1409}
1410
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001411static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001412 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001413{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001414 struct callchain_print_arg arg = {
1415 .fp = fp,
1416 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001417
Namhyung Kim0c841c62016-01-28 00:40:54 +09001418 hist_browser__show_callchain(browser, he, 1, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001419 hist_browser__fprintf_callchain_entry, &arg,
1420 hist_browser__check_dump_full);
1421 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001422}
1423
1424static int hist_browser__fprintf_entry(struct hist_browser *browser,
1425 struct hist_entry *he, FILE *fp)
1426{
1427 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001428 int printed = 0;
1429 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001430 struct perf_hpp hpp = {
1431 .buf = s,
1432 .size = sizeof(s),
1433 };
1434 struct perf_hpp_fmt *fmt;
1435 bool first = true;
1436 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001437
1438 if (symbol_conf.use_callchain)
1439 folded_sign = hist_entry__folded(he);
1440
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001441 if (symbol_conf.use_callchain)
1442 printed += fprintf(fp, "%c ", folded_sign);
1443
Jiri Olsaf0786af2016-01-18 10:24:23 +01001444 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001445 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001446 continue;
1447
Namhyung Kim26d8b332014-03-03 16:16:20 +09001448 if (!first) {
1449 ret = scnprintf(hpp.buf, hpp.size, " ");
1450 advance_hpp(&hpp, ret);
1451 } else
1452 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001453
Namhyung Kim26d8b332014-03-03 16:16:20 +09001454 ret = fmt->entry(fmt, &hpp, he);
1455 advance_hpp(&hpp, ret);
1456 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001457 printed += fprintf(fp, "%s\n", rtrim(s));
1458
1459 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001460 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001461
1462 return printed;
1463}
1464
1465static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1466{
Namhyung Kim064f1982013-05-14 11:09:04 +09001467 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001468 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001469 int printed = 0;
1470
1471 while (nd) {
1472 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1473
1474 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001475 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001476 }
1477
1478 return printed;
1479}
1480
1481static int hist_browser__dump(struct hist_browser *browser)
1482{
1483 char filename[64];
1484 FILE *fp;
1485
1486 while (1) {
1487 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1488 if (access(filename, F_OK))
1489 break;
1490 /*
1491 * XXX: Just an arbitrary lazy upper limit
1492 */
1493 if (++browser->print_seq == 8192) {
1494 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1495 return -1;
1496 }
1497 }
1498
1499 fp = fopen(filename, "w");
1500 if (fp == NULL) {
1501 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001502 const char *err = strerror_r(errno, bf, sizeof(bf));
1503 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001504 return -1;
1505 }
1506
1507 ++browser->print_seq;
1508 hist_browser__fprintf(browser, fp);
1509 fclose(fp);
1510 ui_helpline__fpush("%s written!", filename);
1511
1512 return 0;
1513}
1514
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001515static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001516 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001517 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001518{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001519 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001520
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001521 if (browser) {
1522 browser->hists = hists;
1523 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001524 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001525 browser->b.seek = ui_browser__hists_seek;
1526 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001527 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001528 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001529 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001530 }
1531
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001532 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001533}
1534
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001535static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001536{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001537 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001538}
1539
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001540static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001541{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001542 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001543}
1544
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001545static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001546{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001547 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001548}
1549
Taeung Song1e378eb2014-10-07 16:13:15 +09001550/* Check whether the browser is for 'top' or 'report' */
1551static inline bool is_report_browser(void *timer)
1552{
1553 return timer == NULL;
1554}
1555
1556static int hists__browser_title(struct hists *hists,
1557 struct hist_browser_timer *hbt,
1558 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001559{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001560 char unit;
1561 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001562 const struct dso *dso = hists->dso_filter;
1563 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001564 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001565 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1566 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001567 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001568 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001569 char buf[512];
1570 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001571 char ref[30] = " show reference callgraph, ";
1572 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001573
Namhyung Kimf2148332014-01-14 11:52:48 +09001574 if (symbol_conf.filter_relative) {
1575 nr_samples = hists->stats.nr_non_filtered_samples;
1576 nr_events = hists->stats.total_non_filtered_period;
1577 }
1578
Namhyung Kim759ff492013-03-05 14:53:26 +09001579 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001580 struct perf_evsel *pos;
1581
1582 perf_evsel__group_desc(evsel, buf, buflen);
1583 ev_name = buf;
1584
1585 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001586 struct hists *pos_hists = evsel__hists(pos);
1587
Namhyung Kimf2148332014-01-14 11:52:48 +09001588 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001589 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1590 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001591 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001592 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1593 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001594 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001595 }
1596 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001597
Kan Liang9e207dd2015-08-11 06:30:49 -04001598 if (symbol_conf.show_ref_callgraph &&
1599 strstr(ev_name, "call-graph=no"))
1600 enable_ref = true;
Ashay Ranecc686282012-04-05 21:01:01 -05001601 nr_samples = convert_unit(nr_samples, &unit);
1602 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001603 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1604 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc686282012-04-05 21:01:01 -05001605
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001606
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001607 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001608 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001609 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001610 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001611 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001612 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001613 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001614 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001615 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001616 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001617 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001618 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001619 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001620 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001621 if (!is_report_browser(hbt)) {
1622 struct perf_top *top = hbt->arg;
1623
1624 if (top->zero)
1625 printed += scnprintf(bf + printed, size - printed, " [z]");
1626 }
1627
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001628 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001629}
1630
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001631static inline void free_popup_options(char **options, int n)
1632{
1633 int i;
1634
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001635 for (i = 0; i < n; ++i)
1636 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001637}
1638
Feng Tang341487ab2013-02-03 14:38:20 +08001639/*
1640 * Only runtime switching of perf data file will make "input_name" point
1641 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1642 * whether we need to call free() for current "input_name" during the switch.
1643 */
1644static bool is_input_name_malloced = false;
1645
1646static int switch_data_file(void)
1647{
1648 char *pwd, *options[32], *abs_path[32], *tmp;
1649 DIR *pwd_dir;
1650 int nr_options = 0, choice = -1, ret = -1;
1651 struct dirent *dent;
1652
1653 pwd = getenv("PWD");
1654 if (!pwd)
1655 return ret;
1656
1657 pwd_dir = opendir(pwd);
1658 if (!pwd_dir)
1659 return ret;
1660
1661 memset(options, 0, sizeof(options));
1662 memset(options, 0, sizeof(abs_path));
1663
1664 while ((dent = readdir(pwd_dir))) {
1665 char path[PATH_MAX];
1666 u64 magic;
1667 char *name = dent->d_name;
1668 FILE *file;
1669
1670 if (!(dent->d_type == DT_REG))
1671 continue;
1672
1673 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1674
1675 file = fopen(path, "r");
1676 if (!file)
1677 continue;
1678
1679 if (fread(&magic, 1, 8, file) < 8)
1680 goto close_file_and_continue;
1681
1682 if (is_perf_magic(magic)) {
1683 options[nr_options] = strdup(name);
1684 if (!options[nr_options])
1685 goto close_file_and_continue;
1686
1687 abs_path[nr_options] = strdup(path);
1688 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001689 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001690 ui__warning("Can't search all data files due to memory shortage.\n");
1691 fclose(file);
1692 break;
1693 }
1694
1695 nr_options++;
1696 }
1697
1698close_file_and_continue:
1699 fclose(file);
1700 if (nr_options >= 32) {
1701 ui__warning("Too many perf data files in PWD!\n"
1702 "Only the first 32 files will be listed.\n");
1703 break;
1704 }
1705 }
1706 closedir(pwd_dir);
1707
1708 if (nr_options) {
1709 choice = ui__popup_menu(nr_options, options);
1710 if (choice < nr_options && choice >= 0) {
1711 tmp = strdup(abs_path[choice]);
1712 if (tmp) {
1713 if (is_input_name_malloced)
1714 free((void *)input_name);
1715 input_name = tmp;
1716 is_input_name_malloced = true;
1717 ret = 0;
1718 } else
1719 ui__warning("Data switch failed due to memory shortage!\n");
1720 }
1721 }
1722
1723 free_popup_options(options, nr_options);
1724 free_popup_options(abs_path, nr_options);
1725 return ret;
1726}
1727
Namhyung Kimea7cd592015-04-22 16:18:19 +09001728struct popup_action {
1729 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001730 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001731 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001732
1733 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1734};
1735
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001736static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001737do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001738{
1739 struct perf_evsel *evsel;
1740 struct annotation *notes;
1741 struct hist_entry *he;
1742 int err;
1743
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001744 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001745 return 0;
1746
Namhyung Kimea7cd592015-04-22 16:18:19 +09001747 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001748 if (!notes->src)
1749 return 0;
1750
1751 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001752 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001753 he = hist_browser__selected_entry(browser);
1754 /*
1755 * offer option to annotate the other branch source or target
1756 * (if they exists) when returning from annotate
1757 */
1758 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1759 return 1;
1760
1761 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1762 if (err)
1763 ui_browser__handle_resize(&browser->b);
1764 return 0;
1765}
1766
1767static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001768add_annotate_opt(struct hist_browser *browser __maybe_unused,
1769 struct popup_action *act, char **optstr,
1770 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001771{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001772 if (sym == NULL || map->dso->annotate_warned)
1773 return 0;
1774
1775 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1776 return 0;
1777
1778 act->ms.map = map;
1779 act->ms.sym = sym;
1780 act->fn = do_annotate;
1781 return 1;
1782}
1783
1784static int
1785do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1786{
1787 struct thread *thread = act->thread;
1788
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001789 if (browser->hists->thread_filter) {
1790 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1791 perf_hpp__set_elide(HISTC_THREAD, false);
1792 thread__zput(browser->hists->thread_filter);
1793 ui_helpline__pop();
1794 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001795 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001796 thread->comm_set ? thread__comm_str(thread) : "",
1797 thread->tid);
1798 browser->hists->thread_filter = thread__get(thread);
1799 perf_hpp__set_elide(HISTC_THREAD, false);
1800 pstack__push(browser->pstack, &browser->hists->thread_filter);
1801 }
1802
1803 hists__filter_by_thread(browser->hists);
1804 hist_browser__reset(browser);
1805 return 0;
1806}
1807
1808static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001809add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1810 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001811{
Namhyung Kim2eafd412016-01-21 19:13:24 -03001812 if (!sort__has_thread || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001813 return 0;
1814
1815 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1816 browser->hists->thread_filter ? "out of" : "into",
1817 thread->comm_set ? thread__comm_str(thread) : "",
1818 thread->tid) < 0)
1819 return 0;
1820
1821 act->thread = thread;
1822 act->fn = do_zoom_thread;
1823 return 1;
1824}
1825
1826static int
1827do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1828{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001829 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001830
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001831 if (browser->hists->dso_filter) {
1832 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1833 perf_hpp__set_elide(HISTC_DSO, false);
1834 browser->hists->dso_filter = NULL;
1835 ui_helpline__pop();
1836 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001837 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001838 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001839 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001840 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1841 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001842 perf_hpp__set_elide(HISTC_DSO, true);
1843 pstack__push(browser->pstack, &browser->hists->dso_filter);
1844 }
1845
1846 hists__filter_by_dso(browser->hists);
1847 hist_browser__reset(browser);
1848 return 0;
1849}
1850
1851static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001852add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001853 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001854{
Namhyung Kimb1447a542016-01-22 11:22:41 -03001855 if (!sort__has_dso || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001856 return 0;
1857
1858 if (asprintf(optstr, "Zoom %s %s DSO",
1859 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001860 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001861 return 0;
1862
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001863 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001864 act->fn = do_zoom_dso;
1865 return 1;
1866}
1867
1868static int
1869do_browse_map(struct hist_browser *browser __maybe_unused,
1870 struct popup_action *act)
1871{
1872 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001873 return 0;
1874}
1875
1876static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001877add_map_opt(struct hist_browser *browser __maybe_unused,
1878 struct popup_action *act, char **optstr, struct map *map)
1879{
Namhyung Kimb1447a542016-01-22 11:22:41 -03001880 if (!sort__has_dso || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001881 return 0;
1882
1883 if (asprintf(optstr, "Browse map details") < 0)
1884 return 0;
1885
1886 act->ms.map = map;
1887 act->fn = do_browse_map;
1888 return 1;
1889}
1890
1891static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001892do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001893 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001894{
1895 char script_opt[64];
1896 memset(script_opt, 0, sizeof(script_opt));
1897
Namhyung Kimea7cd592015-04-22 16:18:19 +09001898 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001899 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001900 thread__comm_str(act->thread));
1901 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001902 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001903 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001904 }
1905
1906 script_browse(script_opt);
1907 return 0;
1908}
1909
1910static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001911add_script_opt(struct hist_browser *browser __maybe_unused,
1912 struct popup_action *act, char **optstr,
1913 struct thread *thread, struct symbol *sym)
1914{
1915 if (thread) {
1916 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1917 thread__comm_str(thread)) < 0)
1918 return 0;
1919 } else if (sym) {
1920 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1921 sym->name) < 0)
1922 return 0;
1923 } else {
1924 if (asprintf(optstr, "Run scripts for all samples") < 0)
1925 return 0;
1926 }
1927
1928 act->thread = thread;
1929 act->ms.sym = sym;
1930 act->fn = do_run_script;
1931 return 1;
1932}
1933
1934static int
1935do_switch_data(struct hist_browser *browser __maybe_unused,
1936 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001937{
1938 if (switch_data_file()) {
1939 ui__warning("Won't switch the data files due to\n"
1940 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001941 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001942 }
1943
1944 return K_SWITCH_INPUT_DATA;
1945}
1946
Namhyung Kimea7cd592015-04-22 16:18:19 +09001947static int
1948add_switch_opt(struct hist_browser *browser,
1949 struct popup_action *act, char **optstr)
1950{
1951 if (!is_report_browser(browser->hbt))
1952 return 0;
1953
1954 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1955 return 0;
1956
1957 act->fn = do_switch_data;
1958 return 1;
1959}
1960
1961static int
1962do_exit_browser(struct hist_browser *browser __maybe_unused,
1963 struct popup_action *act __maybe_unused)
1964{
1965 return 0;
1966}
1967
1968static int
1969add_exit_opt(struct hist_browser *browser __maybe_unused,
1970 struct popup_action *act, char **optstr)
1971{
1972 if (asprintf(optstr, "Exit") < 0)
1973 return 0;
1974
1975 act->fn = do_exit_browser;
1976 return 1;
1977}
1978
Kan Liang84734b02015-09-04 10:45:45 -04001979static int
1980do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1981{
1982 if (browser->hists->socket_filter > -1) {
1983 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1984 browser->hists->socket_filter = -1;
1985 perf_hpp__set_elide(HISTC_SOCKET, false);
1986 } else {
1987 browser->hists->socket_filter = act->socket;
1988 perf_hpp__set_elide(HISTC_SOCKET, true);
1989 pstack__push(browser->pstack, &browser->hists->socket_filter);
1990 }
1991
1992 hists__filter_by_socket(browser->hists);
1993 hist_browser__reset(browser);
1994 return 0;
1995}
1996
1997static int
1998add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1999 char **optstr, int socket_id)
2000{
Namhyung Kimd9695d92016-01-22 12:20:18 -03002001 if (!sort__has_socket || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002002 return 0;
2003
2004 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2005 (browser->hists->socket_filter > -1) ? "out of" : "into",
2006 socket_id) < 0)
2007 return 0;
2008
2009 act->socket = socket_id;
2010 act->fn = do_zoom_socket;
2011 return 1;
2012}
2013
Namhyung Kim112f7612014-04-22 14:05:35 +09002014static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002015{
2016 u64 nr_entries = 0;
2017 struct rb_node *nd = rb_first(&hb->hists->entries);
2018
Namhyung Kim268397c2014-04-22 14:49:31 +09002019 if (hb->min_pcnt == 0) {
2020 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2021 return;
2022 }
2023
Namhyung Kim14135662013-10-31 10:17:39 +09002024 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002025 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09002026 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002027 }
2028
Namhyung Kim112f7612014-04-22 14:05:35 +09002029 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002030}
Feng Tang341487ab2013-02-03 14:38:20 +08002031
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002032static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002033 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002034 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002035 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002036 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002037 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002038{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002039 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09002040 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002041 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002042#define MAX_OPTIONS 16
2043 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002044 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002045 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002046 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002047 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002048 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002049 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002050
Namhyung Kime8e684a2013-12-26 14:37:58 +09002051#define HIST_BROWSER_HELP_COMMON \
2052 "h/?/F1 Show this window\n" \
2053 "UP/DOWN/PGUP\n" \
2054 "PGDN/SPACE Navigate\n" \
2055 "q/ESC/CTRL+C Exit browser\n\n" \
2056 "For multiple event sessions:\n\n" \
2057 "TAB/UNTAB Switch events\n\n" \
2058 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002059 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2060 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002061 "a Annotate current symbol\n" \
2062 "C Collapse all callchains\n" \
2063 "d Zoom into current DSO\n" \
2064 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002065 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002066 "H Display column headers\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002067 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002068 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002069
2070 /* help messages are sorted by lexical order of the hotkey */
2071 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002072 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002073 "P Print histograms to perf.hist.N\n"
2074 "r Run available scripts\n"
2075 "s Switch to another data file in PWD\n"
2076 "t Zoom into current Thread\n"
2077 "V Verbose (DSO names in callchains, etc)\n"
2078 "/ Filter symbol by name";
2079 const char top_help[] = HIST_BROWSER_HELP_COMMON
2080 "P Print histograms to perf.hist.N\n"
2081 "t Zoom into current Thread\n"
2082 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002083 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002084 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002085 "/ Filter symbol by name";
2086
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002087 if (browser == NULL)
2088 return -1;
2089
Namhyung Kimed426912015-05-29 21:53:44 +09002090 /* reset abort key so that it can get Ctrl-C as a key */
2091 SLang_reset_tty();
2092 SLang_init_tty(0, 0, 0);
2093
Namhyung Kim03905042015-11-28 02:32:39 +09002094 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002095 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002096 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002097
Kan Liang84734b02015-09-04 10:45:45 -04002098 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002099 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002100 goto out;
2101
2102 ui_helpline__push(helpline);
2103
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002104 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002105 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002106
Jiri Olsaf0786af2016-01-18 10:24:23 +01002107 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002108 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002109 /*
2110 * This is done just once, and activates the horizontal scrolling
2111 * code in the ui_browser code, it would be better to have a the
2112 * counter in the perf_hpp code, but I couldn't find doing it here
2113 * works, FIXME by setting this in hist_browser__new, for now, be
2114 * clever 8-)
2115 */
2116 ++browser->b.columns;
2117 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002118
Namhyung Kim5b591662014-07-31 14:47:38 +09002119 if (symbol_conf.col_width_list_str)
2120 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2121
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002122 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002123 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002124 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002125 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002126 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002127
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002128 nr_options = 0;
2129
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002130 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002131
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002132 if (browser->he_selection != NULL) {
2133 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002134 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002135 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002136 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002137 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002138 case K_TAB:
2139 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002140 if (nr_events == 1)
2141 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002142 /*
2143 * Exit the browser, let hists__browser_tree
2144 * go to the next or previous
2145 */
2146 goto out_free_stack;
2147 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002148 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002149 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002150 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002151 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002152 continue;
2153 }
2154
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002155 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002156 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002157 browser->selection->map->dso->annotate_warned)
2158 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002159
Namhyung Kimea7cd592015-04-22 16:18:19 +09002160 actions->ms.map = browser->selection->map;
2161 actions->ms.sym = browser->selection->sym;
2162 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002163 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002164 case 'P':
2165 hist_browser__dump(browser);
2166 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002167 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002168 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002169 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002170 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002171 case 'V':
2172 browser->show_dso = !browser->show_dso;
2173 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002174 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002175 actions->thread = thread;
2176 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002177 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002178 case 'S':
2179 actions->socket = socked_id;
2180 do_zoom_socket(browser, actions);
2181 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002182 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002183 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e452015-10-12 14:02:29 -03002184 "Please enter the name of symbol you want to see.\n"
2185 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002186 buf, "ENTER: OK, ESC: Cancel",
2187 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002188 hists->symbol_filter_str = *buf ? buf : NULL;
2189 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002190 hist_browser__reset(browser);
2191 }
2192 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002193 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002194 if (is_report_browser(hbt)) {
2195 actions->thread = NULL;
2196 actions->ms.sym = NULL;
2197 do_run_script(browser, actions);
2198 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002199 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002200 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002201 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002202 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002203 if (key == K_SWITCH_INPUT_DATA)
2204 goto out_free_stack;
2205 }
Feng Tang341487ab2013-02-03 14:38:20 +08002206 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002207 case 'i':
2208 /* env->arch is NULL for live-mode (i.e. perf top) */
2209 if (env->arch)
2210 tui__header_window(env);
2211 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002212 case 'F':
2213 symbol_conf.filter_relative ^= 1;
2214 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002215 case 'z':
2216 if (!is_report_browser(hbt)) {
2217 struct perf_top *top = hbt->arg;
2218
2219 top->zero = !top->zero;
2220 }
2221 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002222 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002223 case 'h':
2224 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002225 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002226 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002227 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002228 case K_ENTER:
2229 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002230 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002231 /* menu */
2232 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002233 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002234 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002235 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002236
Namhyung Kim01f00a12015-04-22 16:18:16 +09002237 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002238 /*
2239 * Go back to the perf_evsel_menu__run or other user
2240 */
2241 if (left_exits)
2242 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002243
2244 if (key == K_ESC &&
2245 ui_browser__dialog_yesno(&browser->b,
2246 "Do you really want to exit?"))
2247 goto out_free_stack;
2248
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002249 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002250 }
Namhyung Kim64221842015-04-24 10:15:33 +09002251 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002252 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002253 /*
2254 * No need to set actions->dso here since
2255 * it's just to remove the current filter.
2256 * Ditto for thread below.
2257 */
2258 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002259 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002260 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002261 } else if (top == &browser->hists->socket_filter) {
2262 do_zoom_socket(browser, actions);
2263 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002264 continue;
2265 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002266 case 'q':
2267 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002268 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002269 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002270 if (!is_report_browser(hbt)) {
2271 struct perf_top *top = hbt->arg;
2272
2273 perf_evlist__toggle_enable(top->evlist);
2274 /*
2275 * No need to refresh, resort/decay histogram
2276 * entries if we are not collecting samples:
2277 */
2278 if (top->evlist->enabled) {
2279 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2280 hbt->refresh = delay_secs;
2281 } else {
2282 helpline = "Press 'f' again to re-enable the events";
2283 hbt->refresh = 0;
2284 }
2285 continue;
2286 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002287 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002288 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002289 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002290 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002291 }
2292
Namhyung Kim40561322016-01-22 12:26:06 -03002293 if (!sort__has_sym || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002294 goto skip_annotation;
2295
Namhyung Kim55369fc2013-04-01 20:35:20 +09002296 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002297 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002298
2299 if (bi == NULL)
2300 goto skip_annotation;
2301
Namhyung Kimea7cd592015-04-22 16:18:19 +09002302 nr_options += add_annotate_opt(browser,
2303 &actions[nr_options],
2304 &options[nr_options],
2305 bi->from.map,
2306 bi->from.sym);
2307 if (bi->to.sym != bi->from.sym)
2308 nr_options += add_annotate_opt(browser,
2309 &actions[nr_options],
2310 &options[nr_options],
2311 bi->to.map,
2312 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002313 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002314 nr_options += add_annotate_opt(browser,
2315 &actions[nr_options],
2316 &options[nr_options],
2317 browser->selection->map,
2318 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002319 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002320skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002321 nr_options += add_thread_opt(browser, &actions[nr_options],
2322 &options[nr_options], thread);
2323 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002324 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002325 nr_options += add_map_opt(browser, &actions[nr_options],
2326 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002327 browser->selection ?
2328 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002329 nr_options += add_socket_opt(browser, &actions[nr_options],
2330 &options[nr_options],
2331 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002332 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002333 if (!is_report_browser(hbt))
2334 goto skip_scripting;
2335
Feng Tangcdbab7c2012-10-30 11:56:06 +08002336 if (browser->he_selection) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002337 if (sort__has_thread && thread) {
2338 nr_options += add_script_opt(browser,
2339 &actions[nr_options],
2340 &options[nr_options],
2341 thread, NULL);
2342 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002343 /*
2344 * Note that browser->selection != NULL
2345 * when browser->he_selection is not NULL,
2346 * so we don't need to check browser->selection
2347 * before fetching browser->selection->sym like what
2348 * we do before fetching browser->selection->map.
2349 *
2350 * See hist_browser__show_entry.
2351 */
Namhyung Kimc221acb2016-01-21 19:50:09 -03002352 if (sort__has_sym && browser->selection->sym) {
2353 nr_options += add_script_opt(browser,
2354 &actions[nr_options],
2355 &options[nr_options],
2356 NULL, browser->selection->sym);
2357 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08002358 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002359 nr_options += add_script_opt(browser, &actions[nr_options],
2360 &options[nr_options], NULL, NULL);
2361 nr_options += add_switch_opt(browser, &actions[nr_options],
2362 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03002363skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002364 nr_options += add_exit_opt(browser, &actions[nr_options],
2365 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002366
Namhyung Kimea7cd592015-04-22 16:18:19 +09002367 do {
2368 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002369
Namhyung Kimea7cd592015-04-22 16:18:19 +09002370 choice = ui__popup_menu(nr_options, options);
2371 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002372 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002373
2374 act = &actions[choice];
2375 key = act->fn(browser, act);
2376 } while (key == 1);
2377
2378 if (key == K_SWITCH_INPUT_DATA)
2379 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002380 }
2381out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002382 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002383out:
2384 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002385 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002386 return key;
2387}
2388
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002389struct perf_evsel_menu {
2390 struct ui_browser b;
2391 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002392 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002393 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002394 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002395};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002396
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002397static void perf_evsel_menu__write(struct ui_browser *browser,
2398 void *entry, int row)
2399{
2400 struct perf_evsel_menu *menu = container_of(browser,
2401 struct perf_evsel_menu, b);
2402 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002403 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002404 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002405 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002406 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002407 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002408 const char *warn = " ";
2409 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002410
2411 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2412 HE_COLORSET_NORMAL);
2413
Namhyung Kim759ff492013-03-05 14:53:26 +09002414 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002415 struct perf_evsel *pos;
2416
2417 ev_name = perf_evsel__group_name(evsel);
2418
2419 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002420 struct hists *pos_hists = evsel__hists(pos);
2421 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002422 }
2423 }
2424
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002425 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002426 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002427 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002428 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002429
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002430 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002431 if (nr_events != 0) {
2432 menu->lost_events = true;
2433 if (!current_entry)
2434 ui_browser__set_color(browser, HE_COLORSET_TOP);
2435 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002436 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2437 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002438 warn = bf;
2439 }
2440
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002441 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002442
2443 if (current_entry)
2444 menu->selection = evsel;
2445}
2446
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002447static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2448 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002449 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002450{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002451 struct perf_evlist *evlist = menu->b.priv;
2452 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002453 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002454 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002455 int key;
2456
2457 if (ui_browser__show(&menu->b, title,
2458 "ESC: exit, ENTER|->: Browse histograms") < 0)
2459 return -1;
2460
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002461 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002462 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002463
2464 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002465 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002466 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002467
2468 if (!menu->lost_events_warned && menu->lost_events) {
2469 ui_browser__warn_lost_events(&menu->b);
2470 menu->lost_events_warned = true;
2471 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002472 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002473 case K_RIGHT:
2474 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002475 if (!menu->selection)
2476 continue;
2477 pos = menu->selection;
2478browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002479 perf_evlist__set_selected(evlist, pos);
2480 /*
2481 * Give the calling tool a chance to populate the non
2482 * default evsel resorted hists tree.
2483 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002484 if (hbt)
2485 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002486 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002487 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002488 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002489 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002490 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002491 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002492 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002493 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002494 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002495 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002496 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002497 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002498 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002499 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002500 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002501 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002502 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002503 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002504 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002505 case 'q':
2506 case CTRL('c'):
2507 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002508 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002509 default:
2510 continue;
2511 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002512 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002513 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002514 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002515 if (!ui_browser__dialog_yesno(&menu->b,
2516 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002517 continue;
2518 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002519 case 'q':
2520 case CTRL('c'):
2521 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002522 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002523 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002524 }
2525 }
2526
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002527out:
2528 ui_browser__hide(&menu->b);
2529 return key;
2530}
2531
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002532static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002533 void *entry)
2534{
2535 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2536
2537 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2538 return true;
2539
2540 return false;
2541}
2542
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002543static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002544 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002545 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002546 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002547 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002548{
2549 struct perf_evsel *pos;
2550 struct perf_evsel_menu menu = {
2551 .b = {
2552 .entries = &evlist->entries,
2553 .refresh = ui_browser__list_head_refresh,
2554 .seek = ui_browser__list_head_seek,
2555 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002556 .filter = filter_group_entries,
2557 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002558 .priv = evlist,
2559 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002560 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002561 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002562 };
2563
2564 ui_helpline__push("Press ESC to exit");
2565
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002566 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002567 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002568 size_t line_len = strlen(ev_name) + 7;
2569
2570 if (menu.b.width < line_len)
2571 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002572 }
2573
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002574 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002575}
2576
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002577int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002578 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002579 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002580 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002581{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002582 int nr_entries = evlist->nr_entries;
2583
2584single_entry:
2585 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002586 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002587
2588 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002589 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002590 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002591 }
2592
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002593 if (symbol_conf.event_group) {
2594 struct perf_evsel *pos;
2595
2596 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002597 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002598 if (perf_evsel__is_group_leader(pos))
2599 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002600 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002601
2602 if (nr_entries == 1)
2603 goto single_entry;
2604 }
2605
2606 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002607 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002608}