blob: 81def6c3f24bf16397c8e15d26178cd4957bd86f [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
181static int callchain_node__count_rows(struct callchain_node *node)
182{
183 struct callchain_list *chain;
184 bool unfolded = false;
185 int n = 0;
186
187 list_for_each_entry(chain, &node->val, list) {
188 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900189 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300190 }
191
192 if (unfolded)
193 n += callchain_node__count_rows_rb_tree(node);
194
195 return n;
196}
197
198static int callchain__count_rows(struct rb_root *chain)
199{
200 struct rb_node *nd;
201 int n = 0;
202
203 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
204 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
205 n += callchain_node__count_rows(node);
206 }
207
208 return n;
209}
210
Namhyung Kim3698dab2015-05-05 23:55:46 +0900211static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300212{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900213 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200214 return false;
215
Namhyung Kim3698dab2015-05-05 23:55:46 +0900216 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300217 return false;
218
Namhyung Kim3698dab2015-05-05 23:55:46 +0900219 he->unfolded = !he->unfolded;
220 return true;
221}
222
223static bool callchain_list__toggle_fold(struct callchain_list *cl)
224{
225 if (!cl)
226 return false;
227
228 if (!cl->has_children)
229 return false;
230
231 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300232 return true;
233}
234
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300235static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300236{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300237 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300238
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300239 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300240 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
241 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300242 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300243
244 list_for_each_entry(chain, &child->val, list) {
245 if (first) {
246 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900247 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300248 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300249 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900250 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300251 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300252 }
253
254 callchain_node__init_have_children_rb_tree(child);
255 }
256}
257
Namhyung Kima7444af2014-11-24 17:13:27 +0900258static void callchain_node__init_have_children(struct callchain_node *node,
259 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300260{
261 struct callchain_list *chain;
262
Namhyung Kima7444af2014-11-24 17:13:27 +0900263 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900264 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900265
Namhyung Kim82162b52014-08-13 15:02:41 +0900266 if (!list_empty(&node->val)) {
267 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900268 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900269 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300270
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300271 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300272}
273
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300274static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300275{
Namhyung Kima7444af2014-11-24 17:13:27 +0900276 struct rb_node *nd = rb_first(root);
277 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300278
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300279 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300280 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900281 callchain_node__init_have_children(node, has_sibling);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300282 }
283}
284
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300285static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300286{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300287 if (!he->init_have_children) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900288 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300289 callchain__init_have_children(&he->sorted_chain);
290 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300291 }
292}
293
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300294static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300295{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900296 struct hist_entry *he = browser->he_selection;
297 struct map_symbol *ms = browser->selection;
298 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
299 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300300
Wang Nan4938cf02015-12-07 02:35:44 +0000301 if (!he || !ms)
302 return false;
303
Namhyung Kim3698dab2015-05-05 23:55:46 +0900304 if (ms == &he->ms)
305 has_children = hist_entry__toggle_fold(he);
306 else
307 has_children = callchain_list__toggle_fold(cl);
308
309 if (has_children) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300310 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900311 browser->b.nr_entries -= he->nr_rows;
312 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300313
Namhyung Kim3698dab2015-05-05 23:55:46 +0900314 if (he->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300315 he->nr_rows = callchain__count_rows(&he->sorted_chain);
316 else
317 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900318
319 browser->b.nr_entries += he->nr_rows;
320 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300321
322 return true;
323 }
324
325 /* If it doesn't have children, no toggling performed */
326 return false;
327}
328
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300329static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300330{
331 int n = 0;
332 struct rb_node *nd;
333
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300334 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300335 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
336 struct callchain_list *chain;
337 bool has_children = false;
338
339 list_for_each_entry(chain, &child->val, list) {
340 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900341 callchain_list__set_folding(chain, unfold);
342 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300343 }
344
345 if (has_children)
346 n += callchain_node__set_folding_rb_tree(child, unfold);
347 }
348
349 return n;
350}
351
352static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
353{
354 struct callchain_list *chain;
355 bool has_children = false;
356 int n = 0;
357
358 list_for_each_entry(chain, &node->val, list) {
359 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900360 callchain_list__set_folding(chain, unfold);
361 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300362 }
363
364 if (has_children)
365 n += callchain_node__set_folding_rb_tree(node, unfold);
366
367 return n;
368}
369
370static int callchain__set_folding(struct rb_root *chain, bool unfold)
371{
372 struct rb_node *nd;
373 int n = 0;
374
375 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
376 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
377 n += callchain_node__set_folding(node, unfold);
378 }
379
380 return n;
381}
382
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300383static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300384{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300385 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900386 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300387
Namhyung Kim3698dab2015-05-05 23:55:46 +0900388 if (he->has_children) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300389 int n = callchain__set_folding(&he->sorted_chain, unfold);
390 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300391 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300392 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300393}
394
Namhyung Kimc3b78952014-04-22 15:56:17 +0900395static void
396__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300397{
398 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900399 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300400
Namhyung Kimc3b78952014-04-22 15:56:17 +0900401 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900402 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900403 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300404 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
405 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900406 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300407 }
408}
409
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300410static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300411{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900412 browser->nr_callchain_rows = 0;
413 __hist_browser__set_folding(browser, unfold);
414
415 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300416 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300417 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300418}
419
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200420static void ui_browser__warn_lost_events(struct ui_browser *browser)
421{
422 ui_browser__warning(browser, 4,
423 "Events are being lost, check IO/CPU overload!\n\n"
424 "You may want to run 'perf' using a RT scheduler policy:\n\n"
425 " perf top -r 80\n\n"
426 "Or reduce the sampling frequency.");
427}
428
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300429static int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300430{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300431 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300432 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900433 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900434 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300435
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300436 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900437 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300438
Taeung Song1e378eb2014-10-07 16:13:15 +0900439 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300440
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300441 if (ui_browser__show(&browser->b, title, help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300442 return -1;
443
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300444 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300445 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300446
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300447 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900448 case K_TIMER: {
449 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900450 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900451
Namhyung Kimc3b78952014-04-22 15:56:17 +0900452 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900453 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900454
Namhyung Kimc3b78952014-04-22 15:56:17 +0900455 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900456 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200457
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300458 if (browser->hists->stats.nr_lost_warned !=
459 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
460 browser->hists->stats.nr_lost_warned =
461 browser->hists->stats.nr_events[PERF_RECORD_LOST];
462 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200463 }
464
Taeung Song1e378eb2014-10-07 16:13:15 +0900465 hists__browser_title(browser->hists,
466 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300467 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300468 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900469 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300470 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300471 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300472 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300473 struct hist_entry, rb_node);
474 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300475 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 -0300476 seq++, browser->b.nr_entries,
477 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300478 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300479 browser->b.index,
480 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300481 h->row_offset, h->nr_rows);
482 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300483 break;
484 case 'C':
485 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300486 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300487 break;
488 case 'E':
489 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300490 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300491 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200492 case 'H':
493 browser->show_headers = !browser->show_headers;
494 hist_browser__update_rows(browser);
495 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200496 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300497 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300498 break;
499 /* fall thru */
500 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300501 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300502 }
503 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300504out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300505 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300506 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300507}
508
Namhyung Kim39ee5332014-08-22 09:13:21 +0900509struct callchain_print_arg {
510 /* for hists browser */
511 off_t row_offset;
512 bool is_current_entry;
513
514 /* for file dump */
515 FILE *fp;
516 int printed;
517};
518
519typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
520 struct callchain_list *chain,
521 const char *str, int offset,
522 unsigned short row,
523 struct callchain_print_arg *arg);
524
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900525static void hist_browser__show_callchain_entry(struct hist_browser *browser,
526 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900527 const char *str, int offset,
528 unsigned short row,
529 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900530{
531 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900532 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300533 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900534
535 color = HE_COLORSET_NORMAL;
536 width = browser->b.width - (offset + 2);
537 if (ui_browser__is_current_entry(&browser->b, row)) {
538 browser->selection = &chain->ms;
539 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900540 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900541 }
542
543 ui_browser__set_color(&browser->b, color);
544 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300545 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300546 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300547 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300548 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900549}
550
Namhyung Kim39ee5332014-08-22 09:13:21 +0900551static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
552 struct callchain_list *chain,
553 const char *str, int offset,
554 unsigned short row __maybe_unused,
555 struct callchain_print_arg *arg)
556{
557 char folded_sign = callchain_list__folded(chain);
558
559 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
560 folded_sign, str);
561}
562
563typedef bool (*check_output_full_fn)(struct hist_browser *browser,
564 unsigned short row);
565
566static bool hist_browser__check_output_full(struct hist_browser *browser,
567 unsigned short row)
568{
569 return browser->b.rows == row;
570}
571
572static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
573 unsigned short row __maybe_unused)
574{
575 return false;
576}
577
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300578#define LEVEL_OFFSET_STEP 3
579
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900580static int hist_browser__show_callchain(struct hist_browser *browser,
581 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900582 unsigned short row, u64 total,
583 print_callchain_entry_fn print,
584 struct callchain_print_arg *arg,
585 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300586{
587 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900588 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900589 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900590 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300591
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900592 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900593 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900594
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300595 while (node) {
596 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
597 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100598 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300599 struct callchain_list *chain;
600 char folded_sign = ' ';
601 int first = true;
602 int extra_offset = 0;
603
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300604 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300605 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300606 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607 bool was_first = first;
608
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300609 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300610 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900611 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300612 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300613
614 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900615 if (arg->row_offset != 0) {
616 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300617 goto do_next;
618 }
619
620 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300621 str = callchain_list__sym_name(chain, bf, sizeof(bf),
622 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900623
Namhyung Kim4087d112014-11-24 17:13:26 +0900624 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900625 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300626
627 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
628 str = "Not enough memory!";
629 else
630 str = alloc_str;
631 }
632
Namhyung Kim39ee5332014-08-22 09:13:21 +0900633 print(browser, chain, str, offset + extra_offset, row, arg);
634
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300635 free(alloc_str);
636
Namhyung Kim39ee5332014-08-22 09:13:21 +0900637 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300638 goto out;
639do_next:
640 if (folded_sign == '+')
641 break;
642 }
643
644 if (folded_sign == '-') {
645 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900646
647 if (callchain_param.mode == CHAIN_GRAPH_REL)
648 new_total = child->children_hit;
649 else
650 new_total = total;
651
652 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900653 new_level, row, new_total,
654 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300655 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900656 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900657 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300658 node = next;
659 }
660out:
661 return row - first_row;
662}
663
Namhyung Kim89701462013-01-22 18:09:38 +0900664struct hpp_arg {
665 struct ui_browser *b;
666 char folded_sign;
667 bool current_entry;
668};
669
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900670static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
671{
672 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900673 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900674 va_list args;
675 double percent;
676
677 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900678 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900679 percent = va_arg(args, double);
680 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900681
Namhyung Kim89701462013-01-22 18:09:38 +0900682 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900683
Namhyung Kimd6751072014-07-31 14:47:36 +0900684 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300685 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +0900686
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900687 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900688 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900689}
690
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900691#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900692static u64 __hpp_get_##_field(struct hist_entry *he) \
693{ \
694 return he->stat._field; \
695} \
696 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100697static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900698hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100699 struct perf_hpp *hpp, \
700 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900701{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900702 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
703 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900704}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900705
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900706#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
707static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
708{ \
709 return he->stat_acc->_field; \
710} \
711 \
712static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900713hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900714 struct perf_hpp *hpp, \
715 struct hist_entry *he) \
716{ \
717 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300718 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +0900719 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900720 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900721 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300722 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900723 \
724 return ret; \
725 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900726 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
727 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900728}
729
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900730__HPP_COLOR_PERCENT_FN(overhead, period)
731__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
732__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
733__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
734__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900735__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900736
737#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900738#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900739
740void hist_browser__init_hpp(void)
741{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900742 perf_hpp__format[PERF_HPP__OVERHEAD].color =
743 hist_browser__hpp_color_overhead;
744 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
745 hist_browser__hpp_color_overhead_sys;
746 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
747 hist_browser__hpp_color_overhead_us;
748 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
749 hist_browser__hpp_color_overhead_guest_sys;
750 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
751 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900752 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
753 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900754}
755
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300756static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300757 struct hist_entry *entry,
758 unsigned short row)
759{
760 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200761 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900762 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300763 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300764 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300765 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300766 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200767 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300768
769 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300770 browser->he_selection = entry;
771 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300772 }
773
774 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300775 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300776 folded_sign = hist_entry__folded(entry);
777 }
778
779 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900780 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900781 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900782 .folded_sign = folded_sign,
783 .current_entry = current_entry,
784 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900785 struct perf_hpp hpp = {
786 .buf = s,
787 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900788 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900789 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300790 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300791
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300792 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900793
Jiri Olsa12400052012-10-13 00:06:16 +0200794 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300795 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +0900796 continue;
797
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900798 if (current_entry && browser->b.navkeypressed) {
799 ui_browser__set_color(&browser->b,
800 HE_COLORSET_SELECTED);
801 } else {
802 ui_browser__set_color(&browser->b,
803 HE_COLORSET_NORMAL);
804 }
805
806 if (first) {
807 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300808 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900809 width -= 2;
810 }
811 first = false;
812 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300813 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +0900814 width -= 2;
815 }
816
Jiri Olsa12400052012-10-13 00:06:16 +0200817 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100818 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900819 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100820 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300821 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900822 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300823 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200824
825 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300826 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200827 width += 1;
828
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300829 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +0900830
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300831 ++row;
832 ++printed;
833 } else
834 --row_offset;
835
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300836 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900837 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900838 struct callchain_print_arg arg = {
839 .row_offset = row_offset,
840 .is_current_entry = current_entry,
841 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900842
Namhyung Kim4087d112014-11-24 17:13:26 +0900843 if (callchain_param.mode == CHAIN_GRAPH_REL) {
844 if (symbol_conf.cumulate_callchain)
845 total = entry->stat_acc->period;
846 else
847 total = entry->stat.period;
848 }
849
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900850 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900851 &entry->sorted_chain, 1, row, total,
852 hist_browser__show_callchain_entry, &arg,
853 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900854
Namhyung Kim39ee5332014-08-22 09:13:21 +0900855 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300856 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300857 }
858
859 return printed;
860}
861
Jiri Olsa81a888f2014-06-14 15:44:52 +0200862static int advance_hpp_check(struct perf_hpp *hpp, int inc)
863{
864 advance_hpp(hpp, inc);
865 return hpp->size <= 0;
866}
867
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300868static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +0200869{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300870 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +0200871 struct perf_hpp dummy_hpp = {
872 .buf = buf,
873 .size = size,
874 };
875 struct perf_hpp_fmt *fmt;
876 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300877 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +0200878
879 if (symbol_conf.use_callchain) {
880 ret = scnprintf(buf, size, " ");
881 if (advance_hpp_check(&dummy_hpp, ret))
882 return ret;
883 }
884
885 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300886 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +0200887 continue;
888
Jiri Olsa81a888f2014-06-14 15:44:52 +0200889 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
890 if (advance_hpp_check(&dummy_hpp, ret))
891 break;
892
893 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
894 if (advance_hpp_check(&dummy_hpp, ret))
895 break;
896 }
897
898 return ret;
899}
900
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200901static void hist_browser__show_headers(struct hist_browser *browser)
902{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200903 char headers[1024];
904
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300905 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200906 ui_browser__gotorc(&browser->b, 0, 0);
907 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300908 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200909}
910
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300911static void ui_browser__hists_init_top(struct ui_browser *browser)
912{
913 if (browser->top == NULL) {
914 struct hist_browser *hb;
915
916 hb = container_of(browser, struct hist_browser, b);
917 browser->top = rb_first(&hb->hists->entries);
918 }
919}
920
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300921static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300922{
923 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200924 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300925 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300926 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300927
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200928 if (hb->show_headers) {
929 hist_browser__show_headers(hb);
930 header_offset = 1;
931 }
932
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300933 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +0000934 hb->he_selection = NULL;
935 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300936
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300937 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300938 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900939 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300940
941 if (h->filtered)
942 continue;
943
Namhyung Kim14135662013-10-31 10:17:39 +0900944 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900945 if (percent < hb->min_pcnt)
946 continue;
947
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300948 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300949 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300950 break;
951 }
952
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200953 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300954}
955
Namhyung Kim064f1982013-05-14 11:09:04 +0900956static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900957 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300958{
959 while (nd != NULL) {
960 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900961 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900962
Namhyung Kimc0f15272014-04-16 11:16:33 +0900963 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300964 return nd;
965
966 nd = rb_next(nd);
967 }
968
969 return NULL;
970}
971
Namhyung Kim064f1982013-05-14 11:09:04 +0900972static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900973 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300974{
975 while (nd != NULL) {
976 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900977 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900978
979 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300980 return nd;
981
982 nd = rb_prev(nd);
983 }
984
985 return NULL;
986}
987
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300988static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300989 off_t offset, int whence)
990{
991 struct hist_entry *h;
992 struct rb_node *nd;
993 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900994 struct hist_browser *hb;
995
996 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300997
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300998 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300999 return;
1000
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001001 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001002
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001003 switch (whence) {
1004 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001005 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001006 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001007 break;
1008 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001009 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001010 goto do_offset;
1011 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001012 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001013 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001014 first = false;
1015 break;
1016 default:
1017 return;
1018 }
1019
1020 /*
1021 * Moves not relative to the first visible entry invalidates its
1022 * row_offset:
1023 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001024 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001025 h->row_offset = 0;
1026
1027 /*
1028 * Here we have to check if nd is expanded (+), if it is we can't go
1029 * the next top level hist_entry, instead we must compute an offset of
1030 * what _not_ to show and not change the first visible entry.
1031 *
1032 * This offset increments when we are going from top to bottom and
1033 * decreases when we're going from bottom to top.
1034 *
1035 * As we don't have backpointers to the top level in the callchains
1036 * structure, we need to always print the whole hist_entry callchain,
1037 * skipping the first ones that are before the first visible entry
1038 * and stop when we printed enough lines to fill the screen.
1039 */
1040do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001041 if (!nd)
1042 return;
1043
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001044 if (offset > 0) {
1045 do {
1046 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001047 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001048 u16 remaining = h->nr_rows - h->row_offset;
1049 if (offset > remaining) {
1050 offset -= remaining;
1051 h->row_offset = 0;
1052 } else {
1053 h->row_offset += offset;
1054 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001055 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001056 break;
1057 }
1058 }
Namhyung Kim14135662013-10-31 10:17:39 +09001059 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001060 if (nd == NULL)
1061 break;
1062 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001063 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001064 } while (offset != 0);
1065 } else if (offset < 0) {
1066 while (1) {
1067 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001068 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001069 if (first) {
1070 if (-offset > h->row_offset) {
1071 offset += h->row_offset;
1072 h->row_offset = 0;
1073 } else {
1074 h->row_offset += offset;
1075 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001076 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001077 break;
1078 }
1079 } else {
1080 if (-offset > h->nr_rows) {
1081 offset += h->nr_rows;
1082 h->row_offset = 0;
1083 } else {
1084 h->row_offset = h->nr_rows + offset;
1085 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001086 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001087 break;
1088 }
1089 }
1090 }
1091
Namhyung Kim14135662013-10-31 10:17:39 +09001092 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001093 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001094 if (nd == NULL)
1095 break;
1096 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001097 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001098 if (offset == 0) {
1099 /*
1100 * Last unfiltered hist_entry, check if it is
1101 * unfolded, if it is then we should have
1102 * row_offset at its last entry.
1103 */
1104 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001105 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001106 h->row_offset = h->nr_rows;
1107 break;
1108 }
1109 first = false;
1110 }
1111 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001112 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001113 h = rb_entry(nd, struct hist_entry, rb_node);
1114 h->row_offset = 0;
1115 }
1116}
1117
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001118static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001119 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001120{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001121 u64 total = hists__total_period(he->hists);
1122 struct callchain_print_arg arg = {
1123 .fp = fp,
1124 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001125
Namhyung Kim39ee5332014-08-22 09:13:21 +09001126 if (symbol_conf.cumulate_callchain)
1127 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001128
Namhyung Kim39ee5332014-08-22 09:13:21 +09001129 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1130 hist_browser__fprintf_callchain_entry, &arg,
1131 hist_browser__check_dump_full);
1132 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001133}
1134
1135static int hist_browser__fprintf_entry(struct hist_browser *browser,
1136 struct hist_entry *he, FILE *fp)
1137{
1138 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001139 int printed = 0;
1140 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001141 struct perf_hpp hpp = {
1142 .buf = s,
1143 .size = sizeof(s),
1144 };
1145 struct perf_hpp_fmt *fmt;
1146 bool first = true;
1147 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001148
1149 if (symbol_conf.use_callchain)
1150 folded_sign = hist_entry__folded(he);
1151
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001152 if (symbol_conf.use_callchain)
1153 printed += fprintf(fp, "%c ", folded_sign);
1154
Namhyung Kim26d8b332014-03-03 16:16:20 +09001155 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001156 if (perf_hpp__should_skip(fmt))
1157 continue;
1158
Namhyung Kim26d8b332014-03-03 16:16:20 +09001159 if (!first) {
1160 ret = scnprintf(hpp.buf, hpp.size, " ");
1161 advance_hpp(&hpp, ret);
1162 } else
1163 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001164
Namhyung Kim26d8b332014-03-03 16:16:20 +09001165 ret = fmt->entry(fmt, &hpp, he);
1166 advance_hpp(&hpp, ret);
1167 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001168 printed += fprintf(fp, "%s\n", rtrim(s));
1169
1170 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001171 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001172
1173 return printed;
1174}
1175
1176static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1177{
Namhyung Kim064f1982013-05-14 11:09:04 +09001178 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001179 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001180 int printed = 0;
1181
1182 while (nd) {
1183 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1184
1185 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001186 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001187 }
1188
1189 return printed;
1190}
1191
1192static int hist_browser__dump(struct hist_browser *browser)
1193{
1194 char filename[64];
1195 FILE *fp;
1196
1197 while (1) {
1198 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1199 if (access(filename, F_OK))
1200 break;
1201 /*
1202 * XXX: Just an arbitrary lazy upper limit
1203 */
1204 if (++browser->print_seq == 8192) {
1205 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1206 return -1;
1207 }
1208 }
1209
1210 fp = fopen(filename, "w");
1211 if (fp == NULL) {
1212 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001213 const char *err = strerror_r(errno, bf, sizeof(bf));
1214 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001215 return -1;
1216 }
1217
1218 ++browser->print_seq;
1219 hist_browser__fprintf(browser, fp);
1220 fclose(fp);
1221 ui_helpline__fpush("%s written!", filename);
1222
1223 return 0;
1224}
1225
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001226static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001227 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001228 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001229{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001230 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001231
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001232 if (browser) {
1233 browser->hists = hists;
1234 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001235 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001236 browser->b.seek = ui_browser__hists_seek;
1237 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001238 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001239 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001240 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241 }
1242
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001243 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001244}
1245
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001246static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001247{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001248 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001249}
1250
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001251static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001252{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001253 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001254}
1255
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001256static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001257{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001258 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259}
1260
Taeung Song1e378eb2014-10-07 16:13:15 +09001261/* Check whether the browser is for 'top' or 'report' */
1262static inline bool is_report_browser(void *timer)
1263{
1264 return timer == NULL;
1265}
1266
1267static int hists__browser_title(struct hists *hists,
1268 struct hist_browser_timer *hbt,
1269 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001270{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001271 char unit;
1272 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001273 const struct dso *dso = hists->dso_filter;
1274 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001275 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001276 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1277 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001278 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001279 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001280 char buf[512];
1281 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001282 char ref[30] = " show reference callgraph, ";
1283 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001284
Namhyung Kimf2148332014-01-14 11:52:48 +09001285 if (symbol_conf.filter_relative) {
1286 nr_samples = hists->stats.nr_non_filtered_samples;
1287 nr_events = hists->stats.total_non_filtered_period;
1288 }
1289
Namhyung Kim759ff492013-03-05 14:53:26 +09001290 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001291 struct perf_evsel *pos;
1292
1293 perf_evsel__group_desc(evsel, buf, buflen);
1294 ev_name = buf;
1295
1296 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001297 struct hists *pos_hists = evsel__hists(pos);
1298
Namhyung Kimf2148332014-01-14 11:52:48 +09001299 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001300 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1301 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001302 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001303 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1304 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001305 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001306 }
1307 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001308
Kan Liang9e207dd2015-08-11 06:30:49 -04001309 if (symbol_conf.show_ref_callgraph &&
1310 strstr(ev_name, "call-graph=no"))
1311 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05001312 nr_samples = convert_unit(nr_samples, &unit);
1313 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001314 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1315 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05001316
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001317
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001318 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001319 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001320 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001321 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001322 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001323 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001324 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001325 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001326 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001327 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001328 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001329 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001330 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001331 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001332 if (!is_report_browser(hbt)) {
1333 struct perf_top *top = hbt->arg;
1334
1335 if (top->zero)
1336 printed += scnprintf(bf + printed, size - printed, " [z]");
1337 }
1338
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001339 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001340}
1341
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001342static inline void free_popup_options(char **options, int n)
1343{
1344 int i;
1345
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001346 for (i = 0; i < n; ++i)
1347 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001348}
1349
Feng Tang341487ab2013-02-03 14:38:20 +08001350/*
1351 * Only runtime switching of perf data file will make "input_name" point
1352 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1353 * whether we need to call free() for current "input_name" during the switch.
1354 */
1355static bool is_input_name_malloced = false;
1356
1357static int switch_data_file(void)
1358{
1359 char *pwd, *options[32], *abs_path[32], *tmp;
1360 DIR *pwd_dir;
1361 int nr_options = 0, choice = -1, ret = -1;
1362 struct dirent *dent;
1363
1364 pwd = getenv("PWD");
1365 if (!pwd)
1366 return ret;
1367
1368 pwd_dir = opendir(pwd);
1369 if (!pwd_dir)
1370 return ret;
1371
1372 memset(options, 0, sizeof(options));
1373 memset(options, 0, sizeof(abs_path));
1374
1375 while ((dent = readdir(pwd_dir))) {
1376 char path[PATH_MAX];
1377 u64 magic;
1378 char *name = dent->d_name;
1379 FILE *file;
1380
1381 if (!(dent->d_type == DT_REG))
1382 continue;
1383
1384 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1385
1386 file = fopen(path, "r");
1387 if (!file)
1388 continue;
1389
1390 if (fread(&magic, 1, 8, file) < 8)
1391 goto close_file_and_continue;
1392
1393 if (is_perf_magic(magic)) {
1394 options[nr_options] = strdup(name);
1395 if (!options[nr_options])
1396 goto close_file_and_continue;
1397
1398 abs_path[nr_options] = strdup(path);
1399 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001400 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001401 ui__warning("Can't search all data files due to memory shortage.\n");
1402 fclose(file);
1403 break;
1404 }
1405
1406 nr_options++;
1407 }
1408
1409close_file_and_continue:
1410 fclose(file);
1411 if (nr_options >= 32) {
1412 ui__warning("Too many perf data files in PWD!\n"
1413 "Only the first 32 files will be listed.\n");
1414 break;
1415 }
1416 }
1417 closedir(pwd_dir);
1418
1419 if (nr_options) {
1420 choice = ui__popup_menu(nr_options, options);
1421 if (choice < nr_options && choice >= 0) {
1422 tmp = strdup(abs_path[choice]);
1423 if (tmp) {
1424 if (is_input_name_malloced)
1425 free((void *)input_name);
1426 input_name = tmp;
1427 is_input_name_malloced = true;
1428 ret = 0;
1429 } else
1430 ui__warning("Data switch failed due to memory shortage!\n");
1431 }
1432 }
1433
1434 free_popup_options(options, nr_options);
1435 free_popup_options(abs_path, nr_options);
1436 return ret;
1437}
1438
Namhyung Kimea7cd592015-04-22 16:18:19 +09001439struct popup_action {
1440 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001441 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001442 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001443
1444 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1445};
1446
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001447static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001448do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001449{
1450 struct perf_evsel *evsel;
1451 struct annotation *notes;
1452 struct hist_entry *he;
1453 int err;
1454
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001455 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001456 return 0;
1457
Namhyung Kimea7cd592015-04-22 16:18:19 +09001458 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001459 if (!notes->src)
1460 return 0;
1461
1462 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001463 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001464 he = hist_browser__selected_entry(browser);
1465 /*
1466 * offer option to annotate the other branch source or target
1467 * (if they exists) when returning from annotate
1468 */
1469 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1470 return 1;
1471
1472 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1473 if (err)
1474 ui_browser__handle_resize(&browser->b);
1475 return 0;
1476}
1477
1478static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001479add_annotate_opt(struct hist_browser *browser __maybe_unused,
1480 struct popup_action *act, char **optstr,
1481 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001482{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001483 if (sym == NULL || map->dso->annotate_warned)
1484 return 0;
1485
1486 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1487 return 0;
1488
1489 act->ms.map = map;
1490 act->ms.sym = sym;
1491 act->fn = do_annotate;
1492 return 1;
1493}
1494
1495static int
1496do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1497{
1498 struct thread *thread = act->thread;
1499
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001500 if (browser->hists->thread_filter) {
1501 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1502 perf_hpp__set_elide(HISTC_THREAD, false);
1503 thread__zput(browser->hists->thread_filter);
1504 ui_helpline__pop();
1505 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001506 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001507 thread->comm_set ? thread__comm_str(thread) : "",
1508 thread->tid);
1509 browser->hists->thread_filter = thread__get(thread);
1510 perf_hpp__set_elide(HISTC_THREAD, false);
1511 pstack__push(browser->pstack, &browser->hists->thread_filter);
1512 }
1513
1514 hists__filter_by_thread(browser->hists);
1515 hist_browser__reset(browser);
1516 return 0;
1517}
1518
1519static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001520add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1521 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001522{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001523 if (thread == NULL)
1524 return 0;
1525
1526 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1527 browser->hists->thread_filter ? "out of" : "into",
1528 thread->comm_set ? thread__comm_str(thread) : "",
1529 thread->tid) < 0)
1530 return 0;
1531
1532 act->thread = thread;
1533 act->fn = do_zoom_thread;
1534 return 1;
1535}
1536
1537static int
1538do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1539{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001540 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001541
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001542 if (browser->hists->dso_filter) {
1543 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1544 perf_hpp__set_elide(HISTC_DSO, false);
1545 browser->hists->dso_filter = NULL;
1546 ui_helpline__pop();
1547 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001548 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001549 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001550 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001551 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1552 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001553 perf_hpp__set_elide(HISTC_DSO, true);
1554 pstack__push(browser->pstack, &browser->hists->dso_filter);
1555 }
1556
1557 hists__filter_by_dso(browser->hists);
1558 hist_browser__reset(browser);
1559 return 0;
1560}
1561
1562static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001563add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001564 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001565{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001566 if (map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001567 return 0;
1568
1569 if (asprintf(optstr, "Zoom %s %s DSO",
1570 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001571 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001572 return 0;
1573
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001574 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001575 act->fn = do_zoom_dso;
1576 return 1;
1577}
1578
1579static int
1580do_browse_map(struct hist_browser *browser __maybe_unused,
1581 struct popup_action *act)
1582{
1583 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001584 return 0;
1585}
1586
1587static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001588add_map_opt(struct hist_browser *browser __maybe_unused,
1589 struct popup_action *act, char **optstr, struct map *map)
1590{
1591 if (map == NULL)
1592 return 0;
1593
1594 if (asprintf(optstr, "Browse map details") < 0)
1595 return 0;
1596
1597 act->ms.map = map;
1598 act->fn = do_browse_map;
1599 return 1;
1600}
1601
1602static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001603do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001604 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001605{
1606 char script_opt[64];
1607 memset(script_opt, 0, sizeof(script_opt));
1608
Namhyung Kimea7cd592015-04-22 16:18:19 +09001609 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001610 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001611 thread__comm_str(act->thread));
1612 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001613 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001614 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001615 }
1616
1617 script_browse(script_opt);
1618 return 0;
1619}
1620
1621static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001622add_script_opt(struct hist_browser *browser __maybe_unused,
1623 struct popup_action *act, char **optstr,
1624 struct thread *thread, struct symbol *sym)
1625{
1626 if (thread) {
1627 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1628 thread__comm_str(thread)) < 0)
1629 return 0;
1630 } else if (sym) {
1631 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1632 sym->name) < 0)
1633 return 0;
1634 } else {
1635 if (asprintf(optstr, "Run scripts for all samples") < 0)
1636 return 0;
1637 }
1638
1639 act->thread = thread;
1640 act->ms.sym = sym;
1641 act->fn = do_run_script;
1642 return 1;
1643}
1644
1645static int
1646do_switch_data(struct hist_browser *browser __maybe_unused,
1647 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001648{
1649 if (switch_data_file()) {
1650 ui__warning("Won't switch the data files due to\n"
1651 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001652 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001653 }
1654
1655 return K_SWITCH_INPUT_DATA;
1656}
1657
Namhyung Kimea7cd592015-04-22 16:18:19 +09001658static int
1659add_switch_opt(struct hist_browser *browser,
1660 struct popup_action *act, char **optstr)
1661{
1662 if (!is_report_browser(browser->hbt))
1663 return 0;
1664
1665 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1666 return 0;
1667
1668 act->fn = do_switch_data;
1669 return 1;
1670}
1671
1672static int
1673do_exit_browser(struct hist_browser *browser __maybe_unused,
1674 struct popup_action *act __maybe_unused)
1675{
1676 return 0;
1677}
1678
1679static int
1680add_exit_opt(struct hist_browser *browser __maybe_unused,
1681 struct popup_action *act, char **optstr)
1682{
1683 if (asprintf(optstr, "Exit") < 0)
1684 return 0;
1685
1686 act->fn = do_exit_browser;
1687 return 1;
1688}
1689
Kan Liang84734b02015-09-04 10:45:45 -04001690static int
1691do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1692{
1693 if (browser->hists->socket_filter > -1) {
1694 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1695 browser->hists->socket_filter = -1;
1696 perf_hpp__set_elide(HISTC_SOCKET, false);
1697 } else {
1698 browser->hists->socket_filter = act->socket;
1699 perf_hpp__set_elide(HISTC_SOCKET, true);
1700 pstack__push(browser->pstack, &browser->hists->socket_filter);
1701 }
1702
1703 hists__filter_by_socket(browser->hists);
1704 hist_browser__reset(browser);
1705 return 0;
1706}
1707
1708static int
1709add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1710 char **optstr, int socket_id)
1711{
1712 if (socket_id < 0)
1713 return 0;
1714
1715 if (asprintf(optstr, "Zoom %s Processor Socket %d",
1716 (browser->hists->socket_filter > -1) ? "out of" : "into",
1717 socket_id) < 0)
1718 return 0;
1719
1720 act->socket = socket_id;
1721 act->fn = do_zoom_socket;
1722 return 1;
1723}
1724
Namhyung Kim112f7612014-04-22 14:05:35 +09001725static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001726{
1727 u64 nr_entries = 0;
1728 struct rb_node *nd = rb_first(&hb->hists->entries);
1729
Namhyung Kim268397c2014-04-22 14:49:31 +09001730 if (hb->min_pcnt == 0) {
1731 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1732 return;
1733 }
1734
Namhyung Kim14135662013-10-31 10:17:39 +09001735 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001736 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001737 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001738 }
1739
Namhyung Kim112f7612014-04-22 14:05:35 +09001740 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001741}
Feng Tang341487ab2013-02-03 14:38:20 +08001742
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001743static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001744 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001745 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001746 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001747 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001748 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001749{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001750 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001751 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001752 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001753#define MAX_OPTIONS 16
1754 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09001755 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001756 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001758 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001759 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001760 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761
Namhyung Kime8e684a2013-12-26 14:37:58 +09001762#define HIST_BROWSER_HELP_COMMON \
1763 "h/?/F1 Show this window\n" \
1764 "UP/DOWN/PGUP\n" \
1765 "PGDN/SPACE Navigate\n" \
1766 "q/ESC/CTRL+C Exit browser\n\n" \
1767 "For multiple event sessions:\n\n" \
1768 "TAB/UNTAB Switch events\n\n" \
1769 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001770 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
1771 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001772 "a Annotate current symbol\n" \
1773 "C Collapse all callchains\n" \
1774 "d Zoom into current DSO\n" \
1775 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001776 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001777 "H Display column headers\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09001778 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04001779 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001780
1781 /* help messages are sorted by lexical order of the hotkey */
1782 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001783 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001784 "P Print histograms to perf.hist.N\n"
1785 "r Run available scripts\n"
1786 "s Switch to another data file in PWD\n"
1787 "t Zoom into current Thread\n"
1788 "V Verbose (DSO names in callchains, etc)\n"
1789 "/ Filter symbol by name";
1790 const char top_help[] = HIST_BROWSER_HELP_COMMON
1791 "P Print histograms to perf.hist.N\n"
1792 "t Zoom into current Thread\n"
1793 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001794 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001795 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001796 "/ Filter symbol by name";
1797
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001798 if (browser == NULL)
1799 return -1;
1800
Namhyung Kimed426912015-05-29 21:53:44 +09001801 /* reset abort key so that it can get Ctrl-C as a key */
1802 SLang_reset_tty();
1803 SLang_init_tty(0, 0, 0);
1804
Namhyung Kim064f1982013-05-14 11:09:04 +09001805 if (min_pcnt) {
1806 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001807 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001808 }
1809
Kan Liang84734b02015-09-04 10:45:45 -04001810 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001811 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001812 goto out;
1813
1814 ui_helpline__push(helpline);
1815
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001816 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09001817 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001818
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001819 perf_hpp__for_each_format(fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001820 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001821 /*
1822 * This is done just once, and activates the horizontal scrolling
1823 * code in the ui_browser code, it would be better to have a the
1824 * counter in the perf_hpp code, but I couldn't find doing it here
1825 * works, FIXME by setting this in hist_browser__new, for now, be
1826 * clever 8-)
1827 */
1828 ++browser->b.columns;
1829 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001830
Namhyung Kim5b591662014-07-31 14:47:38 +09001831 if (symbol_conf.col_width_list_str)
1832 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1833
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001834 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001835 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001836 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001837 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04001838 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001839
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001840 nr_options = 0;
1841
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03001842 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001843
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001844 if (browser->he_selection != NULL) {
1845 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001846 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04001847 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001848 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001849 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001850 case K_TAB:
1851 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001852 if (nr_events == 1)
1853 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001854 /*
1855 * Exit the browser, let hists__browser_tree
1856 * go to the next or previous
1857 */
1858 goto out_free_stack;
1859 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001860 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001861 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001862 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001863 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001864 continue;
1865 }
1866
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001867 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001868 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001869 browser->selection->map->dso->annotate_warned)
1870 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001871
Namhyung Kimea7cd592015-04-22 16:18:19 +09001872 actions->ms.map = browser->selection->map;
1873 actions->ms.sym = browser->selection->sym;
1874 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001875 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001876 case 'P':
1877 hist_browser__dump(browser);
1878 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001879 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03001880 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001881 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001882 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001883 case 'V':
1884 browser->show_dso = !browser->show_dso;
1885 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001886 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001887 actions->thread = thread;
1888 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001889 continue;
Kan Liang84734b02015-09-04 10:45:45 -04001890 case 'S':
1891 actions->socket = socked_id;
1892 do_zoom_socket(browser, actions);
1893 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001894 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001895 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03001896 "Please enter the name of symbol you want to see.\n"
1897 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09001898 buf, "ENTER: OK, ESC: Cancel",
1899 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001900 hists->symbol_filter_str = *buf ? buf : NULL;
1901 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001902 hist_browser__reset(browser);
1903 }
1904 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001905 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001906 if (is_report_browser(hbt)) {
1907 actions->thread = NULL;
1908 actions->ms.sym = NULL;
1909 do_run_script(browser, actions);
1910 }
Feng Tangc77d8d72012-11-01 00:00:55 +08001911 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001912 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001913 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001914 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001915 if (key == K_SWITCH_INPUT_DATA)
1916 goto out_free_stack;
1917 }
Feng Tang341487ab2013-02-03 14:38:20 +08001918 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001919 case 'i':
1920 /* env->arch is NULL for live-mode (i.e. perf top) */
1921 if (env->arch)
1922 tui__header_window(env);
1923 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001924 case 'F':
1925 symbol_conf.filter_relative ^= 1;
1926 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001927 case 'z':
1928 if (!is_report_browser(hbt)) {
1929 struct perf_top *top = hbt->arg;
1930
1931 top->zero = !top->zero;
1932 }
1933 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001934 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001935 case 'h':
1936 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001937 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001938 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001939 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001940 case K_ENTER:
1941 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09001942 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001943 /* menu */
1944 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03001945 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001946 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001947 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001948
Namhyung Kim01f00a12015-04-22 16:18:16 +09001949 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001950 /*
1951 * Go back to the perf_evsel_menu__run or other user
1952 */
1953 if (left_exits)
1954 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03001955
1956 if (key == K_ESC &&
1957 ui_browser__dialog_yesno(&browser->b,
1958 "Do you really want to exit?"))
1959 goto out_free_stack;
1960
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001961 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001962 }
Namhyung Kim64221842015-04-24 10:15:33 +09001963 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001964 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001965 /*
1966 * No need to set actions->dso here since
1967 * it's just to remove the current filter.
1968 * Ditto for thread below.
1969 */
1970 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04001971 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001972 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04001973 } else if (top == &browser->hists->socket_filter) {
1974 do_zoom_socket(browser, actions);
1975 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001976 continue;
1977 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001978 case 'q':
1979 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03001980 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001981 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09001982 if (!is_report_browser(hbt)) {
1983 struct perf_top *top = hbt->arg;
1984
1985 perf_evlist__toggle_enable(top->evlist);
1986 /*
1987 * No need to refresh, resort/decay histogram
1988 * entries if we are not collecting samples:
1989 */
1990 if (top->evlist->enabled) {
1991 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
1992 hbt->refresh = delay_secs;
1993 } else {
1994 helpline = "Press 'f' again to re-enable the events";
1995 hbt->refresh = 0;
1996 }
1997 continue;
1998 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03001999 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002000 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002001 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002002 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002003 }
2004
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002005 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002006 goto add_exit_option;
2007
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002008 if (browser->selection == NULL)
2009 goto skip_annotation;
2010
Namhyung Kim55369fc2013-04-01 20:35:20 +09002011 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002012 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002013
2014 if (bi == NULL)
2015 goto skip_annotation;
2016
Namhyung Kimea7cd592015-04-22 16:18:19 +09002017 nr_options += add_annotate_opt(browser,
2018 &actions[nr_options],
2019 &options[nr_options],
2020 bi->from.map,
2021 bi->from.sym);
2022 if (bi->to.sym != bi->from.sym)
2023 nr_options += add_annotate_opt(browser,
2024 &actions[nr_options],
2025 &options[nr_options],
2026 bi->to.map,
2027 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002028 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002029 nr_options += add_annotate_opt(browser,
2030 &actions[nr_options],
2031 &options[nr_options],
2032 browser->selection->map,
2033 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002034 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002035skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002036 nr_options += add_thread_opt(browser, &actions[nr_options],
2037 &options[nr_options], thread);
2038 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002039 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002040 nr_options += add_map_opt(browser, &actions[nr_options],
2041 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002042 browser->selection ?
2043 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002044 nr_options += add_socket_opt(browser, &actions[nr_options],
2045 &options[nr_options],
2046 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002047 /* perf script support */
2048 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002049 nr_options += add_script_opt(browser,
2050 &actions[nr_options],
2051 &options[nr_options],
2052 thread, NULL);
Wang Nanbd315aa2015-09-14 10:23:55 +00002053 /*
2054 * Note that browser->selection != NULL
2055 * when browser->he_selection is not NULL,
2056 * so we don't need to check browser->selection
2057 * before fetching browser->selection->sym like what
2058 * we do before fetching browser->selection->map.
2059 *
2060 * See hist_browser__show_entry.
2061 */
Namhyung Kimea7cd592015-04-22 16:18:19 +09002062 nr_options += add_script_opt(browser,
2063 &actions[nr_options],
2064 &options[nr_options],
2065 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002066 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002067 nr_options += add_script_opt(browser, &actions[nr_options],
2068 &options[nr_options], NULL, NULL);
2069 nr_options += add_switch_opt(browser, &actions[nr_options],
2070 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002071add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002072 nr_options += add_exit_opt(browser, &actions[nr_options],
2073 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002074
Namhyung Kimea7cd592015-04-22 16:18:19 +09002075 do {
2076 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002077
Namhyung Kimea7cd592015-04-22 16:18:19 +09002078 choice = ui__popup_menu(nr_options, options);
2079 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002080 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002081
2082 act = &actions[choice];
2083 key = act->fn(browser, act);
2084 } while (key == 1);
2085
2086 if (key == K_SWITCH_INPUT_DATA)
2087 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002088 }
2089out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002090 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002091out:
2092 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002093 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002094 return key;
2095}
2096
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002097struct perf_evsel_menu {
2098 struct ui_browser b;
2099 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002100 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002101 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002102 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002103};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002104
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002105static void perf_evsel_menu__write(struct ui_browser *browser,
2106 void *entry, int row)
2107{
2108 struct perf_evsel_menu *menu = container_of(browser,
2109 struct perf_evsel_menu, b);
2110 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002111 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002112 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002113 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002114 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002115 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002116 const char *warn = " ";
2117 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002118
2119 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2120 HE_COLORSET_NORMAL);
2121
Namhyung Kim759ff492013-03-05 14:53:26 +09002122 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002123 struct perf_evsel *pos;
2124
2125 ev_name = perf_evsel__group_name(evsel);
2126
2127 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002128 struct hists *pos_hists = evsel__hists(pos);
2129 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002130 }
2131 }
2132
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002133 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002134 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002135 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002136 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002137
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002138 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002139 if (nr_events != 0) {
2140 menu->lost_events = true;
2141 if (!current_entry)
2142 ui_browser__set_color(browser, HE_COLORSET_TOP);
2143 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002144 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2145 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002146 warn = bf;
2147 }
2148
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002149 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002150
2151 if (current_entry)
2152 menu->selection = evsel;
2153}
2154
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002155static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2156 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002157 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002158{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002159 struct perf_evlist *evlist = menu->b.priv;
2160 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002161 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002162 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002163 int key;
2164
2165 if (ui_browser__show(&menu->b, title,
2166 "ESC: exit, ENTER|->: Browse histograms") < 0)
2167 return -1;
2168
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002169 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002170 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002171
2172 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002173 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002174 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002175
2176 if (!menu->lost_events_warned && menu->lost_events) {
2177 ui_browser__warn_lost_events(&menu->b);
2178 menu->lost_events_warned = true;
2179 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002180 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002181 case K_RIGHT:
2182 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002183 if (!menu->selection)
2184 continue;
2185 pos = menu->selection;
2186browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002187 perf_evlist__set_selected(evlist, pos);
2188 /*
2189 * Give the calling tool a chance to populate the non
2190 * default evsel resorted hists tree.
2191 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002192 if (hbt)
2193 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002194 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002195 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002196 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002197 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002198 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002199 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002200 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002201 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002202 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002203 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002204 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002205 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002206 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002207 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002208 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002209 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002210 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002211 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002212 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002213 case 'q':
2214 case CTRL('c'):
2215 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002216 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002217 default:
2218 continue;
2219 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002220 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002221 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002222 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002223 if (!ui_browser__dialog_yesno(&menu->b,
2224 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002225 continue;
2226 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002227 case 'q':
2228 case CTRL('c'):
2229 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002230 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002231 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002232 }
2233 }
2234
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002235out:
2236 ui_browser__hide(&menu->b);
2237 return key;
2238}
2239
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002240static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002241 void *entry)
2242{
2243 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2244
2245 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2246 return true;
2247
2248 return false;
2249}
2250
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002251static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002252 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002253 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002254 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002255 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002256{
2257 struct perf_evsel *pos;
2258 struct perf_evsel_menu menu = {
2259 .b = {
2260 .entries = &evlist->entries,
2261 .refresh = ui_browser__list_head_refresh,
2262 .seek = ui_browser__list_head_seek,
2263 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002264 .filter = filter_group_entries,
2265 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002266 .priv = evlist,
2267 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002268 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002269 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002270 };
2271
2272 ui_helpline__push("Press ESC to exit");
2273
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002274 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002275 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002276 size_t line_len = strlen(ev_name) + 7;
2277
2278 if (menu.b.width < line_len)
2279 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002280 }
2281
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002282 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002283}
2284
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002285int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002286 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002287 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002288 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002289{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002290 int nr_entries = evlist->nr_entries;
2291
2292single_entry:
2293 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002294 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002295
2296 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002297 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002298 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002299 }
2300
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002301 if (symbol_conf.event_group) {
2302 struct perf_evsel *pos;
2303
2304 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002305 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002306 if (perf_evsel__is_group_leader(pos))
2307 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002308 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002309
2310 if (nr_entries == 1)
2311 goto single_entry;
2312 }
2313
2314 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002315 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002316}