blob: 1819771243f97d842200694313b52a1df313be4e [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{
Jiri Olsa12400052012-10-13 00:06:16 +02001064 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001065 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001066 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001067 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001068 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001069 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001070 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001071
1072 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001073 browser->he_selection = entry;
1074 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001075 }
1076
1077 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001078 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001079 folded_sign = hist_entry__folded(entry);
1080 }
1081
1082 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001083 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001084 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001085 .folded_sign = folded_sign,
1086 .current_entry = current_entry,
1087 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001088 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001089
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001090 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001091
Jiri Olsaf0786af2016-01-18 10:24:23 +01001092 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001093 char s[2048];
1094 struct perf_hpp hpp = {
1095 .buf = s,
1096 .size = sizeof(s),
1097 .ptr = &arg,
1098 };
1099
Namhyung Kim361459f2015-12-23 02:07:08 +09001100 if (perf_hpp__should_skip(fmt, entry->hists) ||
1101 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001102 continue;
1103
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001104 if (current_entry && browser->b.navkeypressed) {
1105 ui_browser__set_color(&browser->b,
1106 HE_COLORSET_SELECTED);
1107 } else {
1108 ui_browser__set_color(&browser->b,
1109 HE_COLORSET_NORMAL);
1110 }
1111
1112 if (first) {
1113 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001114 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001115 width -= 2;
1116 }
1117 first = false;
1118 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001119 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001120 width -= 2;
1121 }
1122
Jiri Olsa12400052012-10-13 00:06:16 +02001123 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001124 int ret = fmt->color(fmt, &hpp, entry);
1125 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1126 /*
1127 * fmt->color() already used ui_browser to
1128 * print the non alignment bits, skip it (+ret):
1129 */
1130 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001131 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001132 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001133 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001134 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001135 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001136 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001137
1138 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001139 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001140 width += 1;
1141
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001142 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001143
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001144 ++row;
1145 ++printed;
1146 } else
1147 --row_offset;
1148
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001149 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001150 struct callchain_print_arg arg = {
1151 .row_offset = row_offset,
1152 .is_current_entry = current_entry,
1153 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001154
Namhyung Kim0c841c62016-01-28 00:40:54 +09001155 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001156 hist_browser__show_callchain_entry, &arg,
1157 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001158 }
1159
1160 return printed;
1161}
1162
Jiri Olsa81a888f2014-06-14 15:44:52 +02001163static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1164{
1165 advance_hpp(hpp, inc);
1166 return hpp->size <= 0;
1167}
1168
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001169static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001170{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001171 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001172 struct perf_hpp dummy_hpp = {
1173 .buf = buf,
1174 .size = size,
1175 };
1176 struct perf_hpp_fmt *fmt;
1177 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001178 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001179
1180 if (symbol_conf.use_callchain) {
1181 ret = scnprintf(buf, size, " ");
1182 if (advance_hpp_check(&dummy_hpp, ret))
1183 return ret;
1184 }
1185
Jiri Olsaf0786af2016-01-18 10:24:23 +01001186 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001187 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001188 continue;
1189
Jiri Olsa81a888f2014-06-14 15:44:52 +02001190 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1191 if (advance_hpp_check(&dummy_hpp, ret))
1192 break;
1193
1194 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1195 if (advance_hpp_check(&dummy_hpp, ret))
1196 break;
1197 }
1198
1199 return ret;
1200}
1201
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001202static void hist_browser__show_headers(struct hist_browser *browser)
1203{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001204 char headers[1024];
1205
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001206 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001207 ui_browser__gotorc(&browser->b, 0, 0);
1208 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001209 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001210}
1211
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001212static void ui_browser__hists_init_top(struct ui_browser *browser)
1213{
1214 if (browser->top == NULL) {
1215 struct hist_browser *hb;
1216
1217 hb = container_of(browser, struct hist_browser, b);
1218 browser->top = rb_first(&hb->hists->entries);
1219 }
1220}
1221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001222static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001223{
1224 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001225 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001226 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001227 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001228
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001229 if (hb->show_headers) {
1230 hist_browser__show_headers(hb);
1231 header_offset = 1;
1232 }
1233
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001234 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001235 hb->he_selection = NULL;
1236 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001237
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001238 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001239 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001240 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241
1242 if (h->filtered)
1243 continue;
1244
Namhyung Kim14135662013-10-31 10:17:39 +09001245 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001246 if (percent < hb->min_pcnt)
1247 continue;
1248
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001249 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001250 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001251 break;
1252 }
1253
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001254 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001255}
1256
Namhyung Kim064f1982013-05-14 11:09:04 +09001257static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001258 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259{
1260 while (nd != NULL) {
1261 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001262 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001263
Namhyung Kimc0f15272014-04-16 11:16:33 +09001264 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001265 return nd;
1266
1267 nd = rb_next(nd);
1268 }
1269
1270 return NULL;
1271}
1272
Namhyung Kim064f1982013-05-14 11:09:04 +09001273static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001274 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001275{
1276 while (nd != NULL) {
1277 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001278 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001279
1280 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001281 return nd;
1282
1283 nd = rb_prev(nd);
1284 }
1285
1286 return NULL;
1287}
1288
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001289static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001290 off_t offset, int whence)
1291{
1292 struct hist_entry *h;
1293 struct rb_node *nd;
1294 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001295 struct hist_browser *hb;
1296
1297 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001298
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001299 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001300 return;
1301
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001302 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001303
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001304 switch (whence) {
1305 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001306 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001307 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001308 break;
1309 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001310 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001311 goto do_offset;
1312 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001313 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001314 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001315 first = false;
1316 break;
1317 default:
1318 return;
1319 }
1320
1321 /*
1322 * Moves not relative to the first visible entry invalidates its
1323 * row_offset:
1324 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001325 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001326 h->row_offset = 0;
1327
1328 /*
1329 * Here we have to check if nd is expanded (+), if it is we can't go
1330 * the next top level hist_entry, instead we must compute an offset of
1331 * what _not_ to show and not change the first visible entry.
1332 *
1333 * This offset increments when we are going from top to bottom and
1334 * decreases when we're going from bottom to top.
1335 *
1336 * As we don't have backpointers to the top level in the callchains
1337 * structure, we need to always print the whole hist_entry callchain,
1338 * skipping the first ones that are before the first visible entry
1339 * and stop when we printed enough lines to fill the screen.
1340 */
1341do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001342 if (!nd)
1343 return;
1344
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001345 if (offset > 0) {
1346 do {
1347 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001348 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001349 u16 remaining = h->nr_rows - h->row_offset;
1350 if (offset > remaining) {
1351 offset -= remaining;
1352 h->row_offset = 0;
1353 } else {
1354 h->row_offset += offset;
1355 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001356 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001357 break;
1358 }
1359 }
Namhyung Kim14135662013-10-31 10:17:39 +09001360 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001361 if (nd == NULL)
1362 break;
1363 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001364 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001365 } while (offset != 0);
1366 } else if (offset < 0) {
1367 while (1) {
1368 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001369 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001370 if (first) {
1371 if (-offset > h->row_offset) {
1372 offset += h->row_offset;
1373 h->row_offset = 0;
1374 } else {
1375 h->row_offset += offset;
1376 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001377 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001378 break;
1379 }
1380 } else {
1381 if (-offset > h->nr_rows) {
1382 offset += h->nr_rows;
1383 h->row_offset = 0;
1384 } else {
1385 h->row_offset = h->nr_rows + offset;
1386 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001387 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001388 break;
1389 }
1390 }
1391 }
1392
Namhyung Kim14135662013-10-31 10:17:39 +09001393 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001394 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001395 if (nd == NULL)
1396 break;
1397 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001398 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001399 if (offset == 0) {
1400 /*
1401 * Last unfiltered hist_entry, check if it is
1402 * unfolded, if it is then we should have
1403 * row_offset at its last entry.
1404 */
1405 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001406 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001407 h->row_offset = h->nr_rows;
1408 break;
1409 }
1410 first = false;
1411 }
1412 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001413 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001414 h = rb_entry(nd, struct hist_entry, rb_node);
1415 h->row_offset = 0;
1416 }
1417}
1418
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001419static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001420 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001421{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001422 struct callchain_print_arg arg = {
1423 .fp = fp,
1424 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001425
Namhyung Kim0c841c62016-01-28 00:40:54 +09001426 hist_browser__show_callchain(browser, he, 1, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001427 hist_browser__fprintf_callchain_entry, &arg,
1428 hist_browser__check_dump_full);
1429 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001430}
1431
1432static int hist_browser__fprintf_entry(struct hist_browser *browser,
1433 struct hist_entry *he, FILE *fp)
1434{
1435 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001436 int printed = 0;
1437 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001438 struct perf_hpp hpp = {
1439 .buf = s,
1440 .size = sizeof(s),
1441 };
1442 struct perf_hpp_fmt *fmt;
1443 bool first = true;
1444 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001445
1446 if (symbol_conf.use_callchain)
1447 folded_sign = hist_entry__folded(he);
1448
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001449 if (symbol_conf.use_callchain)
1450 printed += fprintf(fp, "%c ", folded_sign);
1451
Jiri Olsaf0786af2016-01-18 10:24:23 +01001452 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001453 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001454 continue;
1455
Namhyung Kim26d8b332014-03-03 16:16:20 +09001456 if (!first) {
1457 ret = scnprintf(hpp.buf, hpp.size, " ");
1458 advance_hpp(&hpp, ret);
1459 } else
1460 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001461
Namhyung Kim26d8b332014-03-03 16:16:20 +09001462 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001463 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001464 advance_hpp(&hpp, ret);
1465 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001466 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001467
1468 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001469 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001470
1471 return printed;
1472}
1473
1474static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1475{
Namhyung Kim064f1982013-05-14 11:09:04 +09001476 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001477 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001478 int printed = 0;
1479
1480 while (nd) {
1481 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1482
1483 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001484 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001485 }
1486
1487 return printed;
1488}
1489
1490static int hist_browser__dump(struct hist_browser *browser)
1491{
1492 char filename[64];
1493 FILE *fp;
1494
1495 while (1) {
1496 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1497 if (access(filename, F_OK))
1498 break;
1499 /*
1500 * XXX: Just an arbitrary lazy upper limit
1501 */
1502 if (++browser->print_seq == 8192) {
1503 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1504 return -1;
1505 }
1506 }
1507
1508 fp = fopen(filename, "w");
1509 if (fp == NULL) {
1510 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001511 const char *err = strerror_r(errno, bf, sizeof(bf));
1512 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001513 return -1;
1514 }
1515
1516 ++browser->print_seq;
1517 hist_browser__fprintf(browser, fp);
1518 fclose(fp);
1519 ui_helpline__fpush("%s written!", filename);
1520
1521 return 0;
1522}
1523
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001524static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001525 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001526 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001527{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001528 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001529
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001530 if (browser) {
1531 browser->hists = hists;
1532 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001533 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001534 browser->b.seek = ui_browser__hists_seek;
1535 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001536 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001537 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001538 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001539 }
1540
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001541 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001542}
1543
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001544static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001545{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001546 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001547}
1548
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001549static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001550{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001551 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001552}
1553
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001554static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001555{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001556 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001557}
1558
Taeung Song1e378eb2014-10-07 16:13:15 +09001559/* Check whether the browser is for 'top' or 'report' */
1560static inline bool is_report_browser(void *timer)
1561{
1562 return timer == NULL;
1563}
1564
1565static int hists__browser_title(struct hists *hists,
1566 struct hist_browser_timer *hbt,
1567 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001568{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001569 char unit;
1570 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001571 const struct dso *dso = hists->dso_filter;
1572 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001573 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001574 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1575 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001576 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001577 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001578 char buf[512];
1579 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001580 char ref[30] = " show reference callgraph, ";
1581 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001582
Namhyung Kimf2148332014-01-14 11:52:48 +09001583 if (symbol_conf.filter_relative) {
1584 nr_samples = hists->stats.nr_non_filtered_samples;
1585 nr_events = hists->stats.total_non_filtered_period;
1586 }
1587
Namhyung Kim759ff492013-03-05 14:53:26 +09001588 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001589 struct perf_evsel *pos;
1590
1591 perf_evsel__group_desc(evsel, buf, buflen);
1592 ev_name = buf;
1593
1594 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001595 struct hists *pos_hists = evsel__hists(pos);
1596
Namhyung Kimf2148332014-01-14 11:52:48 +09001597 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001598 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1599 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001600 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001601 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1602 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001603 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001604 }
1605 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001606
Kan Liang9e207dd2015-08-11 06:30:49 -04001607 if (symbol_conf.show_ref_callgraph &&
1608 strstr(ev_name, "call-graph=no"))
1609 enable_ref = true;
Ashay Ranecc686282012-04-05 21:01:01 -05001610 nr_samples = convert_unit(nr_samples, &unit);
1611 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001612 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1613 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc686282012-04-05 21:01:01 -05001614
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001615
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001616 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001617 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001618 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001619 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001620 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001621 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001622 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001623 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001624 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001625 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001626 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001627 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001628 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001629 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001630 if (!is_report_browser(hbt)) {
1631 struct perf_top *top = hbt->arg;
1632
1633 if (top->zero)
1634 printed += scnprintf(bf + printed, size - printed, " [z]");
1635 }
1636
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001637 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001638}
1639
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001640static inline void free_popup_options(char **options, int n)
1641{
1642 int i;
1643
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001644 for (i = 0; i < n; ++i)
1645 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001646}
1647
Feng Tang341487ab2013-02-03 14:38:20 +08001648/*
1649 * Only runtime switching of perf data file will make "input_name" point
1650 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1651 * whether we need to call free() for current "input_name" during the switch.
1652 */
1653static bool is_input_name_malloced = false;
1654
1655static int switch_data_file(void)
1656{
1657 char *pwd, *options[32], *abs_path[32], *tmp;
1658 DIR *pwd_dir;
1659 int nr_options = 0, choice = -1, ret = -1;
1660 struct dirent *dent;
1661
1662 pwd = getenv("PWD");
1663 if (!pwd)
1664 return ret;
1665
1666 pwd_dir = opendir(pwd);
1667 if (!pwd_dir)
1668 return ret;
1669
1670 memset(options, 0, sizeof(options));
1671 memset(options, 0, sizeof(abs_path));
1672
1673 while ((dent = readdir(pwd_dir))) {
1674 char path[PATH_MAX];
1675 u64 magic;
1676 char *name = dent->d_name;
1677 FILE *file;
1678
1679 if (!(dent->d_type == DT_REG))
1680 continue;
1681
1682 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1683
1684 file = fopen(path, "r");
1685 if (!file)
1686 continue;
1687
1688 if (fread(&magic, 1, 8, file) < 8)
1689 goto close_file_and_continue;
1690
1691 if (is_perf_magic(magic)) {
1692 options[nr_options] = strdup(name);
1693 if (!options[nr_options])
1694 goto close_file_and_continue;
1695
1696 abs_path[nr_options] = strdup(path);
1697 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001698 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001699 ui__warning("Can't search all data files due to memory shortage.\n");
1700 fclose(file);
1701 break;
1702 }
1703
1704 nr_options++;
1705 }
1706
1707close_file_and_continue:
1708 fclose(file);
1709 if (nr_options >= 32) {
1710 ui__warning("Too many perf data files in PWD!\n"
1711 "Only the first 32 files will be listed.\n");
1712 break;
1713 }
1714 }
1715 closedir(pwd_dir);
1716
1717 if (nr_options) {
1718 choice = ui__popup_menu(nr_options, options);
1719 if (choice < nr_options && choice >= 0) {
1720 tmp = strdup(abs_path[choice]);
1721 if (tmp) {
1722 if (is_input_name_malloced)
1723 free((void *)input_name);
1724 input_name = tmp;
1725 is_input_name_malloced = true;
1726 ret = 0;
1727 } else
1728 ui__warning("Data switch failed due to memory shortage!\n");
1729 }
1730 }
1731
1732 free_popup_options(options, nr_options);
1733 free_popup_options(abs_path, nr_options);
1734 return ret;
1735}
1736
Namhyung Kimea7cd592015-04-22 16:18:19 +09001737struct popup_action {
1738 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001739 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001740 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001741
1742 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1743};
1744
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001745static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001746do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001747{
1748 struct perf_evsel *evsel;
1749 struct annotation *notes;
1750 struct hist_entry *he;
1751 int err;
1752
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001753 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001754 return 0;
1755
Namhyung Kimea7cd592015-04-22 16:18:19 +09001756 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001757 if (!notes->src)
1758 return 0;
1759
1760 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001761 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001762 he = hist_browser__selected_entry(browser);
1763 /*
1764 * offer option to annotate the other branch source or target
1765 * (if they exists) when returning from annotate
1766 */
1767 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1768 return 1;
1769
1770 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1771 if (err)
1772 ui_browser__handle_resize(&browser->b);
1773 return 0;
1774}
1775
1776static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001777add_annotate_opt(struct hist_browser *browser __maybe_unused,
1778 struct popup_action *act, char **optstr,
1779 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001780{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001781 if (sym == NULL || map->dso->annotate_warned)
1782 return 0;
1783
1784 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1785 return 0;
1786
1787 act->ms.map = map;
1788 act->ms.sym = sym;
1789 act->fn = do_annotate;
1790 return 1;
1791}
1792
1793static int
1794do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1795{
1796 struct thread *thread = act->thread;
1797
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001798 if (browser->hists->thread_filter) {
1799 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1800 perf_hpp__set_elide(HISTC_THREAD, false);
1801 thread__zput(browser->hists->thread_filter);
1802 ui_helpline__pop();
1803 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001804 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001805 thread->comm_set ? thread__comm_str(thread) : "",
1806 thread->tid);
1807 browser->hists->thread_filter = thread__get(thread);
1808 perf_hpp__set_elide(HISTC_THREAD, false);
1809 pstack__push(browser->pstack, &browser->hists->thread_filter);
1810 }
1811
1812 hists__filter_by_thread(browser->hists);
1813 hist_browser__reset(browser);
1814 return 0;
1815}
1816
1817static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001818add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1819 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001820{
Namhyung Kim2eafd412016-01-21 19:13:24 -03001821 if (!sort__has_thread || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001822 return 0;
1823
1824 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1825 browser->hists->thread_filter ? "out of" : "into",
1826 thread->comm_set ? thread__comm_str(thread) : "",
1827 thread->tid) < 0)
1828 return 0;
1829
1830 act->thread = thread;
1831 act->fn = do_zoom_thread;
1832 return 1;
1833}
1834
1835static int
1836do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1837{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001838 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001839
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001840 if (browser->hists->dso_filter) {
1841 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1842 perf_hpp__set_elide(HISTC_DSO, false);
1843 browser->hists->dso_filter = NULL;
1844 ui_helpline__pop();
1845 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001846 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001847 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001848 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001849 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1850 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001851 perf_hpp__set_elide(HISTC_DSO, true);
1852 pstack__push(browser->pstack, &browser->hists->dso_filter);
1853 }
1854
1855 hists__filter_by_dso(browser->hists);
1856 hist_browser__reset(browser);
1857 return 0;
1858}
1859
1860static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001861add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001862 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001863{
Namhyung Kimb1447a542016-01-22 11:22:41 -03001864 if (!sort__has_dso || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001865 return 0;
1866
1867 if (asprintf(optstr, "Zoom %s %s DSO",
1868 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001869 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001870 return 0;
1871
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001872 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001873 act->fn = do_zoom_dso;
1874 return 1;
1875}
1876
1877static int
1878do_browse_map(struct hist_browser *browser __maybe_unused,
1879 struct popup_action *act)
1880{
1881 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001882 return 0;
1883}
1884
1885static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001886add_map_opt(struct hist_browser *browser __maybe_unused,
1887 struct popup_action *act, char **optstr, struct map *map)
1888{
Namhyung Kimb1447a542016-01-22 11:22:41 -03001889 if (!sort__has_dso || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001890 return 0;
1891
1892 if (asprintf(optstr, "Browse map details") < 0)
1893 return 0;
1894
1895 act->ms.map = map;
1896 act->fn = do_browse_map;
1897 return 1;
1898}
1899
1900static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001901do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001902 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001903{
1904 char script_opt[64];
1905 memset(script_opt, 0, sizeof(script_opt));
1906
Namhyung Kimea7cd592015-04-22 16:18:19 +09001907 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001908 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001909 thread__comm_str(act->thread));
1910 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001911 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001912 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001913 }
1914
1915 script_browse(script_opt);
1916 return 0;
1917}
1918
1919static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001920add_script_opt(struct hist_browser *browser __maybe_unused,
1921 struct popup_action *act, char **optstr,
1922 struct thread *thread, struct symbol *sym)
1923{
1924 if (thread) {
1925 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1926 thread__comm_str(thread)) < 0)
1927 return 0;
1928 } else if (sym) {
1929 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1930 sym->name) < 0)
1931 return 0;
1932 } else {
1933 if (asprintf(optstr, "Run scripts for all samples") < 0)
1934 return 0;
1935 }
1936
1937 act->thread = thread;
1938 act->ms.sym = sym;
1939 act->fn = do_run_script;
1940 return 1;
1941}
1942
1943static int
1944do_switch_data(struct hist_browser *browser __maybe_unused,
1945 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001946{
1947 if (switch_data_file()) {
1948 ui__warning("Won't switch the data files due to\n"
1949 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001950 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001951 }
1952
1953 return K_SWITCH_INPUT_DATA;
1954}
1955
Namhyung Kimea7cd592015-04-22 16:18:19 +09001956static int
1957add_switch_opt(struct hist_browser *browser,
1958 struct popup_action *act, char **optstr)
1959{
1960 if (!is_report_browser(browser->hbt))
1961 return 0;
1962
1963 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1964 return 0;
1965
1966 act->fn = do_switch_data;
1967 return 1;
1968}
1969
1970static int
1971do_exit_browser(struct hist_browser *browser __maybe_unused,
1972 struct popup_action *act __maybe_unused)
1973{
1974 return 0;
1975}
1976
1977static int
1978add_exit_opt(struct hist_browser *browser __maybe_unused,
1979 struct popup_action *act, char **optstr)
1980{
1981 if (asprintf(optstr, "Exit") < 0)
1982 return 0;
1983
1984 act->fn = do_exit_browser;
1985 return 1;
1986}
1987
Kan Liang84734b02015-09-04 10:45:45 -04001988static int
1989do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1990{
1991 if (browser->hists->socket_filter > -1) {
1992 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1993 browser->hists->socket_filter = -1;
1994 perf_hpp__set_elide(HISTC_SOCKET, false);
1995 } else {
1996 browser->hists->socket_filter = act->socket;
1997 perf_hpp__set_elide(HISTC_SOCKET, true);
1998 pstack__push(browser->pstack, &browser->hists->socket_filter);
1999 }
2000
2001 hists__filter_by_socket(browser->hists);
2002 hist_browser__reset(browser);
2003 return 0;
2004}
2005
2006static int
2007add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2008 char **optstr, int socket_id)
2009{
Namhyung Kimd9695d92016-01-22 12:20:18 -03002010 if (!sort__has_socket || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002011 return 0;
2012
2013 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2014 (browser->hists->socket_filter > -1) ? "out of" : "into",
2015 socket_id) < 0)
2016 return 0;
2017
2018 act->socket = socket_id;
2019 act->fn = do_zoom_socket;
2020 return 1;
2021}
2022
Namhyung Kim112f7612014-04-22 14:05:35 +09002023static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002024{
2025 u64 nr_entries = 0;
2026 struct rb_node *nd = rb_first(&hb->hists->entries);
2027
Namhyung Kim268397c2014-04-22 14:49:31 +09002028 if (hb->min_pcnt == 0) {
2029 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2030 return;
2031 }
2032
Namhyung Kim14135662013-10-31 10:17:39 +09002033 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002034 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09002035 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002036 }
2037
Namhyung Kim112f7612014-04-22 14:05:35 +09002038 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002039}
Feng Tang341487ab2013-02-03 14:38:20 +08002040
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002041static void hist_browser__update_percent_limit(struct hist_browser *hb,
2042 double percent)
2043{
2044 struct hist_entry *he;
2045 struct rb_node *nd = rb_first(&hb->hists->entries);
2046 u64 total = hists__total_period(hb->hists);
2047 u64 min_callchain_hits = total * (percent / 100);
2048
2049 hb->min_pcnt = callchain_param.min_percent = percent;
2050
2051 if (!symbol_conf.use_callchain)
2052 return;
2053
2054 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2055 he = rb_entry(nd, struct hist_entry, rb_node);
2056
2057 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2058 total = he->stat.period;
2059
2060 if (symbol_conf.cumulate_callchain)
2061 total = he->stat_acc->period;
2062
2063 min_callchain_hits = total * (percent / 100);
2064 }
2065
2066 callchain_param.sort(&he->sorted_chain, he->callchain,
2067 min_callchain_hits, &callchain_param);
2068
2069 /* force to re-evaluate folding state of callchains */
2070 he->init_have_children = false;
2071 hist_entry__set_folding(he, false);
2072
2073 nd = rb_next(nd);
2074 }
2075}
2076
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002077static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002078 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002079 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002080 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002081 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002082 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002083{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002084 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09002085 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002086 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002087#define MAX_OPTIONS 16
2088 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002089 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002090 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002091 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002092 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002093 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002094 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002095
Namhyung Kime8e684a2013-12-26 14:37:58 +09002096#define HIST_BROWSER_HELP_COMMON \
2097 "h/?/F1 Show this window\n" \
2098 "UP/DOWN/PGUP\n" \
2099 "PGDN/SPACE Navigate\n" \
2100 "q/ESC/CTRL+C Exit browser\n\n" \
2101 "For multiple event sessions:\n\n" \
2102 "TAB/UNTAB Switch events\n\n" \
2103 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002104 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2105 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002106 "a Annotate current symbol\n" \
2107 "C Collapse all callchains\n" \
2108 "d Zoom into current DSO\n" \
2109 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002110 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002111 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002112 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002113 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002114 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002115
2116 /* help messages are sorted by lexical order of the hotkey */
2117 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002118 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002119 "P Print histograms to perf.hist.N\n"
2120 "r Run available scripts\n"
2121 "s Switch to another data file in PWD\n"
2122 "t Zoom into current Thread\n"
2123 "V Verbose (DSO names in callchains, etc)\n"
2124 "/ Filter symbol by name";
2125 const char top_help[] = HIST_BROWSER_HELP_COMMON
2126 "P Print histograms to perf.hist.N\n"
2127 "t Zoom into current Thread\n"
2128 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002129 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002130 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002131 "/ Filter symbol by name";
2132
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002133 if (browser == NULL)
2134 return -1;
2135
Namhyung Kimed426912015-05-29 21:53:44 +09002136 /* reset abort key so that it can get Ctrl-C as a key */
2137 SLang_reset_tty();
2138 SLang_init_tty(0, 0, 0);
2139
Namhyung Kim03905042015-11-28 02:32:39 +09002140 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002141 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002142 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002143
Kan Liang84734b02015-09-04 10:45:45 -04002144 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002145 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002146 goto out;
2147
2148 ui_helpline__push(helpline);
2149
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002150 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002151 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002152
Jiri Olsaf0786af2016-01-18 10:24:23 +01002153 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002154 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03002155 /*
2156 * This is done just once, and activates the horizontal scrolling
2157 * code in the ui_browser code, it would be better to have a the
2158 * counter in the perf_hpp code, but I couldn't find doing it here
2159 * works, FIXME by setting this in hist_browser__new, for now, be
2160 * clever 8-)
2161 */
2162 ++browser->b.columns;
2163 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09002164
Namhyung Kim5b591662014-07-31 14:47:38 +09002165 if (symbol_conf.col_width_list_str)
2166 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2167
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002168 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002169 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002170 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002171 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002172 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002173
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002174 nr_options = 0;
2175
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002176 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002177
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002178 if (browser->he_selection != NULL) {
2179 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002180 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002181 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002182 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002183 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002184 case K_TAB:
2185 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002186 if (nr_events == 1)
2187 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002188 /*
2189 * Exit the browser, let hists__browser_tree
2190 * go to the next or previous
2191 */
2192 goto out_free_stack;
2193 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002194 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002195 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002196 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002197 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002198 continue;
2199 }
2200
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002201 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002202 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002203 browser->selection->map->dso->annotate_warned)
2204 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002205
Namhyung Kimea7cd592015-04-22 16:18:19 +09002206 actions->ms.map = browser->selection->map;
2207 actions->ms.sym = browser->selection->sym;
2208 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002209 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002210 case 'P':
2211 hist_browser__dump(browser);
2212 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002213 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002214 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002215 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002216 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002217 case 'V':
2218 browser->show_dso = !browser->show_dso;
2219 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002220 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002221 actions->thread = thread;
2222 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002223 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002224 case 'S':
2225 actions->socket = socked_id;
2226 do_zoom_socket(browser, actions);
2227 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002228 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002229 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e452015-10-12 14:02:29 -03002230 "Please enter the name of symbol you want to see.\n"
2231 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002232 buf, "ENTER: OK, ESC: Cancel",
2233 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002234 hists->symbol_filter_str = *buf ? buf : NULL;
2235 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002236 hist_browser__reset(browser);
2237 }
2238 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002239 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002240 if (is_report_browser(hbt)) {
2241 actions->thread = NULL;
2242 actions->ms.sym = NULL;
2243 do_run_script(browser, actions);
2244 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002245 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002246 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002247 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002248 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002249 if (key == K_SWITCH_INPUT_DATA)
2250 goto out_free_stack;
2251 }
Feng Tang341487ab2013-02-03 14:38:20 +08002252 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002253 case 'i':
2254 /* env->arch is NULL for live-mode (i.e. perf top) */
2255 if (env->arch)
2256 tui__header_window(env);
2257 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002258 case 'F':
2259 symbol_conf.filter_relative ^= 1;
2260 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002261 case 'z':
2262 if (!is_report_browser(hbt)) {
2263 struct perf_top *top = hbt->arg;
2264
2265 top->zero = !top->zero;
2266 }
2267 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002268 case 'L':
2269 if (ui_browser__input_window("Percent Limit",
2270 "Please enter the value you want to hide entries under that percent.",
2271 buf, "ENTER: OK, ESC: Cancel",
2272 delay_secs * 2) == K_ENTER) {
2273 char *end;
2274 double new_percent = strtod(buf, &end);
2275
2276 if (new_percent < 0 || new_percent > 100) {
2277 ui_browser__warning(&browser->b, delay_secs * 2,
2278 "Invalid percent: %.2f", new_percent);
2279 continue;
2280 }
2281
2282 hist_browser__update_percent_limit(browser, new_percent);
2283 hist_browser__reset(browser);
2284 }
2285 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002286 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002287 case 'h':
2288 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002289 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002290 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002291 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002292 case K_ENTER:
2293 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002294 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002295 /* menu */
2296 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002297 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002298 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002299 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002300
Namhyung Kim01f00a12015-04-22 16:18:16 +09002301 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002302 /*
2303 * Go back to the perf_evsel_menu__run or other user
2304 */
2305 if (left_exits)
2306 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002307
2308 if (key == K_ESC &&
2309 ui_browser__dialog_yesno(&browser->b,
2310 "Do you really want to exit?"))
2311 goto out_free_stack;
2312
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002313 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002314 }
Namhyung Kim64221842015-04-24 10:15:33 +09002315 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002316 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002317 /*
2318 * No need to set actions->dso here since
2319 * it's just to remove the current filter.
2320 * Ditto for thread below.
2321 */
2322 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002323 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002324 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002325 } else if (top == &browser->hists->socket_filter) {
2326 do_zoom_socket(browser, actions);
2327 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002328 continue;
2329 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002330 case 'q':
2331 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002332 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002333 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002334 if (!is_report_browser(hbt)) {
2335 struct perf_top *top = hbt->arg;
2336
2337 perf_evlist__toggle_enable(top->evlist);
2338 /*
2339 * No need to refresh, resort/decay histogram
2340 * entries if we are not collecting samples:
2341 */
2342 if (top->evlist->enabled) {
2343 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2344 hbt->refresh = delay_secs;
2345 } else {
2346 helpline = "Press 'f' again to re-enable the events";
2347 hbt->refresh = 0;
2348 }
2349 continue;
2350 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002351 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002352 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002353 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002354 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002355 }
2356
Namhyung Kim40561322016-01-22 12:26:06 -03002357 if (!sort__has_sym || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002358 goto skip_annotation;
2359
Namhyung Kim55369fc2013-04-01 20:35:20 +09002360 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002361 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002362
2363 if (bi == NULL)
2364 goto skip_annotation;
2365
Namhyung Kimea7cd592015-04-22 16:18:19 +09002366 nr_options += add_annotate_opt(browser,
2367 &actions[nr_options],
2368 &options[nr_options],
2369 bi->from.map,
2370 bi->from.sym);
2371 if (bi->to.sym != bi->from.sym)
2372 nr_options += add_annotate_opt(browser,
2373 &actions[nr_options],
2374 &options[nr_options],
2375 bi->to.map,
2376 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002377 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002378 nr_options += add_annotate_opt(browser,
2379 &actions[nr_options],
2380 &options[nr_options],
2381 browser->selection->map,
2382 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002383 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002384skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002385 nr_options += add_thread_opt(browser, &actions[nr_options],
2386 &options[nr_options], thread);
2387 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002388 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002389 nr_options += add_map_opt(browser, &actions[nr_options],
2390 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002391 browser->selection ?
2392 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002393 nr_options += add_socket_opt(browser, &actions[nr_options],
2394 &options[nr_options],
2395 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002396 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002397 if (!is_report_browser(hbt))
2398 goto skip_scripting;
2399
Feng Tangcdbab7c2012-10-30 11:56:06 +08002400 if (browser->he_selection) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002401 if (sort__has_thread && thread) {
2402 nr_options += add_script_opt(browser,
2403 &actions[nr_options],
2404 &options[nr_options],
2405 thread, NULL);
2406 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002407 /*
2408 * Note that browser->selection != NULL
2409 * when browser->he_selection is not NULL,
2410 * so we don't need to check browser->selection
2411 * before fetching browser->selection->sym like what
2412 * we do before fetching browser->selection->map.
2413 *
2414 * See hist_browser__show_entry.
2415 */
Namhyung Kimc221acb2016-01-21 19:50:09 -03002416 if (sort__has_sym && browser->selection->sym) {
2417 nr_options += add_script_opt(browser,
2418 &actions[nr_options],
2419 &options[nr_options],
2420 NULL, browser->selection->sym);
2421 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08002422 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002423 nr_options += add_script_opt(browser, &actions[nr_options],
2424 &options[nr_options], NULL, NULL);
2425 nr_options += add_switch_opt(browser, &actions[nr_options],
2426 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03002427skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002428 nr_options += add_exit_opt(browser, &actions[nr_options],
2429 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002430
Namhyung Kimea7cd592015-04-22 16:18:19 +09002431 do {
2432 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002433
Namhyung Kimea7cd592015-04-22 16:18:19 +09002434 choice = ui__popup_menu(nr_options, options);
2435 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002436 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002437
2438 act = &actions[choice];
2439 key = act->fn(browser, act);
2440 } while (key == 1);
2441
2442 if (key == K_SWITCH_INPUT_DATA)
2443 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002444 }
2445out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002446 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002447out:
2448 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002449 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002450 return key;
2451}
2452
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002453struct perf_evsel_menu {
2454 struct ui_browser b;
2455 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002456 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002457 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002458 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002459};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002460
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002461static void perf_evsel_menu__write(struct ui_browser *browser,
2462 void *entry, int row)
2463{
2464 struct perf_evsel_menu *menu = container_of(browser,
2465 struct perf_evsel_menu, b);
2466 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002467 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002468 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002469 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002470 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002471 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002472 const char *warn = " ";
2473 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002474
2475 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2476 HE_COLORSET_NORMAL);
2477
Namhyung Kim759ff492013-03-05 14:53:26 +09002478 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002479 struct perf_evsel *pos;
2480
2481 ev_name = perf_evsel__group_name(evsel);
2482
2483 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002484 struct hists *pos_hists = evsel__hists(pos);
2485 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002486 }
2487 }
2488
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002489 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002490 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002491 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002492 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002493
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002494 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002495 if (nr_events != 0) {
2496 menu->lost_events = true;
2497 if (!current_entry)
2498 ui_browser__set_color(browser, HE_COLORSET_TOP);
2499 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002500 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2501 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002502 warn = bf;
2503 }
2504
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002505 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002506
2507 if (current_entry)
2508 menu->selection = evsel;
2509}
2510
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002511static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2512 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002513 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002514{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002515 struct perf_evlist *evlist = menu->b.priv;
2516 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002517 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002518 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002519 int key;
2520
2521 if (ui_browser__show(&menu->b, title,
2522 "ESC: exit, ENTER|->: Browse histograms") < 0)
2523 return -1;
2524
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002525 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002526 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002527
2528 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002529 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002530 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002531
2532 if (!menu->lost_events_warned && menu->lost_events) {
2533 ui_browser__warn_lost_events(&menu->b);
2534 menu->lost_events_warned = true;
2535 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002536 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002537 case K_RIGHT:
2538 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002539 if (!menu->selection)
2540 continue;
2541 pos = menu->selection;
2542browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002543 perf_evlist__set_selected(evlist, pos);
2544 /*
2545 * Give the calling tool a chance to populate the non
2546 * default evsel resorted hists tree.
2547 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002548 if (hbt)
2549 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002550 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002551 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002552 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002553 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002554 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002555 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002556 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002557 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002558 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002559 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002560 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002561 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002562 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002563 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002564 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002565 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002566 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002567 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002568 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002569 case 'q':
2570 case CTRL('c'):
2571 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002572 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002573 default:
2574 continue;
2575 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002576 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002577 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002578 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002579 if (!ui_browser__dialog_yesno(&menu->b,
2580 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002581 continue;
2582 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002583 case 'q':
2584 case CTRL('c'):
2585 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002586 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002587 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002588 }
2589 }
2590
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002591out:
2592 ui_browser__hide(&menu->b);
2593 return key;
2594}
2595
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002596static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002597 void *entry)
2598{
2599 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2600
2601 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2602 return true;
2603
2604 return false;
2605}
2606
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002607static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002608 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002609 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002610 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002611 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002612{
2613 struct perf_evsel *pos;
2614 struct perf_evsel_menu menu = {
2615 .b = {
2616 .entries = &evlist->entries,
2617 .refresh = ui_browser__list_head_refresh,
2618 .seek = ui_browser__list_head_seek,
2619 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002620 .filter = filter_group_entries,
2621 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002622 .priv = evlist,
2623 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002624 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002625 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002626 };
2627
2628 ui_helpline__push("Press ESC to exit");
2629
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002630 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002631 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002632 size_t line_len = strlen(ev_name) + 7;
2633
2634 if (menu.b.width < line_len)
2635 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002636 }
2637
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002638 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002639}
2640
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002641int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002642 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002643 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002644 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002645{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002646 int nr_entries = evlist->nr_entries;
2647
2648single_entry:
2649 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002650 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002651
2652 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002653 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002654 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002655 }
2656
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002657 if (symbol_conf.event_group) {
2658 struct perf_evsel *pos;
2659
2660 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002661 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002662 if (perf_evsel__is_group_leader(pos))
2663 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002664 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002665
2666 if (nr_entries == 1)
2667 goto single_entry;
2668 }
2669
2670 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002671 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002672}