blob: fb8e42c7507add43bc9c1848cf3ef300382ee313 [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
Jiri Olsa98ba1602016-09-22 17:36:35 +02001083int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001084{
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 Kim5aed9d22013-01-22 18:09:35 +09001100 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001101}
1102
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001103#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001104static u64 __hpp_get_##_field(struct hist_entry *he) \
1105{ \
1106 return he->stat._field; \
1107} \
1108 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001109static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001110hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001111 struct perf_hpp *hpp, \
1112 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001113{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001114 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1115 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001116}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001117
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001118#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1119static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1120{ \
1121 return he->stat_acc->_field; \
1122} \
1123 \
1124static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001125hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001126 struct perf_hpp *hpp, \
1127 struct hist_entry *he) \
1128{ \
1129 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001130 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001131 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001132 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001133 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001134 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001135 \
1136 return ret; \
1137 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001138 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1139 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001140}
1141
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001142__HPP_COLOR_PERCENT_FN(overhead, period)
1143__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1144__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1145__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1146__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001147__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001148
1149#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001150#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001151
1152void hist_browser__init_hpp(void)
1153{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001154 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1155 hist_browser__hpp_color_overhead;
1156 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1157 hist_browser__hpp_color_overhead_sys;
1158 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1159 hist_browser__hpp_color_overhead_us;
1160 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1161 hist_browser__hpp_color_overhead_guest_sys;
1162 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1163 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001164 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1165 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001166}
1167
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001168static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001169 struct hist_entry *entry,
1170 unsigned short row)
1171{
Jiri Olsa12400052012-10-13 00:06:16 +02001172 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001173 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001174 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001175 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001176 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001177 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001178 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001179
1180 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001181 browser->he_selection = entry;
1182 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001183 }
1184
1185 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001186 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001187 folded_sign = hist_entry__folded(entry);
1188 }
1189
1190 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001191 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001192 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001193 .folded_sign = folded_sign,
1194 .current_entry = current_entry,
1195 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001196 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001197
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001198 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001199
Jiri Olsaf0786af2016-01-18 10:24:23 +01001200 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001201 char s[2048];
1202 struct perf_hpp hpp = {
1203 .buf = s,
1204 .size = sizeof(s),
1205 .ptr = &arg,
1206 };
1207
Namhyung Kim361459f2015-12-23 02:07:08 +09001208 if (perf_hpp__should_skip(fmt, entry->hists) ||
1209 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001210 continue;
1211
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001212 if (current_entry && browser->b.navkeypressed) {
1213 ui_browser__set_color(&browser->b,
1214 HE_COLORSET_SELECTED);
1215 } else {
1216 ui_browser__set_color(&browser->b,
1217 HE_COLORSET_NORMAL);
1218 }
1219
1220 if (first) {
1221 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001222 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001223 width -= 2;
1224 }
1225 first = false;
1226 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001227 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001228 width -= 2;
1229 }
1230
Jiri Olsa12400052012-10-13 00:06:16 +02001231 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001232 int ret = fmt->color(fmt, &hpp, entry);
1233 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1234 /*
1235 * fmt->color() already used ui_browser to
1236 * print the non alignment bits, skip it (+ret):
1237 */
1238 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001239 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001240 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001241 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001242 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001243 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001244 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001245
1246 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001247 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001248 width += 1;
1249
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001250 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001251
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001252 ++row;
1253 ++printed;
1254 } else
1255 --row_offset;
1256
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001257 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001258 struct callchain_print_arg arg = {
1259 .row_offset = row_offset,
1260 .is_current_entry = current_entry,
1261 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001262
Namhyung Kim0c841c62016-01-28 00:40:54 +09001263 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001264 hist_browser__show_callchain_entry, &arg,
1265 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001266 }
1267
1268 return printed;
1269}
1270
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001271static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1272 struct hist_entry *entry,
1273 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001274 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001275{
1276 int printed = 0;
1277 int width = browser->b.width;
1278 char folded_sign = ' ';
1279 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1280 off_t row_offset = entry->row_offset;
1281 bool first = true;
1282 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001283 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001284 struct hpp_arg arg = {
1285 .b = &browser->b,
1286 .current_entry = current_entry,
1287 };
1288 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001289 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001290
1291 if (current_entry) {
1292 browser->he_selection = entry;
1293 browser->selection = &entry->ms;
1294 }
1295
1296 hist_entry__init_have_children(entry);
1297 folded_sign = hist_entry__folded(entry);
1298 arg.folded_sign = folded_sign;
1299
1300 if (entry->leaf && row_offset) {
1301 row_offset--;
1302 goto show_callchain;
1303 }
1304
1305 hist_browser__gotorc(browser, row, 0);
1306
1307 if (current_entry && browser->b.navkeypressed)
1308 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1309 else
1310 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1311
1312 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1313 width -= level * HIERARCHY_INDENT;
1314
Namhyung Kima61a22f2016-03-07 16:44:50 -03001315 /* the first hpp_list_node is for overhead columns */
1316 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1317 struct perf_hpp_list_node, list);
1318 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001319 char s[2048];
1320 struct perf_hpp hpp = {
1321 .buf = s,
1322 .size = sizeof(s),
1323 .ptr = &arg,
1324 };
1325
1326 if (perf_hpp__should_skip(fmt, entry->hists) ||
1327 column++ < browser->b.horiz_scroll)
1328 continue;
1329
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001330 if (current_entry && browser->b.navkeypressed) {
1331 ui_browser__set_color(&browser->b,
1332 HE_COLORSET_SELECTED);
1333 } else {
1334 ui_browser__set_color(&browser->b,
1335 HE_COLORSET_NORMAL);
1336 }
1337
1338 if (first) {
1339 ui_browser__printf(&browser->b, "%c", folded_sign);
1340 width--;
1341 first = false;
1342 } else {
1343 ui_browser__printf(&browser->b, " ");
1344 width -= 2;
1345 }
1346
1347 if (fmt->color) {
1348 int ret = fmt->color(fmt, &hpp, entry);
1349 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1350 /*
1351 * fmt->color() already used ui_browser to
1352 * print the non alignment bits, skip it (+ret):
1353 */
1354 ui_browser__printf(&browser->b, "%s", s + ret);
1355 } else {
1356 int ret = fmt->entry(fmt, &hpp, entry);
1357 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1358 ui_browser__printf(&browser->b, "%s", s);
1359 }
1360 width -= hpp.buf - s;
1361 }
1362
1363 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1364 width -= hierarchy_indent;
1365
1366 if (column >= browser->b.horiz_scroll) {
1367 char s[2048];
1368 struct perf_hpp hpp = {
1369 .buf = s,
1370 .size = sizeof(s),
1371 .ptr = &arg,
1372 };
1373
1374 if (current_entry && browser->b.navkeypressed) {
1375 ui_browser__set_color(&browser->b,
1376 HE_COLORSET_SELECTED);
1377 } else {
1378 ui_browser__set_color(&browser->b,
1379 HE_COLORSET_NORMAL);
1380 }
1381
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001382 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1383 ui_browser__write_nstring(&browser->b, "", 2);
1384 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001385
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001386 /*
1387 * No need to call hist_entry__snprintf_alignment()
1388 * since this fmt is always the last column in the
1389 * hierarchy mode.
1390 */
1391 if (fmt->color) {
1392 width -= fmt->color(fmt, &hpp, entry);
1393 } else {
1394 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001395
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001396 width -= fmt->entry(fmt, &hpp, entry);
1397 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001398
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001399 while (isspace(s[i++]))
1400 width++;
1401 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001402 }
1403 }
1404
1405 /* The scroll bar isn't being used */
1406 if (!browser->b.navkeypressed)
1407 width += 1;
1408
1409 ui_browser__write_nstring(&browser->b, "", width);
1410
1411 ++row;
1412 ++printed;
1413
1414show_callchain:
1415 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1416 struct callchain_print_arg carg = {
1417 .row_offset = row_offset,
1418 };
1419
1420 printed += hist_browser__show_callchain(browser, entry,
1421 level + 1, row,
1422 hist_browser__show_callchain_entry, &carg,
1423 hist_browser__check_output_full);
1424 }
1425
1426 return printed;
1427}
1428
Namhyung Kim79dded82016-02-26 21:13:19 +09001429static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001430 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001431{
1432 int width = browser->b.width;
1433 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1434 bool first = true;
1435 int column = 0;
1436 int ret;
1437 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001438 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001439 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001440
1441 if (current_entry) {
1442 browser->he_selection = NULL;
1443 browser->selection = NULL;
1444 }
1445
1446 hist_browser__gotorc(browser, row, 0);
1447
1448 if (current_entry && browser->b.navkeypressed)
1449 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1450 else
1451 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1452
1453 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1454 width -= level * HIERARCHY_INDENT;
1455
Namhyung Kima61a22f2016-03-07 16:44:50 -03001456 /* the first hpp_list_node is for overhead columns */
1457 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1458 struct perf_hpp_list_node, list);
1459 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001460 if (perf_hpp__should_skip(fmt, browser->hists) ||
1461 column++ < browser->b.horiz_scroll)
1462 continue;
1463
Jiri Olsada1b0402016-06-14 20:19:20 +02001464 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001465
1466 if (first) {
1467 /* for folded sign */
1468 first = false;
1469 ret++;
1470 } else {
1471 /* space between columns */
1472 ret += 2;
1473 }
1474
1475 ui_browser__write_nstring(&browser->b, "", ret);
1476 width -= ret;
1477 }
1478
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001479 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1480 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001481
1482 if (column >= browser->b.horiz_scroll) {
1483 char buf[32];
1484
1485 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1486 ui_browser__printf(&browser->b, " %s", buf);
1487 width -= ret + 2;
1488 }
1489
1490 /* The scroll bar isn't being used */
1491 if (!browser->b.navkeypressed)
1492 width += 1;
1493
1494 ui_browser__write_nstring(&browser->b, "", width);
1495 return 1;
1496}
1497
Jiri Olsa81a888f2014-06-14 15:44:52 +02001498static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1499{
1500 advance_hpp(hpp, inc);
1501 return hpp->size <= 0;
1502}
1503
Jiri Olsa69705b32016-08-07 17:28:28 +02001504static int
1505hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1506 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001507{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001508 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001509 struct perf_hpp dummy_hpp = {
1510 .buf = buf,
1511 .size = size,
1512 };
1513 struct perf_hpp_fmt *fmt;
1514 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001515 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001516 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001517
1518 if (symbol_conf.use_callchain) {
1519 ret = scnprintf(buf, size, " ");
1520 if (advance_hpp_check(&dummy_hpp, ret))
1521 return ret;
1522 }
1523
Jiri Olsaf0786af2016-01-18 10:24:23 +01001524 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001525 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001526 continue;
1527
Jiri Olsa29659ab2016-08-07 17:28:30 +02001528 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001529 if (advance_hpp_check(&dummy_hpp, ret))
1530 break;
1531
Jiri Olsa29659ab2016-08-07 17:28:30 +02001532 if (span)
1533 continue;
1534
Jiri Olsa81a888f2014-06-14 15:44:52 +02001535 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1536 if (advance_hpp_check(&dummy_hpp, ret))
1537 break;
1538 }
1539
1540 return ret;
1541}
1542
Namhyung Kimd8b92402016-02-25 00:13:46 +09001543static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1544{
1545 struct hists *hists = browser->hists;
1546 struct perf_hpp dummy_hpp = {
1547 .buf = buf,
1548 .size = size,
1549 };
1550 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001551 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001552 size_t ret = 0;
1553 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001554 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001555 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001556
1557 ret = scnprintf(buf, size, " ");
1558 if (advance_hpp_check(&dummy_hpp, ret))
1559 return ret;
1560
Namhyung Kima61a22f2016-03-07 16:44:50 -03001561 /* the first hpp_list_node is for overhead columns */
1562 fmt_node = list_first_entry(&hists->hpp_formats,
1563 struct perf_hpp_list_node, list);
1564 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001565 if (column++ < browser->b.horiz_scroll)
1566 continue;
1567
Jiri Olsa29659ab2016-08-07 17:28:30 +02001568 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001569 if (advance_hpp_check(&dummy_hpp, ret))
1570 break;
1571
1572 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1573 if (advance_hpp_check(&dummy_hpp, ret))
1574 break;
1575 }
1576
1577 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001578 indent * HIERARCHY_INDENT, "");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001579 if (advance_hpp_check(&dummy_hpp, ret))
1580 return ret;
1581
Namhyung Kima61a22f2016-03-07 16:44:50 -03001582 first_node = true;
1583 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1584 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001585 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1586 if (advance_hpp_check(&dummy_hpp, ret))
1587 break;
1588 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001589 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001590
Namhyung Kima61a22f2016-03-07 16:44:50 -03001591 first_col = true;
1592 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1593 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001594
Namhyung Kima61a22f2016-03-07 16:44:50 -03001595 if (perf_hpp__should_skip(fmt, hists))
1596 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001597
Namhyung Kima61a22f2016-03-07 16:44:50 -03001598 if (!first_col) {
1599 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1600 if (advance_hpp_check(&dummy_hpp, ret))
1601 break;
1602 }
1603 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001604
Jiri Olsa29659ab2016-08-07 17:28:30 +02001605 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001606 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001607
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001608 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001609 ret = strlen(start);
1610
1611 if (start != dummy_hpp.buf)
1612 memmove(dummy_hpp.buf, start, ret + 1);
1613
1614 if (advance_hpp_check(&dummy_hpp, ret))
1615 break;
1616 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001617 }
1618
1619 return ret;
1620}
1621
Jiri Olsa01b47702016-06-14 20:19:13 +02001622static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001623{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001624 char headers[1024];
1625
Jiri Olsa01b47702016-06-14 20:19:13 +02001626 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1627 sizeof(headers));
1628
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001629 ui_browser__gotorc(&browser->b, 0, 0);
1630 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001631 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001632}
1633
Jiri Olsa01b47702016-06-14 20:19:13 +02001634static void hists_browser__headers(struct hist_browser *browser)
1635{
Jiri Olsa69705b32016-08-07 17:28:28 +02001636 struct hists *hists = browser->hists;
1637 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001638
Jiri Olsa69705b32016-08-07 17:28:28 +02001639 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001640
Jiri Olsa69705b32016-08-07 17:28:28 +02001641 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1642 char headers[1024];
1643
1644 hists_browser__scnprintf_headers(browser, headers,
1645 sizeof(headers), line);
1646
1647 ui_browser__gotorc(&browser->b, line, 0);
1648 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1649 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1650 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001651}
1652
1653static void hist_browser__show_headers(struct hist_browser *browser)
1654{
1655 if (symbol_conf.report_hierarchy)
1656 hists_browser__hierarchy_headers(browser);
1657 else
1658 hists_browser__headers(browser);
1659}
1660
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001661static void ui_browser__hists_init_top(struct ui_browser *browser)
1662{
1663 if (browser->top == NULL) {
1664 struct hist_browser *hb;
1665
1666 hb = container_of(browser, struct hist_browser, b);
1667 browser->top = rb_first(&hb->hists->entries);
1668 }
1669}
1670
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001671static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001672{
1673 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001674 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001675 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001676 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001677 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001678
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001679 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001680 struct perf_hpp_list *hpp_list = hists->hpp_list;
1681
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001682 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001683 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001684 }
1685
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001686 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001687 hb->he_selection = NULL;
1688 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001689
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001690 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001691 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001692 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001693
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001694 if (h->filtered) {
1695 /* let it move to sibling */
1696 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001697 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001698 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001699
Namhyung Kim14135662013-10-31 10:17:39 +09001700 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001701 if (percent < hb->min_pcnt)
1702 continue;
1703
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001704 if (symbol_conf.report_hierarchy) {
1705 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001706 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001707 if (row == browser->rows)
1708 break;
1709
1710 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001711 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001712 row++;
1713 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001714 } else {
1715 row += hist_browser__show_entry(hb, h, row);
1716 }
1717
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001718 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001719 break;
1720 }
1721
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001722 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001723}
1724
Namhyung Kim064f1982013-05-14 11:09:04 +09001725static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001726 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001727{
1728 while (nd != NULL) {
1729 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001730 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001731
Namhyung Kimc0f15272014-04-16 11:16:33 +09001732 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001733 return nd;
1734
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001735 /*
1736 * If it's filtered, its all children also were filtered.
1737 * So move to sibling node.
1738 */
1739 if (rb_next(nd))
1740 nd = rb_next(nd);
1741 else
1742 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001743 }
1744
1745 return NULL;
1746}
1747
Namhyung Kim064f1982013-05-14 11:09:04 +09001748static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001749 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001750{
1751 while (nd != NULL) {
1752 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001753 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001754
1755 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001756 return nd;
1757
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001758 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001759 }
1760
1761 return NULL;
1762}
1763
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001764static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001765 off_t offset, int whence)
1766{
1767 struct hist_entry *h;
1768 struct rb_node *nd;
1769 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001770 struct hist_browser *hb;
1771
1772 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001773
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001774 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001775 return;
1776
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001777 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001778
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001779 switch (whence) {
1780 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001781 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001782 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001783 break;
1784 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001785 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001786 goto do_offset;
1787 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001788 nd = rb_hierarchy_last(rb_last(browser->entries));
1789 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001790 first = false;
1791 break;
1792 default:
1793 return;
1794 }
1795
1796 /*
1797 * Moves not relative to the first visible entry invalidates its
1798 * row_offset:
1799 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001800 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001801 h->row_offset = 0;
1802
1803 /*
1804 * Here we have to check if nd is expanded (+), if it is we can't go
1805 * the next top level hist_entry, instead we must compute an offset of
1806 * what _not_ to show and not change the first visible entry.
1807 *
1808 * This offset increments when we are going from top to bottom and
1809 * decreases when we're going from bottom to top.
1810 *
1811 * As we don't have backpointers to the top level in the callchains
1812 * structure, we need to always print the whole hist_entry callchain,
1813 * skipping the first ones that are before the first visible entry
1814 * and stop when we printed enough lines to fill the screen.
1815 */
1816do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001817 if (!nd)
1818 return;
1819
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001820 if (offset > 0) {
1821 do {
1822 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001823 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001824 u16 remaining = h->nr_rows - h->row_offset;
1825 if (offset > remaining) {
1826 offset -= remaining;
1827 h->row_offset = 0;
1828 } else {
1829 h->row_offset += offset;
1830 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001831 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001832 break;
1833 }
1834 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001835 nd = hists__filter_entries(rb_hierarchy_next(nd),
1836 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001837 if (nd == NULL)
1838 break;
1839 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001840 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001841 } while (offset != 0);
1842 } else if (offset < 0) {
1843 while (1) {
1844 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001845 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001846 if (first) {
1847 if (-offset > h->row_offset) {
1848 offset += h->row_offset;
1849 h->row_offset = 0;
1850 } else {
1851 h->row_offset += offset;
1852 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001853 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001854 break;
1855 }
1856 } else {
1857 if (-offset > h->nr_rows) {
1858 offset += h->nr_rows;
1859 h->row_offset = 0;
1860 } else {
1861 h->row_offset = h->nr_rows + offset;
1862 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001863 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001864 break;
1865 }
1866 }
1867 }
1868
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001869 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001870 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001871 if (nd == NULL)
1872 break;
1873 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001874 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001875 if (offset == 0) {
1876 /*
1877 * Last unfiltered hist_entry, check if it is
1878 * unfolded, if it is then we should have
1879 * row_offset at its last entry.
1880 */
1881 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001882 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001883 h->row_offset = h->nr_rows;
1884 break;
1885 }
1886 first = false;
1887 }
1888 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001889 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001890 h = rb_entry(nd, struct hist_entry, rb_node);
1891 h->row_offset = 0;
1892 }
1893}
1894
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001895static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001896 struct hist_entry *he, FILE *fp,
1897 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001898{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001899 struct callchain_print_arg arg = {
1900 .fp = fp,
1901 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001902
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001903 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001904 hist_browser__fprintf_callchain_entry, &arg,
1905 hist_browser__check_dump_full);
1906 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001907}
1908
1909static int hist_browser__fprintf_entry(struct hist_browser *browser,
1910 struct hist_entry *he, FILE *fp)
1911{
1912 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001913 int printed = 0;
1914 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001915 struct perf_hpp hpp = {
1916 .buf = s,
1917 .size = sizeof(s),
1918 };
1919 struct perf_hpp_fmt *fmt;
1920 bool first = true;
1921 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001922
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001923 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001924 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001925 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001926 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001927
Jiri Olsaf0786af2016-01-18 10:24:23 +01001928 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001929 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001930 continue;
1931
Namhyung Kim26d8b332014-03-03 16:16:20 +09001932 if (!first) {
1933 ret = scnprintf(hpp.buf, hpp.size, " ");
1934 advance_hpp(&hpp, ret);
1935 } else
1936 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001937
Namhyung Kim26d8b332014-03-03 16:16:20 +09001938 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001939 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001940 advance_hpp(&hpp, ret);
1941 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001942 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001943
1944 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001945 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1946
1947 return printed;
1948}
1949
1950
1951static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1952 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09001953 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001954{
1955 char s[8192];
1956 int printed = 0;
1957 char folded_sign = ' ';
1958 struct perf_hpp hpp = {
1959 .buf = s,
1960 .size = sizeof(s),
1961 };
1962 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09001963 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001964 bool first = true;
1965 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09001966 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001967
1968 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1969
1970 folded_sign = hist_entry__folded(he);
1971 printed += fprintf(fp, "%c", folded_sign);
1972
Namhyung Kim325a6282016-03-09 22:47:00 +09001973 /* the first hpp_list_node is for overhead columns */
1974 fmt_node = list_first_entry(&he->hists->hpp_formats,
1975 struct perf_hpp_list_node, list);
1976 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001977 if (!first) {
1978 ret = scnprintf(hpp.buf, hpp.size, " ");
1979 advance_hpp(&hpp, ret);
1980 } else
1981 first = false;
1982
1983 ret = fmt->entry(fmt, &hpp, he);
1984 advance_hpp(&hpp, ret);
1985 }
1986
1987 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1988 advance_hpp(&hpp, ret);
1989
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001990 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1991 ret = scnprintf(hpp.buf, hpp.size, " ");
1992 advance_hpp(&hpp, ret);
1993
1994 ret = fmt->entry(fmt, &hpp, he);
1995 advance_hpp(&hpp, ret);
1996 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001997
1998 printed += fprintf(fp, "%s\n", rtrim(s));
1999
2000 if (he->leaf && folded_sign == '-') {
2001 printed += hist_browser__fprintf_callchain(browser, he, fp,
2002 he->depth + 1);
2003 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002004
2005 return printed;
2006}
2007
2008static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2009{
Namhyung Kim064f1982013-05-14 11:09:04 +09002010 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002011 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002012 int printed = 0;
2013
2014 while (nd) {
2015 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2016
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002017 if (symbol_conf.report_hierarchy) {
2018 printed += hist_browser__fprintf_hierarchy_entry(browser,
2019 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002020 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002021 } else {
2022 printed += hist_browser__fprintf_entry(browser, h, fp);
2023 }
2024
2025 nd = hists__filter_entries(rb_hierarchy_next(nd),
2026 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002027 }
2028
2029 return printed;
2030}
2031
2032static int hist_browser__dump(struct hist_browser *browser)
2033{
2034 char filename[64];
2035 FILE *fp;
2036
2037 while (1) {
2038 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2039 if (access(filename, F_OK))
2040 break;
2041 /*
2042 * XXX: Just an arbitrary lazy upper limit
2043 */
2044 if (++browser->print_seq == 8192) {
2045 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2046 return -1;
2047 }
2048 }
2049
2050 fp = fopen(filename, "w");
2051 if (fp == NULL) {
2052 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002053 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002054 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002055 return -1;
2056 }
2057
2058 ++browser->print_seq;
2059 hist_browser__fprintf(browser, fp);
2060 fclose(fp);
2061 ui_helpline__fpush("%s written!", filename);
2062
2063 return 0;
2064}
2065
Jiri Olsafcd864262016-06-20 23:58:18 +02002066void hist_browser__init(struct hist_browser *browser,
2067 struct hists *hists)
2068{
2069 struct perf_hpp_fmt *fmt;
2070
2071 browser->hists = hists;
2072 browser->b.refresh = hist_browser__refresh;
2073 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2074 browser->b.seek = ui_browser__hists_seek;
2075 browser->b.use_navkeypressed = true;
2076 browser->show_headers = symbol_conf.show_hist_headers;
2077
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002078 hists__for_each_format(hists, fmt)
Jiri Olsafcd864262016-06-20 23:58:18 +02002079 ++browser->b.columns;
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002080
2081 hists__reset_column_width(hists);
Jiri Olsafcd864262016-06-20 23:58:18 +02002082}
2083
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002084struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002085{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002086 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002087
Jiri Olsafcd864262016-06-20 23:58:18 +02002088 if (browser)
2089 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002090
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002091 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002092}
2093
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002094static struct hist_browser *
2095perf_evsel_browser__new(struct perf_evsel *evsel,
2096 struct hist_browser_timer *hbt,
2097 struct perf_env *env)
2098{
2099 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2100
2101 if (browser) {
2102 browser->hbt = hbt;
2103 browser->env = env;
2104 browser->title = perf_evsel_browser_title;
2105 }
2106 return browser;
2107}
2108
Jiri Olsadabd2012016-06-20 23:58:14 +02002109void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002110{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002111 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002112}
2113
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002114static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002115{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002116 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002117}
2118
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002119static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002120{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002121 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002122}
2123
Taeung Song1e378eb2014-10-07 16:13:15 +09002124/* Check whether the browser is for 'top' or 'report' */
2125static inline bool is_report_browser(void *timer)
2126{
2127 return timer == NULL;
2128}
2129
Jiri Olsa5b91a862016-06-20 23:58:15 +02002130static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002131 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002132{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002133 struct hist_browser_timer *hbt = browser->hbt;
2134 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002135 char unit;
2136 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002137 const struct dso *dso = hists->dso_filter;
2138 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002139 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002140 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2141 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002142 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002143 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002144 char buf[512];
2145 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002146 char ref[30] = " show reference callgraph, ";
2147 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002148
Namhyung Kimf2148332014-01-14 11:52:48 +09002149 if (symbol_conf.filter_relative) {
2150 nr_samples = hists->stats.nr_non_filtered_samples;
2151 nr_events = hists->stats.total_non_filtered_period;
2152 }
2153
Namhyung Kim759ff492013-03-05 14:53:26 +09002154 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002155 struct perf_evsel *pos;
2156
2157 perf_evsel__group_desc(evsel, buf, buflen);
2158 ev_name = buf;
2159
2160 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002161 struct hists *pos_hists = evsel__hists(pos);
2162
Namhyung Kimf2148332014-01-14 11:52:48 +09002163 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002164 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2165 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002166 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002167 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2168 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002169 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002170 }
2171 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002172
Kan Liang9e207dd2015-08-11 06:30:49 -04002173 if (symbol_conf.show_ref_callgraph &&
2174 strstr(ev_name, "call-graph=no"))
2175 enable_ref = true;
Ashay Ranecc686282012-04-05 21:01:01 -05002176 nr_samples = convert_unit(nr_samples, &unit);
2177 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002178 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2179 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc686282012-04-05 21:01:01 -05002180
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002181
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002182 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002183 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002184 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002185 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002186 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002187 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002188 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002189 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002190 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002191 } else {
2192 printed += scnprintf(bf + printed, size - printed,
2193 ", Thread: %s",
2194 (thread->comm_set ? thread__comm_str(thread) : ""));
2195 }
2196 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002197 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002198 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002199 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002200 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002201 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002202 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002203 if (!is_report_browser(hbt)) {
2204 struct perf_top *top = hbt->arg;
2205
2206 if (top->zero)
2207 printed += scnprintf(bf + printed, size - printed, " [z]");
2208 }
2209
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002210 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002211}
2212
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002213static inline void free_popup_options(char **options, int n)
2214{
2215 int i;
2216
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002217 for (i = 0; i < n; ++i)
2218 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002219}
2220
Feng Tang341487ab2013-02-03 14:38:20 +08002221/*
2222 * Only runtime switching of perf data file will make "input_name" point
2223 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2224 * whether we need to call free() for current "input_name" during the switch.
2225 */
2226static bool is_input_name_malloced = false;
2227
2228static int switch_data_file(void)
2229{
2230 char *pwd, *options[32], *abs_path[32], *tmp;
2231 DIR *pwd_dir;
2232 int nr_options = 0, choice = -1, ret = -1;
2233 struct dirent *dent;
2234
2235 pwd = getenv("PWD");
2236 if (!pwd)
2237 return ret;
2238
2239 pwd_dir = opendir(pwd);
2240 if (!pwd_dir)
2241 return ret;
2242
2243 memset(options, 0, sizeof(options));
2244 memset(options, 0, sizeof(abs_path));
2245
2246 while ((dent = readdir(pwd_dir))) {
2247 char path[PATH_MAX];
2248 u64 magic;
2249 char *name = dent->d_name;
2250 FILE *file;
2251
2252 if (!(dent->d_type == DT_REG))
2253 continue;
2254
2255 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2256
2257 file = fopen(path, "r");
2258 if (!file)
2259 continue;
2260
2261 if (fread(&magic, 1, 8, file) < 8)
2262 goto close_file_and_continue;
2263
2264 if (is_perf_magic(magic)) {
2265 options[nr_options] = strdup(name);
2266 if (!options[nr_options])
2267 goto close_file_and_continue;
2268
2269 abs_path[nr_options] = strdup(path);
2270 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002271 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002272 ui__warning("Can't search all data files due to memory shortage.\n");
2273 fclose(file);
2274 break;
2275 }
2276
2277 nr_options++;
2278 }
2279
2280close_file_and_continue:
2281 fclose(file);
2282 if (nr_options >= 32) {
2283 ui__warning("Too many perf data files in PWD!\n"
2284 "Only the first 32 files will be listed.\n");
2285 break;
2286 }
2287 }
2288 closedir(pwd_dir);
2289
2290 if (nr_options) {
2291 choice = ui__popup_menu(nr_options, options);
2292 if (choice < nr_options && choice >= 0) {
2293 tmp = strdup(abs_path[choice]);
2294 if (tmp) {
2295 if (is_input_name_malloced)
2296 free((void *)input_name);
2297 input_name = tmp;
2298 is_input_name_malloced = true;
2299 ret = 0;
2300 } else
2301 ui__warning("Data switch failed due to memory shortage!\n");
2302 }
2303 }
2304
2305 free_popup_options(options, nr_options);
2306 free_popup_options(abs_path, nr_options);
2307 return ret;
2308}
2309
Namhyung Kimea7cd592015-04-22 16:18:19 +09002310struct popup_action {
2311 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002312 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002313 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002314
2315 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2316};
2317
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002318static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002319do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002320{
2321 struct perf_evsel *evsel;
2322 struct annotation *notes;
2323 struct hist_entry *he;
2324 int err;
2325
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002326 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002327 return 0;
2328
Namhyung Kimea7cd592015-04-22 16:18:19 +09002329 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002330 if (!notes->src)
2331 return 0;
2332
2333 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002334 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002335 he = hist_browser__selected_entry(browser);
2336 /*
2337 * offer option to annotate the other branch source or target
2338 * (if they exists) when returning from annotate
2339 */
2340 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2341 return 1;
2342
2343 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2344 if (err)
2345 ui_browser__handle_resize(&browser->b);
2346 return 0;
2347}
2348
2349static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002350add_annotate_opt(struct hist_browser *browser __maybe_unused,
2351 struct popup_action *act, char **optstr,
2352 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002353{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002354 if (sym == NULL || map->dso->annotate_warned)
2355 return 0;
2356
2357 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2358 return 0;
2359
2360 act->ms.map = map;
2361 act->ms.sym = sym;
2362 act->fn = do_annotate;
2363 return 1;
2364}
2365
2366static int
2367do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2368{
2369 struct thread *thread = act->thread;
2370
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002371 if ((!hists__has(browser->hists, thread) &&
2372 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002373 return 0;
2374
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002375 if (browser->hists->thread_filter) {
2376 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2377 perf_hpp__set_elide(HISTC_THREAD, false);
2378 thread__zput(browser->hists->thread_filter);
2379 ui_helpline__pop();
2380 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002381 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002382 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2383 thread->comm_set ? thread__comm_str(thread) : "",
2384 thread->tid);
2385 } else {
2386 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2387 thread->comm_set ? thread__comm_str(thread) : "");
2388 }
2389
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002390 browser->hists->thread_filter = thread__get(thread);
2391 perf_hpp__set_elide(HISTC_THREAD, false);
2392 pstack__push(browser->pstack, &browser->hists->thread_filter);
2393 }
2394
2395 hists__filter_by_thread(browser->hists);
2396 hist_browser__reset(browser);
2397 return 0;
2398}
2399
2400static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002401add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2402 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002403{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002404 int ret;
2405
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002406 if ((!hists__has(browser->hists, thread) &&
2407 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002408 return 0;
2409
Jiri Olsafa829112016-05-03 13:54:47 +02002410 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002411 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2412 browser->hists->thread_filter ? "out of" : "into",
2413 thread->comm_set ? thread__comm_str(thread) : "",
2414 thread->tid);
2415 } else {
2416 ret = asprintf(optstr, "Zoom %s %s thread",
2417 browser->hists->thread_filter ? "out of" : "into",
2418 thread->comm_set ? thread__comm_str(thread) : "");
2419 }
2420 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002421 return 0;
2422
2423 act->thread = thread;
2424 act->fn = do_zoom_thread;
2425 return 1;
2426}
2427
2428static int
2429do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2430{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002431 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002432
Jiri Olsa69849fc2016-05-03 13:54:45 +02002433 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002434 return 0;
2435
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002436 if (browser->hists->dso_filter) {
2437 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2438 perf_hpp__set_elide(HISTC_DSO, false);
2439 browser->hists->dso_filter = NULL;
2440 ui_helpline__pop();
2441 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002442 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002443 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2444 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002445 perf_hpp__set_elide(HISTC_DSO, true);
2446 pstack__push(browser->pstack, &browser->hists->dso_filter);
2447 }
2448
2449 hists__filter_by_dso(browser->hists);
2450 hist_browser__reset(browser);
2451 return 0;
2452}
2453
2454static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002455add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002456 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002457{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002458 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002459 return 0;
2460
2461 if (asprintf(optstr, "Zoom %s %s DSO",
2462 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002463 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002464 return 0;
2465
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002466 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002467 act->fn = do_zoom_dso;
2468 return 1;
2469}
2470
2471static int
2472do_browse_map(struct hist_browser *browser __maybe_unused,
2473 struct popup_action *act)
2474{
2475 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002476 return 0;
2477}
2478
2479static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002480add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002481 struct popup_action *act, char **optstr, struct map *map)
2482{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002483 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002484 return 0;
2485
2486 if (asprintf(optstr, "Browse map details") < 0)
2487 return 0;
2488
2489 act->ms.map = map;
2490 act->fn = do_browse_map;
2491 return 1;
2492}
2493
2494static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002495do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002496 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002497{
2498 char script_opt[64];
2499 memset(script_opt, 0, sizeof(script_opt));
2500
Namhyung Kimea7cd592015-04-22 16:18:19 +09002501 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002502 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002503 thread__comm_str(act->thread));
2504 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002505 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002506 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002507 }
2508
2509 script_browse(script_opt);
2510 return 0;
2511}
2512
2513static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002514add_script_opt(struct hist_browser *browser __maybe_unused,
2515 struct popup_action *act, char **optstr,
2516 struct thread *thread, struct symbol *sym)
2517{
2518 if (thread) {
2519 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2520 thread__comm_str(thread)) < 0)
2521 return 0;
2522 } else if (sym) {
2523 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2524 sym->name) < 0)
2525 return 0;
2526 } else {
2527 if (asprintf(optstr, "Run scripts for all samples") < 0)
2528 return 0;
2529 }
2530
2531 act->thread = thread;
2532 act->ms.sym = sym;
2533 act->fn = do_run_script;
2534 return 1;
2535}
2536
2537static int
2538do_switch_data(struct hist_browser *browser __maybe_unused,
2539 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002540{
2541 if (switch_data_file()) {
2542 ui__warning("Won't switch the data files due to\n"
2543 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002544 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002545 }
2546
2547 return K_SWITCH_INPUT_DATA;
2548}
2549
Namhyung Kimea7cd592015-04-22 16:18:19 +09002550static int
2551add_switch_opt(struct hist_browser *browser,
2552 struct popup_action *act, char **optstr)
2553{
2554 if (!is_report_browser(browser->hbt))
2555 return 0;
2556
2557 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2558 return 0;
2559
2560 act->fn = do_switch_data;
2561 return 1;
2562}
2563
2564static int
2565do_exit_browser(struct hist_browser *browser __maybe_unused,
2566 struct popup_action *act __maybe_unused)
2567{
2568 return 0;
2569}
2570
2571static int
2572add_exit_opt(struct hist_browser *browser __maybe_unused,
2573 struct popup_action *act, char **optstr)
2574{
2575 if (asprintf(optstr, "Exit") < 0)
2576 return 0;
2577
2578 act->fn = do_exit_browser;
2579 return 1;
2580}
2581
Kan Liang84734b02015-09-04 10:45:45 -04002582static int
2583do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2584{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002585 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002586 return 0;
2587
Kan Liang84734b02015-09-04 10:45:45 -04002588 if (browser->hists->socket_filter > -1) {
2589 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2590 browser->hists->socket_filter = -1;
2591 perf_hpp__set_elide(HISTC_SOCKET, false);
2592 } else {
2593 browser->hists->socket_filter = act->socket;
2594 perf_hpp__set_elide(HISTC_SOCKET, true);
2595 pstack__push(browser->pstack, &browser->hists->socket_filter);
2596 }
2597
2598 hists__filter_by_socket(browser->hists);
2599 hist_browser__reset(browser);
2600 return 0;
2601}
2602
2603static int
2604add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2605 char **optstr, int socket_id)
2606{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002607 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002608 return 0;
2609
2610 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2611 (browser->hists->socket_filter > -1) ? "out of" : "into",
2612 socket_id) < 0)
2613 return 0;
2614
2615 act->socket = socket_id;
2616 act->fn = do_zoom_socket;
2617 return 1;
2618}
2619
Namhyung Kim112f7612014-04-22 14:05:35 +09002620static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002621{
2622 u64 nr_entries = 0;
2623 struct rb_node *nd = rb_first(&hb->hists->entries);
2624
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002625 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002626 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2627 return;
2628 }
2629
Namhyung Kim14135662013-10-31 10:17:39 +09002630 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002631 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002632 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002633 }
2634
Namhyung Kim112f7612014-04-22 14:05:35 +09002635 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002636 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002637}
Feng Tang341487ab2013-02-03 14:38:20 +08002638
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002639static void hist_browser__update_percent_limit(struct hist_browser *hb,
2640 double percent)
2641{
2642 struct hist_entry *he;
2643 struct rb_node *nd = rb_first(&hb->hists->entries);
2644 u64 total = hists__total_period(hb->hists);
2645 u64 min_callchain_hits = total * (percent / 100);
2646
2647 hb->min_pcnt = callchain_param.min_percent = percent;
2648
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002649 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2650 he = rb_entry(nd, struct hist_entry, rb_node);
2651
Namhyung Kim79dded82016-02-26 21:13:19 +09002652 if (he->has_no_entry) {
2653 he->has_no_entry = false;
2654 he->nr_rows = 0;
2655 }
2656
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002657 if (!he->leaf || !symbol_conf.use_callchain)
2658 goto next;
2659
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002660 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2661 total = he->stat.period;
2662
2663 if (symbol_conf.cumulate_callchain)
2664 total = he->stat_acc->period;
2665
2666 min_callchain_hits = total * (percent / 100);
2667 }
2668
2669 callchain_param.sort(&he->sorted_chain, he->callchain,
2670 min_callchain_hits, &callchain_param);
2671
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002672next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002673 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002674
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002675 /* force to re-evaluate folding state of callchains */
2676 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002677 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002678 }
2679}
2680
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002681static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002682 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002683 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002684 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002685 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002686 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002687{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002688 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002689 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002690 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002691#define MAX_OPTIONS 16
2692 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002693 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002694 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002695 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002696 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002697 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002698
Namhyung Kime8e684a2013-12-26 14:37:58 +09002699#define HIST_BROWSER_HELP_COMMON \
2700 "h/?/F1 Show this window\n" \
2701 "UP/DOWN/PGUP\n" \
2702 "PGDN/SPACE Navigate\n" \
2703 "q/ESC/CTRL+C Exit browser\n\n" \
2704 "For multiple event sessions:\n\n" \
2705 "TAB/UNTAB Switch events\n\n" \
2706 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002707 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2708 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002709 "a Annotate current symbol\n" \
2710 "C Collapse all callchains\n" \
2711 "d Zoom into current DSO\n" \
2712 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002713 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002714 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002715 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002716 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002717 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002718
2719 /* help messages are sorted by lexical order of the hotkey */
2720 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002721 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002722 "P Print histograms to perf.hist.N\n"
2723 "r Run available scripts\n"
2724 "s Switch to another data file in PWD\n"
2725 "t Zoom into current Thread\n"
2726 "V Verbose (DSO names in callchains, etc)\n"
2727 "/ Filter symbol by name";
2728 const char top_help[] = HIST_BROWSER_HELP_COMMON
2729 "P Print histograms to perf.hist.N\n"
2730 "t Zoom into current Thread\n"
2731 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002732 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002733 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002734 "/ Filter symbol by name";
2735
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002736 if (browser == NULL)
2737 return -1;
2738
Namhyung Kimed426912015-05-29 21:53:44 +09002739 /* reset abort key so that it can get Ctrl-C as a key */
2740 SLang_reset_tty();
2741 SLang_init_tty(0, 0, 0);
2742
Namhyung Kim03905042015-11-28 02:32:39 +09002743 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002744 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002745 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002746
Kan Liang84734b02015-09-04 10:45:45 -04002747 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002748 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002749 goto out;
2750
2751 ui_helpline__push(helpline);
2752
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002753 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002754 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002755
Namhyung Kim5b591662014-07-31 14:47:38 +09002756 if (symbol_conf.col_width_list_str)
2757 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2758
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002759 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002760 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002761 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002762 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002763 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002764
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002765 nr_options = 0;
2766
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002767 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002768
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002769 if (browser->he_selection != NULL) {
2770 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002771 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002772 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002773 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002774 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002775 case K_TAB:
2776 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002777 if (nr_events == 1)
2778 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002779 /*
2780 * Exit the browser, let hists__browser_tree
2781 * go to the next or previous
2782 */
2783 goto out_free_stack;
2784 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002785 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002786 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002787 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002788 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002789 continue;
2790 }
2791
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002792 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002793 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002794 browser->selection->map->dso->annotate_warned)
2795 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002796
Namhyung Kimea7cd592015-04-22 16:18:19 +09002797 actions->ms.map = browser->selection->map;
2798 actions->ms.sym = browser->selection->sym;
2799 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002800 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002801 case 'P':
2802 hist_browser__dump(browser);
2803 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002804 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002805 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002806 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002807 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002808 case 'V':
2809 browser->show_dso = !browser->show_dso;
2810 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002811 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002812 actions->thread = thread;
2813 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002814 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002815 case 'S':
2816 actions->socket = socked_id;
2817 do_zoom_socket(browser, actions);
2818 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002819 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002820 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e452015-10-12 14:02:29 -03002821 "Please enter the name of symbol you want to see.\n"
2822 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002823 buf, "ENTER: OK, ESC: Cancel",
2824 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002825 hists->symbol_filter_str = *buf ? buf : NULL;
2826 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002827 hist_browser__reset(browser);
2828 }
2829 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002830 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002831 if (is_report_browser(hbt)) {
2832 actions->thread = NULL;
2833 actions->ms.sym = NULL;
2834 do_run_script(browser, actions);
2835 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002836 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002837 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002838 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002839 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002840 if (key == K_SWITCH_INPUT_DATA)
2841 goto out_free_stack;
2842 }
Feng Tang341487ab2013-02-03 14:38:20 +08002843 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002844 case 'i':
2845 /* env->arch is NULL for live-mode (i.e. perf top) */
2846 if (env->arch)
2847 tui__header_window(env);
2848 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002849 case 'F':
2850 symbol_conf.filter_relative ^= 1;
2851 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002852 case 'z':
2853 if (!is_report_browser(hbt)) {
2854 struct perf_top *top = hbt->arg;
2855
2856 top->zero = !top->zero;
2857 }
2858 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002859 case 'L':
2860 if (ui_browser__input_window("Percent Limit",
2861 "Please enter the value you want to hide entries under that percent.",
2862 buf, "ENTER: OK, ESC: Cancel",
2863 delay_secs * 2) == K_ENTER) {
2864 char *end;
2865 double new_percent = strtod(buf, &end);
2866
2867 if (new_percent < 0 || new_percent > 100) {
2868 ui_browser__warning(&browser->b, delay_secs * 2,
2869 "Invalid percent: %.2f", new_percent);
2870 continue;
2871 }
2872
2873 hist_browser__update_percent_limit(browser, new_percent);
2874 hist_browser__reset(browser);
2875 }
2876 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002877 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002878 case 'h':
2879 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002880 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002881 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002882 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002883 case K_ENTER:
2884 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002885 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002886 /* menu */
2887 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002888 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002889 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002890 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002891
Namhyung Kim01f00a12015-04-22 16:18:16 +09002892 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002893 /*
2894 * Go back to the perf_evsel_menu__run or other user
2895 */
2896 if (left_exits)
2897 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002898
2899 if (key == K_ESC &&
2900 ui_browser__dialog_yesno(&browser->b,
2901 "Do you really want to exit?"))
2902 goto out_free_stack;
2903
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002904 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002905 }
Namhyung Kim64221842015-04-24 10:15:33 +09002906 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002907 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002908 /*
2909 * No need to set actions->dso here since
2910 * it's just to remove the current filter.
2911 * Ditto for thread below.
2912 */
2913 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002914 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002915 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002916 } else if (top == &browser->hists->socket_filter) {
2917 do_zoom_socket(browser, actions);
2918 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002919 continue;
2920 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002921 case 'q':
2922 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002923 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002924 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002925 if (!is_report_browser(hbt)) {
2926 struct perf_top *top = hbt->arg;
2927
2928 perf_evlist__toggle_enable(top->evlist);
2929 /*
2930 * No need to refresh, resort/decay histogram
2931 * entries if we are not collecting samples:
2932 */
2933 if (top->evlist->enabled) {
2934 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2935 hbt->refresh = delay_secs;
2936 } else {
2937 helpline = "Press 'f' again to re-enable the events";
2938 hbt->refresh = 0;
2939 }
2940 continue;
2941 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002942 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002943 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002944 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002945 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002946 }
2947
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002948 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002949 goto skip_annotation;
2950
Namhyung Kim55369fc2013-04-01 20:35:20 +09002951 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002952 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002953
2954 if (bi == NULL)
2955 goto skip_annotation;
2956
Namhyung Kimea7cd592015-04-22 16:18:19 +09002957 nr_options += add_annotate_opt(browser,
2958 &actions[nr_options],
2959 &options[nr_options],
2960 bi->from.map,
2961 bi->from.sym);
2962 if (bi->to.sym != bi->from.sym)
2963 nr_options += add_annotate_opt(browser,
2964 &actions[nr_options],
2965 &options[nr_options],
2966 bi->to.map,
2967 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002968 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002969 nr_options += add_annotate_opt(browser,
2970 &actions[nr_options],
2971 &options[nr_options],
2972 browser->selection->map,
2973 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002974 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002975skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002976 nr_options += add_thread_opt(browser, &actions[nr_options],
2977 &options[nr_options], thread);
2978 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002979 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002980 nr_options += add_map_opt(browser, &actions[nr_options],
2981 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002982 browser->selection ?
2983 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002984 nr_options += add_socket_opt(browser, &actions[nr_options],
2985 &options[nr_options],
2986 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002987 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002988 if (!is_report_browser(hbt))
2989 goto skip_scripting;
2990
Feng Tangcdbab7c2012-10-30 11:56:06 +08002991 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02002992 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002993 nr_options += add_script_opt(browser,
2994 &actions[nr_options],
2995 &options[nr_options],
2996 thread, NULL);
2997 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002998 /*
2999 * Note that browser->selection != NULL
3000 * when browser->he_selection is not NULL,
3001 * so we don't need to check browser->selection
3002 * before fetching browser->selection->sym like what
3003 * we do before fetching browser->selection->map.
3004 *
3005 * See hist_browser__show_entry.
3006 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003007 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003008 nr_options += add_script_opt(browser,
3009 &actions[nr_options],
3010 &options[nr_options],
3011 NULL, browser->selection->sym);
3012 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003013 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003014 nr_options += add_script_opt(browser, &actions[nr_options],
3015 &options[nr_options], NULL, NULL);
3016 nr_options += add_switch_opt(browser, &actions[nr_options],
3017 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003018skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003019 nr_options += add_exit_opt(browser, &actions[nr_options],
3020 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003021
Namhyung Kimea7cd592015-04-22 16:18:19 +09003022 do {
3023 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003024
Namhyung Kimea7cd592015-04-22 16:18:19 +09003025 choice = ui__popup_menu(nr_options, options);
3026 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003027 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003028
3029 act = &actions[choice];
3030 key = act->fn(browser, act);
3031 } while (key == 1);
3032
3033 if (key == K_SWITCH_INPUT_DATA)
3034 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003035 }
3036out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003037 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003038out:
3039 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003040 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003041 return key;
3042}
3043
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003044struct perf_evsel_menu {
3045 struct ui_browser b;
3046 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003047 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003048 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003049 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003050};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003051
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003052static void perf_evsel_menu__write(struct ui_browser *browser,
3053 void *entry, int row)
3054{
3055 struct perf_evsel_menu *menu = container_of(browser,
3056 struct perf_evsel_menu, b);
3057 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003058 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003059 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003060 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003061 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003062 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003063 const char *warn = " ";
3064 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003065
3066 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3067 HE_COLORSET_NORMAL);
3068
Namhyung Kim759ff492013-03-05 14:53:26 +09003069 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003070 struct perf_evsel *pos;
3071
3072 ev_name = perf_evsel__group_name(evsel);
3073
3074 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003075 struct hists *pos_hists = evsel__hists(pos);
3076 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003077 }
3078 }
3079
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003080 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003081 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003082 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003083 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003084
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003085 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003086 if (nr_events != 0) {
3087 menu->lost_events = true;
3088 if (!current_entry)
3089 ui_browser__set_color(browser, HE_COLORSET_TOP);
3090 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003091 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3092 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003093 warn = bf;
3094 }
3095
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003096 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003097
3098 if (current_entry)
3099 menu->selection = evsel;
3100}
3101
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003102static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3103 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003104 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003105{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003106 struct perf_evlist *evlist = menu->b.priv;
3107 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003108 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003109 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003110 int key;
3111
3112 if (ui_browser__show(&menu->b, title,
3113 "ESC: exit, ENTER|->: Browse histograms") < 0)
3114 return -1;
3115
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003116 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003117 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003118
3119 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003120 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003121 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003122
3123 if (!menu->lost_events_warned && menu->lost_events) {
3124 ui_browser__warn_lost_events(&menu->b);
3125 menu->lost_events_warned = true;
3126 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003127 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003128 case K_RIGHT:
3129 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003130 if (!menu->selection)
3131 continue;
3132 pos = menu->selection;
3133browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003134 perf_evlist__set_selected(evlist, pos);
3135 /*
3136 * Give the calling tool a chance to populate the non
3137 * default evsel resorted hists tree.
3138 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003139 if (hbt)
3140 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003141 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003142 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003143 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003144 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003145 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003146 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003147 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003148 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003149 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003150 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003151 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003152 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003153 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003154 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003155 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003156 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003157 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003158 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003159 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003160 case 'q':
3161 case CTRL('c'):
3162 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003163 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003164 default:
3165 continue;
3166 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003167 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003168 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003169 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003170 if (!ui_browser__dialog_yesno(&menu->b,
3171 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003172 continue;
3173 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003174 case 'q':
3175 case CTRL('c'):
3176 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003177 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003178 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003179 }
3180 }
3181
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003182out:
3183 ui_browser__hide(&menu->b);
3184 return key;
3185}
3186
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003187static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003188 void *entry)
3189{
3190 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3191
3192 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3193 return true;
3194
3195 return false;
3196}
3197
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003198static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003199 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003200 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003201 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003202 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003203{
3204 struct perf_evsel *pos;
3205 struct perf_evsel_menu menu = {
3206 .b = {
3207 .entries = &evlist->entries,
3208 .refresh = ui_browser__list_head_refresh,
3209 .seek = ui_browser__list_head_seek,
3210 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003211 .filter = filter_group_entries,
3212 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003213 .priv = evlist,
3214 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003215 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003216 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003217 };
3218
3219 ui_helpline__push("Press ESC to exit");
3220
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003221 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003222 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003223 size_t line_len = strlen(ev_name) + 7;
3224
3225 if (menu.b.width < line_len)
3226 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003227 }
3228
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003229 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003230}
3231
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003232int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003233 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003234 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003235 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003236{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003237 int nr_entries = evlist->nr_entries;
3238
3239single_entry:
3240 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003241 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003242
3243 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003244 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003245 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003246 }
3247
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003248 if (symbol_conf.event_group) {
3249 struct perf_evsel *pos;
3250
3251 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003252 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003253 if (perf_evsel__is_group_leader(pos))
3254 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003255 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003256
3257 if (nr_entries == 1)
3258 goto single_entry;
3259 }
3260
3261 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003262 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003263}