blob: 4a7aac8ed5ee90794a3554a83d49eaeddec68a05 [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
Jiri Olsaf7589902016-06-20 23:58:13 +020015#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030016#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
Namhyung Kimf5951d52012-09-03 11:53:09 +090022extern void hist_browser__init_hpp(void);
23
Jiri Olsa5b91a862016-06-20 23:58:15 +020024static int perf_evsel_browser_title(struct hist_browser *browser,
25 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090026static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030027
Namhyung Kimc3b78952014-04-22 15:56:17 +090028static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090029 float min_pcnt);
30
Namhyung Kim268397c2014-04-22 14:49:31 +090031static bool hist_browser__has_filter(struct hist_browser *hb)
32{
Arnaldo Carvalho de Melo9c0fa8d2015-07-13 08:26:35 -030033 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090034}
35
He Kuang4fabf3d2015-03-12 15:21:49 +080036static int hist_browser__get_folding(struct hist_browser *browser)
37{
38 struct rb_node *nd;
39 struct hists *hists = browser->hists;
40 int unfolded_rows = 0;
41
42 for (nd = rb_first(&hists->entries);
43 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090044 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080045 struct hist_entry *he =
46 rb_entry(nd, struct hist_entry, rb_node);
47
Namhyung Kimf5b763f2016-02-25 00:13:43 +090048 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080049 unfolded_rows += he->nr_rows;
50 }
51 return unfolded_rows;
52}
53
Namhyung Kimc3b78952014-04-22 15:56:17 +090054static u32 hist_browser__nr_entries(struct hist_browser *hb)
55{
56 u32 nr_entries;
57
Namhyung Kimf5b763f2016-02-25 00:13:43 +090058 if (symbol_conf.report_hierarchy)
59 nr_entries = hb->nr_hierarchy_entries;
60 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090061 nr_entries = hb->nr_non_filtered_entries;
62 else
63 nr_entries = hb->hists->nr_entries;
64
He Kuang4fabf3d2015-03-12 15:21:49 +080065 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090066 return nr_entries + hb->nr_callchain_rows;
67}
68
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020069static void hist_browser__update_rows(struct hist_browser *hb)
70{
71 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020072 struct hists *hists = hb->hists;
73 struct perf_hpp_list *hpp_list = hists->hpp_list;
74 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020075
Jiri Olsaf8e67102016-08-07 17:28:26 +020076 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020077 browser->rows = browser->height - header_offset;
78 /*
79 * Verify if we were at the last line and that line isn't
80 * visibe because we now show the header line(s).
81 */
82 index_row = browser->index - browser->top_idx;
83 if (index_row >= browser->rows)
84 browser->index -= index_row - browser->rows + 1;
85}
86
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030087static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030088{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030089 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
90
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030091 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030092 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
93 /*
94 * FIXME: Just keeping existing behaviour, but this really should be
95 * before updating browser->width, as it will invalidate the
96 * calculation above. Fix this and the fallout in another
97 * changeset.
98 */
99 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200100 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101}
102
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300103static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
104{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200105 struct hists *hists = browser->hists;
106 struct perf_hpp_list *hpp_list = hists->hpp_list;
107 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200108
Jiri Olsaf8e67102016-08-07 17:28:26 +0200109 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200110 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300111}
112
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300113static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300114{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900115 /*
116 * The hists__remove_entry_filter() already folds non-filtered
117 * entries so we can assume it has 0 callchain rows.
118 */
119 browser->nr_callchain_rows = 0;
120
Namhyung Kim268397c2014-04-22 14:49:31 +0900121 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900122 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300123 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300124 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300125}
126
127static char tree__folded_sign(bool unfolded)
128{
129 return unfolded ? '-' : '+';
130}
131
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900134 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300135}
136
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300138{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900139 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300140}
141
Namhyung Kim3698dab2015-05-05 23:55:46 +0900142static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300143{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900144 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300145}
146
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148{
149 int n = 0;
150 struct rb_node *nd;
151
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300152 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300153 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
154 struct callchain_list *chain;
155 char folded_sign = ' '; /* No children */
156
157 list_for_each_entry(chain, &child->val, list) {
158 ++n;
159 /* We need this because we may not have children */
160 folded_sign = callchain_list__folded(chain);
161 if (folded_sign == '+')
162 break;
163 }
164
165 if (folded_sign == '-') /* Have children and they're unfolded */
166 n += callchain_node__count_rows_rb_tree(child);
167 }
168
169 return n;
170}
171
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900172static int callchain_node__count_flat_rows(struct callchain_node *node)
173{
174 struct callchain_list *chain;
175 char folded_sign = 0;
176 int n = 0;
177
178 list_for_each_entry(chain, &node->parent_val, list) {
179 if (!folded_sign) {
180 /* only check first chain list entry */
181 folded_sign = callchain_list__folded(chain);
182 if (folded_sign == '+')
183 return 1;
184 }
185 n++;
186 }
187
188 list_for_each_entry(chain, &node->val, list) {
189 if (!folded_sign) {
190 /* node->parent_val list might be empty */
191 folded_sign = callchain_list__folded(chain);
192 if (folded_sign == '+')
193 return 1;
194 }
195 n++;
196 }
197
198 return n;
199}
200
Namhyung Kim8c430a32015-11-09 14:45:44 +0900201static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
202{
203 return 1;
204}
205
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300206static int callchain_node__count_rows(struct callchain_node *node)
207{
208 struct callchain_list *chain;
209 bool unfolded = false;
210 int n = 0;
211
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900212 if (callchain_param.mode == CHAIN_FLAT)
213 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900214 else if (callchain_param.mode == CHAIN_FOLDED)
215 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900216
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300217 list_for_each_entry(chain, &node->val, list) {
218 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900219 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300220 }
221
222 if (unfolded)
223 n += callchain_node__count_rows_rb_tree(node);
224
225 return n;
226}
227
228static int callchain__count_rows(struct rb_root *chain)
229{
230 struct rb_node *nd;
231 int n = 0;
232
233 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
234 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
235 n += callchain_node__count_rows(node);
236 }
237
238 return n;
239}
240
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900241static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
242 bool include_children)
243{
244 int count = 0;
245 struct rb_node *node;
246 struct hist_entry *child;
247
248 if (he->leaf)
249 return callchain__count_rows(&he->sorted_chain);
250
Namhyung Kim79dded82016-02-26 21:13:19 +0900251 if (he->has_no_entry)
252 return 1;
253
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900254 node = rb_first(&he->hroot_out);
255 while (node) {
256 float percent;
257
258 child = rb_entry(node, struct hist_entry, rb_node);
259 percent = hist_entry__get_percent_limit(child);
260
261 if (!child->filtered && percent >= hb->min_pcnt) {
262 count++;
263
264 if (include_children && child->unfolded)
265 count += hierarchy_count_rows(hb, child, true);
266 }
267
268 node = rb_next(node);
269 }
270 return count;
271}
272
Namhyung Kim3698dab2015-05-05 23:55:46 +0900273static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300274{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900275 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200276 return false;
277
Namhyung Kim3698dab2015-05-05 23:55:46 +0900278 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300279 return false;
280
Namhyung Kim3698dab2015-05-05 23:55:46 +0900281 he->unfolded = !he->unfolded;
282 return true;
283}
284
285static bool callchain_list__toggle_fold(struct callchain_list *cl)
286{
287 if (!cl)
288 return false;
289
290 if (!cl->has_children)
291 return false;
292
293 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300294 return true;
295}
296
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300297static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300298{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300299 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300300
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300301 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300302 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
303 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300304 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300305
306 list_for_each_entry(chain, &child->val, list) {
307 if (first) {
308 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900309 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300310 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300311 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900312 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300313 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300314 }
315
316 callchain_node__init_have_children_rb_tree(child);
317 }
318}
319
Namhyung Kima7444af2014-11-24 17:13:27 +0900320static void callchain_node__init_have_children(struct callchain_node *node,
321 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300322{
323 struct callchain_list *chain;
324
Namhyung Kima7444af2014-11-24 17:13:27 +0900325 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900326 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900327
Andres Freund90989032016-03-30 21:02:45 +0200328 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900329 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900330 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900331 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300332
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300333 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300334}
335
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300336static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300337{
Namhyung Kima7444af2014-11-24 17:13:27 +0900338 struct rb_node *nd = rb_first(root);
339 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300340
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300341 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300342 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900343 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900344 if (callchain_param.mode == CHAIN_FLAT ||
345 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900346 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300347 }
348}
349
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300350static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300351{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900352 if (he->init_have_children)
353 return;
354
355 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900356 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300357 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900358 } else {
359 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300360 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900361
362 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363}
364
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300365static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300366{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900367 struct hist_entry *he = browser->he_selection;
368 struct map_symbol *ms = browser->selection;
369 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
370 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300371
Wang Nan4938cf02015-12-07 02:35:44 +0000372 if (!he || !ms)
373 return false;
374
Namhyung Kim3698dab2015-05-05 23:55:46 +0900375 if (ms == &he->ms)
376 has_children = hist_entry__toggle_fold(he);
377 else
378 has_children = callchain_list__toggle_fold(cl);
379
380 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900381 int child_rows = 0;
382
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300383 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900384 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900386 if (he->leaf)
387 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300388 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900389 browser->nr_hierarchy_entries -= he->nr_rows;
390
391 if (symbol_conf.report_hierarchy)
392 child_rows = hierarchy_count_rows(browser, he, true);
393
394 if (he->unfolded) {
395 if (he->leaf)
396 he->nr_rows = callchain__count_rows(&he->sorted_chain);
397 else
398 he->nr_rows = hierarchy_count_rows(browser, he, false);
399
400 /* account grand children */
401 if (symbol_conf.report_hierarchy)
402 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900403
404 if (!he->leaf && he->nr_rows == 0) {
405 he->has_no_entry = true;
406 he->nr_rows = 1;
407 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900408 } else {
409 if (symbol_conf.report_hierarchy)
410 browser->b.nr_entries -= child_rows - he->nr_rows;
411
Namhyung Kim79dded82016-02-26 21:13:19 +0900412 if (he->has_no_entry)
413 he->has_no_entry = false;
414
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300415 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900416 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900417
418 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900419
420 if (he->leaf)
421 browser->nr_callchain_rows += he->nr_rows;
422 else
423 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300424
425 return true;
426 }
427
428 /* If it doesn't have children, no toggling performed */
429 return false;
430}
431
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300432static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300433{
434 int n = 0;
435 struct rb_node *nd;
436
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300437 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300438 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
439 struct callchain_list *chain;
440 bool has_children = false;
441
442 list_for_each_entry(chain, &child->val, list) {
443 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900444 callchain_list__set_folding(chain, unfold);
445 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300446 }
447
448 if (has_children)
449 n += callchain_node__set_folding_rb_tree(child, unfold);
450 }
451
452 return n;
453}
454
455static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
456{
457 struct callchain_list *chain;
458 bool has_children = false;
459 int n = 0;
460
461 list_for_each_entry(chain, &node->val, list) {
462 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900463 callchain_list__set_folding(chain, unfold);
464 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300465 }
466
467 if (has_children)
468 n += callchain_node__set_folding_rb_tree(node, unfold);
469
470 return n;
471}
472
473static int callchain__set_folding(struct rb_root *chain, bool unfold)
474{
475 struct rb_node *nd;
476 int n = 0;
477
478 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
479 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
480 n += callchain_node__set_folding(node, unfold);
481 }
482
483 return n;
484}
485
Namhyung Kim492b1012016-02-25 00:13:44 +0900486static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
487 bool unfold __maybe_unused)
488{
489 float percent;
490 struct rb_node *nd;
491 struct hist_entry *child;
492 int n = 0;
493
494 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
495 child = rb_entry(nd, struct hist_entry, rb_node);
496 percent = hist_entry__get_percent_limit(child);
497 if (!child->filtered && percent >= hb->min_pcnt)
498 n++;
499 }
500
501 return n;
502}
503
504static void hist_entry__set_folding(struct hist_entry *he,
505 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300506{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300507 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900508 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300509
Namhyung Kim3698dab2015-05-05 23:55:46 +0900510 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900511 int n;
512
513 if (he->leaf)
514 n = callchain__set_folding(&he->sorted_chain, unfold);
515 else
516 n = hierarchy_set_folding(hb, he, unfold);
517
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300519 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300520 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300521}
522
Namhyung Kimc3b78952014-04-22 15:56:17 +0900523static void
524__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300525{
526 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900527 struct hist_entry *he;
528 double percent;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300529
Namhyung Kim492b1012016-02-25 00:13:44 +0900530 nd = rb_first(&browser->hists->entries);
531 while (nd) {
532 he = rb_entry(nd, struct hist_entry, rb_node);
533
534 /* set folding state even if it's currently folded */
535 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
536
537 hist_entry__set_folding(he, browser, unfold);
538
539 percent = hist_entry__get_percent_limit(he);
540 if (he->filtered || percent < browser->min_pcnt)
541 continue;
542
543 if (!he->depth || unfold)
544 browser->nr_hierarchy_entries++;
545 if (he->leaf)
546 browser->nr_callchain_rows += he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900547 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
548 browser->nr_hierarchy_entries++;
549 he->has_no_entry = true;
550 he->nr_rows = 1;
551 } else
552 he->has_no_entry = false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300553 }
554}
555
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300556static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300557{
Namhyung Kim492b1012016-02-25 00:13:44 +0900558 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900559 browser->nr_callchain_rows = 0;
560 __hist_browser__set_folding(browser, unfold);
561
562 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300563 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300564 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300565}
566
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200567static void ui_browser__warn_lost_events(struct ui_browser *browser)
568{
569 ui_browser__warning(browser, 4,
570 "Events are being lost, check IO/CPU overload!\n\n"
571 "You may want to run 'perf' using a RT scheduler policy:\n\n"
572 " perf top -r 80\n\n"
573 "Or reduce the sampling frequency.");
574}
575
Jiri Olsa5b91a862016-06-20 23:58:15 +0200576static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
577{
578 return browser->title ? browser->title(browser, bf, size) : 0;
579}
580
Jiri Olsadabd2012016-06-20 23:58:14 +0200581int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300582{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300583 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300584 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900585 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900586 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300587
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300588 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900589 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590
Jiri Olsa5b91a862016-06-20 23:58:15 +0200591 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592
Namhyung Kim090cff32016-01-11 19:53:14 +0900593 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300594 return -1;
595
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300596 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300597 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300598
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300599 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900600 case K_TIMER: {
601 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900602 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900603
Namhyung Kimc3b78952014-04-22 15:56:17 +0900604 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900605 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900606
Namhyung Kimc3b78952014-04-22 15:56:17 +0900607 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900608 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200609
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300610 if (browser->hists->stats.nr_lost_warned !=
611 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
612 browser->hists->stats.nr_lost_warned =
613 browser->hists->stats.nr_events[PERF_RECORD_LOST];
614 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200615 }
616
Jiri Olsa5b91a862016-06-20 23:58:15 +0200617 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300618 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300619 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900620 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300621 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300622 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300623 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300624 struct hist_entry, rb_node);
625 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300626 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 -0300627 seq++, browser->b.nr_entries,
628 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300629 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300630 browser->b.index,
631 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300632 h->row_offset, h->nr_rows);
633 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300634 break;
635 case 'C':
636 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300637 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300638 break;
639 case 'E':
640 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300641 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300642 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200643 case 'H':
644 browser->show_headers = !browser->show_headers;
645 hist_browser__update_rows(browser);
646 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200647 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300648 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300649 break;
650 /* fall thru */
651 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300652 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300653 }
654 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300655out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300656 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300657 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300658}
659
Namhyung Kim39ee5332014-08-22 09:13:21 +0900660struct callchain_print_arg {
661 /* for hists browser */
662 off_t row_offset;
663 bool is_current_entry;
664
665 /* for file dump */
666 FILE *fp;
667 int printed;
668};
669
670typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
671 struct callchain_list *chain,
672 const char *str, int offset,
673 unsigned short row,
674 struct callchain_print_arg *arg);
675
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900676static void hist_browser__show_callchain_entry(struct hist_browser *browser,
677 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900678 const char *str, int offset,
679 unsigned short row,
680 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900681{
682 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900683 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300684 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900685
686 color = HE_COLORSET_NORMAL;
687 width = browser->b.width - (offset + 2);
688 if (ui_browser__is_current_entry(&browser->b, row)) {
689 browser->selection = &chain->ms;
690 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900691 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900692 }
693
694 ui_browser__set_color(&browser->b, color);
695 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300696 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300697 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300698 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300699 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900700}
701
Namhyung Kim39ee5332014-08-22 09:13:21 +0900702static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
703 struct callchain_list *chain,
704 const char *str, int offset,
705 unsigned short row __maybe_unused,
706 struct callchain_print_arg *arg)
707{
708 char folded_sign = callchain_list__folded(chain);
709
710 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
711 folded_sign, str);
712}
713
714typedef bool (*check_output_full_fn)(struct hist_browser *browser,
715 unsigned short row);
716
717static bool hist_browser__check_output_full(struct hist_browser *browser,
718 unsigned short row)
719{
720 return browser->b.rows == row;
721}
722
723static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
724 unsigned short row __maybe_unused)
725{
726 return false;
727}
728
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300729#define LEVEL_OFFSET_STEP 3
730
Namhyung Kim18bb8382015-11-09 14:45:42 +0900731static int hist_browser__show_callchain_list(struct hist_browser *browser,
732 struct callchain_node *node,
733 struct callchain_list *chain,
734 unsigned short row, u64 total,
735 bool need_percent, int offset,
736 print_callchain_entry_fn print,
737 struct callchain_print_arg *arg)
738{
739 char bf[1024], *alloc_str;
740 const char *str;
741
742 if (arg->row_offset != 0) {
743 arg->row_offset--;
744 return 0;
745 }
746
747 alloc_str = NULL;
748 str = callchain_list__sym_name(chain, bf, sizeof(bf),
749 browser->show_dso);
750
751 if (need_percent) {
752 char buf[64];
753
754 callchain_node__scnprintf_value(node, buf, sizeof(buf),
755 total);
756
757 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
758 str = "Not enough memory!";
759 else
760 str = alloc_str;
761 }
762
763 print(browser, chain, str, offset, row, arg);
764
765 free(alloc_str);
766 return 1;
767}
768
Namhyung Kim59c624e2016-01-28 00:40:56 +0900769static bool check_percent_display(struct rb_node *node, u64 parent_total)
770{
771 struct callchain_node *child;
772
773 if (node == NULL)
774 return false;
775
776 if (rb_next(node))
777 return true;
778
779 child = rb_entry(node, struct callchain_node, rb_node);
780 return callchain_cumul_hits(child) != parent_total;
781}
782
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900783static int hist_browser__show_callchain_flat(struct hist_browser *browser,
784 struct rb_root *root,
785 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900786 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900787 print_callchain_entry_fn print,
788 struct callchain_print_arg *arg,
789 check_output_full_fn is_output_full)
790{
791 struct rb_node *node;
792 int first_row = row, offset = LEVEL_OFFSET_STEP;
793 bool need_percent;
794
795 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900796 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900797
798 while (node) {
799 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
800 struct rb_node *next = rb_next(node);
801 struct callchain_list *chain;
802 char folded_sign = ' ';
803 int first = true;
804 int extra_offset = 0;
805
806 list_for_each_entry(chain, &child->parent_val, list) {
807 bool was_first = first;
808
809 if (first)
810 first = false;
811 else if (need_percent)
812 extra_offset = LEVEL_OFFSET_STEP;
813
814 folded_sign = callchain_list__folded(chain);
815
816 row += hist_browser__show_callchain_list(browser, child,
817 chain, row, total,
818 was_first && need_percent,
819 offset + extra_offset,
820 print, arg);
821
822 if (is_output_full(browser, row))
823 goto out;
824
825 if (folded_sign == '+')
826 goto next;
827 }
828
829 list_for_each_entry(chain, &child->val, list) {
830 bool was_first = first;
831
832 if (first)
833 first = false;
834 else if (need_percent)
835 extra_offset = LEVEL_OFFSET_STEP;
836
837 folded_sign = callchain_list__folded(chain);
838
839 row += hist_browser__show_callchain_list(browser, child,
840 chain, row, total,
841 was_first && need_percent,
842 offset + extra_offset,
843 print, arg);
844
845 if (is_output_full(browser, row))
846 goto out;
847
848 if (folded_sign == '+')
849 break;
850 }
851
852next:
853 if (is_output_full(browser, row))
854 break;
855 node = next;
856 }
857out:
858 return row - first_row;
859}
860
Namhyung Kim8c430a32015-11-09 14:45:44 +0900861static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
862 struct callchain_list *chain,
863 char *value_str, char *old_str)
864{
865 char bf[1024];
866 const char *str;
867 char *new;
868
869 str = callchain_list__sym_name(chain, bf, sizeof(bf),
870 browser->show_dso);
871 if (old_str) {
872 if (asprintf(&new, "%s%s%s", old_str,
873 symbol_conf.field_sep ?: ";", str) < 0)
874 new = NULL;
875 } else {
876 if (value_str) {
877 if (asprintf(&new, "%s %s", value_str, str) < 0)
878 new = NULL;
879 } else {
880 if (asprintf(&new, "%s", str) < 0)
881 new = NULL;
882 }
883 }
884 return new;
885}
886
887static int hist_browser__show_callchain_folded(struct hist_browser *browser,
888 struct rb_root *root,
889 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900890 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900891 print_callchain_entry_fn print,
892 struct callchain_print_arg *arg,
893 check_output_full_fn is_output_full)
894{
895 struct rb_node *node;
896 int first_row = row, offset = LEVEL_OFFSET_STEP;
897 bool need_percent;
898
899 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900900 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900901
902 while (node) {
903 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
904 struct rb_node *next = rb_next(node);
905 struct callchain_list *chain, *first_chain = NULL;
906 int first = true;
907 char *value_str = NULL, *value_str_alloc = NULL;
908 char *chain_str = NULL, *chain_str_alloc = NULL;
909
910 if (arg->row_offset != 0) {
911 arg->row_offset--;
912 goto next;
913 }
914
915 if (need_percent) {
916 char buf[64];
917
918 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
919 if (asprintf(&value_str, "%s", buf) < 0) {
920 value_str = (char *)"<...>";
921 goto do_print;
922 }
923 value_str_alloc = value_str;
924 }
925
926 list_for_each_entry(chain, &child->parent_val, list) {
927 chain_str = hist_browser__folded_callchain_str(browser,
928 chain, value_str, chain_str);
929 if (first) {
930 first = false;
931 first_chain = chain;
932 }
933
934 if (chain_str == NULL) {
935 chain_str = (char *)"Not enough memory!";
936 goto do_print;
937 }
938
939 chain_str_alloc = chain_str;
940 }
941
942 list_for_each_entry(chain, &child->val, list) {
943 chain_str = hist_browser__folded_callchain_str(browser,
944 chain, value_str, chain_str);
945 if (first) {
946 first = false;
947 first_chain = chain;
948 }
949
950 if (chain_str == NULL) {
951 chain_str = (char *)"Not enough memory!";
952 goto do_print;
953 }
954
955 chain_str_alloc = chain_str;
956 }
957
958do_print:
959 print(browser, first_chain, chain_str, offset, row++, arg);
960 free(value_str_alloc);
961 free(chain_str_alloc);
962
963next:
964 if (is_output_full(browser, row))
965 break;
966 node = next;
967 }
968
969 return row - first_row;
970}
971
Namhyung Kim0c841c62016-01-28 00:40:54 +0900972static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900973 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900974 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900975 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900976 print_callchain_entry_fn print,
977 struct callchain_print_arg *arg,
978 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300979{
980 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900981 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +0900982 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +0900983 u64 percent_total = total;
984
985 if (callchain_param.mode == CHAIN_GRAPH_REL)
986 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300987
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900988 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900989 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +0900990
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300991 while (node) {
992 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
993 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300994 struct callchain_list *chain;
995 char folded_sign = ' ';
996 int first = true;
997 int extra_offset = 0;
998
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300999 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001000 bool was_first = first;
1001
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001002 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001003 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001004 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001005 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001006
1007 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001008
Namhyung Kim18bb8382015-11-09 14:45:42 +09001009 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001010 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001011 was_first && need_percent,
1012 offset + extra_offset,
1013 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001014
Namhyung Kim18bb8382015-11-09 14:45:42 +09001015 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001016 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001017
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001018 if (folded_sign == '+')
1019 break;
1020 }
1021
1022 if (folded_sign == '-') {
1023 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001024
Namhyung Kim0c841c62016-01-28 00:40:54 +09001025 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001026 new_level, row, total,
1027 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001028 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001029 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001030 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001031 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001032 node = next;
1033 }
1034out:
1035 return row - first_row;
1036}
1037
Namhyung Kim0c841c62016-01-28 00:40:54 +09001038static int hist_browser__show_callchain(struct hist_browser *browser,
1039 struct hist_entry *entry, int level,
1040 unsigned short row,
1041 print_callchain_entry_fn print,
1042 struct callchain_print_arg *arg,
1043 check_output_full_fn is_output_full)
1044{
1045 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001046 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001047 int printed;
1048
Namhyung Kim5eca1042016-01-28 00:40:55 +09001049 if (symbol_conf.cumulate_callchain)
1050 parent_total = entry->stat_acc->period;
1051 else
1052 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001053
1054 if (callchain_param.mode == CHAIN_FLAT) {
1055 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001056 &entry->sorted_chain, row,
1057 total, parent_total, print, arg,
1058 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001059 } else if (callchain_param.mode == CHAIN_FOLDED) {
1060 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001061 &entry->sorted_chain, row,
1062 total, parent_total, print, arg,
1063 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001064 } else {
1065 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001066 &entry->sorted_chain, level, row,
1067 total, parent_total, print, arg,
1068 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001069 }
1070
1071 if (arg->is_current_entry)
1072 browser->he_selection = entry;
1073
1074 return printed;
1075}
1076
Namhyung Kim89701462013-01-22 18:09:38 +09001077struct hpp_arg {
1078 struct ui_browser *b;
1079 char folded_sign;
1080 bool current_entry;
1081};
1082
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001083static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
1084{
1085 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001086 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001087 va_list args;
1088 double percent;
1089
1090 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001091 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001092 percent = va_arg(args, double);
1093 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001094
Namhyung Kim89701462013-01-22 18:09:38 +09001095 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001096
Namhyung Kimd6751072014-07-31 14:47:36 +09001097 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001098 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001099
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001100 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001101 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001102}
1103
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001104#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001105static u64 __hpp_get_##_field(struct hist_entry *he) \
1106{ \
1107 return he->stat._field; \
1108} \
1109 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001110static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001111hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001112 struct perf_hpp *hpp, \
1113 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001114{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001115 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1116 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001117}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001118
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001119#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1120static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1121{ \
1122 return he->stat_acc->_field; \
1123} \
1124 \
1125static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001126hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001127 struct perf_hpp *hpp, \
1128 struct hist_entry *he) \
1129{ \
1130 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001131 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001132 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001133 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001134 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001135 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001136 \
1137 return ret; \
1138 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001139 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1140 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001141}
1142
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001143__HPP_COLOR_PERCENT_FN(overhead, period)
1144__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1145__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1146__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1147__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001148__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001149
1150#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001151#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001152
1153void hist_browser__init_hpp(void)
1154{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001155 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1156 hist_browser__hpp_color_overhead;
1157 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1158 hist_browser__hpp_color_overhead_sys;
1159 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1160 hist_browser__hpp_color_overhead_us;
1161 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1162 hist_browser__hpp_color_overhead_guest_sys;
1163 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1164 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001165 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1166 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001167}
1168
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001169static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001170 struct hist_entry *entry,
1171 unsigned short row)
1172{
Jiri Olsa12400052012-10-13 00:06:16 +02001173 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001174 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001175 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001176 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001177 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001178 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001179 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180
1181 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001182 browser->he_selection = entry;
1183 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001184 }
1185
1186 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001187 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001188 folded_sign = hist_entry__folded(entry);
1189 }
1190
1191 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001192 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001193 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001194 .folded_sign = folded_sign,
1195 .current_entry = current_entry,
1196 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001197 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001199 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001200
Jiri Olsaf0786af2016-01-18 10:24:23 +01001201 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001202 char s[2048];
1203 struct perf_hpp hpp = {
1204 .buf = s,
1205 .size = sizeof(s),
1206 .ptr = &arg,
1207 };
1208
Namhyung Kim361459f2015-12-23 02:07:08 +09001209 if (perf_hpp__should_skip(fmt, entry->hists) ||
1210 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001211 continue;
1212
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001213 if (current_entry && browser->b.navkeypressed) {
1214 ui_browser__set_color(&browser->b,
1215 HE_COLORSET_SELECTED);
1216 } else {
1217 ui_browser__set_color(&browser->b,
1218 HE_COLORSET_NORMAL);
1219 }
1220
1221 if (first) {
1222 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001223 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001224 width -= 2;
1225 }
1226 first = false;
1227 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001228 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001229 width -= 2;
1230 }
1231
Jiri Olsa12400052012-10-13 00:06:16 +02001232 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001233 int ret = fmt->color(fmt, &hpp, entry);
1234 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1235 /*
1236 * fmt->color() already used ui_browser to
1237 * print the non alignment bits, skip it (+ret):
1238 */
1239 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001240 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001241 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001242 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001243 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001244 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001245 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001246
1247 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001248 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001249 width += 1;
1250
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001251 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001252
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253 ++row;
1254 ++printed;
1255 } else
1256 --row_offset;
1257
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001258 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001259 struct callchain_print_arg arg = {
1260 .row_offset = row_offset,
1261 .is_current_entry = current_entry,
1262 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001263
Namhyung Kim0c841c62016-01-28 00:40:54 +09001264 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001265 hist_browser__show_callchain_entry, &arg,
1266 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001267 }
1268
1269 return printed;
1270}
1271
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001272static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1273 struct hist_entry *entry,
1274 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001275 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001276{
1277 int printed = 0;
1278 int width = browser->b.width;
1279 char folded_sign = ' ';
1280 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1281 off_t row_offset = entry->row_offset;
1282 bool first = true;
1283 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001284 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001285 struct hpp_arg arg = {
1286 .b = &browser->b,
1287 .current_entry = current_entry,
1288 };
1289 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001290 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001291
1292 if (current_entry) {
1293 browser->he_selection = entry;
1294 browser->selection = &entry->ms;
1295 }
1296
1297 hist_entry__init_have_children(entry);
1298 folded_sign = hist_entry__folded(entry);
1299 arg.folded_sign = folded_sign;
1300
1301 if (entry->leaf && row_offset) {
1302 row_offset--;
1303 goto show_callchain;
1304 }
1305
1306 hist_browser__gotorc(browser, row, 0);
1307
1308 if (current_entry && browser->b.navkeypressed)
1309 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1310 else
1311 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1312
1313 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1314 width -= level * HIERARCHY_INDENT;
1315
Namhyung Kima61a22f2016-03-07 16:44:50 -03001316 /* the first hpp_list_node is for overhead columns */
1317 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1318 struct perf_hpp_list_node, list);
1319 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001320 char s[2048];
1321 struct perf_hpp hpp = {
1322 .buf = s,
1323 .size = sizeof(s),
1324 .ptr = &arg,
1325 };
1326
1327 if (perf_hpp__should_skip(fmt, entry->hists) ||
1328 column++ < browser->b.horiz_scroll)
1329 continue;
1330
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001331 if (current_entry && browser->b.navkeypressed) {
1332 ui_browser__set_color(&browser->b,
1333 HE_COLORSET_SELECTED);
1334 } else {
1335 ui_browser__set_color(&browser->b,
1336 HE_COLORSET_NORMAL);
1337 }
1338
1339 if (first) {
1340 ui_browser__printf(&browser->b, "%c", folded_sign);
1341 width--;
1342 first = false;
1343 } else {
1344 ui_browser__printf(&browser->b, " ");
1345 width -= 2;
1346 }
1347
1348 if (fmt->color) {
1349 int ret = fmt->color(fmt, &hpp, entry);
1350 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1351 /*
1352 * fmt->color() already used ui_browser to
1353 * print the non alignment bits, skip it (+ret):
1354 */
1355 ui_browser__printf(&browser->b, "%s", s + ret);
1356 } else {
1357 int ret = fmt->entry(fmt, &hpp, entry);
1358 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1359 ui_browser__printf(&browser->b, "%s", s);
1360 }
1361 width -= hpp.buf - s;
1362 }
1363
1364 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1365 width -= hierarchy_indent;
1366
1367 if (column >= browser->b.horiz_scroll) {
1368 char s[2048];
1369 struct perf_hpp hpp = {
1370 .buf = s,
1371 .size = sizeof(s),
1372 .ptr = &arg,
1373 };
1374
1375 if (current_entry && browser->b.navkeypressed) {
1376 ui_browser__set_color(&browser->b,
1377 HE_COLORSET_SELECTED);
1378 } else {
1379 ui_browser__set_color(&browser->b,
1380 HE_COLORSET_NORMAL);
1381 }
1382
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001383 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1384 ui_browser__write_nstring(&browser->b, "", 2);
1385 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001386
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001387 /*
1388 * No need to call hist_entry__snprintf_alignment()
1389 * since this fmt is always the last column in the
1390 * hierarchy mode.
1391 */
1392 if (fmt->color) {
1393 width -= fmt->color(fmt, &hpp, entry);
1394 } else {
1395 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001396
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001397 width -= fmt->entry(fmt, &hpp, entry);
1398 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001399
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001400 while (isspace(s[i++]))
1401 width++;
1402 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001403 }
1404 }
1405
1406 /* The scroll bar isn't being used */
1407 if (!browser->b.navkeypressed)
1408 width += 1;
1409
1410 ui_browser__write_nstring(&browser->b, "", width);
1411
1412 ++row;
1413 ++printed;
1414
1415show_callchain:
1416 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1417 struct callchain_print_arg carg = {
1418 .row_offset = row_offset,
1419 };
1420
1421 printed += hist_browser__show_callchain(browser, entry,
1422 level + 1, row,
1423 hist_browser__show_callchain_entry, &carg,
1424 hist_browser__check_output_full);
1425 }
1426
1427 return printed;
1428}
1429
Namhyung Kim79dded82016-02-26 21:13:19 +09001430static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001431 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001432{
1433 int width = browser->b.width;
1434 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1435 bool first = true;
1436 int column = 0;
1437 int ret;
1438 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001439 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001440 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001441
1442 if (current_entry) {
1443 browser->he_selection = NULL;
1444 browser->selection = NULL;
1445 }
1446
1447 hist_browser__gotorc(browser, row, 0);
1448
1449 if (current_entry && browser->b.navkeypressed)
1450 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1451 else
1452 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1453
1454 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1455 width -= level * HIERARCHY_INDENT;
1456
Namhyung Kima61a22f2016-03-07 16:44:50 -03001457 /* the first hpp_list_node is for overhead columns */
1458 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1459 struct perf_hpp_list_node, list);
1460 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001461 if (perf_hpp__should_skip(fmt, browser->hists) ||
1462 column++ < browser->b.horiz_scroll)
1463 continue;
1464
Jiri Olsada1b0402016-06-14 20:19:20 +02001465 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001466
1467 if (first) {
1468 /* for folded sign */
1469 first = false;
1470 ret++;
1471 } else {
1472 /* space between columns */
1473 ret += 2;
1474 }
1475
1476 ui_browser__write_nstring(&browser->b, "", ret);
1477 width -= ret;
1478 }
1479
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001480 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1481 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001482
1483 if (column >= browser->b.horiz_scroll) {
1484 char buf[32];
1485
1486 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1487 ui_browser__printf(&browser->b, " %s", buf);
1488 width -= ret + 2;
1489 }
1490
1491 /* The scroll bar isn't being used */
1492 if (!browser->b.navkeypressed)
1493 width += 1;
1494
1495 ui_browser__write_nstring(&browser->b, "", width);
1496 return 1;
1497}
1498
Jiri Olsa81a888f2014-06-14 15:44:52 +02001499static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1500{
1501 advance_hpp(hpp, inc);
1502 return hpp->size <= 0;
1503}
1504
Jiri Olsa69705b32016-08-07 17:28:28 +02001505static int
1506hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1507 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001508{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001509 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001510 struct perf_hpp dummy_hpp = {
1511 .buf = buf,
1512 .size = size,
1513 };
1514 struct perf_hpp_fmt *fmt;
1515 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001516 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001517
1518 if (symbol_conf.use_callchain) {
1519 ret = scnprintf(buf, size, " ");
1520 if (advance_hpp_check(&dummy_hpp, ret))
1521 return ret;
1522 }
1523
Jiri Olsaf0786af2016-01-18 10:24:23 +01001524 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001525 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001526 continue;
1527
Jiri Olsa69705b32016-08-07 17:28:28 +02001528 ret = fmt->header(fmt, &dummy_hpp, hists, line);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001529 if (advance_hpp_check(&dummy_hpp, ret))
1530 break;
1531
1532 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1533 if (advance_hpp_check(&dummy_hpp, ret))
1534 break;
1535 }
1536
1537 return ret;
1538}
1539
Namhyung Kimd8b92402016-02-25 00:13:46 +09001540static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1541{
1542 struct hists *hists = browser->hists;
1543 struct perf_hpp dummy_hpp = {
1544 .buf = buf,
1545 .size = size,
1546 };
1547 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001548 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001549 size_t ret = 0;
1550 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001551 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001552 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001553
1554 ret = scnprintf(buf, size, " ");
1555 if (advance_hpp_check(&dummy_hpp, ret))
1556 return ret;
1557
Namhyung Kima61a22f2016-03-07 16:44:50 -03001558 /* the first hpp_list_node is for overhead columns */
1559 fmt_node = list_first_entry(&hists->hpp_formats,
1560 struct perf_hpp_list_node, list);
1561 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001562 if (column++ < browser->b.horiz_scroll)
1563 continue;
1564
Jiri Olsa74bb43f2016-08-07 17:28:27 +02001565 ret = fmt->header(fmt, &dummy_hpp, hists, 0);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001566 if (advance_hpp_check(&dummy_hpp, ret))
1567 break;
1568
1569 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1570 if (advance_hpp_check(&dummy_hpp, ret))
1571 break;
1572 }
1573
1574 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001575 indent * HIERARCHY_INDENT, "");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001576 if (advance_hpp_check(&dummy_hpp, ret))
1577 return ret;
1578
Namhyung Kima61a22f2016-03-07 16:44:50 -03001579 first_node = true;
1580 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1581 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001582 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1583 if (advance_hpp_check(&dummy_hpp, ret))
1584 break;
1585 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001586 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001587
Namhyung Kima61a22f2016-03-07 16:44:50 -03001588 first_col = true;
1589 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1590 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001591
Namhyung Kima61a22f2016-03-07 16:44:50 -03001592 if (perf_hpp__should_skip(fmt, hists))
1593 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001594
Namhyung Kima61a22f2016-03-07 16:44:50 -03001595 if (!first_col) {
1596 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1597 if (advance_hpp_check(&dummy_hpp, ret))
1598 break;
1599 }
1600 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001601
Jiri Olsa74bb43f2016-08-07 17:28:27 +02001602 ret = fmt->header(fmt, &dummy_hpp, hists, 0);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001603 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001604
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001605 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001606 ret = strlen(start);
1607
1608 if (start != dummy_hpp.buf)
1609 memmove(dummy_hpp.buf, start, ret + 1);
1610
1611 if (advance_hpp_check(&dummy_hpp, ret))
1612 break;
1613 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001614 }
1615
1616 return ret;
1617}
1618
Jiri Olsa01b47702016-06-14 20:19:13 +02001619static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001620{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001621 char headers[1024];
1622
Jiri Olsa01b47702016-06-14 20:19:13 +02001623 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1624 sizeof(headers));
1625
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001626 ui_browser__gotorc(&browser->b, 0, 0);
1627 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001628 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001629}
1630
Jiri Olsa01b47702016-06-14 20:19:13 +02001631static void hists_browser__headers(struct hist_browser *browser)
1632{
Jiri Olsa69705b32016-08-07 17:28:28 +02001633 struct hists *hists = browser->hists;
1634 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001635
Jiri Olsa69705b32016-08-07 17:28:28 +02001636 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001637
Jiri Olsa69705b32016-08-07 17:28:28 +02001638 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1639 char headers[1024];
1640
1641 hists_browser__scnprintf_headers(browser, headers,
1642 sizeof(headers), line);
1643
1644 ui_browser__gotorc(&browser->b, line, 0);
1645 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1646 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1647 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001648}
1649
1650static void hist_browser__show_headers(struct hist_browser *browser)
1651{
1652 if (symbol_conf.report_hierarchy)
1653 hists_browser__hierarchy_headers(browser);
1654 else
1655 hists_browser__headers(browser);
1656}
1657
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001658static void ui_browser__hists_init_top(struct ui_browser *browser)
1659{
1660 if (browser->top == NULL) {
1661 struct hist_browser *hb;
1662
1663 hb = container_of(browser, struct hist_browser, b);
1664 browser->top = rb_first(&hb->hists->entries);
1665 }
1666}
1667
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001668static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001669{
1670 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001671 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001672 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001673 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001674 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001675
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001676 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001677 struct perf_hpp_list *hpp_list = hists->hpp_list;
1678
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001679 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001680 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001681 }
1682
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001683 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001684 hb->he_selection = NULL;
1685 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001686
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001687 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001688 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001689 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001690
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001691 if (h->filtered) {
1692 /* let it move to sibling */
1693 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001694 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001695 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001696
Namhyung Kim14135662013-10-31 10:17:39 +09001697 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001698 if (percent < hb->min_pcnt)
1699 continue;
1700
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001701 if (symbol_conf.report_hierarchy) {
1702 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001703 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001704 if (row == browser->rows)
1705 break;
1706
1707 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001708 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001709 row++;
1710 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001711 } else {
1712 row += hist_browser__show_entry(hb, h, row);
1713 }
1714
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001715 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001716 break;
1717 }
1718
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001719 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001720}
1721
Namhyung Kim064f1982013-05-14 11:09:04 +09001722static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001723 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001724{
1725 while (nd != NULL) {
1726 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001727 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001728
Namhyung Kimc0f15272014-04-16 11:16:33 +09001729 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001730 return nd;
1731
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001732 /*
1733 * If it's filtered, its all children also were filtered.
1734 * So move to sibling node.
1735 */
1736 if (rb_next(nd))
1737 nd = rb_next(nd);
1738 else
1739 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001740 }
1741
1742 return NULL;
1743}
1744
Namhyung Kim064f1982013-05-14 11:09:04 +09001745static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001746 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001747{
1748 while (nd != NULL) {
1749 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001750 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001751
1752 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001753 return nd;
1754
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001755 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001756 }
1757
1758 return NULL;
1759}
1760
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001761static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001762 off_t offset, int whence)
1763{
1764 struct hist_entry *h;
1765 struct rb_node *nd;
1766 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001767 struct hist_browser *hb;
1768
1769 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001770
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001771 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001772 return;
1773
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001774 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001775
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001776 switch (whence) {
1777 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001778 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001779 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001780 break;
1781 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001782 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001783 goto do_offset;
1784 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001785 nd = rb_hierarchy_last(rb_last(browser->entries));
1786 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001787 first = false;
1788 break;
1789 default:
1790 return;
1791 }
1792
1793 /*
1794 * Moves not relative to the first visible entry invalidates its
1795 * row_offset:
1796 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001797 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001798 h->row_offset = 0;
1799
1800 /*
1801 * Here we have to check if nd is expanded (+), if it is we can't go
1802 * the next top level hist_entry, instead we must compute an offset of
1803 * what _not_ to show and not change the first visible entry.
1804 *
1805 * This offset increments when we are going from top to bottom and
1806 * decreases when we're going from bottom to top.
1807 *
1808 * As we don't have backpointers to the top level in the callchains
1809 * structure, we need to always print the whole hist_entry callchain,
1810 * skipping the first ones that are before the first visible entry
1811 * and stop when we printed enough lines to fill the screen.
1812 */
1813do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001814 if (!nd)
1815 return;
1816
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001817 if (offset > 0) {
1818 do {
1819 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001820 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001821 u16 remaining = h->nr_rows - h->row_offset;
1822 if (offset > remaining) {
1823 offset -= remaining;
1824 h->row_offset = 0;
1825 } else {
1826 h->row_offset += offset;
1827 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001828 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001829 break;
1830 }
1831 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001832 nd = hists__filter_entries(rb_hierarchy_next(nd),
1833 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001834 if (nd == NULL)
1835 break;
1836 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001837 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001838 } while (offset != 0);
1839 } else if (offset < 0) {
1840 while (1) {
1841 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001842 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001843 if (first) {
1844 if (-offset > h->row_offset) {
1845 offset += h->row_offset;
1846 h->row_offset = 0;
1847 } else {
1848 h->row_offset += offset;
1849 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001850 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001851 break;
1852 }
1853 } else {
1854 if (-offset > h->nr_rows) {
1855 offset += h->nr_rows;
1856 h->row_offset = 0;
1857 } else {
1858 h->row_offset = h->nr_rows + offset;
1859 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001860 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001861 break;
1862 }
1863 }
1864 }
1865
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001866 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001867 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001868 if (nd == NULL)
1869 break;
1870 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001871 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001872 if (offset == 0) {
1873 /*
1874 * Last unfiltered hist_entry, check if it is
1875 * unfolded, if it is then we should have
1876 * row_offset at its last entry.
1877 */
1878 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001879 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001880 h->row_offset = h->nr_rows;
1881 break;
1882 }
1883 first = false;
1884 }
1885 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001886 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001887 h = rb_entry(nd, struct hist_entry, rb_node);
1888 h->row_offset = 0;
1889 }
1890}
1891
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001892static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001893 struct hist_entry *he, FILE *fp,
1894 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001895{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001896 struct callchain_print_arg arg = {
1897 .fp = fp,
1898 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001899
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001900 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001901 hist_browser__fprintf_callchain_entry, &arg,
1902 hist_browser__check_dump_full);
1903 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001904}
1905
1906static int hist_browser__fprintf_entry(struct hist_browser *browser,
1907 struct hist_entry *he, FILE *fp)
1908{
1909 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001910 int printed = 0;
1911 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001912 struct perf_hpp hpp = {
1913 .buf = s,
1914 .size = sizeof(s),
1915 };
1916 struct perf_hpp_fmt *fmt;
1917 bool first = true;
1918 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001919
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001920 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001921 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001922 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001923 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001924
Jiri Olsaf0786af2016-01-18 10:24:23 +01001925 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001926 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001927 continue;
1928
Namhyung Kim26d8b332014-03-03 16:16:20 +09001929 if (!first) {
1930 ret = scnprintf(hpp.buf, hpp.size, " ");
1931 advance_hpp(&hpp, ret);
1932 } else
1933 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001934
Namhyung Kim26d8b332014-03-03 16:16:20 +09001935 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001936 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001937 advance_hpp(&hpp, ret);
1938 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001939 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001940
1941 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001942 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1943
1944 return printed;
1945}
1946
1947
1948static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1949 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09001950 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001951{
1952 char s[8192];
1953 int printed = 0;
1954 char folded_sign = ' ';
1955 struct perf_hpp hpp = {
1956 .buf = s,
1957 .size = sizeof(s),
1958 };
1959 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09001960 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001961 bool first = true;
1962 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09001963 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001964
1965 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1966
1967 folded_sign = hist_entry__folded(he);
1968 printed += fprintf(fp, "%c", folded_sign);
1969
Namhyung Kim325a6282016-03-09 22:47:00 +09001970 /* the first hpp_list_node is for overhead columns */
1971 fmt_node = list_first_entry(&he->hists->hpp_formats,
1972 struct perf_hpp_list_node, list);
1973 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001974 if (!first) {
1975 ret = scnprintf(hpp.buf, hpp.size, " ");
1976 advance_hpp(&hpp, ret);
1977 } else
1978 first = false;
1979
1980 ret = fmt->entry(fmt, &hpp, he);
1981 advance_hpp(&hpp, ret);
1982 }
1983
1984 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1985 advance_hpp(&hpp, ret);
1986
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001987 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1988 ret = scnprintf(hpp.buf, hpp.size, " ");
1989 advance_hpp(&hpp, ret);
1990
1991 ret = fmt->entry(fmt, &hpp, he);
1992 advance_hpp(&hpp, ret);
1993 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001994
1995 printed += fprintf(fp, "%s\n", rtrim(s));
1996
1997 if (he->leaf && folded_sign == '-') {
1998 printed += hist_browser__fprintf_callchain(browser, he, fp,
1999 he->depth + 1);
2000 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002001
2002 return printed;
2003}
2004
2005static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2006{
Namhyung Kim064f1982013-05-14 11:09:04 +09002007 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002008 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002009 int printed = 0;
2010
2011 while (nd) {
2012 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2013
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002014 if (symbol_conf.report_hierarchy) {
2015 printed += hist_browser__fprintf_hierarchy_entry(browser,
2016 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002017 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002018 } else {
2019 printed += hist_browser__fprintf_entry(browser, h, fp);
2020 }
2021
2022 nd = hists__filter_entries(rb_hierarchy_next(nd),
2023 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002024 }
2025
2026 return printed;
2027}
2028
2029static int hist_browser__dump(struct hist_browser *browser)
2030{
2031 char filename[64];
2032 FILE *fp;
2033
2034 while (1) {
2035 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2036 if (access(filename, F_OK))
2037 break;
2038 /*
2039 * XXX: Just an arbitrary lazy upper limit
2040 */
2041 if (++browser->print_seq == 8192) {
2042 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2043 return -1;
2044 }
2045 }
2046
2047 fp = fopen(filename, "w");
2048 if (fp == NULL) {
2049 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002050 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002051 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002052 return -1;
2053 }
2054
2055 ++browser->print_seq;
2056 hist_browser__fprintf(browser, fp);
2057 fclose(fp);
2058 ui_helpline__fpush("%s written!", filename);
2059
2060 return 0;
2061}
2062
Jiri Olsafcd86422016-06-20 23:58:18 +02002063void hist_browser__init(struct hist_browser *browser,
2064 struct hists *hists)
2065{
2066 struct perf_hpp_fmt *fmt;
2067
2068 browser->hists = hists;
2069 browser->b.refresh = hist_browser__refresh;
2070 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2071 browser->b.seek = ui_browser__hists_seek;
2072 browser->b.use_navkeypressed = true;
2073 browser->show_headers = symbol_conf.show_hist_headers;
2074
2075 hists__for_each_format(hists, fmt) {
2076 perf_hpp__reset_width(fmt, hists);
2077 ++browser->b.columns;
2078 }
2079}
2080
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002081struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002082{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002083 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002084
Jiri Olsafcd86422016-06-20 23:58:18 +02002085 if (browser)
2086 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002087
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002088 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002089}
2090
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002091static struct hist_browser *
2092perf_evsel_browser__new(struct perf_evsel *evsel,
2093 struct hist_browser_timer *hbt,
2094 struct perf_env *env)
2095{
2096 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2097
2098 if (browser) {
2099 browser->hbt = hbt;
2100 browser->env = env;
2101 browser->title = perf_evsel_browser_title;
2102 }
2103 return browser;
2104}
2105
Jiri Olsadabd2012016-06-20 23:58:14 +02002106void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002107{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002108 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002109}
2110
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002111static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002112{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002113 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002114}
2115
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002116static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002117{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002118 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002119}
2120
Taeung Song1e378eb2014-10-07 16:13:15 +09002121/* Check whether the browser is for 'top' or 'report' */
2122static inline bool is_report_browser(void *timer)
2123{
2124 return timer == NULL;
2125}
2126
Jiri Olsa5b91a862016-06-20 23:58:15 +02002127static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002128 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002129{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002130 struct hist_browser_timer *hbt = browser->hbt;
2131 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002132 char unit;
2133 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002134 const struct dso *dso = hists->dso_filter;
2135 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002136 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002137 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2138 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002139 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002140 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002141 char buf[512];
2142 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002143 char ref[30] = " show reference callgraph, ";
2144 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002145
Namhyung Kimf2148332014-01-14 11:52:48 +09002146 if (symbol_conf.filter_relative) {
2147 nr_samples = hists->stats.nr_non_filtered_samples;
2148 nr_events = hists->stats.total_non_filtered_period;
2149 }
2150
Namhyung Kim759ff492013-03-05 14:53:26 +09002151 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002152 struct perf_evsel *pos;
2153
2154 perf_evsel__group_desc(evsel, buf, buflen);
2155 ev_name = buf;
2156
2157 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002158 struct hists *pos_hists = evsel__hists(pos);
2159
Namhyung Kimf2148332014-01-14 11:52:48 +09002160 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002161 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2162 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002163 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002164 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2165 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002166 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002167 }
2168 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002169
Kan Liang9e207dd2015-08-11 06:30:49 -04002170 if (symbol_conf.show_ref_callgraph &&
2171 strstr(ev_name, "call-graph=no"))
2172 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002173 nr_samples = convert_unit(nr_samples, &unit);
2174 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002175 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2176 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002177
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002178
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002179 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002180 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002181 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002182 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002183 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002184 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002185 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002186 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002187 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002188 } else {
2189 printed += scnprintf(bf + printed, size - printed,
2190 ", Thread: %s",
2191 (thread->comm_set ? thread__comm_str(thread) : ""));
2192 }
2193 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002194 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002195 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002196 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002197 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002198 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002199 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002200 if (!is_report_browser(hbt)) {
2201 struct perf_top *top = hbt->arg;
2202
2203 if (top->zero)
2204 printed += scnprintf(bf + printed, size - printed, " [z]");
2205 }
2206
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002207 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002208}
2209
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002210static inline void free_popup_options(char **options, int n)
2211{
2212 int i;
2213
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002214 for (i = 0; i < n; ++i)
2215 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002216}
2217
Feng Tang341487ab2013-02-03 14:38:20 +08002218/*
2219 * Only runtime switching of perf data file will make "input_name" point
2220 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2221 * whether we need to call free() for current "input_name" during the switch.
2222 */
2223static bool is_input_name_malloced = false;
2224
2225static int switch_data_file(void)
2226{
2227 char *pwd, *options[32], *abs_path[32], *tmp;
2228 DIR *pwd_dir;
2229 int nr_options = 0, choice = -1, ret = -1;
2230 struct dirent *dent;
2231
2232 pwd = getenv("PWD");
2233 if (!pwd)
2234 return ret;
2235
2236 pwd_dir = opendir(pwd);
2237 if (!pwd_dir)
2238 return ret;
2239
2240 memset(options, 0, sizeof(options));
2241 memset(options, 0, sizeof(abs_path));
2242
2243 while ((dent = readdir(pwd_dir))) {
2244 char path[PATH_MAX];
2245 u64 magic;
2246 char *name = dent->d_name;
2247 FILE *file;
2248
2249 if (!(dent->d_type == DT_REG))
2250 continue;
2251
2252 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2253
2254 file = fopen(path, "r");
2255 if (!file)
2256 continue;
2257
2258 if (fread(&magic, 1, 8, file) < 8)
2259 goto close_file_and_continue;
2260
2261 if (is_perf_magic(magic)) {
2262 options[nr_options] = strdup(name);
2263 if (!options[nr_options])
2264 goto close_file_and_continue;
2265
2266 abs_path[nr_options] = strdup(path);
2267 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002268 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002269 ui__warning("Can't search all data files due to memory shortage.\n");
2270 fclose(file);
2271 break;
2272 }
2273
2274 nr_options++;
2275 }
2276
2277close_file_and_continue:
2278 fclose(file);
2279 if (nr_options >= 32) {
2280 ui__warning("Too many perf data files in PWD!\n"
2281 "Only the first 32 files will be listed.\n");
2282 break;
2283 }
2284 }
2285 closedir(pwd_dir);
2286
2287 if (nr_options) {
2288 choice = ui__popup_menu(nr_options, options);
2289 if (choice < nr_options && choice >= 0) {
2290 tmp = strdup(abs_path[choice]);
2291 if (tmp) {
2292 if (is_input_name_malloced)
2293 free((void *)input_name);
2294 input_name = tmp;
2295 is_input_name_malloced = true;
2296 ret = 0;
2297 } else
2298 ui__warning("Data switch failed due to memory shortage!\n");
2299 }
2300 }
2301
2302 free_popup_options(options, nr_options);
2303 free_popup_options(abs_path, nr_options);
2304 return ret;
2305}
2306
Namhyung Kimea7cd592015-04-22 16:18:19 +09002307struct popup_action {
2308 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002309 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002310 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002311
2312 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2313};
2314
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002315static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002316do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002317{
2318 struct perf_evsel *evsel;
2319 struct annotation *notes;
2320 struct hist_entry *he;
2321 int err;
2322
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002323 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002324 return 0;
2325
Namhyung Kimea7cd592015-04-22 16:18:19 +09002326 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002327 if (!notes->src)
2328 return 0;
2329
2330 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002331 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002332 he = hist_browser__selected_entry(browser);
2333 /*
2334 * offer option to annotate the other branch source or target
2335 * (if they exists) when returning from annotate
2336 */
2337 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2338 return 1;
2339
2340 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2341 if (err)
2342 ui_browser__handle_resize(&browser->b);
2343 return 0;
2344}
2345
2346static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002347add_annotate_opt(struct hist_browser *browser __maybe_unused,
2348 struct popup_action *act, char **optstr,
2349 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002350{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002351 if (sym == NULL || map->dso->annotate_warned)
2352 return 0;
2353
2354 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2355 return 0;
2356
2357 act->ms.map = map;
2358 act->ms.sym = sym;
2359 act->fn = do_annotate;
2360 return 1;
2361}
2362
2363static int
2364do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2365{
2366 struct thread *thread = act->thread;
2367
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002368 if ((!hists__has(browser->hists, thread) &&
2369 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002370 return 0;
2371
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002372 if (browser->hists->thread_filter) {
2373 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2374 perf_hpp__set_elide(HISTC_THREAD, false);
2375 thread__zput(browser->hists->thread_filter);
2376 ui_helpline__pop();
2377 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002378 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002379 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2380 thread->comm_set ? thread__comm_str(thread) : "",
2381 thread->tid);
2382 } else {
2383 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2384 thread->comm_set ? thread__comm_str(thread) : "");
2385 }
2386
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002387 browser->hists->thread_filter = thread__get(thread);
2388 perf_hpp__set_elide(HISTC_THREAD, false);
2389 pstack__push(browser->pstack, &browser->hists->thread_filter);
2390 }
2391
2392 hists__filter_by_thread(browser->hists);
2393 hist_browser__reset(browser);
2394 return 0;
2395}
2396
2397static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002398add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2399 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002400{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002401 int ret;
2402
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002403 if ((!hists__has(browser->hists, thread) &&
2404 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002405 return 0;
2406
Jiri Olsafa829112016-05-03 13:54:47 +02002407 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002408 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2409 browser->hists->thread_filter ? "out of" : "into",
2410 thread->comm_set ? thread__comm_str(thread) : "",
2411 thread->tid);
2412 } else {
2413 ret = asprintf(optstr, "Zoom %s %s thread",
2414 browser->hists->thread_filter ? "out of" : "into",
2415 thread->comm_set ? thread__comm_str(thread) : "");
2416 }
2417 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002418 return 0;
2419
2420 act->thread = thread;
2421 act->fn = do_zoom_thread;
2422 return 1;
2423}
2424
2425static int
2426do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2427{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002428 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002429
Jiri Olsa69849fc2016-05-03 13:54:45 +02002430 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002431 return 0;
2432
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002433 if (browser->hists->dso_filter) {
2434 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2435 perf_hpp__set_elide(HISTC_DSO, false);
2436 browser->hists->dso_filter = NULL;
2437 ui_helpline__pop();
2438 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002439 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002440 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002441 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002442 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2443 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002444 perf_hpp__set_elide(HISTC_DSO, true);
2445 pstack__push(browser->pstack, &browser->hists->dso_filter);
2446 }
2447
2448 hists__filter_by_dso(browser->hists);
2449 hist_browser__reset(browser);
2450 return 0;
2451}
2452
2453static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002454add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002455 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002456{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002457 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002458 return 0;
2459
2460 if (asprintf(optstr, "Zoom %s %s DSO",
2461 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002462 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002463 return 0;
2464
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002465 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002466 act->fn = do_zoom_dso;
2467 return 1;
2468}
2469
2470static int
2471do_browse_map(struct hist_browser *browser __maybe_unused,
2472 struct popup_action *act)
2473{
2474 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002475 return 0;
2476}
2477
2478static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002479add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002480 struct popup_action *act, char **optstr, struct map *map)
2481{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002482 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002483 return 0;
2484
2485 if (asprintf(optstr, "Browse map details") < 0)
2486 return 0;
2487
2488 act->ms.map = map;
2489 act->fn = do_browse_map;
2490 return 1;
2491}
2492
2493static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002494do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002495 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002496{
2497 char script_opt[64];
2498 memset(script_opt, 0, sizeof(script_opt));
2499
Namhyung Kimea7cd592015-04-22 16:18:19 +09002500 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002501 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002502 thread__comm_str(act->thread));
2503 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002504 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002505 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002506 }
2507
2508 script_browse(script_opt);
2509 return 0;
2510}
2511
2512static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002513add_script_opt(struct hist_browser *browser __maybe_unused,
2514 struct popup_action *act, char **optstr,
2515 struct thread *thread, struct symbol *sym)
2516{
2517 if (thread) {
2518 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2519 thread__comm_str(thread)) < 0)
2520 return 0;
2521 } else if (sym) {
2522 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2523 sym->name) < 0)
2524 return 0;
2525 } else {
2526 if (asprintf(optstr, "Run scripts for all samples") < 0)
2527 return 0;
2528 }
2529
2530 act->thread = thread;
2531 act->ms.sym = sym;
2532 act->fn = do_run_script;
2533 return 1;
2534}
2535
2536static int
2537do_switch_data(struct hist_browser *browser __maybe_unused,
2538 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002539{
2540 if (switch_data_file()) {
2541 ui__warning("Won't switch the data files due to\n"
2542 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002543 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002544 }
2545
2546 return K_SWITCH_INPUT_DATA;
2547}
2548
Namhyung Kimea7cd592015-04-22 16:18:19 +09002549static int
2550add_switch_opt(struct hist_browser *browser,
2551 struct popup_action *act, char **optstr)
2552{
2553 if (!is_report_browser(browser->hbt))
2554 return 0;
2555
2556 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2557 return 0;
2558
2559 act->fn = do_switch_data;
2560 return 1;
2561}
2562
2563static int
2564do_exit_browser(struct hist_browser *browser __maybe_unused,
2565 struct popup_action *act __maybe_unused)
2566{
2567 return 0;
2568}
2569
2570static int
2571add_exit_opt(struct hist_browser *browser __maybe_unused,
2572 struct popup_action *act, char **optstr)
2573{
2574 if (asprintf(optstr, "Exit") < 0)
2575 return 0;
2576
2577 act->fn = do_exit_browser;
2578 return 1;
2579}
2580
Kan Liang84734b02015-09-04 10:45:45 -04002581static int
2582do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2583{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002584 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002585 return 0;
2586
Kan Liang84734b02015-09-04 10:45:45 -04002587 if (browser->hists->socket_filter > -1) {
2588 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2589 browser->hists->socket_filter = -1;
2590 perf_hpp__set_elide(HISTC_SOCKET, false);
2591 } else {
2592 browser->hists->socket_filter = act->socket;
2593 perf_hpp__set_elide(HISTC_SOCKET, true);
2594 pstack__push(browser->pstack, &browser->hists->socket_filter);
2595 }
2596
2597 hists__filter_by_socket(browser->hists);
2598 hist_browser__reset(browser);
2599 return 0;
2600}
2601
2602static int
2603add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2604 char **optstr, int socket_id)
2605{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002606 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002607 return 0;
2608
2609 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2610 (browser->hists->socket_filter > -1) ? "out of" : "into",
2611 socket_id) < 0)
2612 return 0;
2613
2614 act->socket = socket_id;
2615 act->fn = do_zoom_socket;
2616 return 1;
2617}
2618
Namhyung Kim112f7612014-04-22 14:05:35 +09002619static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002620{
2621 u64 nr_entries = 0;
2622 struct rb_node *nd = rb_first(&hb->hists->entries);
2623
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002624 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002625 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2626 return;
2627 }
2628
Namhyung Kim14135662013-10-31 10:17:39 +09002629 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002630 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002631 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002632 }
2633
Namhyung Kim112f7612014-04-22 14:05:35 +09002634 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002635 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002636}
Feng Tang341487ab2013-02-03 14:38:20 +08002637
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002638static void hist_browser__update_percent_limit(struct hist_browser *hb,
2639 double percent)
2640{
2641 struct hist_entry *he;
2642 struct rb_node *nd = rb_first(&hb->hists->entries);
2643 u64 total = hists__total_period(hb->hists);
2644 u64 min_callchain_hits = total * (percent / 100);
2645
2646 hb->min_pcnt = callchain_param.min_percent = percent;
2647
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002648 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2649 he = rb_entry(nd, struct hist_entry, rb_node);
2650
Namhyung Kim79dded82016-02-26 21:13:19 +09002651 if (he->has_no_entry) {
2652 he->has_no_entry = false;
2653 he->nr_rows = 0;
2654 }
2655
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002656 if (!he->leaf || !symbol_conf.use_callchain)
2657 goto next;
2658
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002659 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2660 total = he->stat.period;
2661
2662 if (symbol_conf.cumulate_callchain)
2663 total = he->stat_acc->period;
2664
2665 min_callchain_hits = total * (percent / 100);
2666 }
2667
2668 callchain_param.sort(&he->sorted_chain, he->callchain,
2669 min_callchain_hits, &callchain_param);
2670
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002671next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002672 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002673
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002674 /* force to re-evaluate folding state of callchains */
2675 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002676 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002677 }
2678}
2679
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002680static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002681 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002682 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002683 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002684 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002685 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002686{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002687 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002688 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002689 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002690#define MAX_OPTIONS 16
2691 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002692 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002693 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002694 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002695 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002696 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002697
Namhyung Kime8e684a2013-12-26 14:37:58 +09002698#define HIST_BROWSER_HELP_COMMON \
2699 "h/?/F1 Show this window\n" \
2700 "UP/DOWN/PGUP\n" \
2701 "PGDN/SPACE Navigate\n" \
2702 "q/ESC/CTRL+C Exit browser\n\n" \
2703 "For multiple event sessions:\n\n" \
2704 "TAB/UNTAB Switch events\n\n" \
2705 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002706 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2707 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002708 "a Annotate current symbol\n" \
2709 "C Collapse all callchains\n" \
2710 "d Zoom into current DSO\n" \
2711 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002712 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002713 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002714 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002715 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002716 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002717
2718 /* help messages are sorted by lexical order of the hotkey */
2719 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002720 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002721 "P Print histograms to perf.hist.N\n"
2722 "r Run available scripts\n"
2723 "s Switch to another data file in PWD\n"
2724 "t Zoom into current Thread\n"
2725 "V Verbose (DSO names in callchains, etc)\n"
2726 "/ Filter symbol by name";
2727 const char top_help[] = HIST_BROWSER_HELP_COMMON
2728 "P Print histograms to perf.hist.N\n"
2729 "t Zoom into current Thread\n"
2730 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002731 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002732 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002733 "/ Filter symbol by name";
2734
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002735 if (browser == NULL)
2736 return -1;
2737
Namhyung Kimed426912015-05-29 21:53:44 +09002738 /* reset abort key so that it can get Ctrl-C as a key */
2739 SLang_reset_tty();
2740 SLang_init_tty(0, 0, 0);
2741
Namhyung Kim03905042015-11-28 02:32:39 +09002742 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002743 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002744 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002745
Kan Liang84734b02015-09-04 10:45:45 -04002746 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002747 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002748 goto out;
2749
2750 ui_helpline__push(helpline);
2751
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002752 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002753 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002754
Namhyung Kim5b591662014-07-31 14:47:38 +09002755 if (symbol_conf.col_width_list_str)
2756 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2757
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002758 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002759 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002760 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002761 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002762 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002763
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002764 nr_options = 0;
2765
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002766 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002767
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002768 if (browser->he_selection != NULL) {
2769 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002770 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002771 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002772 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002773 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002774 case K_TAB:
2775 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002776 if (nr_events == 1)
2777 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002778 /*
2779 * Exit the browser, let hists__browser_tree
2780 * go to the next or previous
2781 */
2782 goto out_free_stack;
2783 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002784 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002785 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002786 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002787 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002788 continue;
2789 }
2790
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002791 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002792 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002793 browser->selection->map->dso->annotate_warned)
2794 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002795
Namhyung Kimea7cd592015-04-22 16:18:19 +09002796 actions->ms.map = browser->selection->map;
2797 actions->ms.sym = browser->selection->sym;
2798 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002799 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002800 case 'P':
2801 hist_browser__dump(browser);
2802 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002803 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002804 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002805 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002806 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002807 case 'V':
2808 browser->show_dso = !browser->show_dso;
2809 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002810 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002811 actions->thread = thread;
2812 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002813 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002814 case 'S':
2815 actions->socket = socked_id;
2816 do_zoom_socket(browser, actions);
2817 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002818 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002819 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002820 "Please enter the name of symbol you want to see.\n"
2821 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002822 buf, "ENTER: OK, ESC: Cancel",
2823 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002824 hists->symbol_filter_str = *buf ? buf : NULL;
2825 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002826 hist_browser__reset(browser);
2827 }
2828 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002829 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002830 if (is_report_browser(hbt)) {
2831 actions->thread = NULL;
2832 actions->ms.sym = NULL;
2833 do_run_script(browser, actions);
2834 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002835 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002836 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002837 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002838 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002839 if (key == K_SWITCH_INPUT_DATA)
2840 goto out_free_stack;
2841 }
Feng Tang341487ab2013-02-03 14:38:20 +08002842 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002843 case 'i':
2844 /* env->arch is NULL for live-mode (i.e. perf top) */
2845 if (env->arch)
2846 tui__header_window(env);
2847 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002848 case 'F':
2849 symbol_conf.filter_relative ^= 1;
2850 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002851 case 'z':
2852 if (!is_report_browser(hbt)) {
2853 struct perf_top *top = hbt->arg;
2854
2855 top->zero = !top->zero;
2856 }
2857 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002858 case 'L':
2859 if (ui_browser__input_window("Percent Limit",
2860 "Please enter the value you want to hide entries under that percent.",
2861 buf, "ENTER: OK, ESC: Cancel",
2862 delay_secs * 2) == K_ENTER) {
2863 char *end;
2864 double new_percent = strtod(buf, &end);
2865
2866 if (new_percent < 0 || new_percent > 100) {
2867 ui_browser__warning(&browser->b, delay_secs * 2,
2868 "Invalid percent: %.2f", new_percent);
2869 continue;
2870 }
2871
2872 hist_browser__update_percent_limit(browser, new_percent);
2873 hist_browser__reset(browser);
2874 }
2875 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002876 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002877 case 'h':
2878 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002879 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002880 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002881 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002882 case K_ENTER:
2883 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002884 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002885 /* menu */
2886 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002887 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002888 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002889 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002890
Namhyung Kim01f00a12015-04-22 16:18:16 +09002891 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002892 /*
2893 * Go back to the perf_evsel_menu__run or other user
2894 */
2895 if (left_exits)
2896 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002897
2898 if (key == K_ESC &&
2899 ui_browser__dialog_yesno(&browser->b,
2900 "Do you really want to exit?"))
2901 goto out_free_stack;
2902
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002903 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002904 }
Namhyung Kim64221842015-04-24 10:15:33 +09002905 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002906 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002907 /*
2908 * No need to set actions->dso here since
2909 * it's just to remove the current filter.
2910 * Ditto for thread below.
2911 */
2912 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002913 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002914 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002915 } else if (top == &browser->hists->socket_filter) {
2916 do_zoom_socket(browser, actions);
2917 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002918 continue;
2919 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002920 case 'q':
2921 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002922 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002923 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002924 if (!is_report_browser(hbt)) {
2925 struct perf_top *top = hbt->arg;
2926
2927 perf_evlist__toggle_enable(top->evlist);
2928 /*
2929 * No need to refresh, resort/decay histogram
2930 * entries if we are not collecting samples:
2931 */
2932 if (top->evlist->enabled) {
2933 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2934 hbt->refresh = delay_secs;
2935 } else {
2936 helpline = "Press 'f' again to re-enable the events";
2937 hbt->refresh = 0;
2938 }
2939 continue;
2940 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002941 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002942 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002943 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002944 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002945 }
2946
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002947 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002948 goto skip_annotation;
2949
Namhyung Kim55369fc2013-04-01 20:35:20 +09002950 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002951 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002952
2953 if (bi == NULL)
2954 goto skip_annotation;
2955
Namhyung Kimea7cd592015-04-22 16:18:19 +09002956 nr_options += add_annotate_opt(browser,
2957 &actions[nr_options],
2958 &options[nr_options],
2959 bi->from.map,
2960 bi->from.sym);
2961 if (bi->to.sym != bi->from.sym)
2962 nr_options += add_annotate_opt(browser,
2963 &actions[nr_options],
2964 &options[nr_options],
2965 bi->to.map,
2966 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002967 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002968 nr_options += add_annotate_opt(browser,
2969 &actions[nr_options],
2970 &options[nr_options],
2971 browser->selection->map,
2972 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002973 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002974skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002975 nr_options += add_thread_opt(browser, &actions[nr_options],
2976 &options[nr_options], thread);
2977 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002978 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002979 nr_options += add_map_opt(browser, &actions[nr_options],
2980 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002981 browser->selection ?
2982 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002983 nr_options += add_socket_opt(browser, &actions[nr_options],
2984 &options[nr_options],
2985 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002986 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002987 if (!is_report_browser(hbt))
2988 goto skip_scripting;
2989
Feng Tangcdbab7c2012-10-30 11:56:06 +08002990 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02002991 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002992 nr_options += add_script_opt(browser,
2993 &actions[nr_options],
2994 &options[nr_options],
2995 thread, NULL);
2996 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002997 /*
2998 * Note that browser->selection != NULL
2999 * when browser->he_selection is not NULL,
3000 * so we don't need to check browser->selection
3001 * before fetching browser->selection->sym like what
3002 * we do before fetching browser->selection->map.
3003 *
3004 * See hist_browser__show_entry.
3005 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003006 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003007 nr_options += add_script_opt(browser,
3008 &actions[nr_options],
3009 &options[nr_options],
3010 NULL, browser->selection->sym);
3011 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003012 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003013 nr_options += add_script_opt(browser, &actions[nr_options],
3014 &options[nr_options], NULL, NULL);
3015 nr_options += add_switch_opt(browser, &actions[nr_options],
3016 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003017skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003018 nr_options += add_exit_opt(browser, &actions[nr_options],
3019 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003020
Namhyung Kimea7cd592015-04-22 16:18:19 +09003021 do {
3022 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003023
Namhyung Kimea7cd592015-04-22 16:18:19 +09003024 choice = ui__popup_menu(nr_options, options);
3025 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003026 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003027
3028 act = &actions[choice];
3029 key = act->fn(browser, act);
3030 } while (key == 1);
3031
3032 if (key == K_SWITCH_INPUT_DATA)
3033 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003034 }
3035out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003036 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003037out:
3038 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003039 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003040 return key;
3041}
3042
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003043struct perf_evsel_menu {
3044 struct ui_browser b;
3045 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003046 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003047 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003048 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003049};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003050
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003051static void perf_evsel_menu__write(struct ui_browser *browser,
3052 void *entry, int row)
3053{
3054 struct perf_evsel_menu *menu = container_of(browser,
3055 struct perf_evsel_menu, b);
3056 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003057 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003058 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003059 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003060 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003061 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003062 const char *warn = " ";
3063 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003064
3065 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3066 HE_COLORSET_NORMAL);
3067
Namhyung Kim759ff492013-03-05 14:53:26 +09003068 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003069 struct perf_evsel *pos;
3070
3071 ev_name = perf_evsel__group_name(evsel);
3072
3073 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003074 struct hists *pos_hists = evsel__hists(pos);
3075 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003076 }
3077 }
3078
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003079 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003080 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003081 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003082 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003083
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003084 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003085 if (nr_events != 0) {
3086 menu->lost_events = true;
3087 if (!current_entry)
3088 ui_browser__set_color(browser, HE_COLORSET_TOP);
3089 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003090 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3091 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003092 warn = bf;
3093 }
3094
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003095 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003096
3097 if (current_entry)
3098 menu->selection = evsel;
3099}
3100
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003101static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3102 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003103 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003104{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003105 struct perf_evlist *evlist = menu->b.priv;
3106 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003107 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003108 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003109 int key;
3110
3111 if (ui_browser__show(&menu->b, title,
3112 "ESC: exit, ENTER|->: Browse histograms") < 0)
3113 return -1;
3114
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003115 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003116 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003117
3118 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003119 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003120 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003121
3122 if (!menu->lost_events_warned && menu->lost_events) {
3123 ui_browser__warn_lost_events(&menu->b);
3124 menu->lost_events_warned = true;
3125 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003126 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003127 case K_RIGHT:
3128 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003129 if (!menu->selection)
3130 continue;
3131 pos = menu->selection;
3132browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003133 perf_evlist__set_selected(evlist, pos);
3134 /*
3135 * Give the calling tool a chance to populate the non
3136 * default evsel resorted hists tree.
3137 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003138 if (hbt)
3139 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003140 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003141 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003142 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003143 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003144 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003145 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003146 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003147 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003148 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003149 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003150 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003151 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003152 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003153 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003154 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003155 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003156 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003157 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003158 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003159 case 'q':
3160 case CTRL('c'):
3161 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003162 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003163 default:
3164 continue;
3165 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003166 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003167 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003168 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003169 if (!ui_browser__dialog_yesno(&menu->b,
3170 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003171 continue;
3172 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003173 case 'q':
3174 case CTRL('c'):
3175 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003176 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003177 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003178 }
3179 }
3180
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003181out:
3182 ui_browser__hide(&menu->b);
3183 return key;
3184}
3185
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003186static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003187 void *entry)
3188{
3189 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3190
3191 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3192 return true;
3193
3194 return false;
3195}
3196
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003197static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003198 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003199 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003200 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003201 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003202{
3203 struct perf_evsel *pos;
3204 struct perf_evsel_menu menu = {
3205 .b = {
3206 .entries = &evlist->entries,
3207 .refresh = ui_browser__list_head_refresh,
3208 .seek = ui_browser__list_head_seek,
3209 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003210 .filter = filter_group_entries,
3211 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003212 .priv = evlist,
3213 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003214 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003215 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003216 };
3217
3218 ui_helpline__push("Press ESC to exit");
3219
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003220 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003221 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003222 size_t line_len = strlen(ev_name) + 7;
3223
3224 if (menu.b.width < line_len)
3225 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003226 }
3227
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003228 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003229}
3230
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003231int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003232 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003233 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003234 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003235{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003236 int nr_entries = evlist->nr_entries;
3237
3238single_entry:
3239 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003240 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003241
3242 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003243 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003244 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003245 }
3246
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003247 if (symbol_conf.event_group) {
3248 struct perf_evsel *pos;
3249
3250 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003251 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003252 if (perf_evsel__is_group_leader(pos))
3253 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003254 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003255
3256 if (nr_entries == 1)
3257 goto single_entry;
3258 }
3259
3260 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003261 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003262}