blob: a4e9b370c0370ab32c8f52880add491ed5de16ba [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 Melod1b4f242010-08-10 15:49:07 -0300787
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300788 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900789
Jiri Olsa12400052012-10-13 00:06:16 +0200790 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +0900791 if (perf_hpp__should_skip(fmt))
792 continue;
793
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900794 if (current_entry && browser->b.navkeypressed) {
795 ui_browser__set_color(&browser->b,
796 HE_COLORSET_SELECTED);
797 } else {
798 ui_browser__set_color(&browser->b,
799 HE_COLORSET_NORMAL);
800 }
801
802 if (first) {
803 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300804 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900805 width -= 2;
806 }
807 first = false;
808 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300809 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +0900810 width -= 2;
811 }
812
Jiri Olsa12400052012-10-13 00:06:16 +0200813 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100814 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900815 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100816 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300817 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900818 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300819 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200820
821 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300822 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200823 width += 1;
824
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300825 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +0900826
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300827 ++row;
828 ++printed;
829 } else
830 --row_offset;
831
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300832 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900833 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900834 struct callchain_print_arg arg = {
835 .row_offset = row_offset,
836 .is_current_entry = current_entry,
837 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900838
Namhyung Kim4087d112014-11-24 17:13:26 +0900839 if (callchain_param.mode == CHAIN_GRAPH_REL) {
840 if (symbol_conf.cumulate_callchain)
841 total = entry->stat_acc->period;
842 else
843 total = entry->stat.period;
844 }
845
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900846 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900847 &entry->sorted_chain, 1, row, total,
848 hist_browser__show_callchain_entry, &arg,
849 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900850
Namhyung Kim39ee5332014-08-22 09:13:21 +0900851 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300852 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300853 }
854
855 return printed;
856}
857
Jiri Olsa81a888f2014-06-14 15:44:52 +0200858static int advance_hpp_check(struct perf_hpp *hpp, int inc)
859{
860 advance_hpp(hpp, inc);
861 return hpp->size <= 0;
862}
863
864static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
865{
866 struct perf_hpp dummy_hpp = {
867 .buf = buf,
868 .size = size,
869 };
870 struct perf_hpp_fmt *fmt;
871 size_t ret = 0;
872
873 if (symbol_conf.use_callchain) {
874 ret = scnprintf(buf, size, " ");
875 if (advance_hpp_check(&dummy_hpp, ret))
876 return ret;
877 }
878
879 perf_hpp__for_each_format(fmt) {
880 if (perf_hpp__should_skip(fmt))
881 continue;
882
Jiri Olsa81a888f2014-06-14 15:44:52 +0200883 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
884 if (advance_hpp_check(&dummy_hpp, ret))
885 break;
886
887 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
888 if (advance_hpp_check(&dummy_hpp, ret))
889 break;
890 }
891
892 return ret;
893}
894
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200895static void hist_browser__show_headers(struct hist_browser *browser)
896{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200897 char headers[1024];
898
899 hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200900 ui_browser__gotorc(&browser->b, 0, 0);
901 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300902 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200903}
904
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300905static void ui_browser__hists_init_top(struct ui_browser *browser)
906{
907 if (browser->top == NULL) {
908 struct hist_browser *hb;
909
910 hb = container_of(browser, struct hist_browser, b);
911 browser->top = rb_first(&hb->hists->entries);
912 }
913}
914
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300915static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300916{
917 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200918 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300919 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300920 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300921
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200922 if (hb->show_headers) {
923 hist_browser__show_headers(hb);
924 header_offset = 1;
925 }
926
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300927 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300928
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300929 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300930 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900931 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300932
933 if (h->filtered)
934 continue;
935
Namhyung Kim14135662013-10-31 10:17:39 +0900936 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900937 if (percent < hb->min_pcnt)
938 continue;
939
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300940 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300941 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300942 break;
943 }
944
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200945 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300946}
947
Namhyung Kim064f1982013-05-14 11:09:04 +0900948static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900949 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300950{
951 while (nd != NULL) {
952 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900953 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900954
Namhyung Kimc0f15272014-04-16 11:16:33 +0900955 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300956 return nd;
957
958 nd = rb_next(nd);
959 }
960
961 return NULL;
962}
963
Namhyung Kim064f1982013-05-14 11:09:04 +0900964static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900965 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300966{
967 while (nd != NULL) {
968 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900969 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900970
971 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300972 return nd;
973
974 nd = rb_prev(nd);
975 }
976
977 return NULL;
978}
979
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300980static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300981 off_t offset, int whence)
982{
983 struct hist_entry *h;
984 struct rb_node *nd;
985 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +0900986 struct hist_browser *hb;
987
988 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300989
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300990 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -0300991 return;
992
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300993 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300994
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300995 switch (whence) {
996 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +0900997 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +0900998 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300999 break;
1000 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001001 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001002 goto do_offset;
1003 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001004 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001005 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001006 first = false;
1007 break;
1008 default:
1009 return;
1010 }
1011
1012 /*
1013 * Moves not relative to the first visible entry invalidates its
1014 * row_offset:
1015 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001016 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001017 h->row_offset = 0;
1018
1019 /*
1020 * Here we have to check if nd is expanded (+), if it is we can't go
1021 * the next top level hist_entry, instead we must compute an offset of
1022 * what _not_ to show and not change the first visible entry.
1023 *
1024 * This offset increments when we are going from top to bottom and
1025 * decreases when we're going from bottom to top.
1026 *
1027 * As we don't have backpointers to the top level in the callchains
1028 * structure, we need to always print the whole hist_entry callchain,
1029 * skipping the first ones that are before the first visible entry
1030 * and stop when we printed enough lines to fill the screen.
1031 */
1032do_offset:
1033 if (offset > 0) {
1034 do {
1035 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001036 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001037 u16 remaining = h->nr_rows - h->row_offset;
1038 if (offset > remaining) {
1039 offset -= remaining;
1040 h->row_offset = 0;
1041 } else {
1042 h->row_offset += offset;
1043 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001044 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001045 break;
1046 }
1047 }
Namhyung Kim14135662013-10-31 10:17:39 +09001048 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001049 if (nd == NULL)
1050 break;
1051 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001052 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001053 } while (offset != 0);
1054 } else if (offset < 0) {
1055 while (1) {
1056 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001057 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001058 if (first) {
1059 if (-offset > h->row_offset) {
1060 offset += h->row_offset;
1061 h->row_offset = 0;
1062 } else {
1063 h->row_offset += offset;
1064 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001065 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001066 break;
1067 }
1068 } else {
1069 if (-offset > h->nr_rows) {
1070 offset += h->nr_rows;
1071 h->row_offset = 0;
1072 } else {
1073 h->row_offset = h->nr_rows + offset;
1074 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001075 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001076 break;
1077 }
1078 }
1079 }
1080
Namhyung Kim14135662013-10-31 10:17:39 +09001081 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001082 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001083 if (nd == NULL)
1084 break;
1085 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001086 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001087 if (offset == 0) {
1088 /*
1089 * Last unfiltered hist_entry, check if it is
1090 * unfolded, if it is then we should have
1091 * row_offset at its last entry.
1092 */
1093 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001094 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001095 h->row_offset = h->nr_rows;
1096 break;
1097 }
1098 first = false;
1099 }
1100 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001101 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001102 h = rb_entry(nd, struct hist_entry, rb_node);
1103 h->row_offset = 0;
1104 }
1105}
1106
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001107static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001108 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001109{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001110 u64 total = hists__total_period(he->hists);
1111 struct callchain_print_arg arg = {
1112 .fp = fp,
1113 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001114
Namhyung Kim39ee5332014-08-22 09:13:21 +09001115 if (symbol_conf.cumulate_callchain)
1116 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001117
Namhyung Kim39ee5332014-08-22 09:13:21 +09001118 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1119 hist_browser__fprintf_callchain_entry, &arg,
1120 hist_browser__check_dump_full);
1121 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001122}
1123
1124static int hist_browser__fprintf_entry(struct hist_browser *browser,
1125 struct hist_entry *he, FILE *fp)
1126{
1127 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001128 int printed = 0;
1129 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001130 struct perf_hpp hpp = {
1131 .buf = s,
1132 .size = sizeof(s),
1133 };
1134 struct perf_hpp_fmt *fmt;
1135 bool first = true;
1136 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001137
1138 if (symbol_conf.use_callchain)
1139 folded_sign = hist_entry__folded(he);
1140
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001141 if (symbol_conf.use_callchain)
1142 printed += fprintf(fp, "%c ", folded_sign);
1143
Namhyung Kim26d8b332014-03-03 16:16:20 +09001144 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001145 if (perf_hpp__should_skip(fmt))
1146 continue;
1147
Namhyung Kim26d8b332014-03-03 16:16:20 +09001148 if (!first) {
1149 ret = scnprintf(hpp.buf, hpp.size, " ");
1150 advance_hpp(&hpp, ret);
1151 } else
1152 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001153
Namhyung Kim26d8b332014-03-03 16:16:20 +09001154 ret = fmt->entry(fmt, &hpp, he);
1155 advance_hpp(&hpp, ret);
1156 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001157 printed += fprintf(fp, "%s\n", rtrim(s));
1158
1159 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001160 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001161
1162 return printed;
1163}
1164
1165static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1166{
Namhyung Kim064f1982013-05-14 11:09:04 +09001167 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001168 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001169 int printed = 0;
1170
1171 while (nd) {
1172 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1173
1174 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001175 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001176 }
1177
1178 return printed;
1179}
1180
1181static int hist_browser__dump(struct hist_browser *browser)
1182{
1183 char filename[64];
1184 FILE *fp;
1185
1186 while (1) {
1187 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1188 if (access(filename, F_OK))
1189 break;
1190 /*
1191 * XXX: Just an arbitrary lazy upper limit
1192 */
1193 if (++browser->print_seq == 8192) {
1194 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1195 return -1;
1196 }
1197 }
1198
1199 fp = fopen(filename, "w");
1200 if (fp == NULL) {
1201 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001202 const char *err = strerror_r(errno, bf, sizeof(bf));
1203 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001204 return -1;
1205 }
1206
1207 ++browser->print_seq;
1208 hist_browser__fprintf(browser, fp);
1209 fclose(fp);
1210 ui_helpline__fpush("%s written!", filename);
1211
1212 return 0;
1213}
1214
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001215static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001216 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001217 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001219 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001221 if (browser) {
1222 browser->hists = hists;
1223 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001224 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001225 browser->b.seek = ui_browser__hists_seek;
1226 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001227 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001228 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001229 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001230 }
1231
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001232 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001233}
1234
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001235static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001236{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001237 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001238}
1239
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001240static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001242 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001243}
1244
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001245static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001246{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001247 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001248}
1249
Taeung Song1e378eb2014-10-07 16:13:15 +09001250/* Check whether the browser is for 'top' or 'report' */
1251static inline bool is_report_browser(void *timer)
1252{
1253 return timer == NULL;
1254}
1255
1256static int hists__browser_title(struct hists *hists,
1257 struct hist_browser_timer *hbt,
1258 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001260 char unit;
1261 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001262 const struct dso *dso = hists->dso_filter;
1263 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001264 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001265 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1266 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001267 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001268 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001269 char buf[512];
1270 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001271 char ref[30] = " show reference callgraph, ";
1272 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001273
Namhyung Kimf2148332014-01-14 11:52:48 +09001274 if (symbol_conf.filter_relative) {
1275 nr_samples = hists->stats.nr_non_filtered_samples;
1276 nr_events = hists->stats.total_non_filtered_period;
1277 }
1278
Namhyung Kim759ff492013-03-05 14:53:26 +09001279 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001280 struct perf_evsel *pos;
1281
1282 perf_evsel__group_desc(evsel, buf, buflen);
1283 ev_name = buf;
1284
1285 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001286 struct hists *pos_hists = evsel__hists(pos);
1287
Namhyung Kimf2148332014-01-14 11:52:48 +09001288 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001289 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1290 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001291 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001292 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1293 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001294 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001295 }
1296 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001297
Kan Liang9e207dd2015-08-11 06:30:49 -04001298 if (symbol_conf.show_ref_callgraph &&
1299 strstr(ev_name, "call-graph=no"))
1300 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05001301 nr_samples = convert_unit(nr_samples, &unit);
1302 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001303 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1304 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05001305
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001306
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001307 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001308 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001309 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001310 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001311 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001312 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001313 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001314 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001315 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001316 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001317 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001318 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001319 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001320 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001321 if (!is_report_browser(hbt)) {
1322 struct perf_top *top = hbt->arg;
1323
1324 if (top->zero)
1325 printed += scnprintf(bf + printed, size - printed, " [z]");
1326 }
1327
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001328 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001329}
1330
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001331static inline void free_popup_options(char **options, int n)
1332{
1333 int i;
1334
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001335 for (i = 0; i < n; ++i)
1336 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001337}
1338
Feng Tang341487ab2013-02-03 14:38:20 +08001339/*
1340 * Only runtime switching of perf data file will make "input_name" point
1341 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1342 * whether we need to call free() for current "input_name" during the switch.
1343 */
1344static bool is_input_name_malloced = false;
1345
1346static int switch_data_file(void)
1347{
1348 char *pwd, *options[32], *abs_path[32], *tmp;
1349 DIR *pwd_dir;
1350 int nr_options = 0, choice = -1, ret = -1;
1351 struct dirent *dent;
1352
1353 pwd = getenv("PWD");
1354 if (!pwd)
1355 return ret;
1356
1357 pwd_dir = opendir(pwd);
1358 if (!pwd_dir)
1359 return ret;
1360
1361 memset(options, 0, sizeof(options));
1362 memset(options, 0, sizeof(abs_path));
1363
1364 while ((dent = readdir(pwd_dir))) {
1365 char path[PATH_MAX];
1366 u64 magic;
1367 char *name = dent->d_name;
1368 FILE *file;
1369
1370 if (!(dent->d_type == DT_REG))
1371 continue;
1372
1373 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1374
1375 file = fopen(path, "r");
1376 if (!file)
1377 continue;
1378
1379 if (fread(&magic, 1, 8, file) < 8)
1380 goto close_file_and_continue;
1381
1382 if (is_perf_magic(magic)) {
1383 options[nr_options] = strdup(name);
1384 if (!options[nr_options])
1385 goto close_file_and_continue;
1386
1387 abs_path[nr_options] = strdup(path);
1388 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001389 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001390 ui__warning("Can't search all data files due to memory shortage.\n");
1391 fclose(file);
1392 break;
1393 }
1394
1395 nr_options++;
1396 }
1397
1398close_file_and_continue:
1399 fclose(file);
1400 if (nr_options >= 32) {
1401 ui__warning("Too many perf data files in PWD!\n"
1402 "Only the first 32 files will be listed.\n");
1403 break;
1404 }
1405 }
1406 closedir(pwd_dir);
1407
1408 if (nr_options) {
1409 choice = ui__popup_menu(nr_options, options);
1410 if (choice < nr_options && choice >= 0) {
1411 tmp = strdup(abs_path[choice]);
1412 if (tmp) {
1413 if (is_input_name_malloced)
1414 free((void *)input_name);
1415 input_name = tmp;
1416 is_input_name_malloced = true;
1417 ret = 0;
1418 } else
1419 ui__warning("Data switch failed due to memory shortage!\n");
1420 }
1421 }
1422
1423 free_popup_options(options, nr_options);
1424 free_popup_options(abs_path, nr_options);
1425 return ret;
1426}
1427
Namhyung Kimea7cd592015-04-22 16:18:19 +09001428struct popup_action {
1429 struct thread *thread;
1430 struct dso *dso;
1431 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001432 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001433
1434 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1435};
1436
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001437static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001438do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001439{
1440 struct perf_evsel *evsel;
1441 struct annotation *notes;
1442 struct hist_entry *he;
1443 int err;
1444
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001445 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001446 return 0;
1447
Namhyung Kimea7cd592015-04-22 16:18:19 +09001448 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001449 if (!notes->src)
1450 return 0;
1451
1452 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001453 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001454 he = hist_browser__selected_entry(browser);
1455 /*
1456 * offer option to annotate the other branch source or target
1457 * (if they exists) when returning from annotate
1458 */
1459 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1460 return 1;
1461
1462 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1463 if (err)
1464 ui_browser__handle_resize(&browser->b);
1465 return 0;
1466}
1467
1468static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001469add_annotate_opt(struct hist_browser *browser __maybe_unused,
1470 struct popup_action *act, char **optstr,
1471 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001472{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001473 if (sym == NULL || map->dso->annotate_warned)
1474 return 0;
1475
1476 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1477 return 0;
1478
1479 act->ms.map = map;
1480 act->ms.sym = sym;
1481 act->fn = do_annotate;
1482 return 1;
1483}
1484
1485static int
1486do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1487{
1488 struct thread *thread = act->thread;
1489
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001490 if (browser->hists->thread_filter) {
1491 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1492 perf_hpp__set_elide(HISTC_THREAD, false);
1493 thread__zput(browser->hists->thread_filter);
1494 ui_helpline__pop();
1495 } else {
1496 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1497 thread->comm_set ? thread__comm_str(thread) : "",
1498 thread->tid);
1499 browser->hists->thread_filter = thread__get(thread);
1500 perf_hpp__set_elide(HISTC_THREAD, false);
1501 pstack__push(browser->pstack, &browser->hists->thread_filter);
1502 }
1503
1504 hists__filter_by_thread(browser->hists);
1505 hist_browser__reset(browser);
1506 return 0;
1507}
1508
1509static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001510add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1511 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001512{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001513 if (thread == NULL)
1514 return 0;
1515
1516 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1517 browser->hists->thread_filter ? "out of" : "into",
1518 thread->comm_set ? thread__comm_str(thread) : "",
1519 thread->tid) < 0)
1520 return 0;
1521
1522 act->thread = thread;
1523 act->fn = do_zoom_thread;
1524 return 1;
1525}
1526
1527static int
1528do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1529{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001530 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001531
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001532 if (browser->hists->dso_filter) {
1533 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1534 perf_hpp__set_elide(HISTC_DSO, false);
1535 browser->hists->dso_filter = NULL;
1536 ui_helpline__pop();
1537 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001538 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001539 return 0;
1540 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001541 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1542 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001543 perf_hpp__set_elide(HISTC_DSO, true);
1544 pstack__push(browser->pstack, &browser->hists->dso_filter);
1545 }
1546
1547 hists__filter_by_dso(browser->hists);
1548 hist_browser__reset(browser);
1549 return 0;
1550}
1551
1552static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001553add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001554 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001555{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001556 if (map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001557 return 0;
1558
1559 if (asprintf(optstr, "Zoom %s %s DSO",
1560 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001561 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001562 return 0;
1563
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001564 act->ms.map = map;
1565 act->dso = map->dso;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001566 act->fn = do_zoom_dso;
1567 return 1;
1568}
1569
1570static int
1571do_browse_map(struct hist_browser *browser __maybe_unused,
1572 struct popup_action *act)
1573{
1574 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001575 return 0;
1576}
1577
1578static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001579add_map_opt(struct hist_browser *browser __maybe_unused,
1580 struct popup_action *act, char **optstr, struct map *map)
1581{
1582 if (map == NULL)
1583 return 0;
1584
1585 if (asprintf(optstr, "Browse map details") < 0)
1586 return 0;
1587
1588 act->ms.map = map;
1589 act->fn = do_browse_map;
1590 return 1;
1591}
1592
1593static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001594do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001595 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001596{
1597 char script_opt[64];
1598 memset(script_opt, 0, sizeof(script_opt));
1599
Namhyung Kimea7cd592015-04-22 16:18:19 +09001600 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001601 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001602 thread__comm_str(act->thread));
1603 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001604 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001605 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001606 }
1607
1608 script_browse(script_opt);
1609 return 0;
1610}
1611
1612static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001613add_script_opt(struct hist_browser *browser __maybe_unused,
1614 struct popup_action *act, char **optstr,
1615 struct thread *thread, struct symbol *sym)
1616{
1617 if (thread) {
1618 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1619 thread__comm_str(thread)) < 0)
1620 return 0;
1621 } else if (sym) {
1622 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1623 sym->name) < 0)
1624 return 0;
1625 } else {
1626 if (asprintf(optstr, "Run scripts for all samples") < 0)
1627 return 0;
1628 }
1629
1630 act->thread = thread;
1631 act->ms.sym = sym;
1632 act->fn = do_run_script;
1633 return 1;
1634}
1635
1636static int
1637do_switch_data(struct hist_browser *browser __maybe_unused,
1638 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001639{
1640 if (switch_data_file()) {
1641 ui__warning("Won't switch the data files due to\n"
1642 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001643 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001644 }
1645
1646 return K_SWITCH_INPUT_DATA;
1647}
1648
Namhyung Kimea7cd592015-04-22 16:18:19 +09001649static int
1650add_switch_opt(struct hist_browser *browser,
1651 struct popup_action *act, char **optstr)
1652{
1653 if (!is_report_browser(browser->hbt))
1654 return 0;
1655
1656 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1657 return 0;
1658
1659 act->fn = do_switch_data;
1660 return 1;
1661}
1662
1663static int
1664do_exit_browser(struct hist_browser *browser __maybe_unused,
1665 struct popup_action *act __maybe_unused)
1666{
1667 return 0;
1668}
1669
1670static int
1671add_exit_opt(struct hist_browser *browser __maybe_unused,
1672 struct popup_action *act, char **optstr)
1673{
1674 if (asprintf(optstr, "Exit") < 0)
1675 return 0;
1676
1677 act->fn = do_exit_browser;
1678 return 1;
1679}
1680
Kan Liang84734b02015-09-04 10:45:45 -04001681static int
1682do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1683{
1684 if (browser->hists->socket_filter > -1) {
1685 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1686 browser->hists->socket_filter = -1;
1687 perf_hpp__set_elide(HISTC_SOCKET, false);
1688 } else {
1689 browser->hists->socket_filter = act->socket;
1690 perf_hpp__set_elide(HISTC_SOCKET, true);
1691 pstack__push(browser->pstack, &browser->hists->socket_filter);
1692 }
1693
1694 hists__filter_by_socket(browser->hists);
1695 hist_browser__reset(browser);
1696 return 0;
1697}
1698
1699static int
1700add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1701 char **optstr, int socket_id)
1702{
1703 if (socket_id < 0)
1704 return 0;
1705
1706 if (asprintf(optstr, "Zoom %s Processor Socket %d",
1707 (browser->hists->socket_filter > -1) ? "out of" : "into",
1708 socket_id) < 0)
1709 return 0;
1710
1711 act->socket = socket_id;
1712 act->fn = do_zoom_socket;
1713 return 1;
1714}
1715
Namhyung Kim112f7612014-04-22 14:05:35 +09001716static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001717{
1718 u64 nr_entries = 0;
1719 struct rb_node *nd = rb_first(&hb->hists->entries);
1720
Namhyung Kim268397c2014-04-22 14:49:31 +09001721 if (hb->min_pcnt == 0) {
1722 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1723 return;
1724 }
1725
Namhyung Kim14135662013-10-31 10:17:39 +09001726 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001727 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001728 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001729 }
1730
Namhyung Kim112f7612014-04-22 14:05:35 +09001731 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001732}
Feng Tang341487ab2013-02-03 14:38:20 +08001733
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001734static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001735 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001736 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001737 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001738 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001739 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001740{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001741 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001742 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001743 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001744#define MAX_OPTIONS 16
1745 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09001746 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001747 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001748 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001749 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001750 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001751 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001752
Namhyung Kime8e684a2013-12-26 14:37:58 +09001753#define HIST_BROWSER_HELP_COMMON \
1754 "h/?/F1 Show this window\n" \
1755 "UP/DOWN/PGUP\n" \
1756 "PGDN/SPACE Navigate\n" \
1757 "q/ESC/CTRL+C Exit browser\n\n" \
1758 "For multiple event sessions:\n\n" \
1759 "TAB/UNTAB Switch events\n\n" \
1760 "For symbolic views (--sort has sym):\n\n" \
1761 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1762 "<- Zoom out\n" \
1763 "a Annotate current symbol\n" \
1764 "C Collapse all callchains\n" \
1765 "d Zoom into current DSO\n" \
1766 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001767 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001768 "H Display column headers\n" \
Kan Liang84734b02015-09-04 10:45:45 -04001769 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001770
1771 /* help messages are sorted by lexical order of the hotkey */
1772 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001773 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001774 "P Print histograms to perf.hist.N\n"
1775 "r Run available scripts\n"
1776 "s Switch to another data file in PWD\n"
1777 "t Zoom into current Thread\n"
1778 "V Verbose (DSO names in callchains, etc)\n"
1779 "/ Filter symbol by name";
1780 const char top_help[] = HIST_BROWSER_HELP_COMMON
1781 "P Print histograms to perf.hist.N\n"
1782 "t Zoom into current Thread\n"
1783 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001784 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001785 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001786 "/ Filter symbol by name";
1787
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001788 if (browser == NULL)
1789 return -1;
1790
Namhyung Kimed426912015-05-29 21:53:44 +09001791 /* reset abort key so that it can get Ctrl-C as a key */
1792 SLang_reset_tty();
1793 SLang_init_tty(0, 0, 0);
1794
Namhyung Kim064f1982013-05-14 11:09:04 +09001795 if (min_pcnt) {
1796 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001797 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001798 }
1799
Kan Liang84734b02015-09-04 10:45:45 -04001800 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001801 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001802 goto out;
1803
1804 ui_helpline__push(helpline);
1805
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001806 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09001807 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001808
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001809 perf_hpp__for_each_format(fmt)
1810 perf_hpp__reset_width(fmt, hists);
1811
Namhyung Kim5b591662014-07-31 14:47:38 +09001812 if (symbol_conf.col_width_list_str)
1813 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1814
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001815 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001816 struct thread *thread = NULL;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001817 struct dso *dso = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001818 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001819 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04001820 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001821
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001822 nr_options = 0;
1823
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03001824 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001825
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001826 if (browser->he_selection != NULL) {
1827 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001828 map = browser->selection->map;
1829 if (map)
1830 dso = map->dso;
Kan Liang84734b02015-09-04 10:45:45 -04001831 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001832 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001833 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001834 case K_TAB:
1835 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001836 if (nr_events == 1)
1837 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001838 /*
1839 * Exit the browser, let hists__browser_tree
1840 * go to the next or previous
1841 */
1842 goto out_free_stack;
1843 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001844 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001845 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001846 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001847 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001848 continue;
1849 }
1850
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001851 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001852 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001853 browser->selection->map->dso->annotate_warned)
1854 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001855
Namhyung Kimea7cd592015-04-22 16:18:19 +09001856 actions->ms.map = browser->selection->map;
1857 actions->ms.sym = browser->selection->sym;
1858 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001859 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001860 case 'P':
1861 hist_browser__dump(browser);
1862 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001863 case 'd':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001864 actions->dso = dso;
1865 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001866 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001867 case 'V':
1868 browser->show_dso = !browser->show_dso;
1869 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001870 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001871 actions->thread = thread;
1872 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001873 continue;
Kan Liang84734b02015-09-04 10:45:45 -04001874 case 'S':
1875 actions->socket = socked_id;
1876 do_zoom_socket(browser, actions);
1877 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001878 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001879 if (ui_browser__input_window("Symbol to show",
1880 "Please enter the name of symbol you want to see",
1881 buf, "ENTER: OK, ESC: Cancel",
1882 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001883 hists->symbol_filter_str = *buf ? buf : NULL;
1884 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001885 hist_browser__reset(browser);
1886 }
1887 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001888 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001889 if (is_report_browser(hbt)) {
1890 actions->thread = NULL;
1891 actions->ms.sym = NULL;
1892 do_run_script(browser, actions);
1893 }
Feng Tangc77d8d72012-11-01 00:00:55 +08001894 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001895 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001896 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001897 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001898 if (key == K_SWITCH_INPUT_DATA)
1899 goto out_free_stack;
1900 }
Feng Tang341487ab2013-02-03 14:38:20 +08001901 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001902 case 'i':
1903 /* env->arch is NULL for live-mode (i.e. perf top) */
1904 if (env->arch)
1905 tui__header_window(env);
1906 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001907 case 'F':
1908 symbol_conf.filter_relative ^= 1;
1909 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001910 case 'z':
1911 if (!is_report_browser(hbt)) {
1912 struct perf_top *top = hbt->arg;
1913
1914 top->zero = !top->zero;
1915 }
1916 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001917 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001918 case 'h':
1919 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001920 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001921 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001922 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001923 case K_ENTER:
1924 case K_RIGHT:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001925 /* menu */
1926 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03001927 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001928 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001929 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001930
Namhyung Kim01f00a12015-04-22 16:18:16 +09001931 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001932 /*
1933 * Go back to the perf_evsel_menu__run or other user
1934 */
1935 if (left_exits)
1936 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03001937
1938 if (key == K_ESC &&
1939 ui_browser__dialog_yesno(&browser->b,
1940 "Do you really want to exit?"))
1941 goto out_free_stack;
1942
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001943 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001944 }
Namhyung Kim64221842015-04-24 10:15:33 +09001945 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001946 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001947 /*
1948 * No need to set actions->dso here since
1949 * it's just to remove the current filter.
1950 * Ditto for thread below.
1951 */
1952 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04001953 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001954 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04001955 } else if (top == &browser->hists->socket_filter) {
1956 do_zoom_socket(browser, actions);
1957 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001958 continue;
1959 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001960 case 'q':
1961 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03001962 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001963 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09001964 if (!is_report_browser(hbt)) {
1965 struct perf_top *top = hbt->arg;
1966
1967 perf_evlist__toggle_enable(top->evlist);
1968 /*
1969 * No need to refresh, resort/decay histogram
1970 * entries if we are not collecting samples:
1971 */
1972 if (top->evlist->enabled) {
1973 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
1974 hbt->refresh = delay_secs;
1975 } else {
1976 helpline = "Press 'f' again to re-enable the events";
1977 hbt->refresh = 0;
1978 }
1979 continue;
1980 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03001981 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001982 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03001983 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001984 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001985 }
1986
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001987 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03001988 goto add_exit_option;
1989
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001990 if (browser->selection == NULL)
1991 goto skip_annotation;
1992
Namhyung Kim55369fc2013-04-01 20:35:20 +09001993 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001994 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03001995
1996 if (bi == NULL)
1997 goto skip_annotation;
1998
Namhyung Kimea7cd592015-04-22 16:18:19 +09001999 nr_options += add_annotate_opt(browser,
2000 &actions[nr_options],
2001 &options[nr_options],
2002 bi->from.map,
2003 bi->from.sym);
2004 if (bi->to.sym != bi->from.sym)
2005 nr_options += add_annotate_opt(browser,
2006 &actions[nr_options],
2007 &options[nr_options],
2008 bi->to.map,
2009 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002010 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002011 nr_options += add_annotate_opt(browser,
2012 &actions[nr_options],
2013 &options[nr_options],
2014 browser->selection->map,
2015 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002016 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002017skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002018 nr_options += add_thread_opt(browser, &actions[nr_options],
2019 &options[nr_options], thread);
2020 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002021 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002022 nr_options += add_map_opt(browser, &actions[nr_options],
2023 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002024 browser->selection ?
2025 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002026 nr_options += add_socket_opt(browser, &actions[nr_options],
2027 &options[nr_options],
2028 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002029 /* perf script support */
2030 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002031 nr_options += add_script_opt(browser,
2032 &actions[nr_options],
2033 &options[nr_options],
2034 thread, NULL);
Wang Nanbd315aa2015-09-14 10:23:55 +00002035 /*
2036 * Note that browser->selection != NULL
2037 * when browser->he_selection is not NULL,
2038 * so we don't need to check browser->selection
2039 * before fetching browser->selection->sym like what
2040 * we do before fetching browser->selection->map.
2041 *
2042 * See hist_browser__show_entry.
2043 */
Namhyung Kimea7cd592015-04-22 16:18:19 +09002044 nr_options += add_script_opt(browser,
2045 &actions[nr_options],
2046 &options[nr_options],
2047 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002048 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002049 nr_options += add_script_opt(browser, &actions[nr_options],
2050 &options[nr_options], NULL, NULL);
2051 nr_options += add_switch_opt(browser, &actions[nr_options],
2052 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002053add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002054 nr_options += add_exit_opt(browser, &actions[nr_options],
2055 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002056
Namhyung Kimea7cd592015-04-22 16:18:19 +09002057 do {
2058 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002059
Namhyung Kimea7cd592015-04-22 16:18:19 +09002060 choice = ui__popup_menu(nr_options, options);
2061 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002062 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002063
2064 act = &actions[choice];
2065 key = act->fn(browser, act);
2066 } while (key == 1);
2067
2068 if (key == K_SWITCH_INPUT_DATA)
2069 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002070 }
2071out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002072 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002073out:
2074 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002075 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002076 return key;
2077}
2078
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002079struct perf_evsel_menu {
2080 struct ui_browser b;
2081 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002082 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002083 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002084 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002085};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002086
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002087static void perf_evsel_menu__write(struct ui_browser *browser,
2088 void *entry, int row)
2089{
2090 struct perf_evsel_menu *menu = container_of(browser,
2091 struct perf_evsel_menu, b);
2092 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002093 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002094 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002095 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002096 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002097 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002098 const char *warn = " ";
2099 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002100
2101 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2102 HE_COLORSET_NORMAL);
2103
Namhyung Kim759ff492013-03-05 14:53:26 +09002104 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002105 struct perf_evsel *pos;
2106
2107 ev_name = perf_evsel__group_name(evsel);
2108
2109 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002110 struct hists *pos_hists = evsel__hists(pos);
2111 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002112 }
2113 }
2114
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002115 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002116 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002117 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002118 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002119
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002120 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002121 if (nr_events != 0) {
2122 menu->lost_events = true;
2123 if (!current_entry)
2124 ui_browser__set_color(browser, HE_COLORSET_TOP);
2125 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002126 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2127 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002128 warn = bf;
2129 }
2130
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002131 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002132
2133 if (current_entry)
2134 menu->selection = evsel;
2135}
2136
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002137static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2138 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002139 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002140{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002141 struct perf_evlist *evlist = menu->b.priv;
2142 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002143 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002144 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002145 int key;
2146
2147 if (ui_browser__show(&menu->b, title,
2148 "ESC: exit, ENTER|->: Browse histograms") < 0)
2149 return -1;
2150
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002151 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002152 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002153
2154 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002155 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002156 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002157
2158 if (!menu->lost_events_warned && menu->lost_events) {
2159 ui_browser__warn_lost_events(&menu->b);
2160 menu->lost_events_warned = true;
2161 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002162 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002163 case K_RIGHT:
2164 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002165 if (!menu->selection)
2166 continue;
2167 pos = menu->selection;
2168browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002169 perf_evlist__set_selected(evlist, pos);
2170 /*
2171 * Give the calling tool a chance to populate the non
2172 * default evsel resorted hists tree.
2173 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002174 if (hbt)
2175 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002176 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002177 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002178 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002179 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002180 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002181 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002182 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002183 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002184 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002185 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002186 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002187 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002188 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002189 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002190 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002191 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002192 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002193 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002194 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002195 case 'q':
2196 case CTRL('c'):
2197 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002198 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002199 default:
2200 continue;
2201 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002202 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002203 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002204 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002205 if (!ui_browser__dialog_yesno(&menu->b,
2206 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002207 continue;
2208 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002209 case 'q':
2210 case CTRL('c'):
2211 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002212 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002213 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002214 }
2215 }
2216
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002217out:
2218 ui_browser__hide(&menu->b);
2219 return key;
2220}
2221
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002222static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002223 void *entry)
2224{
2225 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2226
2227 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2228 return true;
2229
2230 return false;
2231}
2232
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002233static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002234 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002235 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002236 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002237 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002238{
2239 struct perf_evsel *pos;
2240 struct perf_evsel_menu menu = {
2241 .b = {
2242 .entries = &evlist->entries,
2243 .refresh = ui_browser__list_head_refresh,
2244 .seek = ui_browser__list_head_seek,
2245 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002246 .filter = filter_group_entries,
2247 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002248 .priv = evlist,
2249 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002250 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002251 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002252 };
2253
2254 ui_helpline__push("Press ESC to exit");
2255
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002256 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002257 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002258 size_t line_len = strlen(ev_name) + 7;
2259
2260 if (menu.b.width < line_len)
2261 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002262 }
2263
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002264 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002265}
2266
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002267int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002268 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002269 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002270 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002271{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002272 int nr_entries = evlist->nr_entries;
2273
2274single_entry:
2275 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002276 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002277
2278 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002279 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002280 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002281 }
2282
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002283 if (symbol_conf.event_group) {
2284 struct perf_evsel *pos;
2285
2286 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002287 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002288 if (perf_evsel__is_group_leader(pos))
2289 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002290 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002291
2292 if (nr_entries == 1)
2293 goto single_entry;
2294 }
2295
2296 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002297 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002298}