blob: 66676cb8effe8f488d93ece2373ce1adb32d2e8d [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{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010033 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_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 Kimc6111522016-10-07 14:04:12 +0900604 if (hist_browser__has_filter(browser) ||
605 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900606 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900607
Namhyung Kimc3b78952014-04-22 15:56:17 +0900608 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900609 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200610
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300611 if (browser->hists->stats.nr_lost_warned !=
612 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
613 browser->hists->stats.nr_lost_warned =
614 browser->hists->stats.nr_events[PERF_RECORD_LOST];
615 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200616 }
617
Jiri Olsa5b91a862016-06-20 23:58:15 +0200618 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300619 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300620 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900621 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300622 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300623 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300624 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300625 struct hist_entry, rb_node);
626 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300627 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 -0300628 seq++, browser->b.nr_entries,
629 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300630 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300631 browser->b.index,
632 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300633 h->row_offset, h->nr_rows);
634 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300635 break;
636 case 'C':
637 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300638 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300639 break;
640 case 'E':
641 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300642 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300643 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200644 case 'H':
645 browser->show_headers = !browser->show_headers;
646 hist_browser__update_rows(browser);
647 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200648 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300649 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300650 break;
651 /* fall thru */
652 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300653 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300654 }
655 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300656out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300657 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300658 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300659}
660
Namhyung Kim39ee5332014-08-22 09:13:21 +0900661struct callchain_print_arg {
662 /* for hists browser */
663 off_t row_offset;
664 bool is_current_entry;
665
666 /* for file dump */
667 FILE *fp;
668 int printed;
669};
670
671typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
672 struct callchain_list *chain,
673 const char *str, int offset,
674 unsigned short row,
675 struct callchain_print_arg *arg);
676
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900677static void hist_browser__show_callchain_entry(struct hist_browser *browser,
678 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900679 const char *str, int offset,
680 unsigned short row,
681 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900682{
683 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900684 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300685 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900686
687 color = HE_COLORSET_NORMAL;
688 width = browser->b.width - (offset + 2);
689 if (ui_browser__is_current_entry(&browser->b, row)) {
690 browser->selection = &chain->ms;
691 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900692 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900693 }
694
695 ui_browser__set_color(&browser->b, color);
696 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300697 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300698 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300699 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300700 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900701}
702
Namhyung Kim39ee5332014-08-22 09:13:21 +0900703static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
704 struct callchain_list *chain,
705 const char *str, int offset,
706 unsigned short row __maybe_unused,
707 struct callchain_print_arg *arg)
708{
709 char folded_sign = callchain_list__folded(chain);
710
711 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
712 folded_sign, str);
713}
714
715typedef bool (*check_output_full_fn)(struct hist_browser *browser,
716 unsigned short row);
717
718static bool hist_browser__check_output_full(struct hist_browser *browser,
719 unsigned short row)
720{
721 return browser->b.rows == row;
722}
723
724static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
725 unsigned short row __maybe_unused)
726{
727 return false;
728}
729
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300730#define LEVEL_OFFSET_STEP 3
731
Namhyung Kim18bb8382015-11-09 14:45:42 +0900732static int hist_browser__show_callchain_list(struct hist_browser *browser,
733 struct callchain_node *node,
734 struct callchain_list *chain,
735 unsigned short row, u64 total,
736 bool need_percent, int offset,
737 print_callchain_entry_fn print,
738 struct callchain_print_arg *arg)
739{
740 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800741 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900742 const char *str;
743
744 if (arg->row_offset != 0) {
745 arg->row_offset--;
746 return 0;
747 }
748
749 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800750 alloc_str2 = NULL;
751
Namhyung Kim18bb8382015-11-09 14:45:42 +0900752 str = callchain_list__sym_name(chain, bf, sizeof(bf),
753 browser->show_dso);
754
Jin Yaofef51ec2016-10-31 09:19:53 +0800755 if (symbol_conf.show_branchflag_count) {
756 if (need_percent)
757 callchain_list_counts__printf_value(node, chain, NULL,
758 buf, sizeof(buf));
759 else
760 callchain_list_counts__printf_value(NULL, chain, NULL,
761 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900762
Jin Yaofef51ec2016-10-31 09:19:53 +0800763 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
764 str = "Not enough memory!";
765 else
766 str = alloc_str2;
767 }
768
769 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900770 callchain_node__scnprintf_value(node, buf, sizeof(buf),
771 total);
772
773 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
774 str = "Not enough memory!";
775 else
776 str = alloc_str;
777 }
778
779 print(browser, chain, str, offset, row, arg);
780
781 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800782 free(alloc_str2);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900783 return 1;
784}
785
Namhyung Kim59c624e2016-01-28 00:40:56 +0900786static bool check_percent_display(struct rb_node *node, u64 parent_total)
787{
788 struct callchain_node *child;
789
790 if (node == NULL)
791 return false;
792
793 if (rb_next(node))
794 return true;
795
796 child = rb_entry(node, struct callchain_node, rb_node);
797 return callchain_cumul_hits(child) != parent_total;
798}
799
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900800static int hist_browser__show_callchain_flat(struct hist_browser *browser,
801 struct rb_root *root,
802 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900803 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900804 print_callchain_entry_fn print,
805 struct callchain_print_arg *arg,
806 check_output_full_fn is_output_full)
807{
808 struct rb_node *node;
809 int first_row = row, offset = LEVEL_OFFSET_STEP;
810 bool need_percent;
811
812 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900813 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900814
815 while (node) {
816 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
817 struct rb_node *next = rb_next(node);
818 struct callchain_list *chain;
819 char folded_sign = ' ';
820 int first = true;
821 int extra_offset = 0;
822
823 list_for_each_entry(chain, &child->parent_val, list) {
824 bool was_first = first;
825
826 if (first)
827 first = false;
828 else if (need_percent)
829 extra_offset = LEVEL_OFFSET_STEP;
830
831 folded_sign = callchain_list__folded(chain);
832
833 row += hist_browser__show_callchain_list(browser, child,
834 chain, row, total,
835 was_first && need_percent,
836 offset + extra_offset,
837 print, arg);
838
839 if (is_output_full(browser, row))
840 goto out;
841
842 if (folded_sign == '+')
843 goto next;
844 }
845
846 list_for_each_entry(chain, &child->val, list) {
847 bool was_first = first;
848
849 if (first)
850 first = false;
851 else if (need_percent)
852 extra_offset = LEVEL_OFFSET_STEP;
853
854 folded_sign = callchain_list__folded(chain);
855
856 row += hist_browser__show_callchain_list(browser, child,
857 chain, row, total,
858 was_first && need_percent,
859 offset + extra_offset,
860 print, arg);
861
862 if (is_output_full(browser, row))
863 goto out;
864
865 if (folded_sign == '+')
866 break;
867 }
868
869next:
870 if (is_output_full(browser, row))
871 break;
872 node = next;
873 }
874out:
875 return row - first_row;
876}
877
Namhyung Kim8c430a32015-11-09 14:45:44 +0900878static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
879 struct callchain_list *chain,
880 char *value_str, char *old_str)
881{
882 char bf[1024];
883 const char *str;
884 char *new;
885
886 str = callchain_list__sym_name(chain, bf, sizeof(bf),
887 browser->show_dso);
888 if (old_str) {
889 if (asprintf(&new, "%s%s%s", old_str,
890 symbol_conf.field_sep ?: ";", str) < 0)
891 new = NULL;
892 } else {
893 if (value_str) {
894 if (asprintf(&new, "%s %s", value_str, str) < 0)
895 new = NULL;
896 } else {
897 if (asprintf(&new, "%s", str) < 0)
898 new = NULL;
899 }
900 }
901 return new;
902}
903
904static int hist_browser__show_callchain_folded(struct hist_browser *browser,
905 struct rb_root *root,
906 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900907 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900908 print_callchain_entry_fn print,
909 struct callchain_print_arg *arg,
910 check_output_full_fn is_output_full)
911{
912 struct rb_node *node;
913 int first_row = row, offset = LEVEL_OFFSET_STEP;
914 bool need_percent;
915
916 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900917 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900918
919 while (node) {
920 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
921 struct rb_node *next = rb_next(node);
922 struct callchain_list *chain, *first_chain = NULL;
923 int first = true;
924 char *value_str = NULL, *value_str_alloc = NULL;
925 char *chain_str = NULL, *chain_str_alloc = NULL;
926
927 if (arg->row_offset != 0) {
928 arg->row_offset--;
929 goto next;
930 }
931
932 if (need_percent) {
933 char buf[64];
934
935 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
936 if (asprintf(&value_str, "%s", buf) < 0) {
937 value_str = (char *)"<...>";
938 goto do_print;
939 }
940 value_str_alloc = value_str;
941 }
942
943 list_for_each_entry(chain, &child->parent_val, list) {
944 chain_str = hist_browser__folded_callchain_str(browser,
945 chain, value_str, chain_str);
946 if (first) {
947 first = false;
948 first_chain = chain;
949 }
950
951 if (chain_str == NULL) {
952 chain_str = (char *)"Not enough memory!";
953 goto do_print;
954 }
955
956 chain_str_alloc = chain_str;
957 }
958
959 list_for_each_entry(chain, &child->val, list) {
960 chain_str = hist_browser__folded_callchain_str(browser,
961 chain, value_str, chain_str);
962 if (first) {
963 first = false;
964 first_chain = chain;
965 }
966
967 if (chain_str == NULL) {
968 chain_str = (char *)"Not enough memory!";
969 goto do_print;
970 }
971
972 chain_str_alloc = chain_str;
973 }
974
975do_print:
976 print(browser, first_chain, chain_str, offset, row++, arg);
977 free(value_str_alloc);
978 free(chain_str_alloc);
979
980next:
981 if (is_output_full(browser, row))
982 break;
983 node = next;
984 }
985
986 return row - first_row;
987}
988
Namhyung Kim0c841c62016-01-28 00:40:54 +0900989static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900990 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900991 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900992 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900993 print_callchain_entry_fn print,
994 struct callchain_print_arg *arg,
995 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300996{
997 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900998 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +0900999 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001000 u64 percent_total = total;
1001
1002 if (callchain_param.mode == CHAIN_GRAPH_REL)
1003 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001004
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001005 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001006 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001007
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001008 while (node) {
1009 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1010 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001011 struct callchain_list *chain;
1012 char folded_sign = ' ';
1013 int first = true;
1014 int extra_offset = 0;
1015
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001016 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001017 bool was_first = first;
1018
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001019 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001020 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001021 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001022 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001023
1024 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001025
Namhyung Kim18bb8382015-11-09 14:45:42 +09001026 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001027 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001028 was_first && need_percent,
1029 offset + extra_offset,
1030 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001031
Namhyung Kim18bb8382015-11-09 14:45:42 +09001032 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001033 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001034
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001035 if (folded_sign == '+')
1036 break;
1037 }
1038
1039 if (folded_sign == '-') {
1040 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001041
Namhyung Kim0c841c62016-01-28 00:40:54 +09001042 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001043 new_level, row, total,
1044 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001045 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001046 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001047 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001048 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001049 node = next;
1050 }
1051out:
1052 return row - first_row;
1053}
1054
Namhyung Kim0c841c62016-01-28 00:40:54 +09001055static int hist_browser__show_callchain(struct hist_browser *browser,
1056 struct hist_entry *entry, int level,
1057 unsigned short row,
1058 print_callchain_entry_fn print,
1059 struct callchain_print_arg *arg,
1060 check_output_full_fn is_output_full)
1061{
1062 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001063 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001064 int printed;
1065
Namhyung Kim5eca1042016-01-28 00:40:55 +09001066 if (symbol_conf.cumulate_callchain)
1067 parent_total = entry->stat_acc->period;
1068 else
1069 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001070
1071 if (callchain_param.mode == CHAIN_FLAT) {
1072 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001073 &entry->sorted_chain, row,
1074 total, parent_total, print, arg,
1075 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001076 } else if (callchain_param.mode == CHAIN_FOLDED) {
1077 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001078 &entry->sorted_chain, row,
1079 total, parent_total, print, arg,
1080 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001081 } else {
1082 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001083 &entry->sorted_chain, level, row,
1084 total, parent_total, print, arg,
1085 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001086 }
1087
1088 if (arg->is_current_entry)
1089 browser->he_selection = entry;
1090
1091 return printed;
1092}
1093
Namhyung Kim89701462013-01-22 18:09:38 +09001094struct hpp_arg {
1095 struct ui_browser *b;
1096 char folded_sign;
1097 bool current_entry;
1098};
1099
Jiri Olsa98ba1602016-09-22 17:36:35 +02001100int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001101{
1102 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001103 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001104 va_list args;
1105 double percent;
1106
1107 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001108 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001109 percent = va_arg(args, double);
1110 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001111
Namhyung Kim89701462013-01-22 18:09:38 +09001112 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001113
Namhyung Kimd6751072014-07-31 14:47:36 +09001114 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001115 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001116
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001117 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001118}
1119
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001120#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001121static u64 __hpp_get_##_field(struct hist_entry *he) \
1122{ \
1123 return he->stat._field; \
1124} \
1125 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001126static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001127hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001128 struct perf_hpp *hpp, \
1129 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001130{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001131 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1132 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001133}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001134
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001135#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1136static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1137{ \
1138 return he->stat_acc->_field; \
1139} \
1140 \
1141static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001142hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001143 struct perf_hpp *hpp, \
1144 struct hist_entry *he) \
1145{ \
1146 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001147 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001148 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001149 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001150 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001151 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001152 \
1153 return ret; \
1154 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001155 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1156 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001157}
1158
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001159__HPP_COLOR_PERCENT_FN(overhead, period)
1160__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1161__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1162__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1163__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001164__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001165
1166#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001167#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001168
1169void hist_browser__init_hpp(void)
1170{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001171 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1172 hist_browser__hpp_color_overhead;
1173 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1174 hist_browser__hpp_color_overhead_sys;
1175 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1176 hist_browser__hpp_color_overhead_us;
1177 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1178 hist_browser__hpp_color_overhead_guest_sys;
1179 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1180 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001181 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1182 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001183}
1184
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001185static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001186 struct hist_entry *entry,
1187 unsigned short row)
1188{
Jiri Olsa12400052012-10-13 00:06:16 +02001189 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001190 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001191 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001192 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001193 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001194 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001195 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196
1197 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001198 browser->he_selection = entry;
1199 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200 }
1201
1202 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001203 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204 folded_sign = hist_entry__folded(entry);
1205 }
1206
1207 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001208 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001209 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001210 .folded_sign = folded_sign,
1211 .current_entry = current_entry,
1212 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001213 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001214
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001215 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001216
Jiri Olsaf0786af2016-01-18 10:24:23 +01001217 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001218 char s[2048];
1219 struct perf_hpp hpp = {
1220 .buf = s,
1221 .size = sizeof(s),
1222 .ptr = &arg,
1223 };
1224
Namhyung Kim361459f2015-12-23 02:07:08 +09001225 if (perf_hpp__should_skip(fmt, entry->hists) ||
1226 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001227 continue;
1228
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001229 if (current_entry && browser->b.navkeypressed) {
1230 ui_browser__set_color(&browser->b,
1231 HE_COLORSET_SELECTED);
1232 } else {
1233 ui_browser__set_color(&browser->b,
1234 HE_COLORSET_NORMAL);
1235 }
1236
1237 if (first) {
1238 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001239 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001240 width -= 2;
1241 }
1242 first = false;
1243 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001244 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001245 width -= 2;
1246 }
1247
Jiri Olsa12400052012-10-13 00:06:16 +02001248 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001249 int ret = fmt->color(fmt, &hpp, entry);
1250 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1251 /*
1252 * fmt->color() already used ui_browser to
1253 * print the non alignment bits, skip it (+ret):
1254 */
1255 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001256 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001257 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001258 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001259 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001260 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001261 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001262
1263 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001264 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001265 width += 1;
1266
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001267 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001268
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001269 ++row;
1270 ++printed;
1271 } else
1272 --row_offset;
1273
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001274 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001275 struct callchain_print_arg arg = {
1276 .row_offset = row_offset,
1277 .is_current_entry = current_entry,
1278 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001279
Namhyung Kim0c841c62016-01-28 00:40:54 +09001280 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001281 hist_browser__show_callchain_entry, &arg,
1282 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001283 }
1284
1285 return printed;
1286}
1287
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001288static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1289 struct hist_entry *entry,
1290 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001291 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001292{
1293 int printed = 0;
1294 int width = browser->b.width;
1295 char folded_sign = ' ';
1296 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1297 off_t row_offset = entry->row_offset;
1298 bool first = true;
1299 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001300 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001301 struct hpp_arg arg = {
1302 .b = &browser->b,
1303 .current_entry = current_entry,
1304 };
1305 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001306 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001307
1308 if (current_entry) {
1309 browser->he_selection = entry;
1310 browser->selection = &entry->ms;
1311 }
1312
1313 hist_entry__init_have_children(entry);
1314 folded_sign = hist_entry__folded(entry);
1315 arg.folded_sign = folded_sign;
1316
1317 if (entry->leaf && row_offset) {
1318 row_offset--;
1319 goto show_callchain;
1320 }
1321
1322 hist_browser__gotorc(browser, row, 0);
1323
1324 if (current_entry && browser->b.navkeypressed)
1325 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1326 else
1327 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1328
1329 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1330 width -= level * HIERARCHY_INDENT;
1331
Namhyung Kima61a22f2016-03-07 16:44:50 -03001332 /* the first hpp_list_node is for overhead columns */
1333 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1334 struct perf_hpp_list_node, list);
1335 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001336 char s[2048];
1337 struct perf_hpp hpp = {
1338 .buf = s,
1339 .size = sizeof(s),
1340 .ptr = &arg,
1341 };
1342
1343 if (perf_hpp__should_skip(fmt, entry->hists) ||
1344 column++ < browser->b.horiz_scroll)
1345 continue;
1346
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001347 if (current_entry && browser->b.navkeypressed) {
1348 ui_browser__set_color(&browser->b,
1349 HE_COLORSET_SELECTED);
1350 } else {
1351 ui_browser__set_color(&browser->b,
1352 HE_COLORSET_NORMAL);
1353 }
1354
1355 if (first) {
1356 ui_browser__printf(&browser->b, "%c", folded_sign);
1357 width--;
1358 first = false;
1359 } else {
1360 ui_browser__printf(&browser->b, " ");
1361 width -= 2;
1362 }
1363
1364 if (fmt->color) {
1365 int ret = fmt->color(fmt, &hpp, entry);
1366 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1367 /*
1368 * fmt->color() already used ui_browser to
1369 * print the non alignment bits, skip it (+ret):
1370 */
1371 ui_browser__printf(&browser->b, "%s", s + ret);
1372 } else {
1373 int ret = fmt->entry(fmt, &hpp, entry);
1374 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1375 ui_browser__printf(&browser->b, "%s", s);
1376 }
1377 width -= hpp.buf - s;
1378 }
1379
1380 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1381 width -= hierarchy_indent;
1382
1383 if (column >= browser->b.horiz_scroll) {
1384 char s[2048];
1385 struct perf_hpp hpp = {
1386 .buf = s,
1387 .size = sizeof(s),
1388 .ptr = &arg,
1389 };
1390
1391 if (current_entry && browser->b.navkeypressed) {
1392 ui_browser__set_color(&browser->b,
1393 HE_COLORSET_SELECTED);
1394 } else {
1395 ui_browser__set_color(&browser->b,
1396 HE_COLORSET_NORMAL);
1397 }
1398
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001399 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1400 ui_browser__write_nstring(&browser->b, "", 2);
1401 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001402
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001403 /*
1404 * No need to call hist_entry__snprintf_alignment()
1405 * since this fmt is always the last column in the
1406 * hierarchy mode.
1407 */
1408 if (fmt->color) {
1409 width -= fmt->color(fmt, &hpp, entry);
1410 } else {
1411 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001412
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001413 width -= fmt->entry(fmt, &hpp, entry);
1414 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001415
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001416 while (isspace(s[i++]))
1417 width++;
1418 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001419 }
1420 }
1421
1422 /* The scroll bar isn't being used */
1423 if (!browser->b.navkeypressed)
1424 width += 1;
1425
1426 ui_browser__write_nstring(&browser->b, "", width);
1427
1428 ++row;
1429 ++printed;
1430
1431show_callchain:
1432 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1433 struct callchain_print_arg carg = {
1434 .row_offset = row_offset,
1435 };
1436
1437 printed += hist_browser__show_callchain(browser, entry,
1438 level + 1, row,
1439 hist_browser__show_callchain_entry, &carg,
1440 hist_browser__check_output_full);
1441 }
1442
1443 return printed;
1444}
1445
Namhyung Kim79dded82016-02-26 21:13:19 +09001446static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001447 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001448{
1449 int width = browser->b.width;
1450 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1451 bool first = true;
1452 int column = 0;
1453 int ret;
1454 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001455 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001456 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001457
1458 if (current_entry) {
1459 browser->he_selection = NULL;
1460 browser->selection = NULL;
1461 }
1462
1463 hist_browser__gotorc(browser, row, 0);
1464
1465 if (current_entry && browser->b.navkeypressed)
1466 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1467 else
1468 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1469
1470 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1471 width -= level * HIERARCHY_INDENT;
1472
Namhyung Kima61a22f2016-03-07 16:44:50 -03001473 /* the first hpp_list_node is for overhead columns */
1474 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1475 struct perf_hpp_list_node, list);
1476 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001477 if (perf_hpp__should_skip(fmt, browser->hists) ||
1478 column++ < browser->b.horiz_scroll)
1479 continue;
1480
Jiri Olsada1b0402016-06-14 20:19:20 +02001481 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001482
1483 if (first) {
1484 /* for folded sign */
1485 first = false;
1486 ret++;
1487 } else {
1488 /* space between columns */
1489 ret += 2;
1490 }
1491
1492 ui_browser__write_nstring(&browser->b, "", ret);
1493 width -= ret;
1494 }
1495
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001496 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1497 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001498
1499 if (column >= browser->b.horiz_scroll) {
1500 char buf[32];
1501
1502 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1503 ui_browser__printf(&browser->b, " %s", buf);
1504 width -= ret + 2;
1505 }
1506
1507 /* The scroll bar isn't being used */
1508 if (!browser->b.navkeypressed)
1509 width += 1;
1510
1511 ui_browser__write_nstring(&browser->b, "", width);
1512 return 1;
1513}
1514
Jiri Olsa81a888f2014-06-14 15:44:52 +02001515static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1516{
1517 advance_hpp(hpp, inc);
1518 return hpp->size <= 0;
1519}
1520
Jiri Olsa69705b32016-08-07 17:28:28 +02001521static int
1522hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1523 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001524{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001525 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001526 struct perf_hpp dummy_hpp = {
1527 .buf = buf,
1528 .size = size,
1529 };
1530 struct perf_hpp_fmt *fmt;
1531 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001532 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001533 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001534
1535 if (symbol_conf.use_callchain) {
1536 ret = scnprintf(buf, size, " ");
1537 if (advance_hpp_check(&dummy_hpp, ret))
1538 return ret;
1539 }
1540
Jiri Olsaf0786af2016-01-18 10:24:23 +01001541 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001542 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001543 continue;
1544
Jiri Olsa29659ab2016-08-07 17:28:30 +02001545 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001546 if (advance_hpp_check(&dummy_hpp, ret))
1547 break;
1548
Jiri Olsa29659ab2016-08-07 17:28:30 +02001549 if (span)
1550 continue;
1551
Jiri Olsa81a888f2014-06-14 15:44:52 +02001552 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1553 if (advance_hpp_check(&dummy_hpp, ret))
1554 break;
1555 }
1556
1557 return ret;
1558}
1559
Namhyung Kimd8b92402016-02-25 00:13:46 +09001560static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1561{
1562 struct hists *hists = browser->hists;
1563 struct perf_hpp dummy_hpp = {
1564 .buf = buf,
1565 .size = size,
1566 };
1567 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001568 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001569 size_t ret = 0;
1570 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001571 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001572 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001573
1574 ret = scnprintf(buf, size, " ");
1575 if (advance_hpp_check(&dummy_hpp, ret))
1576 return ret;
1577
Namhyung Kima61a22f2016-03-07 16:44:50 -03001578 /* the first hpp_list_node is for overhead columns */
1579 fmt_node = list_first_entry(&hists->hpp_formats,
1580 struct perf_hpp_list_node, list);
1581 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001582 if (column++ < browser->b.horiz_scroll)
1583 continue;
1584
Jiri Olsa29659ab2016-08-07 17:28:30 +02001585 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001586 if (advance_hpp_check(&dummy_hpp, ret))
1587 break;
1588
1589 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1590 if (advance_hpp_check(&dummy_hpp, ret))
1591 break;
1592 }
1593
1594 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001595 indent * HIERARCHY_INDENT, "");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001596 if (advance_hpp_check(&dummy_hpp, ret))
1597 return ret;
1598
Namhyung Kima61a22f2016-03-07 16:44:50 -03001599 first_node = true;
1600 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1601 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001602 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1603 if (advance_hpp_check(&dummy_hpp, ret))
1604 break;
1605 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001606 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001607
Namhyung Kima61a22f2016-03-07 16:44:50 -03001608 first_col = true;
1609 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1610 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001611
Namhyung Kima61a22f2016-03-07 16:44:50 -03001612 if (perf_hpp__should_skip(fmt, hists))
1613 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001614
Namhyung Kima61a22f2016-03-07 16:44:50 -03001615 if (!first_col) {
1616 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1617 if (advance_hpp_check(&dummy_hpp, ret))
1618 break;
1619 }
1620 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001621
Jiri Olsa29659ab2016-08-07 17:28:30 +02001622 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001623 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001624
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001625 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001626 ret = strlen(start);
1627
1628 if (start != dummy_hpp.buf)
1629 memmove(dummy_hpp.buf, start, ret + 1);
1630
1631 if (advance_hpp_check(&dummy_hpp, ret))
1632 break;
1633 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001634 }
1635
1636 return ret;
1637}
1638
Jiri Olsa01b47702016-06-14 20:19:13 +02001639static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001640{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001641 char headers[1024];
1642
Jiri Olsa01b47702016-06-14 20:19:13 +02001643 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1644 sizeof(headers));
1645
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001646 ui_browser__gotorc(&browser->b, 0, 0);
1647 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001648 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001649}
1650
Jiri Olsa01b47702016-06-14 20:19:13 +02001651static void hists_browser__headers(struct hist_browser *browser)
1652{
Jiri Olsa69705b32016-08-07 17:28:28 +02001653 struct hists *hists = browser->hists;
1654 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001655
Jiri Olsa69705b32016-08-07 17:28:28 +02001656 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001657
Jiri Olsa69705b32016-08-07 17:28:28 +02001658 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1659 char headers[1024];
1660
1661 hists_browser__scnprintf_headers(browser, headers,
1662 sizeof(headers), line);
1663
1664 ui_browser__gotorc(&browser->b, line, 0);
1665 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1666 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1667 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001668}
1669
1670static void hist_browser__show_headers(struct hist_browser *browser)
1671{
1672 if (symbol_conf.report_hierarchy)
1673 hists_browser__hierarchy_headers(browser);
1674 else
1675 hists_browser__headers(browser);
1676}
1677
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001678static void ui_browser__hists_init_top(struct ui_browser *browser)
1679{
1680 if (browser->top == NULL) {
1681 struct hist_browser *hb;
1682
1683 hb = container_of(browser, struct hist_browser, b);
1684 browser->top = rb_first(&hb->hists->entries);
1685 }
1686}
1687
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001688static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001689{
1690 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001691 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001692 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001693 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001694 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001695
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001696 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001697 struct perf_hpp_list *hpp_list = hists->hpp_list;
1698
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001699 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001700 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001701 }
1702
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001703 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001704 hb->he_selection = NULL;
1705 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001706
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001707 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001708 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001709 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001710
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001711 if (h->filtered) {
1712 /* let it move to sibling */
1713 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001714 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001715 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001716
Namhyung Kim14135662013-10-31 10:17:39 +09001717 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001718 if (percent < hb->min_pcnt)
1719 continue;
1720
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001721 if (symbol_conf.report_hierarchy) {
1722 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001723 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001724 if (row == browser->rows)
1725 break;
1726
1727 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001728 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001729 row++;
1730 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001731 } else {
1732 row += hist_browser__show_entry(hb, h, row);
1733 }
1734
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001735 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001736 break;
1737 }
1738
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001739 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001740}
1741
Namhyung Kim064f1982013-05-14 11:09:04 +09001742static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001743 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001744{
1745 while (nd != NULL) {
1746 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001747 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001748
Namhyung Kimc0f15272014-04-16 11:16:33 +09001749 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001750 return nd;
1751
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001752 /*
1753 * If it's filtered, its all children also were filtered.
1754 * So move to sibling node.
1755 */
1756 if (rb_next(nd))
1757 nd = rb_next(nd);
1758 else
1759 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001760 }
1761
1762 return NULL;
1763}
1764
Namhyung Kim064f1982013-05-14 11:09:04 +09001765static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001766 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001767{
1768 while (nd != NULL) {
1769 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001770 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001771
1772 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001773 return nd;
1774
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001775 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001776 }
1777
1778 return NULL;
1779}
1780
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001781static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001782 off_t offset, int whence)
1783{
1784 struct hist_entry *h;
1785 struct rb_node *nd;
1786 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001787 struct hist_browser *hb;
1788
1789 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001790
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001791 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001792 return;
1793
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001794 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001795
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001796 switch (whence) {
1797 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001798 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001799 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001800 break;
1801 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001802 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001803 goto do_offset;
1804 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001805 nd = rb_hierarchy_last(rb_last(browser->entries));
1806 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001807 first = false;
1808 break;
1809 default:
1810 return;
1811 }
1812
1813 /*
1814 * Moves not relative to the first visible entry invalidates its
1815 * row_offset:
1816 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001817 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001818 h->row_offset = 0;
1819
1820 /*
1821 * Here we have to check if nd is expanded (+), if it is we can't go
1822 * the next top level hist_entry, instead we must compute an offset of
1823 * what _not_ to show and not change the first visible entry.
1824 *
1825 * This offset increments when we are going from top to bottom and
1826 * decreases when we're going from bottom to top.
1827 *
1828 * As we don't have backpointers to the top level in the callchains
1829 * structure, we need to always print the whole hist_entry callchain,
1830 * skipping the first ones that are before the first visible entry
1831 * and stop when we printed enough lines to fill the screen.
1832 */
1833do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001834 if (!nd)
1835 return;
1836
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001837 if (offset > 0) {
1838 do {
1839 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001840 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001841 u16 remaining = h->nr_rows - h->row_offset;
1842 if (offset > remaining) {
1843 offset -= remaining;
1844 h->row_offset = 0;
1845 } else {
1846 h->row_offset += offset;
1847 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001848 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001849 break;
1850 }
1851 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001852 nd = hists__filter_entries(rb_hierarchy_next(nd),
1853 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001854 if (nd == NULL)
1855 break;
1856 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001857 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001858 } while (offset != 0);
1859 } else if (offset < 0) {
1860 while (1) {
1861 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001862 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001863 if (first) {
1864 if (-offset > h->row_offset) {
1865 offset += h->row_offset;
1866 h->row_offset = 0;
1867 } else {
1868 h->row_offset += offset;
1869 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001870 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001871 break;
1872 }
1873 } else {
1874 if (-offset > h->nr_rows) {
1875 offset += h->nr_rows;
1876 h->row_offset = 0;
1877 } else {
1878 h->row_offset = h->nr_rows + offset;
1879 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001880 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001881 break;
1882 }
1883 }
1884 }
1885
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001886 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001887 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001888 if (nd == NULL)
1889 break;
1890 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001891 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001892 if (offset == 0) {
1893 /*
1894 * Last unfiltered hist_entry, check if it is
1895 * unfolded, if it is then we should have
1896 * row_offset at its last entry.
1897 */
1898 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001899 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001900 h->row_offset = h->nr_rows;
1901 break;
1902 }
1903 first = false;
1904 }
1905 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001906 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001907 h = rb_entry(nd, struct hist_entry, rb_node);
1908 h->row_offset = 0;
1909 }
1910}
1911
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001912static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001913 struct hist_entry *he, FILE *fp,
1914 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001915{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001916 struct callchain_print_arg arg = {
1917 .fp = fp,
1918 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001919
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001920 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001921 hist_browser__fprintf_callchain_entry, &arg,
1922 hist_browser__check_dump_full);
1923 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001924}
1925
1926static int hist_browser__fprintf_entry(struct hist_browser *browser,
1927 struct hist_entry *he, FILE *fp)
1928{
1929 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001930 int printed = 0;
1931 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001932 struct perf_hpp hpp = {
1933 .buf = s,
1934 .size = sizeof(s),
1935 };
1936 struct perf_hpp_fmt *fmt;
1937 bool first = true;
1938 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001939
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001940 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001941 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001942 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001943 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001944
Jiri Olsaf0786af2016-01-18 10:24:23 +01001945 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001946 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001947 continue;
1948
Namhyung Kim26d8b332014-03-03 16:16:20 +09001949 if (!first) {
1950 ret = scnprintf(hpp.buf, hpp.size, " ");
1951 advance_hpp(&hpp, ret);
1952 } else
1953 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001954
Namhyung Kim26d8b332014-03-03 16:16:20 +09001955 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001956 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001957 advance_hpp(&hpp, ret);
1958 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001959 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001960
1961 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001962 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1963
1964 return printed;
1965}
1966
1967
1968static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1969 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09001970 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001971{
1972 char s[8192];
1973 int printed = 0;
1974 char folded_sign = ' ';
1975 struct perf_hpp hpp = {
1976 .buf = s,
1977 .size = sizeof(s),
1978 };
1979 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09001980 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001981 bool first = true;
1982 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09001983 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001984
1985 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1986
1987 folded_sign = hist_entry__folded(he);
1988 printed += fprintf(fp, "%c", folded_sign);
1989
Namhyung Kim325a6282016-03-09 22:47:00 +09001990 /* the first hpp_list_node is for overhead columns */
1991 fmt_node = list_first_entry(&he->hists->hpp_formats,
1992 struct perf_hpp_list_node, list);
1993 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001994 if (!first) {
1995 ret = scnprintf(hpp.buf, hpp.size, " ");
1996 advance_hpp(&hpp, ret);
1997 } else
1998 first = false;
1999
2000 ret = fmt->entry(fmt, &hpp, he);
2001 advance_hpp(&hpp, ret);
2002 }
2003
2004 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2005 advance_hpp(&hpp, ret);
2006
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002007 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2008 ret = scnprintf(hpp.buf, hpp.size, " ");
2009 advance_hpp(&hpp, ret);
2010
2011 ret = fmt->entry(fmt, &hpp, he);
2012 advance_hpp(&hpp, ret);
2013 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002014
2015 printed += fprintf(fp, "%s\n", rtrim(s));
2016
2017 if (he->leaf && folded_sign == '-') {
2018 printed += hist_browser__fprintf_callchain(browser, he, fp,
2019 he->depth + 1);
2020 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002021
2022 return printed;
2023}
2024
2025static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2026{
Namhyung Kim064f1982013-05-14 11:09:04 +09002027 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002028 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002029 int printed = 0;
2030
2031 while (nd) {
2032 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2033
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002034 if (symbol_conf.report_hierarchy) {
2035 printed += hist_browser__fprintf_hierarchy_entry(browser,
2036 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002037 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002038 } else {
2039 printed += hist_browser__fprintf_entry(browser, h, fp);
2040 }
2041
2042 nd = hists__filter_entries(rb_hierarchy_next(nd),
2043 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002044 }
2045
2046 return printed;
2047}
2048
2049static int hist_browser__dump(struct hist_browser *browser)
2050{
2051 char filename[64];
2052 FILE *fp;
2053
2054 while (1) {
2055 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2056 if (access(filename, F_OK))
2057 break;
2058 /*
2059 * XXX: Just an arbitrary lazy upper limit
2060 */
2061 if (++browser->print_seq == 8192) {
2062 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2063 return -1;
2064 }
2065 }
2066
2067 fp = fopen(filename, "w");
2068 if (fp == NULL) {
2069 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002070 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002071 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002072 return -1;
2073 }
2074
2075 ++browser->print_seq;
2076 hist_browser__fprintf(browser, fp);
2077 fclose(fp);
2078 ui_helpline__fpush("%s written!", filename);
2079
2080 return 0;
2081}
2082
Jiri Olsafcd86422016-06-20 23:58:18 +02002083void hist_browser__init(struct hist_browser *browser,
2084 struct hists *hists)
2085{
2086 struct perf_hpp_fmt *fmt;
2087
2088 browser->hists = hists;
2089 browser->b.refresh = hist_browser__refresh;
2090 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2091 browser->b.seek = ui_browser__hists_seek;
2092 browser->b.use_navkeypressed = true;
2093 browser->show_headers = symbol_conf.show_hist_headers;
2094
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002095 if (symbol_conf.report_hierarchy) {
2096 struct perf_hpp_list_node *fmt_node;
2097
2098 /* count overhead columns (in the first node) */
2099 fmt_node = list_first_entry(&hists->hpp_formats,
2100 struct perf_hpp_list_node, list);
2101 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2102 ++browser->b.columns;
2103
2104 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002105 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002106 } else {
2107 hists__for_each_format(hists, fmt)
2108 ++browser->b.columns;
2109 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002110
2111 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002112}
2113
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002114struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002115{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002116 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002117
Jiri Olsafcd86422016-06-20 23:58:18 +02002118 if (browser)
2119 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002120
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002121 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002122}
2123
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002124static struct hist_browser *
2125perf_evsel_browser__new(struct perf_evsel *evsel,
2126 struct hist_browser_timer *hbt,
2127 struct perf_env *env)
2128{
2129 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2130
2131 if (browser) {
2132 browser->hbt = hbt;
2133 browser->env = env;
2134 browser->title = perf_evsel_browser_title;
2135 }
2136 return browser;
2137}
2138
Jiri Olsadabd2012016-06-20 23:58:14 +02002139void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002140{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002141 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002142}
2143
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002144static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002145{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002146 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002147}
2148
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002149static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002150{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002151 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002152}
2153
Taeung Song1e378eb2014-10-07 16:13:15 +09002154/* Check whether the browser is for 'top' or 'report' */
2155static inline bool is_report_browser(void *timer)
2156{
2157 return timer == NULL;
2158}
2159
Jiri Olsa5b91a862016-06-20 23:58:15 +02002160static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002161 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002162{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002163 struct hist_browser_timer *hbt = browser->hbt;
2164 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002165 char unit;
2166 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002167 const struct dso *dso = hists->dso_filter;
2168 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002169 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002170 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2171 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002172 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002173 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002174 char buf[512];
2175 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002176 char ref[30] = " show reference callgraph, ";
2177 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002178
Namhyung Kimf2148332014-01-14 11:52:48 +09002179 if (symbol_conf.filter_relative) {
2180 nr_samples = hists->stats.nr_non_filtered_samples;
2181 nr_events = hists->stats.total_non_filtered_period;
2182 }
2183
Namhyung Kim759ff492013-03-05 14:53:26 +09002184 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002185 struct perf_evsel *pos;
2186
2187 perf_evsel__group_desc(evsel, buf, buflen);
2188 ev_name = buf;
2189
2190 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002191 struct hists *pos_hists = evsel__hists(pos);
2192
Namhyung Kimf2148332014-01-14 11:52:48 +09002193 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002194 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2195 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002196 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002197 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2198 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002199 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002200 }
2201 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002202
Kan Liang9e207dd2015-08-11 06:30:49 -04002203 if (symbol_conf.show_ref_callgraph &&
2204 strstr(ev_name, "call-graph=no"))
2205 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002206 nr_samples = convert_unit(nr_samples, &unit);
2207 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002208 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2209 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002210
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002211
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002212 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002213 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002214 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002215 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002216 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002217 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002218 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002219 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002220 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002221 } else {
2222 printed += scnprintf(bf + printed, size - printed,
2223 ", Thread: %s",
2224 (thread->comm_set ? thread__comm_str(thread) : ""));
2225 }
2226 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002227 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002228 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002229 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002230 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002231 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002232 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002233 if (!is_report_browser(hbt)) {
2234 struct perf_top *top = hbt->arg;
2235
2236 if (top->zero)
2237 printed += scnprintf(bf + printed, size - printed, " [z]");
2238 }
2239
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002240 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002241}
2242
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002243static inline void free_popup_options(char **options, int n)
2244{
2245 int i;
2246
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002247 for (i = 0; i < n; ++i)
2248 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002249}
2250
Feng Tang341487ab2013-02-03 14:38:20 +08002251/*
2252 * Only runtime switching of perf data file will make "input_name" point
2253 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2254 * whether we need to call free() for current "input_name" during the switch.
2255 */
2256static bool is_input_name_malloced = false;
2257
2258static int switch_data_file(void)
2259{
2260 char *pwd, *options[32], *abs_path[32], *tmp;
2261 DIR *pwd_dir;
2262 int nr_options = 0, choice = -1, ret = -1;
2263 struct dirent *dent;
2264
2265 pwd = getenv("PWD");
2266 if (!pwd)
2267 return ret;
2268
2269 pwd_dir = opendir(pwd);
2270 if (!pwd_dir)
2271 return ret;
2272
2273 memset(options, 0, sizeof(options));
2274 memset(options, 0, sizeof(abs_path));
2275
2276 while ((dent = readdir(pwd_dir))) {
2277 char path[PATH_MAX];
2278 u64 magic;
2279 char *name = dent->d_name;
2280 FILE *file;
2281
2282 if (!(dent->d_type == DT_REG))
2283 continue;
2284
2285 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2286
2287 file = fopen(path, "r");
2288 if (!file)
2289 continue;
2290
2291 if (fread(&magic, 1, 8, file) < 8)
2292 goto close_file_and_continue;
2293
2294 if (is_perf_magic(magic)) {
2295 options[nr_options] = strdup(name);
2296 if (!options[nr_options])
2297 goto close_file_and_continue;
2298
2299 abs_path[nr_options] = strdup(path);
2300 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002301 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002302 ui__warning("Can't search all data files due to memory shortage.\n");
2303 fclose(file);
2304 break;
2305 }
2306
2307 nr_options++;
2308 }
2309
2310close_file_and_continue:
2311 fclose(file);
2312 if (nr_options >= 32) {
2313 ui__warning("Too many perf data files in PWD!\n"
2314 "Only the first 32 files will be listed.\n");
2315 break;
2316 }
2317 }
2318 closedir(pwd_dir);
2319
2320 if (nr_options) {
2321 choice = ui__popup_menu(nr_options, options);
2322 if (choice < nr_options && choice >= 0) {
2323 tmp = strdup(abs_path[choice]);
2324 if (tmp) {
2325 if (is_input_name_malloced)
2326 free((void *)input_name);
2327 input_name = tmp;
2328 is_input_name_malloced = true;
2329 ret = 0;
2330 } else
2331 ui__warning("Data switch failed due to memory shortage!\n");
2332 }
2333 }
2334
2335 free_popup_options(options, nr_options);
2336 free_popup_options(abs_path, nr_options);
2337 return ret;
2338}
2339
Namhyung Kimea7cd592015-04-22 16:18:19 +09002340struct popup_action {
2341 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002342 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002343 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002344
2345 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2346};
2347
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002348static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002349do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002350{
2351 struct perf_evsel *evsel;
2352 struct annotation *notes;
2353 struct hist_entry *he;
2354 int err;
2355
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002356 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002357 return 0;
2358
Namhyung Kimea7cd592015-04-22 16:18:19 +09002359 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002360 if (!notes->src)
2361 return 0;
2362
2363 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002364 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002365 he = hist_browser__selected_entry(browser);
2366 /*
2367 * offer option to annotate the other branch source or target
2368 * (if they exists) when returning from annotate
2369 */
2370 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2371 return 1;
2372
2373 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2374 if (err)
2375 ui_browser__handle_resize(&browser->b);
2376 return 0;
2377}
2378
2379static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002380add_annotate_opt(struct hist_browser *browser __maybe_unused,
2381 struct popup_action *act, char **optstr,
2382 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002383{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002384 if (sym == NULL || map->dso->annotate_warned)
2385 return 0;
2386
2387 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2388 return 0;
2389
2390 act->ms.map = map;
2391 act->ms.sym = sym;
2392 act->fn = do_annotate;
2393 return 1;
2394}
2395
2396static int
2397do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2398{
2399 struct thread *thread = act->thread;
2400
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002401 if ((!hists__has(browser->hists, thread) &&
2402 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002403 return 0;
2404
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002405 if (browser->hists->thread_filter) {
2406 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2407 perf_hpp__set_elide(HISTC_THREAD, false);
2408 thread__zput(browser->hists->thread_filter);
2409 ui_helpline__pop();
2410 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002411 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002412 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2413 thread->comm_set ? thread__comm_str(thread) : "",
2414 thread->tid);
2415 } else {
2416 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2417 thread->comm_set ? thread__comm_str(thread) : "");
2418 }
2419
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002420 browser->hists->thread_filter = thread__get(thread);
2421 perf_hpp__set_elide(HISTC_THREAD, false);
2422 pstack__push(browser->pstack, &browser->hists->thread_filter);
2423 }
2424
2425 hists__filter_by_thread(browser->hists);
2426 hist_browser__reset(browser);
2427 return 0;
2428}
2429
2430static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002431add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2432 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002433{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002434 int ret;
2435
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002436 if ((!hists__has(browser->hists, thread) &&
2437 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002438 return 0;
2439
Jiri Olsafa829112016-05-03 13:54:47 +02002440 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002441 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2442 browser->hists->thread_filter ? "out of" : "into",
2443 thread->comm_set ? thread__comm_str(thread) : "",
2444 thread->tid);
2445 } else {
2446 ret = asprintf(optstr, "Zoom %s %s thread",
2447 browser->hists->thread_filter ? "out of" : "into",
2448 thread->comm_set ? thread__comm_str(thread) : "");
2449 }
2450 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002451 return 0;
2452
2453 act->thread = thread;
2454 act->fn = do_zoom_thread;
2455 return 1;
2456}
2457
2458static int
2459do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2460{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002461 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002462
Jiri Olsa69849fc2016-05-03 13:54:45 +02002463 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002464 return 0;
2465
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002466 if (browser->hists->dso_filter) {
2467 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2468 perf_hpp__set_elide(HISTC_DSO, false);
2469 browser->hists->dso_filter = NULL;
2470 ui_helpline__pop();
2471 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002472 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002473 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2474 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002475 perf_hpp__set_elide(HISTC_DSO, true);
2476 pstack__push(browser->pstack, &browser->hists->dso_filter);
2477 }
2478
2479 hists__filter_by_dso(browser->hists);
2480 hist_browser__reset(browser);
2481 return 0;
2482}
2483
2484static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002485add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002486 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002487{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002488 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002489 return 0;
2490
2491 if (asprintf(optstr, "Zoom %s %s DSO",
2492 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002493 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002494 return 0;
2495
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002496 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002497 act->fn = do_zoom_dso;
2498 return 1;
2499}
2500
2501static int
2502do_browse_map(struct hist_browser *browser __maybe_unused,
2503 struct popup_action *act)
2504{
2505 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002506 return 0;
2507}
2508
2509static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002510add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002511 struct popup_action *act, char **optstr, struct map *map)
2512{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002513 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002514 return 0;
2515
2516 if (asprintf(optstr, "Browse map details") < 0)
2517 return 0;
2518
2519 act->ms.map = map;
2520 act->fn = do_browse_map;
2521 return 1;
2522}
2523
2524static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002525do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002526 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002527{
2528 char script_opt[64];
2529 memset(script_opt, 0, sizeof(script_opt));
2530
Namhyung Kimea7cd592015-04-22 16:18:19 +09002531 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002532 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002533 thread__comm_str(act->thread));
2534 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002535 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002536 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002537 }
2538
2539 script_browse(script_opt);
2540 return 0;
2541}
2542
2543static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002544add_script_opt(struct hist_browser *browser __maybe_unused,
2545 struct popup_action *act, char **optstr,
2546 struct thread *thread, struct symbol *sym)
2547{
2548 if (thread) {
2549 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2550 thread__comm_str(thread)) < 0)
2551 return 0;
2552 } else if (sym) {
2553 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2554 sym->name) < 0)
2555 return 0;
2556 } else {
2557 if (asprintf(optstr, "Run scripts for all samples") < 0)
2558 return 0;
2559 }
2560
2561 act->thread = thread;
2562 act->ms.sym = sym;
2563 act->fn = do_run_script;
2564 return 1;
2565}
2566
2567static int
2568do_switch_data(struct hist_browser *browser __maybe_unused,
2569 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002570{
2571 if (switch_data_file()) {
2572 ui__warning("Won't switch the data files due to\n"
2573 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002574 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002575 }
2576
2577 return K_SWITCH_INPUT_DATA;
2578}
2579
Namhyung Kimea7cd592015-04-22 16:18:19 +09002580static int
2581add_switch_opt(struct hist_browser *browser,
2582 struct popup_action *act, char **optstr)
2583{
2584 if (!is_report_browser(browser->hbt))
2585 return 0;
2586
2587 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2588 return 0;
2589
2590 act->fn = do_switch_data;
2591 return 1;
2592}
2593
2594static int
2595do_exit_browser(struct hist_browser *browser __maybe_unused,
2596 struct popup_action *act __maybe_unused)
2597{
2598 return 0;
2599}
2600
2601static int
2602add_exit_opt(struct hist_browser *browser __maybe_unused,
2603 struct popup_action *act, char **optstr)
2604{
2605 if (asprintf(optstr, "Exit") < 0)
2606 return 0;
2607
2608 act->fn = do_exit_browser;
2609 return 1;
2610}
2611
Kan Liang84734b02015-09-04 10:45:45 -04002612static int
2613do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2614{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002615 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002616 return 0;
2617
Kan Liang84734b02015-09-04 10:45:45 -04002618 if (browser->hists->socket_filter > -1) {
2619 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2620 browser->hists->socket_filter = -1;
2621 perf_hpp__set_elide(HISTC_SOCKET, false);
2622 } else {
2623 browser->hists->socket_filter = act->socket;
2624 perf_hpp__set_elide(HISTC_SOCKET, true);
2625 pstack__push(browser->pstack, &browser->hists->socket_filter);
2626 }
2627
2628 hists__filter_by_socket(browser->hists);
2629 hist_browser__reset(browser);
2630 return 0;
2631}
2632
2633static int
2634add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2635 char **optstr, int socket_id)
2636{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002637 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002638 return 0;
2639
2640 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2641 (browser->hists->socket_filter > -1) ? "out of" : "into",
2642 socket_id) < 0)
2643 return 0;
2644
2645 act->socket = socket_id;
2646 act->fn = do_zoom_socket;
2647 return 1;
2648}
2649
Namhyung Kim112f7612014-04-22 14:05:35 +09002650static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002651{
2652 u64 nr_entries = 0;
2653 struct rb_node *nd = rb_first(&hb->hists->entries);
2654
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002655 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002656 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2657 return;
2658 }
2659
Namhyung Kim14135662013-10-31 10:17:39 +09002660 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002661 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002662 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002663 }
2664
Namhyung Kim112f7612014-04-22 14:05:35 +09002665 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002666 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002667}
Feng Tang341487ab2013-02-03 14:38:20 +08002668
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002669static void hist_browser__update_percent_limit(struct hist_browser *hb,
2670 double percent)
2671{
2672 struct hist_entry *he;
2673 struct rb_node *nd = rb_first(&hb->hists->entries);
2674 u64 total = hists__total_period(hb->hists);
2675 u64 min_callchain_hits = total * (percent / 100);
2676
2677 hb->min_pcnt = callchain_param.min_percent = percent;
2678
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002679 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2680 he = rb_entry(nd, struct hist_entry, rb_node);
2681
Namhyung Kim79dded82016-02-26 21:13:19 +09002682 if (he->has_no_entry) {
2683 he->has_no_entry = false;
2684 he->nr_rows = 0;
2685 }
2686
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002687 if (!he->leaf || !symbol_conf.use_callchain)
2688 goto next;
2689
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002690 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2691 total = he->stat.period;
2692
2693 if (symbol_conf.cumulate_callchain)
2694 total = he->stat_acc->period;
2695
2696 min_callchain_hits = total * (percent / 100);
2697 }
2698
2699 callchain_param.sort(&he->sorted_chain, he->callchain,
2700 min_callchain_hits, &callchain_param);
2701
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002702next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002703 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002704
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002705 /* force to re-evaluate folding state of callchains */
2706 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002707 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002708 }
2709}
2710
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002711static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002712 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002713 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002714 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002715 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002716 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002717{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002718 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002719 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002720 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002721#define MAX_OPTIONS 16
2722 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002723 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002724 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002725 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002726 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002727 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002728
Namhyung Kime8e684a2013-12-26 14:37:58 +09002729#define HIST_BROWSER_HELP_COMMON \
2730 "h/?/F1 Show this window\n" \
2731 "UP/DOWN/PGUP\n" \
2732 "PGDN/SPACE Navigate\n" \
2733 "q/ESC/CTRL+C Exit browser\n\n" \
2734 "For multiple event sessions:\n\n" \
2735 "TAB/UNTAB Switch events\n\n" \
2736 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002737 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2738 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002739 "a Annotate current symbol\n" \
2740 "C Collapse all callchains\n" \
2741 "d Zoom into current DSO\n" \
2742 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002743 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002744 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002745 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002746 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002747 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002748
2749 /* help messages are sorted by lexical order of the hotkey */
2750 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002751 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002752 "P Print histograms to perf.hist.N\n"
2753 "r Run available scripts\n"
2754 "s Switch to another data file in PWD\n"
2755 "t Zoom into current Thread\n"
2756 "V Verbose (DSO names in callchains, etc)\n"
2757 "/ Filter symbol by name";
2758 const char top_help[] = HIST_BROWSER_HELP_COMMON
2759 "P Print histograms to perf.hist.N\n"
2760 "t Zoom into current Thread\n"
2761 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002762 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002763 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002764 "/ Filter symbol by name";
2765
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002766 if (browser == NULL)
2767 return -1;
2768
Namhyung Kimed426912015-05-29 21:53:44 +09002769 /* reset abort key so that it can get Ctrl-C as a key */
2770 SLang_reset_tty();
2771 SLang_init_tty(0, 0, 0);
2772
Namhyung Kim03905042015-11-28 02:32:39 +09002773 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002774 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002775 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002776
Kan Liang84734b02015-09-04 10:45:45 -04002777 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002778 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002779 goto out;
2780
2781 ui_helpline__push(helpline);
2782
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002783 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002784 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002785
Namhyung Kim5b591662014-07-31 14:47:38 +09002786 if (symbol_conf.col_width_list_str)
2787 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2788
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002789 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002790 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002791 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002792 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002793 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002794
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002795 nr_options = 0;
2796
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002797 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002798
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002799 if (browser->he_selection != NULL) {
2800 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002801 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002802 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002803 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002804 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002805 case K_TAB:
2806 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002807 if (nr_events == 1)
2808 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002809 /*
2810 * Exit the browser, let hists__browser_tree
2811 * go to the next or previous
2812 */
2813 goto out_free_stack;
2814 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002815 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002816 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002817 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002818 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002819 continue;
2820 }
2821
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002822 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002823 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002824 browser->selection->map->dso->annotate_warned)
2825 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002826
Namhyung Kimea7cd592015-04-22 16:18:19 +09002827 actions->ms.map = browser->selection->map;
2828 actions->ms.sym = browser->selection->sym;
2829 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002830 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002831 case 'P':
2832 hist_browser__dump(browser);
2833 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002834 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002835 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002836 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002837 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002838 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02002839 verbose = (verbose + 1) % 4;
2840 browser->show_dso = verbose > 0;
2841 ui_helpline__fpush("Verbosity level set to %d\n",
2842 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002843 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002844 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002845 actions->thread = thread;
2846 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002847 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002848 case 'S':
2849 actions->socket = socked_id;
2850 do_zoom_socket(browser, actions);
2851 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002852 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002853 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002854 "Please enter the name of symbol you want to see.\n"
2855 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002856 buf, "ENTER: OK, ESC: Cancel",
2857 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002858 hists->symbol_filter_str = *buf ? buf : NULL;
2859 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002860 hist_browser__reset(browser);
2861 }
2862 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002863 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002864 if (is_report_browser(hbt)) {
2865 actions->thread = NULL;
2866 actions->ms.sym = NULL;
2867 do_run_script(browser, actions);
2868 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002869 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002870 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002871 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002872 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002873 if (key == K_SWITCH_INPUT_DATA)
2874 goto out_free_stack;
2875 }
Feng Tang341487ab2013-02-03 14:38:20 +08002876 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002877 case 'i':
2878 /* env->arch is NULL for live-mode (i.e. perf top) */
2879 if (env->arch)
2880 tui__header_window(env);
2881 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002882 case 'F':
2883 symbol_conf.filter_relative ^= 1;
2884 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002885 case 'z':
2886 if (!is_report_browser(hbt)) {
2887 struct perf_top *top = hbt->arg;
2888
2889 top->zero = !top->zero;
2890 }
2891 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002892 case 'L':
2893 if (ui_browser__input_window("Percent Limit",
2894 "Please enter the value you want to hide entries under that percent.",
2895 buf, "ENTER: OK, ESC: Cancel",
2896 delay_secs * 2) == K_ENTER) {
2897 char *end;
2898 double new_percent = strtod(buf, &end);
2899
2900 if (new_percent < 0 || new_percent > 100) {
2901 ui_browser__warning(&browser->b, delay_secs * 2,
2902 "Invalid percent: %.2f", new_percent);
2903 continue;
2904 }
2905
2906 hist_browser__update_percent_limit(browser, new_percent);
2907 hist_browser__reset(browser);
2908 }
2909 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002910 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002911 case 'h':
2912 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002913 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002914 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002915 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002916 case K_ENTER:
2917 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002918 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002919 /* menu */
2920 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002921 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002922 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002923 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002924
Namhyung Kim01f00a12015-04-22 16:18:16 +09002925 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002926 /*
2927 * Go back to the perf_evsel_menu__run or other user
2928 */
2929 if (left_exits)
2930 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002931
2932 if (key == K_ESC &&
2933 ui_browser__dialog_yesno(&browser->b,
2934 "Do you really want to exit?"))
2935 goto out_free_stack;
2936
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002937 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002938 }
Namhyung Kim64221842015-04-24 10:15:33 +09002939 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002940 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002941 /*
2942 * No need to set actions->dso here since
2943 * it's just to remove the current filter.
2944 * Ditto for thread below.
2945 */
2946 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002947 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002948 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002949 } else if (top == &browser->hists->socket_filter) {
2950 do_zoom_socket(browser, actions);
2951 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002952 continue;
2953 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002954 case 'q':
2955 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002956 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002957 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002958 if (!is_report_browser(hbt)) {
2959 struct perf_top *top = hbt->arg;
2960
2961 perf_evlist__toggle_enable(top->evlist);
2962 /*
2963 * No need to refresh, resort/decay histogram
2964 * entries if we are not collecting samples:
2965 */
2966 if (top->evlist->enabled) {
2967 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2968 hbt->refresh = delay_secs;
2969 } else {
2970 helpline = "Press 'f' again to re-enable the events";
2971 hbt->refresh = 0;
2972 }
2973 continue;
2974 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002975 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002976 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002977 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002978 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002979 }
2980
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002981 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002982 goto skip_annotation;
2983
Namhyung Kim55369fc2013-04-01 20:35:20 +09002984 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002985 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002986
2987 if (bi == NULL)
2988 goto skip_annotation;
2989
Namhyung Kimea7cd592015-04-22 16:18:19 +09002990 nr_options += add_annotate_opt(browser,
2991 &actions[nr_options],
2992 &options[nr_options],
2993 bi->from.map,
2994 bi->from.sym);
2995 if (bi->to.sym != bi->from.sym)
2996 nr_options += add_annotate_opt(browser,
2997 &actions[nr_options],
2998 &options[nr_options],
2999 bi->to.map,
3000 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003001 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003002 nr_options += add_annotate_opt(browser,
3003 &actions[nr_options],
3004 &options[nr_options],
3005 browser->selection->map,
3006 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003007 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003008skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003009 nr_options += add_thread_opt(browser, &actions[nr_options],
3010 &options[nr_options], thread);
3011 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003012 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003013 nr_options += add_map_opt(browser, &actions[nr_options],
3014 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003015 browser->selection ?
3016 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003017 nr_options += add_socket_opt(browser, &actions[nr_options],
3018 &options[nr_options],
3019 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003020 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003021 if (!is_report_browser(hbt))
3022 goto skip_scripting;
3023
Feng Tangcdbab7c2012-10-30 11:56:06 +08003024 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003025 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003026 nr_options += add_script_opt(browser,
3027 &actions[nr_options],
3028 &options[nr_options],
3029 thread, NULL);
3030 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003031 /*
3032 * Note that browser->selection != NULL
3033 * when browser->he_selection is not NULL,
3034 * so we don't need to check browser->selection
3035 * before fetching browser->selection->sym like what
3036 * we do before fetching browser->selection->map.
3037 *
3038 * See hist_browser__show_entry.
3039 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003040 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003041 nr_options += add_script_opt(browser,
3042 &actions[nr_options],
3043 &options[nr_options],
3044 NULL, browser->selection->sym);
3045 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003046 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003047 nr_options += add_script_opt(browser, &actions[nr_options],
3048 &options[nr_options], NULL, NULL);
3049 nr_options += add_switch_opt(browser, &actions[nr_options],
3050 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003051skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003052 nr_options += add_exit_opt(browser, &actions[nr_options],
3053 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003054
Namhyung Kimea7cd592015-04-22 16:18:19 +09003055 do {
3056 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003057
Namhyung Kimea7cd592015-04-22 16:18:19 +09003058 choice = ui__popup_menu(nr_options, options);
3059 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003060 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003061
3062 act = &actions[choice];
3063 key = act->fn(browser, act);
3064 } while (key == 1);
3065
3066 if (key == K_SWITCH_INPUT_DATA)
3067 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003068 }
3069out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003070 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003071out:
3072 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003073 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003074 return key;
3075}
3076
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003077struct perf_evsel_menu {
3078 struct ui_browser b;
3079 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003080 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003081 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003082 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003083};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003084
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003085static void perf_evsel_menu__write(struct ui_browser *browser,
3086 void *entry, int row)
3087{
3088 struct perf_evsel_menu *menu = container_of(browser,
3089 struct perf_evsel_menu, b);
3090 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003091 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003092 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003093 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003094 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003095 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003096 const char *warn = " ";
3097 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003098
3099 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3100 HE_COLORSET_NORMAL);
3101
Namhyung Kim759ff492013-03-05 14:53:26 +09003102 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003103 struct perf_evsel *pos;
3104
3105 ev_name = perf_evsel__group_name(evsel);
3106
3107 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003108 struct hists *pos_hists = evsel__hists(pos);
3109 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003110 }
3111 }
3112
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003113 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003114 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003115 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003116 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003117
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003118 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003119 if (nr_events != 0) {
3120 menu->lost_events = true;
3121 if (!current_entry)
3122 ui_browser__set_color(browser, HE_COLORSET_TOP);
3123 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003124 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3125 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003126 warn = bf;
3127 }
3128
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003129 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003130
3131 if (current_entry)
3132 menu->selection = evsel;
3133}
3134
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003135static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3136 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003137 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003138{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003139 struct perf_evlist *evlist = menu->b.priv;
3140 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003141 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003142 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003143 int key;
3144
3145 if (ui_browser__show(&menu->b, title,
3146 "ESC: exit, ENTER|->: Browse histograms") < 0)
3147 return -1;
3148
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003149 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003150 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003151
3152 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003153 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003154 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003155
3156 if (!menu->lost_events_warned && menu->lost_events) {
3157 ui_browser__warn_lost_events(&menu->b);
3158 menu->lost_events_warned = true;
3159 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003160 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003161 case K_RIGHT:
3162 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003163 if (!menu->selection)
3164 continue;
3165 pos = menu->selection;
3166browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003167 perf_evlist__set_selected(evlist, pos);
3168 /*
3169 * Give the calling tool a chance to populate the non
3170 * default evsel resorted hists tree.
3171 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003172 if (hbt)
3173 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003174 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003175 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003176 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003177 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003178 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003179 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003180 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003181 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003182 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003183 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003184 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003185 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003186 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003187 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003188 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003189 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003190 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003191 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003192 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003193 case 'q':
3194 case CTRL('c'):
3195 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003196 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003197 default:
3198 continue;
3199 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003200 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003201 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003202 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003203 if (!ui_browser__dialog_yesno(&menu->b,
3204 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003205 continue;
3206 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003207 case 'q':
3208 case CTRL('c'):
3209 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003210 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003211 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003212 }
3213 }
3214
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003215out:
3216 ui_browser__hide(&menu->b);
3217 return key;
3218}
3219
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003220static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003221 void *entry)
3222{
3223 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3224
3225 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3226 return true;
3227
3228 return false;
3229}
3230
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003231static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003232 int nr_entries, 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{
3237 struct perf_evsel *pos;
3238 struct perf_evsel_menu menu = {
3239 .b = {
3240 .entries = &evlist->entries,
3241 .refresh = ui_browser__list_head_refresh,
3242 .seek = ui_browser__list_head_seek,
3243 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003244 .filter = filter_group_entries,
3245 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003246 .priv = evlist,
3247 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003248 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003249 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003250 };
3251
3252 ui_helpline__push("Press ESC to exit");
3253
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003254 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003255 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003256 size_t line_len = strlen(ev_name) + 7;
3257
3258 if (menu.b.width < line_len)
3259 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003260 }
3261
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003262 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003263}
3264
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003265int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003266 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003267 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003268 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003269{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003270 int nr_entries = evlist->nr_entries;
3271
3272single_entry:
3273 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003274 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003275
3276 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003277 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003278 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003279 }
3280
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003281 if (symbol_conf.event_group) {
3282 struct perf_evsel *pos;
3283
3284 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003285 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003286 if (perf_evsel__is_group_leader(pos))
3287 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003288 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003289
3290 if (nr_entries == 1)
3291 goto single_entry;
3292 }
3293
3294 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003295 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003296}