blob: 84c8251f39a1f3ada8600286738f168eb369b8f1 [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
Namhyung Kim3698dab2015-05-05 23:55:46 +0900301 if (ms == &he->ms)
302 has_children = hist_entry__toggle_fold(he);
303 else
304 has_children = callchain_list__toggle_fold(cl);
305
306 if (has_children) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300307 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900308 browser->b.nr_entries -= he->nr_rows;
309 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300310
Namhyung Kim3698dab2015-05-05 23:55:46 +0900311 if (he->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300312 he->nr_rows = callchain__count_rows(&he->sorted_chain);
313 else
314 he->nr_rows = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900315
316 browser->b.nr_entries += he->nr_rows;
317 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300318
319 return true;
320 }
321
322 /* If it doesn't have children, no toggling performed */
323 return false;
324}
325
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300326static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300327{
328 int n = 0;
329 struct rb_node *nd;
330
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300331 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300332 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
333 struct callchain_list *chain;
334 bool has_children = false;
335
336 list_for_each_entry(chain, &child->val, list) {
337 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900338 callchain_list__set_folding(chain, unfold);
339 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300340 }
341
342 if (has_children)
343 n += callchain_node__set_folding_rb_tree(child, unfold);
344 }
345
346 return n;
347}
348
349static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
350{
351 struct callchain_list *chain;
352 bool has_children = false;
353 int n = 0;
354
355 list_for_each_entry(chain, &node->val, list) {
356 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900357 callchain_list__set_folding(chain, unfold);
358 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300359 }
360
361 if (has_children)
362 n += callchain_node__set_folding_rb_tree(node, unfold);
363
364 return n;
365}
366
367static int callchain__set_folding(struct rb_root *chain, bool unfold)
368{
369 struct rb_node *nd;
370 int n = 0;
371
372 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
373 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
374 n += callchain_node__set_folding(node, unfold);
375 }
376
377 return n;
378}
379
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300380static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300381{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300382 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900383 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300384
Namhyung Kim3698dab2015-05-05 23:55:46 +0900385 if (he->has_children) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300386 int n = callchain__set_folding(&he->sorted_chain, unfold);
387 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300388 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300389 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300390}
391
Namhyung Kimc3b78952014-04-22 15:56:17 +0900392static void
393__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300394{
395 struct rb_node *nd;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900396 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300397
Namhyung Kimc3b78952014-04-22 15:56:17 +0900398 for (nd = rb_first(&hists->entries);
Namhyung Kim14135662013-10-31 10:17:39 +0900399 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900400 nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300401 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
402 hist_entry__set_folding(he, unfold);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900403 browser->nr_callchain_rows += he->nr_rows;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300404 }
405}
406
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300407static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300408{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900409 browser->nr_callchain_rows = 0;
410 __hist_browser__set_folding(browser, unfold);
411
412 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300413 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300414 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300415}
416
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200417static void ui_browser__warn_lost_events(struct ui_browser *browser)
418{
419 ui_browser__warning(browser, 4,
420 "Events are being lost, check IO/CPU overload!\n\n"
421 "You may want to run 'perf' using a RT scheduler policy:\n\n"
422 " perf top -r 80\n\n"
423 "Or reduce the sampling frequency.");
424}
425
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300426static int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300427{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300428 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300429 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900430 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900431 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300432
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300433 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900434 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300435
Taeung Song1e378eb2014-10-07 16:13:15 +0900436 hists__browser_title(browser->hists, hbt, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300437
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -0300438 if (ui_browser__show(&browser->b, title, help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300439 return -1;
440
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300441 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300442 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300443
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300444 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900445 case K_TIMER: {
446 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900447 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900448
Namhyung Kimc3b78952014-04-22 15:56:17 +0900449 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900450 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900451
Namhyung Kimc3b78952014-04-22 15:56:17 +0900452 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900453 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200454
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300455 if (browser->hists->stats.nr_lost_warned !=
456 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
457 browser->hists->stats.nr_lost_warned =
458 browser->hists->stats.nr_events[PERF_RECORD_LOST];
459 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200460 }
461
Taeung Song1e378eb2014-10-07 16:13:15 +0900462 hists__browser_title(browser->hists,
463 hbt, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300464 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300465 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900466 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300467 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300468 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300469 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300470 struct hist_entry, rb_node);
471 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300472 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 -0300473 seq++, browser->b.nr_entries,
474 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300475 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300476 browser->b.index,
477 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300478 h->row_offset, h->nr_rows);
479 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300480 break;
481 case 'C':
482 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300483 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300484 break;
485 case 'E':
486 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300487 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300488 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200489 case 'H':
490 browser->show_headers = !browser->show_headers;
491 hist_browser__update_rows(browser);
492 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200493 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300494 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300495 break;
496 /* fall thru */
497 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300498 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300499 }
500 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300501out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300502 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300503 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300504}
505
Namhyung Kim39ee5332014-08-22 09:13:21 +0900506struct callchain_print_arg {
507 /* for hists browser */
508 off_t row_offset;
509 bool is_current_entry;
510
511 /* for file dump */
512 FILE *fp;
513 int printed;
514};
515
516typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
517 struct callchain_list *chain,
518 const char *str, int offset,
519 unsigned short row,
520 struct callchain_print_arg *arg);
521
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900522static void hist_browser__show_callchain_entry(struct hist_browser *browser,
523 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900524 const char *str, int offset,
525 unsigned short row,
526 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900527{
528 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900529 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300530 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900531
532 color = HE_COLORSET_NORMAL;
533 width = browser->b.width - (offset + 2);
534 if (ui_browser__is_current_entry(&browser->b, row)) {
535 browser->selection = &chain->ms;
536 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900537 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900538 }
539
540 ui_browser__set_color(&browser->b, color);
541 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300542 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300543 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300544 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300545 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900546}
547
Namhyung Kim39ee5332014-08-22 09:13:21 +0900548static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
549 struct callchain_list *chain,
550 const char *str, int offset,
551 unsigned short row __maybe_unused,
552 struct callchain_print_arg *arg)
553{
554 char folded_sign = callchain_list__folded(chain);
555
556 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
557 folded_sign, str);
558}
559
560typedef bool (*check_output_full_fn)(struct hist_browser *browser,
561 unsigned short row);
562
563static bool hist_browser__check_output_full(struct hist_browser *browser,
564 unsigned short row)
565{
566 return browser->b.rows == row;
567}
568
569static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
570 unsigned short row __maybe_unused)
571{
572 return false;
573}
574
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300575#define LEVEL_OFFSET_STEP 3
576
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900577static int hist_browser__show_callchain(struct hist_browser *browser,
578 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900579 unsigned short row, u64 total,
580 print_callchain_entry_fn print,
581 struct callchain_print_arg *arg,
582 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300583{
584 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900585 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900586 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900587 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300588
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900589 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900590 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900591
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592 while (node) {
593 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
594 struct rb_node *next = rb_next(node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100595 u64 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300596 struct callchain_list *chain;
597 char folded_sign = ' ';
598 int first = true;
599 int extra_offset = 0;
600
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300601 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300602 char bf[1024], *alloc_str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300603 const char *str;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300604 bool was_first = first;
605
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300606 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300607 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900608 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300609 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300610
611 folded_sign = callchain_list__folded(chain);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900612 if (arg->row_offset != 0) {
613 arg->row_offset--;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300614 goto do_next;
615 }
616
617 alloc_str = NULL;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -0300618 str = callchain_list__sym_name(chain, bf, sizeof(bf),
619 browser->show_dso);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900620
Namhyung Kim4087d112014-11-24 17:13:26 +0900621 if (was_first && need_percent) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900622 double percent = cumul * 100.0 / total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300623
624 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
625 str = "Not enough memory!";
626 else
627 str = alloc_str;
628 }
629
Namhyung Kim39ee5332014-08-22 09:13:21 +0900630 print(browser, chain, str, offset + extra_offset, row, arg);
631
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300632 free(alloc_str);
633
Namhyung Kim39ee5332014-08-22 09:13:21 +0900634 if (is_output_full(browser, ++row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300635 goto out;
636do_next:
637 if (folded_sign == '+')
638 break;
639 }
640
641 if (folded_sign == '-') {
642 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900643
644 if (callchain_param.mode == CHAIN_GRAPH_REL)
645 new_total = child->children_hit;
646 else
647 new_total = total;
648
649 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900650 new_level, row, new_total,
651 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300652 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900653 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900654 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300655 node = next;
656 }
657out:
658 return row - first_row;
659}
660
Namhyung Kim89701462013-01-22 18:09:38 +0900661struct hpp_arg {
662 struct ui_browser *b;
663 char folded_sign;
664 bool current_entry;
665};
666
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900667static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
668{
669 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd675107c2014-07-31 14:47:36 +0900670 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900671 va_list args;
672 double percent;
673
674 va_start(args, fmt);
Namhyung Kimd675107c2014-07-31 14:47:36 +0900675 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900676 percent = va_arg(args, double);
677 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900678
Namhyung Kim89701462013-01-22 18:09:38 +0900679 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900680
Namhyung Kimd675107c2014-07-31 14:47:36 +0900681 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300682 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +0900683
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900684 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900685 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900686}
687
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900688#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900689static u64 __hpp_get_##_field(struct hist_entry *he) \
690{ \
691 return he->stat._field; \
692} \
693 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100694static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900695hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100696 struct perf_hpp *hpp, \
697 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900698{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900699 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
700 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900701}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900702
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900703#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
704static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
705{ \
706 return he->stat_acc->_field; \
707} \
708 \
709static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900710hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900711 struct perf_hpp *hpp, \
712 struct hist_entry *he) \
713{ \
714 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300715 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +0900716 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd675107c2014-07-31 14:47:36 +0900717 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900718 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300719 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900720 \
721 return ret; \
722 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900723 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
724 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900725}
726
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900727__HPP_COLOR_PERCENT_FN(overhead, period)
728__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
729__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
730__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
731__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900732__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900733
734#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900735#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900736
737void hist_browser__init_hpp(void)
738{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900739 perf_hpp__format[PERF_HPP__OVERHEAD].color =
740 hist_browser__hpp_color_overhead;
741 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
742 hist_browser__hpp_color_overhead_sys;
743 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
744 hist_browser__hpp_color_overhead_us;
745 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
746 hist_browser__hpp_color_overhead_guest_sys;
747 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
748 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900749 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
750 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900751}
752
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300753static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300754 struct hist_entry *entry,
755 unsigned short row)
756{
757 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200758 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900759 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300760 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300761 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300762 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300763 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200764 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300765
766 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300767 browser->he_selection = entry;
768 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300769 }
770
771 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300772 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300773 folded_sign = hist_entry__folded(entry);
774 }
775
776 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900777 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900778 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900779 .folded_sign = folded_sign,
780 .current_entry = current_entry,
781 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900782 struct perf_hpp hpp = {
783 .buf = s,
784 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900785 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900786 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300787 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300788
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300789 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900790
Jiri Olsa12400052012-10-13 00:06:16 +0200791 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300792 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +0900793 continue;
794
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900795 if (current_entry && browser->b.navkeypressed) {
796 ui_browser__set_color(&browser->b,
797 HE_COLORSET_SELECTED);
798 } else {
799 ui_browser__set_color(&browser->b,
800 HE_COLORSET_NORMAL);
801 }
802
803 if (first) {
804 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300805 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900806 width -= 2;
807 }
808 first = false;
809 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300810 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +0900811 width -= 2;
812 }
813
Jiri Olsa12400052012-10-13 00:06:16 +0200814 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100815 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900816 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100817 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300818 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900819 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300820 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200821
822 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300823 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200824 width += 1;
825
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300826 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +0900827
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300828 ++row;
829 ++printed;
830 } else
831 --row_offset;
832
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300833 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900834 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900835 struct callchain_print_arg arg = {
836 .row_offset = row_offset,
837 .is_current_entry = current_entry,
838 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900839
Namhyung Kim4087d112014-11-24 17:13:26 +0900840 if (callchain_param.mode == CHAIN_GRAPH_REL) {
841 if (symbol_conf.cumulate_callchain)
842 total = entry->stat_acc->period;
843 else
844 total = entry->stat.period;
845 }
846
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900847 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900848 &entry->sorted_chain, 1, row, total,
849 hist_browser__show_callchain_entry, &arg,
850 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900851
Namhyung Kim39ee5332014-08-22 09:13:21 +0900852 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300853 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300854 }
855
856 return printed;
857}
858
Jiri Olsa81a888f2014-06-14 15:44:52 +0200859static int advance_hpp_check(struct perf_hpp *hpp, int inc)
860{
861 advance_hpp(hpp, inc);
862 return hpp->size <= 0;
863}
864
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300865static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +0200866{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300867 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +0200868 struct perf_hpp dummy_hpp = {
869 .buf = buf,
870 .size = size,
871 };
872 struct perf_hpp_fmt *fmt;
873 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300874 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +0200875
876 if (symbol_conf.use_callchain) {
877 ret = scnprintf(buf, size, " ");
878 if (advance_hpp_check(&dummy_hpp, ret))
879 return ret;
880 }
881
882 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300883 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +0200884 continue;
885
Jiri Olsa81a888f2014-06-14 15:44:52 +0200886 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
887 if (advance_hpp_check(&dummy_hpp, ret))
888 break;
889
890 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
891 if (advance_hpp_check(&dummy_hpp, ret))
892 break;
893 }
894
895 return ret;
896}
897
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200898static void hist_browser__show_headers(struct hist_browser *browser)
899{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200900 char headers[1024];
901
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300902 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200903 ui_browser__gotorc(&browser->b, 0, 0);
904 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300905 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200906}
907
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300908static void ui_browser__hists_init_top(struct ui_browser *browser)
909{
910 if (browser->top == NULL) {
911 struct hist_browser *hb;
912
913 hb = container_of(browser, struct hist_browser, b);
914 browser->top = rb_first(&hb->hists->entries);
915 }
916}
917
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300918static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300919{
920 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200921 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300922 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300923 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300924
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200925 if (hb->show_headers) {
926 hist_browser__show_headers(hb);
927 header_offset = 1;
928 }
929
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300930 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +0000931 hb->he_selection = NULL;
932 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300933
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300934 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300935 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900936 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300937
938 if (h->filtered)
939 continue;
940
Namhyung Kim14135662013-10-31 10:17:39 +0900941 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900942 if (percent < hb->min_pcnt)
943 continue;
944
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300945 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300946 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300947 break;
948 }
949
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200950 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300951}
952
Namhyung Kim064f1982013-05-14 11:09:04 +0900953static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900954 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300955{
956 while (nd != NULL) {
957 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900958 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900959
Namhyung Kimc0f15272014-04-16 11:16:33 +0900960 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300961 return nd;
962
963 nd = rb_next(nd);
964 }
965
966 return NULL;
967}
968
Namhyung Kim064f1982013-05-14 11:09:04 +0900969static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900970 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300971{
972 while (nd != NULL) {
973 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900974 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900975
976 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300977 return nd;
978
979 nd = rb_prev(nd);
980 }
981
982 return NULL;
983}
984
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300985static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300986 off_t offset, int whence)
987{
988 struct hist_entry *h;
989 struct rb_node *nd;
990 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900991 struct hist_browser *hb;
992
993 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300994
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300995 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300996 return;
997
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300998 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300999
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001000 switch (whence) {
1001 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001002 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001003 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001004 break;
1005 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001006 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001007 goto do_offset;
1008 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001009 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001010 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001011 first = false;
1012 break;
1013 default:
1014 return;
1015 }
1016
1017 /*
1018 * Moves not relative to the first visible entry invalidates its
1019 * row_offset:
1020 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001021 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001022 h->row_offset = 0;
1023
1024 /*
1025 * Here we have to check if nd is expanded (+), if it is we can't go
1026 * the next top level hist_entry, instead we must compute an offset of
1027 * what _not_ to show and not change the first visible entry.
1028 *
1029 * This offset increments when we are going from top to bottom and
1030 * decreases when we're going from bottom to top.
1031 *
1032 * As we don't have backpointers to the top level in the callchains
1033 * structure, we need to always print the whole hist_entry callchain,
1034 * skipping the first ones that are before the first visible entry
1035 * and stop when we printed enough lines to fill the screen.
1036 */
1037do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001038 if (!nd)
1039 return;
1040
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001041 if (offset > 0) {
1042 do {
1043 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001044 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001045 u16 remaining = h->nr_rows - h->row_offset;
1046 if (offset > remaining) {
1047 offset -= remaining;
1048 h->row_offset = 0;
1049 } else {
1050 h->row_offset += offset;
1051 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001052 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001053 break;
1054 }
1055 }
Namhyung Kim14135662013-10-31 10:17:39 +09001056 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001057 if (nd == NULL)
1058 break;
1059 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001060 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001061 } while (offset != 0);
1062 } else if (offset < 0) {
1063 while (1) {
1064 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001065 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001066 if (first) {
1067 if (-offset > h->row_offset) {
1068 offset += h->row_offset;
1069 h->row_offset = 0;
1070 } else {
1071 h->row_offset += offset;
1072 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001073 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001074 break;
1075 }
1076 } else {
1077 if (-offset > h->nr_rows) {
1078 offset += h->nr_rows;
1079 h->row_offset = 0;
1080 } else {
1081 h->row_offset = h->nr_rows + offset;
1082 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001083 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001084 break;
1085 }
1086 }
1087 }
1088
Namhyung Kim14135662013-10-31 10:17:39 +09001089 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001090 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001091 if (nd == NULL)
1092 break;
1093 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001094 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001095 if (offset == 0) {
1096 /*
1097 * Last unfiltered hist_entry, check if it is
1098 * unfolded, if it is then we should have
1099 * row_offset at its last entry.
1100 */
1101 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001102 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001103 h->row_offset = h->nr_rows;
1104 break;
1105 }
1106 first = false;
1107 }
1108 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001109 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001110 h = rb_entry(nd, struct hist_entry, rb_node);
1111 h->row_offset = 0;
1112 }
1113}
1114
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001115static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001116 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001117{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001118 u64 total = hists__total_period(he->hists);
1119 struct callchain_print_arg arg = {
1120 .fp = fp,
1121 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001122
Namhyung Kim39ee5332014-08-22 09:13:21 +09001123 if (symbol_conf.cumulate_callchain)
1124 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001125
Namhyung Kim39ee5332014-08-22 09:13:21 +09001126 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1127 hist_browser__fprintf_callchain_entry, &arg,
1128 hist_browser__check_dump_full);
1129 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001130}
1131
1132static int hist_browser__fprintf_entry(struct hist_browser *browser,
1133 struct hist_entry *he, FILE *fp)
1134{
1135 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001136 int printed = 0;
1137 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001138 struct perf_hpp hpp = {
1139 .buf = s,
1140 .size = sizeof(s),
1141 };
1142 struct perf_hpp_fmt *fmt;
1143 bool first = true;
1144 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001145
1146 if (symbol_conf.use_callchain)
1147 folded_sign = hist_entry__folded(he);
1148
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001149 if (symbol_conf.use_callchain)
1150 printed += fprintf(fp, "%c ", folded_sign);
1151
Namhyung Kim26d8b332014-03-03 16:16:20 +09001152 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001153 if (perf_hpp__should_skip(fmt))
1154 continue;
1155
Namhyung Kim26d8b332014-03-03 16:16:20 +09001156 if (!first) {
1157 ret = scnprintf(hpp.buf, hpp.size, " ");
1158 advance_hpp(&hpp, ret);
1159 } else
1160 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001161
Namhyung Kim26d8b332014-03-03 16:16:20 +09001162 ret = fmt->entry(fmt, &hpp, he);
1163 advance_hpp(&hpp, ret);
1164 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001165 printed += fprintf(fp, "%s\n", rtrim(s));
1166
1167 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001168 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001169
1170 return printed;
1171}
1172
1173static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1174{
Namhyung Kim064f1982013-05-14 11:09:04 +09001175 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001176 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001177 int printed = 0;
1178
1179 while (nd) {
1180 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1181
1182 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001183 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001184 }
1185
1186 return printed;
1187}
1188
1189static int hist_browser__dump(struct hist_browser *browser)
1190{
1191 char filename[64];
1192 FILE *fp;
1193
1194 while (1) {
1195 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1196 if (access(filename, F_OK))
1197 break;
1198 /*
1199 * XXX: Just an arbitrary lazy upper limit
1200 */
1201 if (++browser->print_seq == 8192) {
1202 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1203 return -1;
1204 }
1205 }
1206
1207 fp = fopen(filename, "w");
1208 if (fp == NULL) {
1209 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001210 const char *err = strerror_r(errno, bf, sizeof(bf));
1211 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001212 return -1;
1213 }
1214
1215 ++browser->print_seq;
1216 hist_browser__fprintf(browser, fp);
1217 fclose(fp);
1218 ui_helpline__fpush("%s written!", filename);
1219
1220 return 0;
1221}
1222
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001223static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001224 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001225 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001226{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001227 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001228
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001229 if (browser) {
1230 browser->hists = hists;
1231 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001232 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001233 browser->b.seek = ui_browser__hists_seek;
1234 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001235 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001236 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001237 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001238 }
1239
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001240 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241}
1242
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001243static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001244{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001245 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001246}
1247
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001248static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001249{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001250 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001251}
1252
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001253static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001254{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001255 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001256}
1257
Taeung Song1e378eb2014-10-07 16:13:15 +09001258/* Check whether the browser is for 'top' or 'report' */
1259static inline bool is_report_browser(void *timer)
1260{
1261 return timer == NULL;
1262}
1263
1264static int hists__browser_title(struct hists *hists,
1265 struct hist_browser_timer *hbt,
1266 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001267{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001268 char unit;
1269 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001270 const struct dso *dso = hists->dso_filter;
1271 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001272 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001273 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1274 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001275 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001276 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001277 char buf[512];
1278 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001279 char ref[30] = " show reference callgraph, ";
1280 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001281
Namhyung Kimf2148332014-01-14 11:52:48 +09001282 if (symbol_conf.filter_relative) {
1283 nr_samples = hists->stats.nr_non_filtered_samples;
1284 nr_events = hists->stats.total_non_filtered_period;
1285 }
1286
Namhyung Kim759ff492013-03-05 14:53:26 +09001287 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001288 struct perf_evsel *pos;
1289
1290 perf_evsel__group_desc(evsel, buf, buflen);
1291 ev_name = buf;
1292
1293 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001294 struct hists *pos_hists = evsel__hists(pos);
1295
Namhyung Kimf2148332014-01-14 11:52:48 +09001296 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001297 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1298 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001299 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001300 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1301 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001302 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001303 }
1304 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001305
Kan Liang9e207dd2015-08-11 06:30:49 -04001306 if (symbol_conf.show_ref_callgraph &&
1307 strstr(ev_name, "call-graph=no"))
1308 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05001309 nr_samples = convert_unit(nr_samples, &unit);
1310 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001311 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1312 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05001313
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001314
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001315 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001316 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001317 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001318 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001319 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001320 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001321 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001322 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001323 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001324 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001325 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001326 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001327 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001328 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001329 if (!is_report_browser(hbt)) {
1330 struct perf_top *top = hbt->arg;
1331
1332 if (top->zero)
1333 printed += scnprintf(bf + printed, size - printed, " [z]");
1334 }
1335
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001336 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001337}
1338
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001339static inline void free_popup_options(char **options, int n)
1340{
1341 int i;
1342
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001343 for (i = 0; i < n; ++i)
1344 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001345}
1346
Feng Tang341487ab2013-02-03 14:38:20 +08001347/*
1348 * Only runtime switching of perf data file will make "input_name" point
1349 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1350 * whether we need to call free() for current "input_name" during the switch.
1351 */
1352static bool is_input_name_malloced = false;
1353
1354static int switch_data_file(void)
1355{
1356 char *pwd, *options[32], *abs_path[32], *tmp;
1357 DIR *pwd_dir;
1358 int nr_options = 0, choice = -1, ret = -1;
1359 struct dirent *dent;
1360
1361 pwd = getenv("PWD");
1362 if (!pwd)
1363 return ret;
1364
1365 pwd_dir = opendir(pwd);
1366 if (!pwd_dir)
1367 return ret;
1368
1369 memset(options, 0, sizeof(options));
1370 memset(options, 0, sizeof(abs_path));
1371
1372 while ((dent = readdir(pwd_dir))) {
1373 char path[PATH_MAX];
1374 u64 magic;
1375 char *name = dent->d_name;
1376 FILE *file;
1377
1378 if (!(dent->d_type == DT_REG))
1379 continue;
1380
1381 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1382
1383 file = fopen(path, "r");
1384 if (!file)
1385 continue;
1386
1387 if (fread(&magic, 1, 8, file) < 8)
1388 goto close_file_and_continue;
1389
1390 if (is_perf_magic(magic)) {
1391 options[nr_options] = strdup(name);
1392 if (!options[nr_options])
1393 goto close_file_and_continue;
1394
1395 abs_path[nr_options] = strdup(path);
1396 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001397 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001398 ui__warning("Can't search all data files due to memory shortage.\n");
1399 fclose(file);
1400 break;
1401 }
1402
1403 nr_options++;
1404 }
1405
1406close_file_and_continue:
1407 fclose(file);
1408 if (nr_options >= 32) {
1409 ui__warning("Too many perf data files in PWD!\n"
1410 "Only the first 32 files will be listed.\n");
1411 break;
1412 }
1413 }
1414 closedir(pwd_dir);
1415
1416 if (nr_options) {
1417 choice = ui__popup_menu(nr_options, options);
1418 if (choice < nr_options && choice >= 0) {
1419 tmp = strdup(abs_path[choice]);
1420 if (tmp) {
1421 if (is_input_name_malloced)
1422 free((void *)input_name);
1423 input_name = tmp;
1424 is_input_name_malloced = true;
1425 ret = 0;
1426 } else
1427 ui__warning("Data switch failed due to memory shortage!\n");
1428 }
1429 }
1430
1431 free_popup_options(options, nr_options);
1432 free_popup_options(abs_path, nr_options);
1433 return ret;
1434}
1435
Namhyung Kimea7cd592015-04-22 16:18:19 +09001436struct popup_action {
1437 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001438 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001439 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001440
1441 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1442};
1443
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001444static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001445do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001446{
1447 struct perf_evsel *evsel;
1448 struct annotation *notes;
1449 struct hist_entry *he;
1450 int err;
1451
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001452 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001453 return 0;
1454
Namhyung Kimea7cd592015-04-22 16:18:19 +09001455 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001456 if (!notes->src)
1457 return 0;
1458
1459 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001460 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001461 he = hist_browser__selected_entry(browser);
1462 /*
1463 * offer option to annotate the other branch source or target
1464 * (if they exists) when returning from annotate
1465 */
1466 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1467 return 1;
1468
1469 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1470 if (err)
1471 ui_browser__handle_resize(&browser->b);
1472 return 0;
1473}
1474
1475static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001476add_annotate_opt(struct hist_browser *browser __maybe_unused,
1477 struct popup_action *act, char **optstr,
1478 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001479{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001480 if (sym == NULL || map->dso->annotate_warned)
1481 return 0;
1482
1483 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1484 return 0;
1485
1486 act->ms.map = map;
1487 act->ms.sym = sym;
1488 act->fn = do_annotate;
1489 return 1;
1490}
1491
1492static int
1493do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1494{
1495 struct thread *thread = act->thread;
1496
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001497 if (browser->hists->thread_filter) {
1498 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1499 perf_hpp__set_elide(HISTC_THREAD, false);
1500 thread__zput(browser->hists->thread_filter);
1501 ui_helpline__pop();
1502 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001503 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001504 thread->comm_set ? thread__comm_str(thread) : "",
1505 thread->tid);
1506 browser->hists->thread_filter = thread__get(thread);
1507 perf_hpp__set_elide(HISTC_THREAD, false);
1508 pstack__push(browser->pstack, &browser->hists->thread_filter);
1509 }
1510
1511 hists__filter_by_thread(browser->hists);
1512 hist_browser__reset(browser);
1513 return 0;
1514}
1515
1516static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001517add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1518 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001519{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001520 if (thread == NULL)
1521 return 0;
1522
1523 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1524 browser->hists->thread_filter ? "out of" : "into",
1525 thread->comm_set ? thread__comm_str(thread) : "",
1526 thread->tid) < 0)
1527 return 0;
1528
1529 act->thread = thread;
1530 act->fn = do_zoom_thread;
1531 return 1;
1532}
1533
1534static int
1535do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1536{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001537 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001538
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001539 if (browser->hists->dso_filter) {
1540 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1541 perf_hpp__set_elide(HISTC_DSO, false);
1542 browser->hists->dso_filter = NULL;
1543 ui_helpline__pop();
1544 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001545 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001546 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001547 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001548 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1549 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001550 perf_hpp__set_elide(HISTC_DSO, true);
1551 pstack__push(browser->pstack, &browser->hists->dso_filter);
1552 }
1553
1554 hists__filter_by_dso(browser->hists);
1555 hist_browser__reset(browser);
1556 return 0;
1557}
1558
1559static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001560add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001561 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001562{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001563 if (map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001564 return 0;
1565
1566 if (asprintf(optstr, "Zoom %s %s DSO",
1567 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001568 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001569 return 0;
1570
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001571 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001572 act->fn = do_zoom_dso;
1573 return 1;
1574}
1575
1576static int
1577do_browse_map(struct hist_browser *browser __maybe_unused,
1578 struct popup_action *act)
1579{
1580 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001581 return 0;
1582}
1583
1584static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001585add_map_opt(struct hist_browser *browser __maybe_unused,
1586 struct popup_action *act, char **optstr, struct map *map)
1587{
1588 if (map == NULL)
1589 return 0;
1590
1591 if (asprintf(optstr, "Browse map details") < 0)
1592 return 0;
1593
1594 act->ms.map = map;
1595 act->fn = do_browse_map;
1596 return 1;
1597}
1598
1599static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001600do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001601 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001602{
1603 char script_opt[64];
1604 memset(script_opt, 0, sizeof(script_opt));
1605
Namhyung Kimea7cd592015-04-22 16:18:19 +09001606 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001607 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001608 thread__comm_str(act->thread));
1609 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001610 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001611 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001612 }
1613
1614 script_browse(script_opt);
1615 return 0;
1616}
1617
1618static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001619add_script_opt(struct hist_browser *browser __maybe_unused,
1620 struct popup_action *act, char **optstr,
1621 struct thread *thread, struct symbol *sym)
1622{
1623 if (thread) {
1624 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1625 thread__comm_str(thread)) < 0)
1626 return 0;
1627 } else if (sym) {
1628 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1629 sym->name) < 0)
1630 return 0;
1631 } else {
1632 if (asprintf(optstr, "Run scripts for all samples") < 0)
1633 return 0;
1634 }
1635
1636 act->thread = thread;
1637 act->ms.sym = sym;
1638 act->fn = do_run_script;
1639 return 1;
1640}
1641
1642static int
1643do_switch_data(struct hist_browser *browser __maybe_unused,
1644 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001645{
1646 if (switch_data_file()) {
1647 ui__warning("Won't switch the data files due to\n"
1648 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001649 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001650 }
1651
1652 return K_SWITCH_INPUT_DATA;
1653}
1654
Namhyung Kimea7cd592015-04-22 16:18:19 +09001655static int
1656add_switch_opt(struct hist_browser *browser,
1657 struct popup_action *act, char **optstr)
1658{
1659 if (!is_report_browser(browser->hbt))
1660 return 0;
1661
1662 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1663 return 0;
1664
1665 act->fn = do_switch_data;
1666 return 1;
1667}
1668
1669static int
1670do_exit_browser(struct hist_browser *browser __maybe_unused,
1671 struct popup_action *act __maybe_unused)
1672{
1673 return 0;
1674}
1675
1676static int
1677add_exit_opt(struct hist_browser *browser __maybe_unused,
1678 struct popup_action *act, char **optstr)
1679{
1680 if (asprintf(optstr, "Exit") < 0)
1681 return 0;
1682
1683 act->fn = do_exit_browser;
1684 return 1;
1685}
1686
Kan Liang84734b02015-09-04 10:45:45 -04001687static int
1688do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1689{
1690 if (browser->hists->socket_filter > -1) {
1691 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1692 browser->hists->socket_filter = -1;
1693 perf_hpp__set_elide(HISTC_SOCKET, false);
1694 } else {
1695 browser->hists->socket_filter = act->socket;
1696 perf_hpp__set_elide(HISTC_SOCKET, true);
1697 pstack__push(browser->pstack, &browser->hists->socket_filter);
1698 }
1699
1700 hists__filter_by_socket(browser->hists);
1701 hist_browser__reset(browser);
1702 return 0;
1703}
1704
1705static int
1706add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1707 char **optstr, int socket_id)
1708{
1709 if (socket_id < 0)
1710 return 0;
1711
1712 if (asprintf(optstr, "Zoom %s Processor Socket %d",
1713 (browser->hists->socket_filter > -1) ? "out of" : "into",
1714 socket_id) < 0)
1715 return 0;
1716
1717 act->socket = socket_id;
1718 act->fn = do_zoom_socket;
1719 return 1;
1720}
1721
Namhyung Kim112f7612014-04-22 14:05:35 +09001722static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001723{
1724 u64 nr_entries = 0;
1725 struct rb_node *nd = rb_first(&hb->hists->entries);
1726
Namhyung Kim268397c2014-04-22 14:49:31 +09001727 if (hb->min_pcnt == 0) {
1728 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1729 return;
1730 }
1731
Namhyung Kim14135662013-10-31 10:17:39 +09001732 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001733 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001734 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001735 }
1736
Namhyung Kim112f7612014-04-22 14:05:35 +09001737 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001738}
Feng Tang341487ab2013-02-03 14:38:20 +08001739
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001740static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001741 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001742 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001743 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001744 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001745 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001746{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001747 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001748 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001749 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001750#define MAX_OPTIONS 16
1751 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09001752 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001753 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001754 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001755 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001756 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001757 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758
Namhyung Kime8e684a2013-12-26 14:37:58 +09001759#define HIST_BROWSER_HELP_COMMON \
1760 "h/?/F1 Show this window\n" \
1761 "UP/DOWN/PGUP\n" \
1762 "PGDN/SPACE Navigate\n" \
1763 "q/ESC/CTRL+C Exit browser\n\n" \
1764 "For multiple event sessions:\n\n" \
1765 "TAB/UNTAB Switch events\n\n" \
1766 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001767 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
1768 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001769 "a Annotate current symbol\n" \
1770 "C Collapse all callchains\n" \
1771 "d Zoom into current DSO\n" \
1772 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001773 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001774 "H Display column headers\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09001775 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04001776 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001777
1778 /* help messages are sorted by lexical order of the hotkey */
1779 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001780 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001781 "P Print histograms to perf.hist.N\n"
1782 "r Run available scripts\n"
1783 "s Switch to another data file in PWD\n"
1784 "t Zoom into current Thread\n"
1785 "V Verbose (DSO names in callchains, etc)\n"
1786 "/ Filter symbol by name";
1787 const char top_help[] = HIST_BROWSER_HELP_COMMON
1788 "P Print histograms to perf.hist.N\n"
1789 "t Zoom into current Thread\n"
1790 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001791 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001792 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001793 "/ Filter symbol by name";
1794
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001795 if (browser == NULL)
1796 return -1;
1797
Namhyung Kimed426912015-05-29 21:53:44 +09001798 /* reset abort key so that it can get Ctrl-C as a key */
1799 SLang_reset_tty();
1800 SLang_init_tty(0, 0, 0);
1801
Namhyung Kim064f1982013-05-14 11:09:04 +09001802 if (min_pcnt) {
1803 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001804 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001805 }
1806
Kan Liang84734b02015-09-04 10:45:45 -04001807 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001808 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001809 goto out;
1810
1811 ui_helpline__push(helpline);
1812
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001813 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09001814 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001815
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001816 perf_hpp__for_each_format(fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001817 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001818 /*
1819 * This is done just once, and activates the horizontal scrolling
1820 * code in the ui_browser code, it would be better to have a the
1821 * counter in the perf_hpp code, but I couldn't find doing it here
1822 * works, FIXME by setting this in hist_browser__new, for now, be
1823 * clever 8-)
1824 */
1825 ++browser->b.columns;
1826 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001827
Namhyung Kim5b591662014-07-31 14:47:38 +09001828 if (symbol_conf.col_width_list_str)
1829 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1830
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001831 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001832 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001833 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001834 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04001835 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001836
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001837 nr_options = 0;
1838
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03001839 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001840
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001841 if (browser->he_selection != NULL) {
1842 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001843 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04001844 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001845 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001846 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001847 case K_TAB:
1848 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001849 if (nr_events == 1)
1850 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001851 /*
1852 * Exit the browser, let hists__browser_tree
1853 * go to the next or previous
1854 */
1855 goto out_free_stack;
1856 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001857 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001858 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001859 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001860 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001861 continue;
1862 }
1863
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001864 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001865 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001866 browser->selection->map->dso->annotate_warned)
1867 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001868
Namhyung Kimea7cd592015-04-22 16:18:19 +09001869 actions->ms.map = browser->selection->map;
1870 actions->ms.sym = browser->selection->sym;
1871 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001872 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001873 case 'P':
1874 hist_browser__dump(browser);
1875 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001876 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03001877 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001878 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001879 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001880 case 'V':
1881 browser->show_dso = !browser->show_dso;
1882 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001883 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001884 actions->thread = thread;
1885 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001886 continue;
Kan Liang84734b02015-09-04 10:45:45 -04001887 case 'S':
1888 actions->socket = socked_id;
1889 do_zoom_socket(browser, actions);
1890 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001891 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001892 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03001893 "Please enter the name of symbol you want to see.\n"
1894 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09001895 buf, "ENTER: OK, ESC: Cancel",
1896 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001897 hists->symbol_filter_str = *buf ? buf : NULL;
1898 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001899 hist_browser__reset(browser);
1900 }
1901 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001902 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001903 if (is_report_browser(hbt)) {
1904 actions->thread = NULL;
1905 actions->ms.sym = NULL;
1906 do_run_script(browser, actions);
1907 }
Feng Tangc77d8d72012-11-01 00:00:55 +08001908 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001909 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001910 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001911 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001912 if (key == K_SWITCH_INPUT_DATA)
1913 goto out_free_stack;
1914 }
Feng Tang341487ab2013-02-03 14:38:20 +08001915 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001916 case 'i':
1917 /* env->arch is NULL for live-mode (i.e. perf top) */
1918 if (env->arch)
1919 tui__header_window(env);
1920 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001921 case 'F':
1922 symbol_conf.filter_relative ^= 1;
1923 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001924 case 'z':
1925 if (!is_report_browser(hbt)) {
1926 struct perf_top *top = hbt->arg;
1927
1928 top->zero = !top->zero;
1929 }
1930 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001931 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001932 case 'h':
1933 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001934 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001935 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001936 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001937 case K_ENTER:
1938 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09001939 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001940 /* menu */
1941 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03001942 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001943 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001944 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001945
Namhyung Kim01f00a12015-04-22 16:18:16 +09001946 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001947 /*
1948 * Go back to the perf_evsel_menu__run or other user
1949 */
1950 if (left_exits)
1951 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03001952
1953 if (key == K_ESC &&
1954 ui_browser__dialog_yesno(&browser->b,
1955 "Do you really want to exit?"))
1956 goto out_free_stack;
1957
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001958 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001959 }
Namhyung Kim64221842015-04-24 10:15:33 +09001960 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001961 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001962 /*
1963 * No need to set actions->dso here since
1964 * it's just to remove the current filter.
1965 * Ditto for thread below.
1966 */
1967 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04001968 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001969 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04001970 } else if (top == &browser->hists->socket_filter) {
1971 do_zoom_socket(browser, actions);
1972 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001973 continue;
1974 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001975 case 'q':
1976 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03001977 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001978 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09001979 if (!is_report_browser(hbt)) {
1980 struct perf_top *top = hbt->arg;
1981
1982 perf_evlist__toggle_enable(top->evlist);
1983 /*
1984 * No need to refresh, resort/decay histogram
1985 * entries if we are not collecting samples:
1986 */
1987 if (top->evlist->enabled) {
1988 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
1989 hbt->refresh = delay_secs;
1990 } else {
1991 helpline = "Press 'f' again to re-enable the events";
1992 hbt->refresh = 0;
1993 }
1994 continue;
1995 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03001996 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001997 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03001998 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001999 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002000 }
2001
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002002 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002003 goto add_exit_option;
2004
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002005 if (browser->selection == NULL)
2006 goto skip_annotation;
2007
Namhyung Kim55369fc2013-04-01 20:35:20 +09002008 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002009 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002010
2011 if (bi == NULL)
2012 goto skip_annotation;
2013
Namhyung Kimea7cd592015-04-22 16:18:19 +09002014 nr_options += add_annotate_opt(browser,
2015 &actions[nr_options],
2016 &options[nr_options],
2017 bi->from.map,
2018 bi->from.sym);
2019 if (bi->to.sym != bi->from.sym)
2020 nr_options += add_annotate_opt(browser,
2021 &actions[nr_options],
2022 &options[nr_options],
2023 bi->to.map,
2024 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002025 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002026 nr_options += add_annotate_opt(browser,
2027 &actions[nr_options],
2028 &options[nr_options],
2029 browser->selection->map,
2030 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002031 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002032skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002033 nr_options += add_thread_opt(browser, &actions[nr_options],
2034 &options[nr_options], thread);
2035 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002036 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002037 nr_options += add_map_opt(browser, &actions[nr_options],
2038 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002039 browser->selection ?
2040 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002041 nr_options += add_socket_opt(browser, &actions[nr_options],
2042 &options[nr_options],
2043 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002044 /* perf script support */
2045 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002046 nr_options += add_script_opt(browser,
2047 &actions[nr_options],
2048 &options[nr_options],
2049 thread, NULL);
Wang Nanbd315aa2015-09-14 10:23:55 +00002050 /*
2051 * Note that browser->selection != NULL
2052 * when browser->he_selection is not NULL,
2053 * so we don't need to check browser->selection
2054 * before fetching browser->selection->sym like what
2055 * we do before fetching browser->selection->map.
2056 *
2057 * See hist_browser__show_entry.
2058 */
Namhyung Kimea7cd592015-04-22 16:18:19 +09002059 nr_options += add_script_opt(browser,
2060 &actions[nr_options],
2061 &options[nr_options],
2062 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002063 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002064 nr_options += add_script_opt(browser, &actions[nr_options],
2065 &options[nr_options], NULL, NULL);
2066 nr_options += add_switch_opt(browser, &actions[nr_options],
2067 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002068add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002069 nr_options += add_exit_opt(browser, &actions[nr_options],
2070 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002071
Namhyung Kimea7cd592015-04-22 16:18:19 +09002072 do {
2073 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002074
Namhyung Kimea7cd592015-04-22 16:18:19 +09002075 choice = ui__popup_menu(nr_options, options);
2076 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002077 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002078
2079 act = &actions[choice];
2080 key = act->fn(browser, act);
2081 } while (key == 1);
2082
2083 if (key == K_SWITCH_INPUT_DATA)
2084 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002085 }
2086out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002087 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002088out:
2089 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002090 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002091 return key;
2092}
2093
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002094struct perf_evsel_menu {
2095 struct ui_browser b;
2096 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002097 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002098 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002099 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002100};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002101
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002102static void perf_evsel_menu__write(struct ui_browser *browser,
2103 void *entry, int row)
2104{
2105 struct perf_evsel_menu *menu = container_of(browser,
2106 struct perf_evsel_menu, b);
2107 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002108 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002109 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002110 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002111 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002112 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002113 const char *warn = " ";
2114 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002115
2116 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2117 HE_COLORSET_NORMAL);
2118
Namhyung Kim759ff492013-03-05 14:53:26 +09002119 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002120 struct perf_evsel *pos;
2121
2122 ev_name = perf_evsel__group_name(evsel);
2123
2124 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002125 struct hists *pos_hists = evsel__hists(pos);
2126 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002127 }
2128 }
2129
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002130 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002131 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002132 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002133 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002134
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002135 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002136 if (nr_events != 0) {
2137 menu->lost_events = true;
2138 if (!current_entry)
2139 ui_browser__set_color(browser, HE_COLORSET_TOP);
2140 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002141 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2142 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002143 warn = bf;
2144 }
2145
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002146 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002147
2148 if (current_entry)
2149 menu->selection = evsel;
2150}
2151
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002152static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2153 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002154 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002155{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002156 struct perf_evlist *evlist = menu->b.priv;
2157 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002158 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002159 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002160 int key;
2161
2162 if (ui_browser__show(&menu->b, title,
2163 "ESC: exit, ENTER|->: Browse histograms") < 0)
2164 return -1;
2165
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002166 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002167 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002168
2169 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002170 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002171 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002172
2173 if (!menu->lost_events_warned && menu->lost_events) {
2174 ui_browser__warn_lost_events(&menu->b);
2175 menu->lost_events_warned = true;
2176 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002177 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002178 case K_RIGHT:
2179 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002180 if (!menu->selection)
2181 continue;
2182 pos = menu->selection;
2183browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002184 perf_evlist__set_selected(evlist, pos);
2185 /*
2186 * Give the calling tool a chance to populate the non
2187 * default evsel resorted hists tree.
2188 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002189 if (hbt)
2190 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002191 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002192 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002193 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002194 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002195 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002196 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002197 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002198 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002199 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002200 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002201 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002202 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002203 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002204 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002205 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002206 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002207 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002208 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002209 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002210 case 'q':
2211 case CTRL('c'):
2212 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002213 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002214 default:
2215 continue;
2216 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002217 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002218 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002219 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002220 if (!ui_browser__dialog_yesno(&menu->b,
2221 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002222 continue;
2223 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002224 case 'q':
2225 case CTRL('c'):
2226 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002227 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002228 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002229 }
2230 }
2231
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002232out:
2233 ui_browser__hide(&menu->b);
2234 return key;
2235}
2236
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002237static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002238 void *entry)
2239{
2240 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2241
2242 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2243 return true;
2244
2245 return false;
2246}
2247
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002248static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002249 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002250 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002251 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002252 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002253{
2254 struct perf_evsel *pos;
2255 struct perf_evsel_menu menu = {
2256 .b = {
2257 .entries = &evlist->entries,
2258 .refresh = ui_browser__list_head_refresh,
2259 .seek = ui_browser__list_head_seek,
2260 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002261 .filter = filter_group_entries,
2262 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002263 .priv = evlist,
2264 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002265 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002266 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002267 };
2268
2269 ui_helpline__push("Press ESC to exit");
2270
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002271 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002272 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002273 size_t line_len = strlen(ev_name) + 7;
2274
2275 if (menu.b.width < line_len)
2276 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002277 }
2278
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002279 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002280}
2281
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002282int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002283 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002284 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002285 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002286{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002287 int nr_entries = evlist->nr_entries;
2288
2289single_entry:
2290 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002291 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002292
2293 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002294 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002295 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002296 }
2297
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002298 if (symbol_conf.event_group) {
2299 struct perf_evsel *pos;
2300
2301 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002302 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002303 if (perf_evsel__is_group_leader(pos))
2304 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002305 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002306
2307 if (nr_entries == 1)
2308 goto single_entry;
2309 }
2310
2311 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002312 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002313}