blob: 0746d41d9efed7d2a730c087af9597d0ee404518 [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 Kim18bb8382015-11-09 14:45:42 +0900577static int hist_browser__show_callchain_list(struct hist_browser *browser,
578 struct callchain_node *node,
579 struct callchain_list *chain,
580 unsigned short row, u64 total,
581 bool need_percent, int offset,
582 print_callchain_entry_fn print,
583 struct callchain_print_arg *arg)
584{
585 char bf[1024], *alloc_str;
586 const char *str;
587
588 if (arg->row_offset != 0) {
589 arg->row_offset--;
590 return 0;
591 }
592
593 alloc_str = NULL;
594 str = callchain_list__sym_name(chain, bf, sizeof(bf),
595 browser->show_dso);
596
597 if (need_percent) {
598 char buf[64];
599
600 callchain_node__scnprintf_value(node, buf, sizeof(buf),
601 total);
602
603 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
604 str = "Not enough memory!";
605 else
606 str = alloc_str;
607 }
608
609 print(browser, chain, str, offset, row, arg);
610
611 free(alloc_str);
612 return 1;
613}
614
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900615static int hist_browser__show_callchain(struct hist_browser *browser,
616 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900617 unsigned short row, u64 total,
618 print_callchain_entry_fn print,
619 struct callchain_print_arg *arg,
620 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300621{
622 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900623 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim36e15dd2014-08-20 17:07:58 +0900624 u64 new_total;
Namhyung Kim4087d112014-11-24 17:13:26 +0900625 bool need_percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300626
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900627 node = rb_first(root);
Namhyung Kimc09e31c2014-12-24 15:04:36 +0900628 need_percent = node && rb_next(node);
Namhyung Kim4087d112014-11-24 17:13:26 +0900629
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300630 while (node) {
631 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
632 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300633 struct callchain_list *chain;
634 char folded_sign = ' ';
635 int first = true;
636 int extra_offset = 0;
637
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300638 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300639 bool was_first = first;
640
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300641 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300642 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900643 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300644 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300645
646 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300647
Namhyung Kim18bb8382015-11-09 14:45:42 +0900648 row += hist_browser__show_callchain_list(browser, child,
649 chain, row, total,
650 was_first && need_percent,
651 offset + extra_offset,
652 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900653
Namhyung Kim18bb8382015-11-09 14:45:42 +0900654 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300655 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900656
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300657 if (folded_sign == '+')
658 break;
659 }
660
661 if (folded_sign == '-') {
662 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900663
664 if (callchain_param.mode == CHAIN_GRAPH_REL)
665 new_total = child->children_hit;
666 else
667 new_total = total;
668
669 row += hist_browser__show_callchain(browser, &child->rb_root,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900670 new_level, row, new_total,
671 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300672 }
Namhyung Kim39ee5332014-08-22 09:13:21 +0900673 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900674 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300675 node = next;
676 }
677out:
678 return row - first_row;
679}
680
Namhyung Kim89701462013-01-22 18:09:38 +0900681struct hpp_arg {
682 struct ui_browser *b;
683 char folded_sign;
684 bool current_entry;
685};
686
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900687static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
688{
689 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +0900690 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900691 va_list args;
692 double percent;
693
694 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +0900695 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900696 percent = va_arg(args, double);
697 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900698
Namhyung Kim89701462013-01-22 18:09:38 +0900699 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900700
Namhyung Kimd6751072014-07-31 14:47:36 +0900701 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300702 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +0900703
Namhyung Kim2f6d9002014-03-03 10:14:05 +0900704 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900705 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900706}
707
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900708#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900709static u64 __hpp_get_##_field(struct hist_entry *he) \
710{ \
711 return he->stat._field; \
712} \
713 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100714static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900715hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100716 struct perf_hpp *hpp, \
717 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900718{ \
Namhyung Kim5b591662014-07-31 14:47:38 +0900719 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
720 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900721}
Namhyung Kimf5951d52012-09-03 11:53:09 +0900722
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900723#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
724static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
725{ \
726 return he->stat_acc->_field; \
727} \
728 \
729static int \
Namhyung Kim5b591662014-07-31 14:47:38 +0900730hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900731 struct perf_hpp *hpp, \
732 struct hist_entry *he) \
733{ \
734 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300735 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +0900736 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +0900737 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +0900738 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300739 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900740 \
741 return ret; \
742 } \
Namhyung Kim5b591662014-07-31 14:47:38 +0900743 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
744 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900745}
746
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900747__HPP_COLOR_PERCENT_FN(overhead, period)
748__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
749__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
750__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
751__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900752__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +0900753
754#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900755#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +0900756
757void hist_browser__init_hpp(void)
758{
Namhyung Kimf5951d52012-09-03 11:53:09 +0900759 perf_hpp__format[PERF_HPP__OVERHEAD].color =
760 hist_browser__hpp_color_overhead;
761 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
762 hist_browser__hpp_color_overhead_sys;
763 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
764 hist_browser__hpp_color_overhead_us;
765 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
766 hist_browser__hpp_color_overhead_guest_sys;
767 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
768 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +0900769 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
770 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +0900771}
772
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300773static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300774 struct hist_entry *entry,
775 unsigned short row)
776{
777 char s[256];
Jiri Olsa12400052012-10-13 00:06:16 +0200778 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +0900779 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300780 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300781 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300782 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -0300783 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +0200784 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300785
786 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300787 browser->he_selection = entry;
788 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300789 }
790
791 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300792 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300793 folded_sign = hist_entry__folded(entry);
794 }
795
796 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +0900797 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900798 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +0900799 .folded_sign = folded_sign,
800 .current_entry = current_entry,
801 };
Namhyung Kimf5951d52012-09-03 11:53:09 +0900802 struct perf_hpp hpp = {
803 .buf = s,
804 .size = sizeof(s),
Namhyung Kim89701462013-01-22 18:09:38 +0900805 .ptr = &arg,
Namhyung Kimf5951d52012-09-03 11:53:09 +0900806 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300807 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300808
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300809 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900810
Jiri Olsa12400052012-10-13 00:06:16 +0200811 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300812 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +0900813 continue;
814
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900815 if (current_entry && browser->b.navkeypressed) {
816 ui_browser__set_color(&browser->b,
817 HE_COLORSET_SELECTED);
818 } else {
819 ui_browser__set_color(&browser->b,
820 HE_COLORSET_NORMAL);
821 }
822
823 if (first) {
824 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300825 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +0900826 width -= 2;
827 }
828 first = false;
829 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300830 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +0900831 width -= 2;
832 }
833
Jiri Olsa12400052012-10-13 00:06:16 +0200834 if (fmt->color) {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100835 width -= fmt->color(fmt, &hpp, entry);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900836 } else {
Jiri Olsa2c5d4b42013-01-31 23:31:11 +0100837 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300838 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +0900839 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300840 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200841
842 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300843 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200844 width += 1;
845
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300846 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +0900847
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300848 ++row;
849 ++printed;
850 } else
851 --row_offset;
852
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300853 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900854 u64 total = hists__total_period(entry->hists);
Namhyung Kim39ee5332014-08-22 09:13:21 +0900855 struct callchain_print_arg arg = {
856 .row_offset = row_offset,
857 .is_current_entry = current_entry,
858 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900859
Namhyung Kim4087d112014-11-24 17:13:26 +0900860 if (callchain_param.mode == CHAIN_GRAPH_REL) {
861 if (symbol_conf.cumulate_callchain)
862 total = entry->stat_acc->period;
863 else
864 total = entry->stat.period;
865 }
866
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900867 printed += hist_browser__show_callchain(browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900868 &entry->sorted_chain, 1, row, total,
869 hist_browser__show_callchain_entry, &arg,
870 hist_browser__check_output_full);
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900871
Namhyung Kim39ee5332014-08-22 09:13:21 +0900872 if (arg.is_current_entry)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300873 browser->he_selection = entry;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300874 }
875
876 return printed;
877}
878
Jiri Olsa81a888f2014-06-14 15:44:52 +0200879static int advance_hpp_check(struct perf_hpp *hpp, int inc)
880{
881 advance_hpp(hpp, inc);
882 return hpp->size <= 0;
883}
884
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300885static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +0200886{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300887 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +0200888 struct perf_hpp dummy_hpp = {
889 .buf = buf,
890 .size = size,
891 };
892 struct perf_hpp_fmt *fmt;
893 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300894 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +0200895
896 if (symbol_conf.use_callchain) {
897 ret = scnprintf(buf, size, " ");
898 if (advance_hpp_check(&dummy_hpp, ret))
899 return ret;
900 }
901
902 perf_hpp__for_each_format(fmt) {
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300903 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +0200904 continue;
905
Jiri Olsa81a888f2014-06-14 15:44:52 +0200906 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
907 if (advance_hpp_check(&dummy_hpp, ret))
908 break;
909
910 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
911 if (advance_hpp_check(&dummy_hpp, ret))
912 break;
913 }
914
915 return ret;
916}
917
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200918static void hist_browser__show_headers(struct hist_browser *browser)
919{
Jiri Olsa81a888f2014-06-14 15:44:52 +0200920 char headers[1024];
921
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -0300922 hists_browser__scnprintf_headers(browser, headers, sizeof(headers));
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200923 ui_browser__gotorc(&browser->b, 0, 0);
924 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300925 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200926}
927
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -0300928static void ui_browser__hists_init_top(struct ui_browser *browser)
929{
930 if (browser->top == NULL) {
931 struct hist_browser *hb;
932
933 hb = container_of(browser, struct hist_browser, b);
934 browser->top = rb_first(&hb->hists->entries);
935 }
936}
937
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300938static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300939{
940 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200941 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300942 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300943 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300944
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200945 if (hb->show_headers) {
946 hist_browser__show_headers(hb);
947 header_offset = 1;
948 }
949
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300950 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300951
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300952 for (nd = browser->top; nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300953 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900954 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300955
956 if (h->filtered)
957 continue;
958
Namhyung Kim14135662013-10-31 10:17:39 +0900959 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900960 if (percent < hb->min_pcnt)
961 continue;
962
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300963 row += hist_browser__show_entry(hb, h, row);
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300964 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300965 break;
966 }
967
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200968 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300969}
970
Namhyung Kim064f1982013-05-14 11:09:04 +0900971static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900972 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300973{
974 while (nd != NULL) {
975 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900976 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900977
Namhyung Kimc0f15272014-04-16 11:16:33 +0900978 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300979 return nd;
980
981 nd = rb_next(nd);
982 }
983
984 return NULL;
985}
986
Namhyung Kim064f1982013-05-14 11:09:04 +0900987static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +0900988 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300989{
990 while (nd != NULL) {
991 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +0900992 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +0900993
994 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300995 return nd;
996
997 nd = rb_prev(nd);
998 }
999
1000 return NULL;
1001}
1002
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001003static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001004 off_t offset, int whence)
1005{
1006 struct hist_entry *h;
1007 struct rb_node *nd;
1008 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001009 struct hist_browser *hb;
1010
1011 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001012
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001013 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001014 return;
1015
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001016 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001017
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001018 switch (whence) {
1019 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001020 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001021 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001022 break;
1023 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001024 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001025 goto do_offset;
1026 case SEEK_END:
Namhyung Kim064f1982013-05-14 11:09:04 +09001027 nd = hists__filter_prev_entries(rb_last(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001028 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001029 first = false;
1030 break;
1031 default:
1032 return;
1033 }
1034
1035 /*
1036 * Moves not relative to the first visible entry invalidates its
1037 * row_offset:
1038 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001039 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001040 h->row_offset = 0;
1041
1042 /*
1043 * Here we have to check if nd is expanded (+), if it is we can't go
1044 * the next top level hist_entry, instead we must compute an offset of
1045 * what _not_ to show and not change the first visible entry.
1046 *
1047 * This offset increments when we are going from top to bottom and
1048 * decreases when we're going from bottom to top.
1049 *
1050 * As we don't have backpointers to the top level in the callchains
1051 * structure, we need to always print the whole hist_entry callchain,
1052 * skipping the first ones that are before the first visible entry
1053 * and stop when we printed enough lines to fill the screen.
1054 */
1055do_offset:
1056 if (offset > 0) {
1057 do {
1058 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001059 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001060 u16 remaining = h->nr_rows - h->row_offset;
1061 if (offset > remaining) {
1062 offset -= remaining;
1063 h->row_offset = 0;
1064 } else {
1065 h->row_offset += offset;
1066 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001067 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001068 break;
1069 }
1070 }
Namhyung Kim14135662013-10-31 10:17:39 +09001071 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001072 if (nd == NULL)
1073 break;
1074 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001075 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001076 } while (offset != 0);
1077 } else if (offset < 0) {
1078 while (1) {
1079 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001080 if (h->unfolded) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001081 if (first) {
1082 if (-offset > h->row_offset) {
1083 offset += h->row_offset;
1084 h->row_offset = 0;
1085 } else {
1086 h->row_offset += offset;
1087 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001088 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001089 break;
1090 }
1091 } else {
1092 if (-offset > h->nr_rows) {
1093 offset += h->nr_rows;
1094 h->row_offset = 0;
1095 } else {
1096 h->row_offset = h->nr_rows + offset;
1097 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001098 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001099 break;
1100 }
1101 }
1102 }
1103
Namhyung Kim14135662013-10-31 10:17:39 +09001104 nd = hists__filter_prev_entries(rb_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001105 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001106 if (nd == NULL)
1107 break;
1108 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001109 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001110 if (offset == 0) {
1111 /*
1112 * Last unfiltered hist_entry, check if it is
1113 * unfolded, if it is then we should have
1114 * row_offset at its last entry.
1115 */
1116 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim3698dab2015-05-05 23:55:46 +09001117 if (h->unfolded)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001118 h->row_offset = h->nr_rows;
1119 break;
1120 }
1121 first = false;
1122 }
1123 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001124 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001125 h = rb_entry(nd, struct hist_entry, rb_node);
1126 h->row_offset = 0;
1127 }
1128}
1129
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001130static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001131 struct hist_entry *he, FILE *fp)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001132{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001133 u64 total = hists__total_period(he->hists);
1134 struct callchain_print_arg arg = {
1135 .fp = fp,
1136 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001137
Namhyung Kim39ee5332014-08-22 09:13:21 +09001138 if (symbol_conf.cumulate_callchain)
1139 total = he->stat_acc->period;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001140
Namhyung Kim39ee5332014-08-22 09:13:21 +09001141 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1142 hist_browser__fprintf_callchain_entry, &arg,
1143 hist_browser__check_dump_full);
1144 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001145}
1146
1147static int hist_browser__fprintf_entry(struct hist_browser *browser,
1148 struct hist_entry *he, FILE *fp)
1149{
1150 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001151 int printed = 0;
1152 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001153 struct perf_hpp hpp = {
1154 .buf = s,
1155 .size = sizeof(s),
1156 };
1157 struct perf_hpp_fmt *fmt;
1158 bool first = true;
1159 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001160
1161 if (symbol_conf.use_callchain)
1162 folded_sign = hist_entry__folded(he);
1163
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001164 if (symbol_conf.use_callchain)
1165 printed += fprintf(fp, "%c ", folded_sign);
1166
Namhyung Kim26d8b332014-03-03 16:16:20 +09001167 perf_hpp__for_each_format(fmt) {
Namhyung Kime67d49a2014-03-18 13:00:59 +09001168 if (perf_hpp__should_skip(fmt))
1169 continue;
1170
Namhyung Kim26d8b332014-03-03 16:16:20 +09001171 if (!first) {
1172 ret = scnprintf(hpp.buf, hpp.size, " ");
1173 advance_hpp(&hpp, ret);
1174 } else
1175 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001176
Namhyung Kim26d8b332014-03-03 16:16:20 +09001177 ret = fmt->entry(fmt, &hpp, he);
1178 advance_hpp(&hpp, ret);
1179 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001180 printed += fprintf(fp, "%s\n", rtrim(s));
1181
1182 if (folded_sign == '-')
Namhyung Kim39ee5332014-08-22 09:13:21 +09001183 printed += hist_browser__fprintf_callchain(browser, he, fp);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001184
1185 return printed;
1186}
1187
1188static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1189{
Namhyung Kim064f1982013-05-14 11:09:04 +09001190 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001191 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001192 int printed = 0;
1193
1194 while (nd) {
1195 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1196
1197 printed += hist_browser__fprintf_entry(browser, h, fp);
Namhyung Kim14135662013-10-31 10:17:39 +09001198 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001199 }
1200
1201 return printed;
1202}
1203
1204static int hist_browser__dump(struct hist_browser *browser)
1205{
1206 char filename[64];
1207 FILE *fp;
1208
1209 while (1) {
1210 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1211 if (access(filename, F_OK))
1212 break;
1213 /*
1214 * XXX: Just an arbitrary lazy upper limit
1215 */
1216 if (++browser->print_seq == 8192) {
1217 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1218 return -1;
1219 }
1220 }
1221
1222 fp = fopen(filename, "w");
1223 if (fp == NULL) {
1224 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03001225 const char *err = strerror_r(errno, bf, sizeof(bf));
1226 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001227 return -1;
1228 }
1229
1230 ++browser->print_seq;
1231 hist_browser__fprintf(browser, fp);
1232 fclose(fp);
1233 ui_helpline__fpush("%s written!", filename);
1234
1235 return 0;
1236}
1237
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001238static struct hist_browser *hist_browser__new(struct hists *hists,
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001239 struct hist_browser_timer *hbt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001240 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001242 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001243
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001244 if (browser) {
1245 browser->hists = hists;
1246 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03001247 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001248 browser->b.seek = ui_browser__hists_seek;
1249 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02001250 browser->show_headers = symbol_conf.show_hist_headers;
Namhyung Kimc2a51ab2015-04-22 16:18:15 +09001251 browser->hbt = hbt;
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001252 browser->env = env;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253 }
1254
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001255 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001256}
1257
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001258static void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001259{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001260 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001261}
1262
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001263static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001264{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001265 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001266}
1267
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001268static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001269{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001270 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001271}
1272
Taeung Song1e378eb2014-10-07 16:13:15 +09001273/* Check whether the browser is for 'top' or 'report' */
1274static inline bool is_report_browser(void *timer)
1275{
1276 return timer == NULL;
1277}
1278
1279static int hists__browser_title(struct hists *hists,
1280 struct hist_browser_timer *hbt,
1281 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001282{
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001283 char unit;
1284 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001285 const struct dso *dso = hists->dso_filter;
1286 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04001287 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001288 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1289 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09001290 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02001291 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09001292 char buf[512];
1293 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04001294 char ref[30] = " show reference callgraph, ";
1295 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09001296
Namhyung Kimf2148332014-01-14 11:52:48 +09001297 if (symbol_conf.filter_relative) {
1298 nr_samples = hists->stats.nr_non_filtered_samples;
1299 nr_events = hists->stats.total_non_filtered_period;
1300 }
1301
Namhyung Kim759ff492013-03-05 14:53:26 +09001302 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09001303 struct perf_evsel *pos;
1304
1305 perf_evsel__group_desc(evsel, buf, buflen);
1306 ev_name = buf;
1307
1308 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001309 struct hists *pos_hists = evsel__hists(pos);
1310
Namhyung Kimf2148332014-01-14 11:52:48 +09001311 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001312 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1313 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001314 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001315 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1316 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09001317 }
Namhyung Kim717e2632013-01-22 18:09:44 +09001318 }
1319 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001320
Kan Liang9e207dd2015-08-11 06:30:49 -04001321 if (symbol_conf.show_ref_callgraph &&
1322 strstr(ev_name, "call-graph=no"))
1323 enable_ref = true;
Ashay Ranecc686282012-04-05 21:01:01 -05001324 nr_samples = convert_unit(nr_samples, &unit);
1325 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04001326 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
1327 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc686282012-04-05 21:01:01 -05001328
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001329
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001330 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02001331 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001332 ", UID: %s", hists->uid_filter_str);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001333 if (thread)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001334 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001335 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02001336 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03001337 thread->tid);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001338 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03001339 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001340 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04001341 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04001342 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04001343 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09001344 if (!is_report_browser(hbt)) {
1345 struct perf_top *top = hbt->arg;
1346
1347 if (top->zero)
1348 printed += scnprintf(bf + printed, size - printed, " [z]");
1349 }
1350
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03001351 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001352}
1353
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001354static inline void free_popup_options(char **options, int n)
1355{
1356 int i;
1357
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001358 for (i = 0; i < n; ++i)
1359 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001360}
1361
Feng Tang341487ab2013-02-03 14:38:20 +08001362/*
1363 * Only runtime switching of perf data file will make "input_name" point
1364 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1365 * whether we need to call free() for current "input_name" during the switch.
1366 */
1367static bool is_input_name_malloced = false;
1368
1369static int switch_data_file(void)
1370{
1371 char *pwd, *options[32], *abs_path[32], *tmp;
1372 DIR *pwd_dir;
1373 int nr_options = 0, choice = -1, ret = -1;
1374 struct dirent *dent;
1375
1376 pwd = getenv("PWD");
1377 if (!pwd)
1378 return ret;
1379
1380 pwd_dir = opendir(pwd);
1381 if (!pwd_dir)
1382 return ret;
1383
1384 memset(options, 0, sizeof(options));
1385 memset(options, 0, sizeof(abs_path));
1386
1387 while ((dent = readdir(pwd_dir))) {
1388 char path[PATH_MAX];
1389 u64 magic;
1390 char *name = dent->d_name;
1391 FILE *file;
1392
1393 if (!(dent->d_type == DT_REG))
1394 continue;
1395
1396 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1397
1398 file = fopen(path, "r");
1399 if (!file)
1400 continue;
1401
1402 if (fread(&magic, 1, 8, file) < 8)
1403 goto close_file_and_continue;
1404
1405 if (is_perf_magic(magic)) {
1406 options[nr_options] = strdup(name);
1407 if (!options[nr_options])
1408 goto close_file_and_continue;
1409
1410 abs_path[nr_options] = strdup(path);
1411 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001412 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08001413 ui__warning("Can't search all data files due to memory shortage.\n");
1414 fclose(file);
1415 break;
1416 }
1417
1418 nr_options++;
1419 }
1420
1421close_file_and_continue:
1422 fclose(file);
1423 if (nr_options >= 32) {
1424 ui__warning("Too many perf data files in PWD!\n"
1425 "Only the first 32 files will be listed.\n");
1426 break;
1427 }
1428 }
1429 closedir(pwd_dir);
1430
1431 if (nr_options) {
1432 choice = ui__popup_menu(nr_options, options);
1433 if (choice < nr_options && choice >= 0) {
1434 tmp = strdup(abs_path[choice]);
1435 if (tmp) {
1436 if (is_input_name_malloced)
1437 free((void *)input_name);
1438 input_name = tmp;
1439 is_input_name_malloced = true;
1440 ret = 0;
1441 } else
1442 ui__warning("Data switch failed due to memory shortage!\n");
1443 }
1444 }
1445
1446 free_popup_options(options, nr_options);
1447 free_popup_options(abs_path, nr_options);
1448 return ret;
1449}
1450
Namhyung Kimea7cd592015-04-22 16:18:19 +09001451struct popup_action {
1452 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001453 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04001454 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001455
1456 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1457};
1458
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001459static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001460do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001461{
1462 struct perf_evsel *evsel;
1463 struct annotation *notes;
1464 struct hist_entry *he;
1465 int err;
1466
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03001467 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001468 return 0;
1469
Namhyung Kimea7cd592015-04-22 16:18:19 +09001470 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001471 if (!notes->src)
1472 return 0;
1473
1474 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09001475 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001476 he = hist_browser__selected_entry(browser);
1477 /*
1478 * offer option to annotate the other branch source or target
1479 * (if they exists) when returning from annotate
1480 */
1481 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1482 return 1;
1483
1484 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1485 if (err)
1486 ui_browser__handle_resize(&browser->b);
1487 return 0;
1488}
1489
1490static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001491add_annotate_opt(struct hist_browser *browser __maybe_unused,
1492 struct popup_action *act, char **optstr,
1493 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001494{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001495 if (sym == NULL || map->dso->annotate_warned)
1496 return 0;
1497
1498 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1499 return 0;
1500
1501 act->ms.map = map;
1502 act->ms.sym = sym;
1503 act->fn = do_annotate;
1504 return 1;
1505}
1506
1507static int
1508do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1509{
1510 struct thread *thread = act->thread;
1511
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001512 if (browser->hists->thread_filter) {
1513 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1514 perf_hpp__set_elide(HISTC_THREAD, false);
1515 thread__zput(browser->hists->thread_filter);
1516 ui_helpline__pop();
1517 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001518 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001519 thread->comm_set ? thread__comm_str(thread) : "",
1520 thread->tid);
1521 browser->hists->thread_filter = thread__get(thread);
1522 perf_hpp__set_elide(HISTC_THREAD, false);
1523 pstack__push(browser->pstack, &browser->hists->thread_filter);
1524 }
1525
1526 hists__filter_by_thread(browser->hists);
1527 hist_browser__reset(browser);
1528 return 0;
1529}
1530
1531static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001532add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1533 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001534{
Namhyung Kimea7cd592015-04-22 16:18:19 +09001535 if (thread == NULL)
1536 return 0;
1537
1538 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1539 browser->hists->thread_filter ? "out of" : "into",
1540 thread->comm_set ? thread__comm_str(thread) : "",
1541 thread->tid) < 0)
1542 return 0;
1543
1544 act->thread = thread;
1545 act->fn = do_zoom_thread;
1546 return 1;
1547}
1548
1549static int
1550do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1551{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001552 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001553
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001554 if (browser->hists->dso_filter) {
1555 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1556 perf_hpp__set_elide(HISTC_DSO, false);
1557 browser->hists->dso_filter = NULL;
1558 ui_helpline__pop();
1559 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001560 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001561 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001562 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001563 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
1564 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001565 perf_hpp__set_elide(HISTC_DSO, true);
1566 pstack__push(browser->pstack, &browser->hists->dso_filter);
1567 }
1568
1569 hists__filter_by_dso(browser->hists);
1570 hist_browser__reset(browser);
1571 return 0;
1572}
1573
1574static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001575add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001576 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001577{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001578 if (map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001579 return 0;
1580
1581 if (asprintf(optstr, "Zoom %s %s DSO",
1582 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001583 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09001584 return 0;
1585
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001586 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001587 act->fn = do_zoom_dso;
1588 return 1;
1589}
1590
1591static int
1592do_browse_map(struct hist_browser *browser __maybe_unused,
1593 struct popup_action *act)
1594{
1595 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001596 return 0;
1597}
1598
1599static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001600add_map_opt(struct hist_browser *browser __maybe_unused,
1601 struct popup_action *act, char **optstr, struct map *map)
1602{
1603 if (map == NULL)
1604 return 0;
1605
1606 if (asprintf(optstr, "Browse map details") < 0)
1607 return 0;
1608
1609 act->ms.map = map;
1610 act->fn = do_browse_map;
1611 return 1;
1612}
1613
1614static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001615do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09001616 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001617{
1618 char script_opt[64];
1619 memset(script_opt, 0, sizeof(script_opt));
1620
Namhyung Kimea7cd592015-04-22 16:18:19 +09001621 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001622 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001623 thread__comm_str(act->thread));
1624 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001625 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09001626 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001627 }
1628
1629 script_browse(script_opt);
1630 return 0;
1631}
1632
1633static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09001634add_script_opt(struct hist_browser *browser __maybe_unused,
1635 struct popup_action *act, char **optstr,
1636 struct thread *thread, struct symbol *sym)
1637{
1638 if (thread) {
1639 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1640 thread__comm_str(thread)) < 0)
1641 return 0;
1642 } else if (sym) {
1643 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1644 sym->name) < 0)
1645 return 0;
1646 } else {
1647 if (asprintf(optstr, "Run scripts for all samples") < 0)
1648 return 0;
1649 }
1650
1651 act->thread = thread;
1652 act->ms.sym = sym;
1653 act->fn = do_run_script;
1654 return 1;
1655}
1656
1657static int
1658do_switch_data(struct hist_browser *browser __maybe_unused,
1659 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001660{
1661 if (switch_data_file()) {
1662 ui__warning("Won't switch the data files due to\n"
1663 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09001664 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001665 }
1666
1667 return K_SWITCH_INPUT_DATA;
1668}
1669
Namhyung Kimea7cd592015-04-22 16:18:19 +09001670static int
1671add_switch_opt(struct hist_browser *browser,
1672 struct popup_action *act, char **optstr)
1673{
1674 if (!is_report_browser(browser->hbt))
1675 return 0;
1676
1677 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1678 return 0;
1679
1680 act->fn = do_switch_data;
1681 return 1;
1682}
1683
1684static int
1685do_exit_browser(struct hist_browser *browser __maybe_unused,
1686 struct popup_action *act __maybe_unused)
1687{
1688 return 0;
1689}
1690
1691static int
1692add_exit_opt(struct hist_browser *browser __maybe_unused,
1693 struct popup_action *act, char **optstr)
1694{
1695 if (asprintf(optstr, "Exit") < 0)
1696 return 0;
1697
1698 act->fn = do_exit_browser;
1699 return 1;
1700}
1701
Kan Liang84734b02015-09-04 10:45:45 -04001702static int
1703do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1704{
1705 if (browser->hists->socket_filter > -1) {
1706 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1707 browser->hists->socket_filter = -1;
1708 perf_hpp__set_elide(HISTC_SOCKET, false);
1709 } else {
1710 browser->hists->socket_filter = act->socket;
1711 perf_hpp__set_elide(HISTC_SOCKET, true);
1712 pstack__push(browser->pstack, &browser->hists->socket_filter);
1713 }
1714
1715 hists__filter_by_socket(browser->hists);
1716 hist_browser__reset(browser);
1717 return 0;
1718}
1719
1720static int
1721add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1722 char **optstr, int socket_id)
1723{
1724 if (socket_id < 0)
1725 return 0;
1726
1727 if (asprintf(optstr, "Zoom %s Processor Socket %d",
1728 (browser->hists->socket_filter > -1) ? "out of" : "into",
1729 socket_id) < 0)
1730 return 0;
1731
1732 act->socket = socket_id;
1733 act->fn = do_zoom_socket;
1734 return 1;
1735}
1736
Namhyung Kim112f7612014-04-22 14:05:35 +09001737static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09001738{
1739 u64 nr_entries = 0;
1740 struct rb_node *nd = rb_first(&hb->hists->entries);
1741
Namhyung Kim268397c2014-04-22 14:49:31 +09001742 if (hb->min_pcnt == 0) {
1743 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1744 return;
1745 }
1746
Namhyung Kim14135662013-10-31 10:17:39 +09001747 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09001748 nr_entries++;
Namhyung Kimc481f932014-04-22 13:56:11 +09001749 nd = rb_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09001750 }
1751
Namhyung Kim112f7612014-04-22 14:05:35 +09001752 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09001753}
Feng Tang341487ab2013-02-03 14:38:20 +08001754
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03001755static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02001756 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03001757 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09001758 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09001759 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04001760 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001762 struct hists *hists = evsel__hists(evsel);
Namhyung Kimb1a9cee2015-04-22 16:18:17 +09001763 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001764 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09001765#define MAX_OPTIONS 16
1766 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09001767 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001768 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09001770 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09001771 int delay_secs = hbt ? hbt->refresh : 0;
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001772 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001773
Namhyung Kime8e684a2013-12-26 14:37:58 +09001774#define HIST_BROWSER_HELP_COMMON \
1775 "h/?/F1 Show this window\n" \
1776 "UP/DOWN/PGUP\n" \
1777 "PGDN/SPACE Navigate\n" \
1778 "q/ESC/CTRL+C Exit browser\n\n" \
1779 "For multiple event sessions:\n\n" \
1780 "TAB/UNTAB Switch events\n\n" \
1781 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03001782 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
1783 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001784 "a Annotate current symbol\n" \
1785 "C Collapse all callchains\n" \
1786 "d Zoom into current DSO\n" \
1787 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09001788 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001789 "H Display column headers\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09001790 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04001791 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09001792
1793 /* help messages are sorted by lexical order of the hotkey */
1794 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09001795 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001796 "P Print histograms to perf.hist.N\n"
1797 "r Run available scripts\n"
1798 "s Switch to another data file in PWD\n"
1799 "t Zoom into current Thread\n"
1800 "V Verbose (DSO names in callchains, etc)\n"
1801 "/ Filter symbol by name";
1802 const char top_help[] = HIST_BROWSER_HELP_COMMON
1803 "P Print histograms to perf.hist.N\n"
1804 "t Zoom into current Thread\n"
1805 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09001806 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001807 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09001808 "/ Filter symbol by name";
1809
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001810 if (browser == NULL)
1811 return -1;
1812
Namhyung Kimed426912015-05-29 21:53:44 +09001813 /* reset abort key so that it can get Ctrl-C as a key */
1814 SLang_reset_tty();
1815 SLang_init_tty(0, 0, 0);
1816
Namhyung Kim064f1982013-05-14 11:09:04 +09001817 if (min_pcnt) {
1818 browser->min_pcnt = min_pcnt;
Namhyung Kim112f7612014-04-22 14:05:35 +09001819 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09001820 }
1821
Kan Liang84734b02015-09-04 10:45:45 -04001822 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09001823 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001824 goto out;
1825
1826 ui_helpline__push(helpline);
1827
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001828 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09001829 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001830
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001831 perf_hpp__for_each_format(fmt) {
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001832 perf_hpp__reset_width(fmt, hists);
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001833 /*
1834 * This is done just once, and activates the horizontal scrolling
1835 * code in the ui_browser code, it would be better to have a the
1836 * counter in the perf_hpp code, but I couldn't find doing it here
1837 * works, FIXME by setting this in hist_browser__new, for now, be
1838 * clever 8-)
1839 */
1840 ++browser->b.columns;
1841 }
Namhyung Kim59dc9f22014-07-31 14:47:41 +09001842
Namhyung Kim5b591662014-07-31 14:47:38 +09001843 if (symbol_conf.col_width_list_str)
1844 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1845
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001846 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001847 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001848 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001849 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04001850 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001851
Stephane Eranian24bff2d2012-03-12 16:13:30 +01001852 nr_options = 0;
1853
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03001854 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001855
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001856 if (browser->he_selection != NULL) {
1857 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03001858 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04001859 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001860 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001861 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001862 case K_TAB:
1863 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06001864 if (nr_events == 1)
1865 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001866 /*
1867 * Exit the browser, let hists__browser_tree
1868 * go to the next or previous
1869 */
1870 goto out_free_stack;
1871 case 'a':
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03001872 if (!sort__has_sym) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02001873 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001874 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01001875 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02001876 continue;
1877 }
1878
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001879 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08001880 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001881 browser->selection->map->dso->annotate_warned)
1882 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001883
Namhyung Kimea7cd592015-04-22 16:18:19 +09001884 actions->ms.map = browser->selection->map;
1885 actions->ms.sym = browser->selection->sym;
1886 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001887 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001888 case 'P':
1889 hist_browser__dump(browser);
1890 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001891 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03001892 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09001893 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001894 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03001895 case 'V':
1896 browser->show_dso = !browser->show_dso;
1897 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001898 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001899 actions->thread = thread;
1900 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001901 continue;
Kan Liang84734b02015-09-04 10:45:45 -04001902 case 'S':
1903 actions->socket = socked_id;
1904 do_zoom_socket(browser, actions);
1905 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03001906 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09001907 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e452015-10-12 14:02:29 -03001908 "Please enter the name of symbol you want to see.\n"
1909 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09001910 buf, "ENTER: OK, ESC: Cancel",
1911 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001912 hists->symbol_filter_str = *buf ? buf : NULL;
1913 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09001914 hist_browser__reset(browser);
1915 }
1916 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08001917 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09001918 if (is_report_browser(hbt)) {
1919 actions->thread = NULL;
1920 actions->ms.sym = NULL;
1921 do_run_script(browser, actions);
1922 }
Feng Tangc77d8d72012-11-01 00:00:55 +08001923 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08001924 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001925 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09001926 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001927 if (key == K_SWITCH_INPUT_DATA)
1928 goto out_free_stack;
1929 }
Feng Tang341487ab2013-02-03 14:38:20 +08001930 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09001931 case 'i':
1932 /* env->arch is NULL for live-mode (i.e. perf top) */
1933 if (env->arch)
1934 tui__header_window(env);
1935 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09001936 case 'F':
1937 symbol_conf.filter_relative ^= 1;
1938 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09001939 case 'z':
1940 if (!is_report_browser(hbt)) {
1941 struct perf_top *top = hbt->arg;
1942
1943 top->zero = !top->zero;
1944 }
1945 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001946 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001947 case 'h':
1948 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02001949 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09001950 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001951 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001952 case K_ENTER:
1953 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09001954 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001955 /* menu */
1956 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03001957 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02001958 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001959 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001960
Namhyung Kim01f00a12015-04-22 16:18:16 +09001961 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001962 /*
1963 * Go back to the perf_evsel_menu__run or other user
1964 */
1965 if (left_exits)
1966 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03001967
1968 if (key == K_ESC &&
1969 ui_browser__dialog_yesno(&browser->b,
1970 "Do you really want to exit?"))
1971 goto out_free_stack;
1972
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001973 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03001974 }
Namhyung Kim64221842015-04-24 10:15:33 +09001975 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09001976 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001977 /*
1978 * No need to set actions->dso here since
1979 * it's just to remove the current filter.
1980 * Ditto for thread below.
1981 */
1982 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04001983 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09001984 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04001985 } else if (top == &browser->hists->socket_filter) {
1986 do_zoom_socket(browser, actions);
1987 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03001988 continue;
1989 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03001990 case 'q':
1991 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03001992 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03001993 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09001994 if (!is_report_browser(hbt)) {
1995 struct perf_top *top = hbt->arg;
1996
1997 perf_evlist__toggle_enable(top->evlist);
1998 /*
1999 * No need to refresh, resort/decay histogram
2000 * entries if we are not collecting samples:
2001 */
2002 if (top->evlist->enabled) {
2003 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2004 hbt->refresh = delay_secs;
2005 } else {
2006 helpline = "Press 'f' again to re-enable the events";
2007 hbt->refresh = 0;
2008 }
2009 continue;
2010 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002011 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002012 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002013 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002014 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002015 }
2016
Arnaldo Carvalho de Melo9c796ec2013-04-26 14:28:46 -03002017 if (!sort__has_sym)
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002018 goto add_exit_option;
2019
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002020 if (browser->selection == NULL)
2021 goto skip_annotation;
2022
Namhyung Kim55369fc2013-04-01 20:35:20 +09002023 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002024 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002025
2026 if (bi == NULL)
2027 goto skip_annotation;
2028
Namhyung Kimea7cd592015-04-22 16:18:19 +09002029 nr_options += add_annotate_opt(browser,
2030 &actions[nr_options],
2031 &options[nr_options],
2032 bi->from.map,
2033 bi->from.sym);
2034 if (bi->to.sym != bi->from.sym)
2035 nr_options += add_annotate_opt(browser,
2036 &actions[nr_options],
2037 &options[nr_options],
2038 bi->to.map,
2039 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002040 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002041 nr_options += add_annotate_opt(browser,
2042 &actions[nr_options],
2043 &options[nr_options],
2044 browser->selection->map,
2045 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002046 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002047skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002048 nr_options += add_thread_opt(browser, &actions[nr_options],
2049 &options[nr_options], thread);
2050 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002051 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002052 nr_options += add_map_opt(browser, &actions[nr_options],
2053 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002054 browser->selection ?
2055 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002056 nr_options += add_socket_opt(browser, &actions[nr_options],
2057 &options[nr_options],
2058 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002059 /* perf script support */
2060 if (browser->he_selection) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002061 nr_options += add_script_opt(browser,
2062 &actions[nr_options],
2063 &options[nr_options],
2064 thread, NULL);
Wang Nanbd315aa2015-09-14 10:23:55 +00002065 /*
2066 * Note that browser->selection != NULL
2067 * when browser->he_selection is not NULL,
2068 * so we don't need to check browser->selection
2069 * before fetching browser->selection->sym like what
2070 * we do before fetching browser->selection->map.
2071 *
2072 * See hist_browser__show_entry.
2073 */
Namhyung Kimea7cd592015-04-22 16:18:19 +09002074 nr_options += add_script_opt(browser,
2075 &actions[nr_options],
2076 &options[nr_options],
2077 NULL, browser->selection->sym);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002078 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002079 nr_options += add_script_opt(browser, &actions[nr_options],
2080 &options[nr_options], NULL, NULL);
2081 nr_options += add_switch_opt(browser, &actions[nr_options],
2082 &options[nr_options]);
Arnaldo Carvalho de Melo724c9c92011-10-06 10:36:35 -03002083add_exit_option:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002084 nr_options += add_exit_opt(browser, &actions[nr_options],
2085 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002086
Namhyung Kimea7cd592015-04-22 16:18:19 +09002087 do {
2088 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002089
Namhyung Kimea7cd592015-04-22 16:18:19 +09002090 choice = ui__popup_menu(nr_options, options);
2091 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08002092 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002093
2094 act = &actions[choice];
2095 key = act->fn(browser, act);
2096 } while (key == 1);
2097
2098 if (key == K_SWITCH_INPUT_DATA)
2099 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002100 }
2101out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09002102 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002103out:
2104 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002105 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002106 return key;
2107}
2108
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002109struct perf_evsel_menu {
2110 struct ui_browser b;
2111 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002112 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09002113 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04002114 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002115};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002116
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002117static void perf_evsel_menu__write(struct ui_browser *browser,
2118 void *entry, int row)
2119{
2120 struct perf_evsel_menu *menu = container_of(browser,
2121 struct perf_evsel_menu, b);
2122 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002123 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002124 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002125 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002126 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002127 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002128 const char *warn = " ";
2129 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002130
2131 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
2132 HE_COLORSET_NORMAL);
2133
Namhyung Kim759ff492013-03-05 14:53:26 +09002134 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002135 struct perf_evsel *pos;
2136
2137 ev_name = perf_evsel__group_name(evsel);
2138
2139 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002140 struct hists *pos_hists = evsel__hists(pos);
2141 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09002142 }
2143 }
2144
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002145 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002146 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002147 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03002148 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002149
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002150 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002151 if (nr_events != 0) {
2152 menu->lost_events = true;
2153 if (!current_entry)
2154 ui_browser__set_color(browser, HE_COLORSET_TOP);
2155 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002156 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
2157 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002158 warn = bf;
2159 }
2160
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03002161 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002162
2163 if (current_entry)
2164 menu->selection = evsel;
2165}
2166
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002167static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
2168 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09002169 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002170{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002171 struct perf_evlist *evlist = menu->b.priv;
2172 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02002173 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09002174 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002175 int key;
2176
2177 if (ui_browser__show(&menu->b, title,
2178 "ESC: exit, ENTER|->: Browse histograms") < 0)
2179 return -1;
2180
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002181 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03002182 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002183
2184 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002185 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09002186 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002187
2188 if (!menu->lost_events_warned && menu->lost_events) {
2189 ui_browser__warn_lost_events(&menu->b);
2190 menu->lost_events_warned = true;
2191 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002192 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002193 case K_RIGHT:
2194 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002195 if (!menu->selection)
2196 continue;
2197 pos = menu->selection;
2198browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002199 perf_evlist__set_selected(evlist, pos);
2200 /*
2201 * Give the calling tool a chance to populate the non
2202 * default evsel resorted hists tree.
2203 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09002204 if (hbt)
2205 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002206 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002207 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002208 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002209 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002210 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002211 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002212 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002213 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002214 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002215 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002216 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002217 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002218 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002219 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002220 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002221 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03002222 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002223 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08002224 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002225 case 'q':
2226 case CTRL('c'):
2227 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002228 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002229 default:
2230 continue;
2231 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002232 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002233 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002234 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002235 if (!ui_browser__dialog_yesno(&menu->b,
2236 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002237 continue;
2238 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002239 case 'q':
2240 case CTRL('c'):
2241 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002242 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03002243 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002244 }
2245 }
2246
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002247out:
2248 ui_browser__hide(&menu->b);
2249 return key;
2250}
2251
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03002252static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002253 void *entry)
2254{
2255 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
2256
2257 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
2258 return true;
2259
2260 return false;
2261}
2262
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002263static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002264 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002265 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002266 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002267 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002268{
2269 struct perf_evsel *pos;
2270 struct perf_evsel_menu menu = {
2271 .b = {
2272 .entries = &evlist->entries,
2273 .refresh = ui_browser__list_head_refresh,
2274 .seek = ui_browser__list_head_seek,
2275 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002276 .filter = filter_group_entries,
2277 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002278 .priv = evlist,
2279 },
Namhyung Kim064f1982013-05-14 11:09:04 +09002280 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09002281 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002282 };
2283
2284 ui_helpline__push("Press ESC to exit");
2285
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002286 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03002287 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002288 size_t line_len = strlen(ev_name) + 7;
2289
2290 if (menu.b.width < line_len)
2291 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002292 }
2293
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002294 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002295}
2296
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002297int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09002298 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002299 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002300 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002301{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002302 int nr_entries = evlist->nr_entries;
2303
2304single_entry:
2305 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03002306 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002307
2308 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02002309 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002310 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002311 }
2312
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002313 if (symbol_conf.event_group) {
2314 struct perf_evsel *pos;
2315
2316 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002317 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002318 if (perf_evsel__is_group_leader(pos))
2319 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03002320 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09002321
2322 if (nr_entries == 1)
2323 goto single_entry;
2324 }
2325
2326 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09002327 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002328}