blob: 303ed62a8f5327861e1647d9cf5790dd7aebad96 [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
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001505static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001506{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001507 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001508 struct perf_hpp dummy_hpp = {
1509 .buf = buf,
1510 .size = size,
1511 };
1512 struct perf_hpp_fmt *fmt;
1513 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001514 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001515
1516 if (symbol_conf.use_callchain) {
1517 ret = scnprintf(buf, size, " ");
1518 if (advance_hpp_check(&dummy_hpp, ret))
1519 return ret;
1520 }
1521
Jiri Olsaf0786af2016-01-18 10:24:23 +01001522 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001523 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001524 continue;
1525
Jiri Olsa74bb43f2016-08-07 17:28:27 +02001526 ret = fmt->header(fmt, &dummy_hpp, hists, 0);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001527 if (advance_hpp_check(&dummy_hpp, ret))
1528 break;
1529
1530 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1531 if (advance_hpp_check(&dummy_hpp, ret))
1532 break;
1533 }
1534
1535 return ret;
1536}
1537
Namhyung Kimd8b92402016-02-25 00:13:46 +09001538static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1539{
1540 struct hists *hists = browser->hists;
1541 struct perf_hpp dummy_hpp = {
1542 .buf = buf,
1543 .size = size,
1544 };
1545 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001546 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001547 size_t ret = 0;
1548 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001549 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001550 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001551
1552 ret = scnprintf(buf, size, " ");
1553 if (advance_hpp_check(&dummy_hpp, ret))
1554 return ret;
1555
Namhyung Kima61a22f2016-03-07 16:44:50 -03001556 /* the first hpp_list_node is for overhead columns */
1557 fmt_node = list_first_entry(&hists->hpp_formats,
1558 struct perf_hpp_list_node, list);
1559 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001560 if (column++ < browser->b.horiz_scroll)
1561 continue;
1562
Jiri Olsa74bb43f2016-08-07 17:28:27 +02001563 ret = fmt->header(fmt, &dummy_hpp, hists, 0);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001564 if (advance_hpp_check(&dummy_hpp, ret))
1565 break;
1566
1567 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1568 if (advance_hpp_check(&dummy_hpp, ret))
1569 break;
1570 }
1571
1572 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001573 indent * HIERARCHY_INDENT, "");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001574 if (advance_hpp_check(&dummy_hpp, ret))
1575 return ret;
1576
Namhyung Kima61a22f2016-03-07 16:44:50 -03001577 first_node = true;
1578 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1579 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001580 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1581 if (advance_hpp_check(&dummy_hpp, ret))
1582 break;
1583 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001584 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001585
Namhyung Kima61a22f2016-03-07 16:44:50 -03001586 first_col = true;
1587 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1588 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001589
Namhyung Kima61a22f2016-03-07 16:44:50 -03001590 if (perf_hpp__should_skip(fmt, hists))
1591 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001592
Namhyung Kima61a22f2016-03-07 16:44:50 -03001593 if (!first_col) {
1594 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1595 if (advance_hpp_check(&dummy_hpp, ret))
1596 break;
1597 }
1598 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001599
Jiri Olsa74bb43f2016-08-07 17:28:27 +02001600 ret = fmt->header(fmt, &dummy_hpp, hists, 0);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001601 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001602
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001603 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001604 ret = strlen(start);
1605
1606 if (start != dummy_hpp.buf)
1607 memmove(dummy_hpp.buf, start, ret + 1);
1608
1609 if (advance_hpp_check(&dummy_hpp, ret))
1610 break;
1611 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001612 }
1613
1614 return ret;
1615}
1616
Jiri Olsa01b47702016-06-14 20:19:13 +02001617static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001618{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001619 char headers[1024];
1620
Jiri Olsa01b47702016-06-14 20:19:13 +02001621 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1622 sizeof(headers));
1623
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001624 ui_browser__gotorc(&browser->b, 0, 0);
1625 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001626 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001627}
1628
Jiri Olsa01b47702016-06-14 20:19:13 +02001629static void hists_browser__headers(struct hist_browser *browser)
1630{
1631 char headers[1024];
1632
1633 hists_browser__scnprintf_headers(browser, headers,
1634 sizeof(headers));
1635
1636 ui_browser__gotorc(&browser->b, 0, 0);
1637 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1638 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1639}
1640
1641static void hist_browser__show_headers(struct hist_browser *browser)
1642{
1643 if (symbol_conf.report_hierarchy)
1644 hists_browser__hierarchy_headers(browser);
1645 else
1646 hists_browser__headers(browser);
1647}
1648
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001649static void ui_browser__hists_init_top(struct ui_browser *browser)
1650{
1651 if (browser->top == NULL) {
1652 struct hist_browser *hb;
1653
1654 hb = container_of(browser, struct hist_browser, b);
1655 browser->top = rb_first(&hb->hists->entries);
1656 }
1657}
1658
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001659static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001660{
1661 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001662 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001663 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001664 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001665 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001666
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001667 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001668 struct perf_hpp_list *hpp_list = hists->hpp_list;
1669
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001670 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001671 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001672 }
1673
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001674 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001675 hb->he_selection = NULL;
1676 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001677
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001678 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001679 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001680 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001681
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001682 if (h->filtered) {
1683 /* let it move to sibling */
1684 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001685 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001686 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001687
Namhyung Kim14135662013-10-31 10:17:39 +09001688 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001689 if (percent < hb->min_pcnt)
1690 continue;
1691
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001692 if (symbol_conf.report_hierarchy) {
1693 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001694 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001695 if (row == browser->rows)
1696 break;
1697
1698 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001699 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001700 row++;
1701 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001702 } else {
1703 row += hist_browser__show_entry(hb, h, row);
1704 }
1705
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001706 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001707 break;
1708 }
1709
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001710 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001711}
1712
Namhyung Kim064f1982013-05-14 11:09:04 +09001713static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001714 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001715{
1716 while (nd != NULL) {
1717 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001718 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001719
Namhyung Kimc0f15272014-04-16 11:16:33 +09001720 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001721 return nd;
1722
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001723 /*
1724 * If it's filtered, its all children also were filtered.
1725 * So move to sibling node.
1726 */
1727 if (rb_next(nd))
1728 nd = rb_next(nd);
1729 else
1730 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001731 }
1732
1733 return NULL;
1734}
1735
Namhyung Kim064f1982013-05-14 11:09:04 +09001736static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001737 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001738{
1739 while (nd != NULL) {
1740 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001741 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001742
1743 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001744 return nd;
1745
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001746 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001747 }
1748
1749 return NULL;
1750}
1751
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001752static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001753 off_t offset, int whence)
1754{
1755 struct hist_entry *h;
1756 struct rb_node *nd;
1757 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001758 struct hist_browser *hb;
1759
1760 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001761
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001762 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001763 return;
1764
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001765 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001766
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001767 switch (whence) {
1768 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001769 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001770 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001771 break;
1772 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001773 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001774 goto do_offset;
1775 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001776 nd = rb_hierarchy_last(rb_last(browser->entries));
1777 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001778 first = false;
1779 break;
1780 default:
1781 return;
1782 }
1783
1784 /*
1785 * Moves not relative to the first visible entry invalidates its
1786 * row_offset:
1787 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001788 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001789 h->row_offset = 0;
1790
1791 /*
1792 * Here we have to check if nd is expanded (+), if it is we can't go
1793 * the next top level hist_entry, instead we must compute an offset of
1794 * what _not_ to show and not change the first visible entry.
1795 *
1796 * This offset increments when we are going from top to bottom and
1797 * decreases when we're going from bottom to top.
1798 *
1799 * As we don't have backpointers to the top level in the callchains
1800 * structure, we need to always print the whole hist_entry callchain,
1801 * skipping the first ones that are before the first visible entry
1802 * and stop when we printed enough lines to fill the screen.
1803 */
1804do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001805 if (!nd)
1806 return;
1807
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001808 if (offset > 0) {
1809 do {
1810 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001811 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001812 u16 remaining = h->nr_rows - h->row_offset;
1813 if (offset > remaining) {
1814 offset -= remaining;
1815 h->row_offset = 0;
1816 } else {
1817 h->row_offset += offset;
1818 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001819 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001820 break;
1821 }
1822 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001823 nd = hists__filter_entries(rb_hierarchy_next(nd),
1824 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001825 if (nd == NULL)
1826 break;
1827 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001828 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001829 } while (offset != 0);
1830 } else if (offset < 0) {
1831 while (1) {
1832 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001833 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001834 if (first) {
1835 if (-offset > h->row_offset) {
1836 offset += h->row_offset;
1837 h->row_offset = 0;
1838 } else {
1839 h->row_offset += offset;
1840 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001841 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001842 break;
1843 }
1844 } else {
1845 if (-offset > h->nr_rows) {
1846 offset += h->nr_rows;
1847 h->row_offset = 0;
1848 } else {
1849 h->row_offset = h->nr_rows + offset;
1850 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001851 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001852 break;
1853 }
1854 }
1855 }
1856
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001857 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001858 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001859 if (nd == NULL)
1860 break;
1861 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001862 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001863 if (offset == 0) {
1864 /*
1865 * Last unfiltered hist_entry, check if it is
1866 * unfolded, if it is then we should have
1867 * row_offset at its last entry.
1868 */
1869 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001870 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001871 h->row_offset = h->nr_rows;
1872 break;
1873 }
1874 first = false;
1875 }
1876 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001877 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001878 h = rb_entry(nd, struct hist_entry, rb_node);
1879 h->row_offset = 0;
1880 }
1881}
1882
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001883static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001884 struct hist_entry *he, FILE *fp,
1885 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001886{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001887 struct callchain_print_arg arg = {
1888 .fp = fp,
1889 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001890
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001891 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001892 hist_browser__fprintf_callchain_entry, &arg,
1893 hist_browser__check_dump_full);
1894 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001895}
1896
1897static int hist_browser__fprintf_entry(struct hist_browser *browser,
1898 struct hist_entry *he, FILE *fp)
1899{
1900 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001901 int printed = 0;
1902 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001903 struct perf_hpp hpp = {
1904 .buf = s,
1905 .size = sizeof(s),
1906 };
1907 struct perf_hpp_fmt *fmt;
1908 bool first = true;
1909 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001910
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001911 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001912 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001913 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001914 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001915
Jiri Olsaf0786af2016-01-18 10:24:23 +01001916 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001917 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001918 continue;
1919
Namhyung Kim26d8b332014-03-03 16:16:20 +09001920 if (!first) {
1921 ret = scnprintf(hpp.buf, hpp.size, " ");
1922 advance_hpp(&hpp, ret);
1923 } else
1924 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001925
Namhyung Kim26d8b332014-03-03 16:16:20 +09001926 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001927 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001928 advance_hpp(&hpp, ret);
1929 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001930 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001931
1932 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001933 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1934
1935 return printed;
1936}
1937
1938
1939static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1940 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09001941 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001942{
1943 char s[8192];
1944 int printed = 0;
1945 char folded_sign = ' ';
1946 struct perf_hpp hpp = {
1947 .buf = s,
1948 .size = sizeof(s),
1949 };
1950 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09001951 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001952 bool first = true;
1953 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09001954 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001955
1956 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1957
1958 folded_sign = hist_entry__folded(he);
1959 printed += fprintf(fp, "%c", folded_sign);
1960
Namhyung Kim325a6282016-03-09 22:47:00 +09001961 /* the first hpp_list_node is for overhead columns */
1962 fmt_node = list_first_entry(&he->hists->hpp_formats,
1963 struct perf_hpp_list_node, list);
1964 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001965 if (!first) {
1966 ret = scnprintf(hpp.buf, hpp.size, " ");
1967 advance_hpp(&hpp, ret);
1968 } else
1969 first = false;
1970
1971 ret = fmt->entry(fmt, &hpp, he);
1972 advance_hpp(&hpp, ret);
1973 }
1974
1975 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1976 advance_hpp(&hpp, ret);
1977
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001978 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1979 ret = scnprintf(hpp.buf, hpp.size, " ");
1980 advance_hpp(&hpp, ret);
1981
1982 ret = fmt->entry(fmt, &hpp, he);
1983 advance_hpp(&hpp, ret);
1984 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001985
1986 printed += fprintf(fp, "%s\n", rtrim(s));
1987
1988 if (he->leaf && folded_sign == '-') {
1989 printed += hist_browser__fprintf_callchain(browser, he, fp,
1990 he->depth + 1);
1991 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001992
1993 return printed;
1994}
1995
1996static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1997{
Namhyung Kim064f1982013-05-14 11:09:04 +09001998 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001999 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002000 int printed = 0;
2001
2002 while (nd) {
2003 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2004
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002005 if (symbol_conf.report_hierarchy) {
2006 printed += hist_browser__fprintf_hierarchy_entry(browser,
2007 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002008 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002009 } else {
2010 printed += hist_browser__fprintf_entry(browser, h, fp);
2011 }
2012
2013 nd = hists__filter_entries(rb_hierarchy_next(nd),
2014 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002015 }
2016
2017 return printed;
2018}
2019
2020static int hist_browser__dump(struct hist_browser *browser)
2021{
2022 char filename[64];
2023 FILE *fp;
2024
2025 while (1) {
2026 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2027 if (access(filename, F_OK))
2028 break;
2029 /*
2030 * XXX: Just an arbitrary lazy upper limit
2031 */
2032 if (++browser->print_seq == 8192) {
2033 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2034 return -1;
2035 }
2036 }
2037
2038 fp = fopen(filename, "w");
2039 if (fp == NULL) {
2040 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002041 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002042 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002043 return -1;
2044 }
2045
2046 ++browser->print_seq;
2047 hist_browser__fprintf(browser, fp);
2048 fclose(fp);
2049 ui_helpline__fpush("%s written!", filename);
2050
2051 return 0;
2052}
2053
Jiri Olsafcd86422016-06-20 23:58:18 +02002054void hist_browser__init(struct hist_browser *browser,
2055 struct hists *hists)
2056{
2057 struct perf_hpp_fmt *fmt;
2058
2059 browser->hists = hists;
2060 browser->b.refresh = hist_browser__refresh;
2061 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2062 browser->b.seek = ui_browser__hists_seek;
2063 browser->b.use_navkeypressed = true;
2064 browser->show_headers = symbol_conf.show_hist_headers;
2065
2066 hists__for_each_format(hists, fmt) {
2067 perf_hpp__reset_width(fmt, hists);
2068 ++browser->b.columns;
2069 }
2070}
2071
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002072struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002073{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002074 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002075
Jiri Olsafcd86422016-06-20 23:58:18 +02002076 if (browser)
2077 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002078
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002079 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002080}
2081
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002082static struct hist_browser *
2083perf_evsel_browser__new(struct perf_evsel *evsel,
2084 struct hist_browser_timer *hbt,
2085 struct perf_env *env)
2086{
2087 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2088
2089 if (browser) {
2090 browser->hbt = hbt;
2091 browser->env = env;
2092 browser->title = perf_evsel_browser_title;
2093 }
2094 return browser;
2095}
2096
Jiri Olsadabd2012016-06-20 23:58:14 +02002097void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002098{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002099 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002100}
2101
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002102static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002103{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002104 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002105}
2106
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002107static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002108{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002109 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002110}
2111
Taeung Song1e378eb2014-10-07 16:13:15 +09002112/* Check whether the browser is for 'top' or 'report' */
2113static inline bool is_report_browser(void *timer)
2114{
2115 return timer == NULL;
2116}
2117
Jiri Olsa5b91a862016-06-20 23:58:15 +02002118static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002119 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002120{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002121 struct hist_browser_timer *hbt = browser->hbt;
2122 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002123 char unit;
2124 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002125 const struct dso *dso = hists->dso_filter;
2126 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002127 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002128 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2129 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002130 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002131 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002132 char buf[512];
2133 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002134 char ref[30] = " show reference callgraph, ";
2135 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002136
Namhyung Kimf2148332014-01-14 11:52:48 +09002137 if (symbol_conf.filter_relative) {
2138 nr_samples = hists->stats.nr_non_filtered_samples;
2139 nr_events = hists->stats.total_non_filtered_period;
2140 }
2141
Namhyung Kim759ff492013-03-05 14:53:26 +09002142 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002143 struct perf_evsel *pos;
2144
2145 perf_evsel__group_desc(evsel, buf, buflen);
2146 ev_name = buf;
2147
2148 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002149 struct hists *pos_hists = evsel__hists(pos);
2150
Namhyung Kimf2148332014-01-14 11:52:48 +09002151 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002152 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2153 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002154 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002155 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2156 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002157 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002158 }
2159 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002160
Kan Liang9e207dd2015-08-11 06:30:49 -04002161 if (symbol_conf.show_ref_callgraph &&
2162 strstr(ev_name, "call-graph=no"))
2163 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002164 nr_samples = convert_unit(nr_samples, &unit);
2165 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002166 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2167 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002168
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002169
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002170 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002171 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002172 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002173 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002174 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002175 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002176 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002177 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002178 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002179 } else {
2180 printed += scnprintf(bf + printed, size - printed,
2181 ", Thread: %s",
2182 (thread->comm_set ? thread__comm_str(thread) : ""));
2183 }
2184 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002185 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002186 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002187 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002188 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002189 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002190 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002191 if (!is_report_browser(hbt)) {
2192 struct perf_top *top = hbt->arg;
2193
2194 if (top->zero)
2195 printed += scnprintf(bf + printed, size - printed, " [z]");
2196 }
2197
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002198 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002199}
2200
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002201static inline void free_popup_options(char **options, int n)
2202{
2203 int i;
2204
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002205 for (i = 0; i < n; ++i)
2206 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002207}
2208
Feng Tang341487ab2013-02-03 14:38:20 +08002209/*
2210 * Only runtime switching of perf data file will make "input_name" point
2211 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2212 * whether we need to call free() for current "input_name" during the switch.
2213 */
2214static bool is_input_name_malloced = false;
2215
2216static int switch_data_file(void)
2217{
2218 char *pwd, *options[32], *abs_path[32], *tmp;
2219 DIR *pwd_dir;
2220 int nr_options = 0, choice = -1, ret = -1;
2221 struct dirent *dent;
2222
2223 pwd = getenv("PWD");
2224 if (!pwd)
2225 return ret;
2226
2227 pwd_dir = opendir(pwd);
2228 if (!pwd_dir)
2229 return ret;
2230
2231 memset(options, 0, sizeof(options));
2232 memset(options, 0, sizeof(abs_path));
2233
2234 while ((dent = readdir(pwd_dir))) {
2235 char path[PATH_MAX];
2236 u64 magic;
2237 char *name = dent->d_name;
2238 FILE *file;
2239
2240 if (!(dent->d_type == DT_REG))
2241 continue;
2242
2243 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2244
2245 file = fopen(path, "r");
2246 if (!file)
2247 continue;
2248
2249 if (fread(&magic, 1, 8, file) < 8)
2250 goto close_file_and_continue;
2251
2252 if (is_perf_magic(magic)) {
2253 options[nr_options] = strdup(name);
2254 if (!options[nr_options])
2255 goto close_file_and_continue;
2256
2257 abs_path[nr_options] = strdup(path);
2258 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002259 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002260 ui__warning("Can't search all data files due to memory shortage.\n");
2261 fclose(file);
2262 break;
2263 }
2264
2265 nr_options++;
2266 }
2267
2268close_file_and_continue:
2269 fclose(file);
2270 if (nr_options >= 32) {
2271 ui__warning("Too many perf data files in PWD!\n"
2272 "Only the first 32 files will be listed.\n");
2273 break;
2274 }
2275 }
2276 closedir(pwd_dir);
2277
2278 if (nr_options) {
2279 choice = ui__popup_menu(nr_options, options);
2280 if (choice < nr_options && choice >= 0) {
2281 tmp = strdup(abs_path[choice]);
2282 if (tmp) {
2283 if (is_input_name_malloced)
2284 free((void *)input_name);
2285 input_name = tmp;
2286 is_input_name_malloced = true;
2287 ret = 0;
2288 } else
2289 ui__warning("Data switch failed due to memory shortage!\n");
2290 }
2291 }
2292
2293 free_popup_options(options, nr_options);
2294 free_popup_options(abs_path, nr_options);
2295 return ret;
2296}
2297
Namhyung Kimea7cd592015-04-22 16:18:19 +09002298struct popup_action {
2299 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002300 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002301 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002302
2303 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2304};
2305
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002306static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002307do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002308{
2309 struct perf_evsel *evsel;
2310 struct annotation *notes;
2311 struct hist_entry *he;
2312 int err;
2313
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002314 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002315 return 0;
2316
Namhyung Kimea7cd592015-04-22 16:18:19 +09002317 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002318 if (!notes->src)
2319 return 0;
2320
2321 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002322 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002323 he = hist_browser__selected_entry(browser);
2324 /*
2325 * offer option to annotate the other branch source or target
2326 * (if they exists) when returning from annotate
2327 */
2328 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2329 return 1;
2330
2331 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2332 if (err)
2333 ui_browser__handle_resize(&browser->b);
2334 return 0;
2335}
2336
2337static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002338add_annotate_opt(struct hist_browser *browser __maybe_unused,
2339 struct popup_action *act, char **optstr,
2340 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002341{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002342 if (sym == NULL || map->dso->annotate_warned)
2343 return 0;
2344
2345 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2346 return 0;
2347
2348 act->ms.map = map;
2349 act->ms.sym = sym;
2350 act->fn = do_annotate;
2351 return 1;
2352}
2353
2354static int
2355do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2356{
2357 struct thread *thread = act->thread;
2358
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002359 if ((!hists__has(browser->hists, thread) &&
2360 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002361 return 0;
2362
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002363 if (browser->hists->thread_filter) {
2364 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2365 perf_hpp__set_elide(HISTC_THREAD, false);
2366 thread__zput(browser->hists->thread_filter);
2367 ui_helpline__pop();
2368 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002369 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002370 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2371 thread->comm_set ? thread__comm_str(thread) : "",
2372 thread->tid);
2373 } else {
2374 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2375 thread->comm_set ? thread__comm_str(thread) : "");
2376 }
2377
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002378 browser->hists->thread_filter = thread__get(thread);
2379 perf_hpp__set_elide(HISTC_THREAD, false);
2380 pstack__push(browser->pstack, &browser->hists->thread_filter);
2381 }
2382
2383 hists__filter_by_thread(browser->hists);
2384 hist_browser__reset(browser);
2385 return 0;
2386}
2387
2388static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002389add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2390 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002391{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002392 int ret;
2393
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002394 if ((!hists__has(browser->hists, thread) &&
2395 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002396 return 0;
2397
Jiri Olsafa829112016-05-03 13:54:47 +02002398 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002399 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2400 browser->hists->thread_filter ? "out of" : "into",
2401 thread->comm_set ? thread__comm_str(thread) : "",
2402 thread->tid);
2403 } else {
2404 ret = asprintf(optstr, "Zoom %s %s thread",
2405 browser->hists->thread_filter ? "out of" : "into",
2406 thread->comm_set ? thread__comm_str(thread) : "");
2407 }
2408 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002409 return 0;
2410
2411 act->thread = thread;
2412 act->fn = do_zoom_thread;
2413 return 1;
2414}
2415
2416static int
2417do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2418{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002419 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002420
Jiri Olsa69849fc2016-05-03 13:54:45 +02002421 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002422 return 0;
2423
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002424 if (browser->hists->dso_filter) {
2425 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2426 perf_hpp__set_elide(HISTC_DSO, false);
2427 browser->hists->dso_filter = NULL;
2428 ui_helpline__pop();
2429 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002430 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002431 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002432 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002433 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2434 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002435 perf_hpp__set_elide(HISTC_DSO, true);
2436 pstack__push(browser->pstack, &browser->hists->dso_filter);
2437 }
2438
2439 hists__filter_by_dso(browser->hists);
2440 hist_browser__reset(browser);
2441 return 0;
2442}
2443
2444static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002445add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002446 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002447{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002448 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002449 return 0;
2450
2451 if (asprintf(optstr, "Zoom %s %s DSO",
2452 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002453 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002454 return 0;
2455
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002456 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002457 act->fn = do_zoom_dso;
2458 return 1;
2459}
2460
2461static int
2462do_browse_map(struct hist_browser *browser __maybe_unused,
2463 struct popup_action *act)
2464{
2465 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002466 return 0;
2467}
2468
2469static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002470add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002471 struct popup_action *act, char **optstr, struct map *map)
2472{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002473 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002474 return 0;
2475
2476 if (asprintf(optstr, "Browse map details") < 0)
2477 return 0;
2478
2479 act->ms.map = map;
2480 act->fn = do_browse_map;
2481 return 1;
2482}
2483
2484static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002485do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002486 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002487{
2488 char script_opt[64];
2489 memset(script_opt, 0, sizeof(script_opt));
2490
Namhyung Kimea7cd592015-04-22 16:18:19 +09002491 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002492 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002493 thread__comm_str(act->thread));
2494 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002495 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002496 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002497 }
2498
2499 script_browse(script_opt);
2500 return 0;
2501}
2502
2503static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002504add_script_opt(struct hist_browser *browser __maybe_unused,
2505 struct popup_action *act, char **optstr,
2506 struct thread *thread, struct symbol *sym)
2507{
2508 if (thread) {
2509 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2510 thread__comm_str(thread)) < 0)
2511 return 0;
2512 } else if (sym) {
2513 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2514 sym->name) < 0)
2515 return 0;
2516 } else {
2517 if (asprintf(optstr, "Run scripts for all samples") < 0)
2518 return 0;
2519 }
2520
2521 act->thread = thread;
2522 act->ms.sym = sym;
2523 act->fn = do_run_script;
2524 return 1;
2525}
2526
2527static int
2528do_switch_data(struct hist_browser *browser __maybe_unused,
2529 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002530{
2531 if (switch_data_file()) {
2532 ui__warning("Won't switch the data files due to\n"
2533 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002534 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002535 }
2536
2537 return K_SWITCH_INPUT_DATA;
2538}
2539
Namhyung Kimea7cd592015-04-22 16:18:19 +09002540static int
2541add_switch_opt(struct hist_browser *browser,
2542 struct popup_action *act, char **optstr)
2543{
2544 if (!is_report_browser(browser->hbt))
2545 return 0;
2546
2547 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2548 return 0;
2549
2550 act->fn = do_switch_data;
2551 return 1;
2552}
2553
2554static int
2555do_exit_browser(struct hist_browser *browser __maybe_unused,
2556 struct popup_action *act __maybe_unused)
2557{
2558 return 0;
2559}
2560
2561static int
2562add_exit_opt(struct hist_browser *browser __maybe_unused,
2563 struct popup_action *act, char **optstr)
2564{
2565 if (asprintf(optstr, "Exit") < 0)
2566 return 0;
2567
2568 act->fn = do_exit_browser;
2569 return 1;
2570}
2571
Kan Liang84734b02015-09-04 10:45:45 -04002572static int
2573do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2574{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002575 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002576 return 0;
2577
Kan Liang84734b02015-09-04 10:45:45 -04002578 if (browser->hists->socket_filter > -1) {
2579 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2580 browser->hists->socket_filter = -1;
2581 perf_hpp__set_elide(HISTC_SOCKET, false);
2582 } else {
2583 browser->hists->socket_filter = act->socket;
2584 perf_hpp__set_elide(HISTC_SOCKET, true);
2585 pstack__push(browser->pstack, &browser->hists->socket_filter);
2586 }
2587
2588 hists__filter_by_socket(browser->hists);
2589 hist_browser__reset(browser);
2590 return 0;
2591}
2592
2593static int
2594add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2595 char **optstr, int socket_id)
2596{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002597 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002598 return 0;
2599
2600 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2601 (browser->hists->socket_filter > -1) ? "out of" : "into",
2602 socket_id) < 0)
2603 return 0;
2604
2605 act->socket = socket_id;
2606 act->fn = do_zoom_socket;
2607 return 1;
2608}
2609
Namhyung Kim112f7612014-04-22 14:05:35 +09002610static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002611{
2612 u64 nr_entries = 0;
2613 struct rb_node *nd = rb_first(&hb->hists->entries);
2614
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002615 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002616 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2617 return;
2618 }
2619
Namhyung Kim14135662013-10-31 10:17:39 +09002620 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002621 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002622 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002623 }
2624
Namhyung Kim112f7612014-04-22 14:05:35 +09002625 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002626 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002627}
Feng Tang341487ab2013-02-03 14:38:20 +08002628
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002629static void hist_browser__update_percent_limit(struct hist_browser *hb,
2630 double percent)
2631{
2632 struct hist_entry *he;
2633 struct rb_node *nd = rb_first(&hb->hists->entries);
2634 u64 total = hists__total_period(hb->hists);
2635 u64 min_callchain_hits = total * (percent / 100);
2636
2637 hb->min_pcnt = callchain_param.min_percent = percent;
2638
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002639 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2640 he = rb_entry(nd, struct hist_entry, rb_node);
2641
Namhyung Kim79dded82016-02-26 21:13:19 +09002642 if (he->has_no_entry) {
2643 he->has_no_entry = false;
2644 he->nr_rows = 0;
2645 }
2646
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002647 if (!he->leaf || !symbol_conf.use_callchain)
2648 goto next;
2649
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002650 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2651 total = he->stat.period;
2652
2653 if (symbol_conf.cumulate_callchain)
2654 total = he->stat_acc->period;
2655
2656 min_callchain_hits = total * (percent / 100);
2657 }
2658
2659 callchain_param.sort(&he->sorted_chain, he->callchain,
2660 min_callchain_hits, &callchain_param);
2661
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002662next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002663 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002664
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002665 /* force to re-evaluate folding state of callchains */
2666 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002667 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002668 }
2669}
2670
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002671static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002672 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002673 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002674 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002675 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002676 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002677{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002678 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002679 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002680 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002681#define MAX_OPTIONS 16
2682 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002683 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002684 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002685 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002686 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002687 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002688
Namhyung Kime8e684a2013-12-26 14:37:58 +09002689#define HIST_BROWSER_HELP_COMMON \
2690 "h/?/F1 Show this window\n" \
2691 "UP/DOWN/PGUP\n" \
2692 "PGDN/SPACE Navigate\n" \
2693 "q/ESC/CTRL+C Exit browser\n\n" \
2694 "For multiple event sessions:\n\n" \
2695 "TAB/UNTAB Switch events\n\n" \
2696 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002697 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2698 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002699 "a Annotate current symbol\n" \
2700 "C Collapse all callchains\n" \
2701 "d Zoom into current DSO\n" \
2702 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002703 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002704 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002705 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002706 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002707 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002708
2709 /* help messages are sorted by lexical order of the hotkey */
2710 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002711 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002712 "P Print histograms to perf.hist.N\n"
2713 "r Run available scripts\n"
2714 "s Switch to another data file in PWD\n"
2715 "t Zoom into current Thread\n"
2716 "V Verbose (DSO names in callchains, etc)\n"
2717 "/ Filter symbol by name";
2718 const char top_help[] = HIST_BROWSER_HELP_COMMON
2719 "P Print histograms to perf.hist.N\n"
2720 "t Zoom into current Thread\n"
2721 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002722 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002723 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002724 "/ Filter symbol by name";
2725
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002726 if (browser == NULL)
2727 return -1;
2728
Namhyung Kimed426912015-05-29 21:53:44 +09002729 /* reset abort key so that it can get Ctrl-C as a key */
2730 SLang_reset_tty();
2731 SLang_init_tty(0, 0, 0);
2732
Namhyung Kim03905042015-11-28 02:32:39 +09002733 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002734 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002735 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002736
Kan Liang84734b02015-09-04 10:45:45 -04002737 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002738 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002739 goto out;
2740
2741 ui_helpline__push(helpline);
2742
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002743 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002744 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002745
Namhyung Kim5b591662014-07-31 14:47:38 +09002746 if (symbol_conf.col_width_list_str)
2747 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2748
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002749 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002750 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002751 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002752 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002753 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002754
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002755 nr_options = 0;
2756
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002757 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002758
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002759 if (browser->he_selection != NULL) {
2760 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002761 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002762 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002763 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002764 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002765 case K_TAB:
2766 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002767 if (nr_events == 1)
2768 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002769 /*
2770 * Exit the browser, let hists__browser_tree
2771 * go to the next or previous
2772 */
2773 goto out_free_stack;
2774 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002775 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002776 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002777 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002778 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002779 continue;
2780 }
2781
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002782 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002783 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002784 browser->selection->map->dso->annotate_warned)
2785 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002786
Namhyung Kimea7cd592015-04-22 16:18:19 +09002787 actions->ms.map = browser->selection->map;
2788 actions->ms.sym = browser->selection->sym;
2789 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002790 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002791 case 'P':
2792 hist_browser__dump(browser);
2793 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002794 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002795 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002796 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002797 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002798 case 'V':
2799 browser->show_dso = !browser->show_dso;
2800 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002801 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002802 actions->thread = thread;
2803 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002804 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002805 case 'S':
2806 actions->socket = socked_id;
2807 do_zoom_socket(browser, actions);
2808 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002809 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002810 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002811 "Please enter the name of symbol you want to see.\n"
2812 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002813 buf, "ENTER: OK, ESC: Cancel",
2814 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002815 hists->symbol_filter_str = *buf ? buf : NULL;
2816 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002817 hist_browser__reset(browser);
2818 }
2819 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002820 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002821 if (is_report_browser(hbt)) {
2822 actions->thread = NULL;
2823 actions->ms.sym = NULL;
2824 do_run_script(browser, actions);
2825 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002826 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002827 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002828 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002829 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002830 if (key == K_SWITCH_INPUT_DATA)
2831 goto out_free_stack;
2832 }
Feng Tang341487ab2013-02-03 14:38:20 +08002833 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002834 case 'i':
2835 /* env->arch is NULL for live-mode (i.e. perf top) */
2836 if (env->arch)
2837 tui__header_window(env);
2838 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002839 case 'F':
2840 symbol_conf.filter_relative ^= 1;
2841 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002842 case 'z':
2843 if (!is_report_browser(hbt)) {
2844 struct perf_top *top = hbt->arg;
2845
2846 top->zero = !top->zero;
2847 }
2848 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002849 case 'L':
2850 if (ui_browser__input_window("Percent Limit",
2851 "Please enter the value you want to hide entries under that percent.",
2852 buf, "ENTER: OK, ESC: Cancel",
2853 delay_secs * 2) == K_ENTER) {
2854 char *end;
2855 double new_percent = strtod(buf, &end);
2856
2857 if (new_percent < 0 || new_percent > 100) {
2858 ui_browser__warning(&browser->b, delay_secs * 2,
2859 "Invalid percent: %.2f", new_percent);
2860 continue;
2861 }
2862
2863 hist_browser__update_percent_limit(browser, new_percent);
2864 hist_browser__reset(browser);
2865 }
2866 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002867 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002868 case 'h':
2869 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002870 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002871 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002872 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002873 case K_ENTER:
2874 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002875 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002876 /* menu */
2877 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002878 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002879 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002880 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002881
Namhyung Kim01f00a12015-04-22 16:18:16 +09002882 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002883 /*
2884 * Go back to the perf_evsel_menu__run or other user
2885 */
2886 if (left_exits)
2887 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002888
2889 if (key == K_ESC &&
2890 ui_browser__dialog_yesno(&browser->b,
2891 "Do you really want to exit?"))
2892 goto out_free_stack;
2893
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002894 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002895 }
Namhyung Kim64221842015-04-24 10:15:33 +09002896 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002897 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002898 /*
2899 * No need to set actions->dso here since
2900 * it's just to remove the current filter.
2901 * Ditto for thread below.
2902 */
2903 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002904 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002905 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002906 } else if (top == &browser->hists->socket_filter) {
2907 do_zoom_socket(browser, actions);
2908 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002909 continue;
2910 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002911 case 'q':
2912 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002913 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002914 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002915 if (!is_report_browser(hbt)) {
2916 struct perf_top *top = hbt->arg;
2917
2918 perf_evlist__toggle_enable(top->evlist);
2919 /*
2920 * No need to refresh, resort/decay histogram
2921 * entries if we are not collecting samples:
2922 */
2923 if (top->evlist->enabled) {
2924 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2925 hbt->refresh = delay_secs;
2926 } else {
2927 helpline = "Press 'f' again to re-enable the events";
2928 hbt->refresh = 0;
2929 }
2930 continue;
2931 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002932 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002933 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002934 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002935 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002936 }
2937
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002938 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002939 goto skip_annotation;
2940
Namhyung Kim55369fc2013-04-01 20:35:20 +09002941 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002942 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002943
2944 if (bi == NULL)
2945 goto skip_annotation;
2946
Namhyung Kimea7cd592015-04-22 16:18:19 +09002947 nr_options += add_annotate_opt(browser,
2948 &actions[nr_options],
2949 &options[nr_options],
2950 bi->from.map,
2951 bi->from.sym);
2952 if (bi->to.sym != bi->from.sym)
2953 nr_options += add_annotate_opt(browser,
2954 &actions[nr_options],
2955 &options[nr_options],
2956 bi->to.map,
2957 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002958 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002959 nr_options += add_annotate_opt(browser,
2960 &actions[nr_options],
2961 &options[nr_options],
2962 browser->selection->map,
2963 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002964 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002965skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002966 nr_options += add_thread_opt(browser, &actions[nr_options],
2967 &options[nr_options], thread);
2968 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002969 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002970 nr_options += add_map_opt(browser, &actions[nr_options],
2971 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002972 browser->selection ?
2973 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002974 nr_options += add_socket_opt(browser, &actions[nr_options],
2975 &options[nr_options],
2976 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002977 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002978 if (!is_report_browser(hbt))
2979 goto skip_scripting;
2980
Feng Tangcdbab7c2012-10-30 11:56:06 +08002981 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02002982 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002983 nr_options += add_script_opt(browser,
2984 &actions[nr_options],
2985 &options[nr_options],
2986 thread, NULL);
2987 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002988 /*
2989 * Note that browser->selection != NULL
2990 * when browser->he_selection is not NULL,
2991 * so we don't need to check browser->selection
2992 * before fetching browser->selection->sym like what
2993 * we do before fetching browser->selection->map.
2994 *
2995 * See hist_browser__show_entry.
2996 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002997 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03002998 nr_options += add_script_opt(browser,
2999 &actions[nr_options],
3000 &options[nr_options],
3001 NULL, browser->selection->sym);
3002 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003003 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003004 nr_options += add_script_opt(browser, &actions[nr_options],
3005 &options[nr_options], NULL, NULL);
3006 nr_options += add_switch_opt(browser, &actions[nr_options],
3007 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003008skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003009 nr_options += add_exit_opt(browser, &actions[nr_options],
3010 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003011
Namhyung Kimea7cd592015-04-22 16:18:19 +09003012 do {
3013 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003014
Namhyung Kimea7cd592015-04-22 16:18:19 +09003015 choice = ui__popup_menu(nr_options, options);
3016 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003017 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003018
3019 act = &actions[choice];
3020 key = act->fn(browser, act);
3021 } while (key == 1);
3022
3023 if (key == K_SWITCH_INPUT_DATA)
3024 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003025 }
3026out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003027 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003028out:
3029 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003030 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003031 return key;
3032}
3033
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003034struct perf_evsel_menu {
3035 struct ui_browser b;
3036 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003037 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003038 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003039 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003040};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003041
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003042static void perf_evsel_menu__write(struct ui_browser *browser,
3043 void *entry, int row)
3044{
3045 struct perf_evsel_menu *menu = container_of(browser,
3046 struct perf_evsel_menu, b);
3047 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003048 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003049 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003050 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003051 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003052 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003053 const char *warn = " ";
3054 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003055
3056 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3057 HE_COLORSET_NORMAL);
3058
Namhyung Kim759ff492013-03-05 14:53:26 +09003059 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003060 struct perf_evsel *pos;
3061
3062 ev_name = perf_evsel__group_name(evsel);
3063
3064 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003065 struct hists *pos_hists = evsel__hists(pos);
3066 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003067 }
3068 }
3069
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003070 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003071 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003072 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003073 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003074
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003075 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003076 if (nr_events != 0) {
3077 menu->lost_events = true;
3078 if (!current_entry)
3079 ui_browser__set_color(browser, HE_COLORSET_TOP);
3080 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003081 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3082 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003083 warn = bf;
3084 }
3085
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003086 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003087
3088 if (current_entry)
3089 menu->selection = evsel;
3090}
3091
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003092static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3093 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003094 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003095{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003096 struct perf_evlist *evlist = menu->b.priv;
3097 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003098 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003099 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003100 int key;
3101
3102 if (ui_browser__show(&menu->b, title,
3103 "ESC: exit, ENTER|->: Browse histograms") < 0)
3104 return -1;
3105
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003106 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003107 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003108
3109 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003110 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003111 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003112
3113 if (!menu->lost_events_warned && menu->lost_events) {
3114 ui_browser__warn_lost_events(&menu->b);
3115 menu->lost_events_warned = true;
3116 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003117 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003118 case K_RIGHT:
3119 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003120 if (!menu->selection)
3121 continue;
3122 pos = menu->selection;
3123browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003124 perf_evlist__set_selected(evlist, pos);
3125 /*
3126 * Give the calling tool a chance to populate the non
3127 * default evsel resorted hists tree.
3128 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003129 if (hbt)
3130 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003131 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003132 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003133 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003134 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003135 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003136 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003137 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003138 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003139 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003140 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003141 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003142 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003143 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003144 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003145 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003146 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003147 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003148 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003149 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003150 case 'q':
3151 case CTRL('c'):
3152 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003153 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003154 default:
3155 continue;
3156 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003157 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003158 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003159 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003160 if (!ui_browser__dialog_yesno(&menu->b,
3161 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003162 continue;
3163 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003164 case 'q':
3165 case CTRL('c'):
3166 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003167 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003168 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003169 }
3170 }
3171
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003172out:
3173 ui_browser__hide(&menu->b);
3174 return key;
3175}
3176
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003177static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003178 void *entry)
3179{
3180 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3181
3182 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3183 return true;
3184
3185 return false;
3186}
3187
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003188static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003189 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003190 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003191 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003192 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003193{
3194 struct perf_evsel *pos;
3195 struct perf_evsel_menu menu = {
3196 .b = {
3197 .entries = &evlist->entries,
3198 .refresh = ui_browser__list_head_refresh,
3199 .seek = ui_browser__list_head_seek,
3200 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003201 .filter = filter_group_entries,
3202 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003203 .priv = evlist,
3204 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003205 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003206 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003207 };
3208
3209 ui_helpline__push("Press ESC to exit");
3210
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003211 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003212 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003213 size_t line_len = strlen(ev_name) + 7;
3214
3215 if (menu.b.width < line_len)
3216 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003217 }
3218
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003219 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003220}
3221
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003222int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003223 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003224 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003225 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003226{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003227 int nr_entries = evlist->nr_entries;
3228
3229single_entry:
3230 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003231 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003232
3233 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003234 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003235 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003236 }
3237
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003238 if (symbol_conf.event_group) {
3239 struct perf_evsel *pos;
3240
3241 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003242 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003243 if (perf_evsel__is_group_leader(pos))
3244 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003245 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003246
3247 if (nr_entries == 1)
3248 goto single_entry;
3249 }
3250
3251 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003252 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003253}