blob: 4ffff7be92993e02f37fd4be8d79c23b11be9d85 [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include <stdlib.h>
3#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <linux/rbtree.h>
5
Namhyung Kimaca7a942012-04-04 00:14:26 -07006#include "../../util/evsel.h"
7#include "../../util/evlist.h"
8#include "../../util/hist.h"
9#include "../../util/pstack.h"
10#include "../../util/sort.h"
11#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090012#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
Jiri Olsaf7589902016-06-20 23:58:13 +020015#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030016#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020020#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021
Namhyung Kimf5951d52012-09-03 11:53:09 +090022extern void hist_browser__init_hpp(void);
23
Jiri Olsa5b91a862016-06-20 23:58:15 +020024static int perf_evsel_browser_title(struct hist_browser *browser,
25 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090026static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030027
Namhyung Kimc3b78952014-04-22 15:56:17 +090028static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090029 float min_pcnt);
30
Namhyung Kim268397c2014-04-22 14:49:31 +090031static bool hist_browser__has_filter(struct hist_browser *hb)
32{
Arnaldo Carvalho de Melo9c0fa8d2015-07-13 08:26:35 -030033 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090034}
35
He Kuang4fabf3d2015-03-12 15:21:49 +080036static int hist_browser__get_folding(struct hist_browser *browser)
37{
38 struct rb_node *nd;
39 struct hists *hists = browser->hists;
40 int unfolded_rows = 0;
41
42 for (nd = rb_first(&hists->entries);
43 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090044 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080045 struct hist_entry *he =
46 rb_entry(nd, struct hist_entry, rb_node);
47
Namhyung Kimf5b763f2016-02-25 00:13:43 +090048 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080049 unfolded_rows += he->nr_rows;
50 }
51 return unfolded_rows;
52}
53
Namhyung Kimc3b78952014-04-22 15:56:17 +090054static u32 hist_browser__nr_entries(struct hist_browser *hb)
55{
56 u32 nr_entries;
57
Namhyung Kimf5b763f2016-02-25 00:13:43 +090058 if (symbol_conf.report_hierarchy)
59 nr_entries = hb->nr_hierarchy_entries;
60 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090061 nr_entries = hb->nr_non_filtered_entries;
62 else
63 nr_entries = hb->hists->nr_entries;
64
He Kuang4fabf3d2015-03-12 15:21:49 +080065 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090066 return nr_entries + hb->nr_callchain_rows;
67}
68
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020069static void hist_browser__update_rows(struct hist_browser *hb)
70{
71 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020072 struct hists *hists = hb->hists;
73 struct perf_hpp_list *hpp_list = hists->hpp_list;
74 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020075
Jiri Olsaf8e67102016-08-07 17:28:26 +020076 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020077 browser->rows = browser->height - header_offset;
78 /*
79 * Verify if we were at the last line and that line isn't
80 * visibe because we now show the header line(s).
81 */
82 index_row = browser->index - browser->top_idx;
83 if (index_row >= browser->rows)
84 browser->index -= index_row - browser->rows + 1;
85}
86
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030087static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030088{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030089 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
90
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030091 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030092 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
93 /*
94 * FIXME: Just keeping existing behaviour, but this really should be
95 * before updating browser->width, as it will invalidate the
96 * calculation above. Fix this and the fallout in another
97 * changeset.
98 */
99 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200100 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101}
102
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300103static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
104{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200105 struct hists *hists = browser->hists;
106 struct perf_hpp_list *hpp_list = hists->hpp_list;
107 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200108
Jiri Olsaf8e67102016-08-07 17:28:26 +0200109 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200110 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300111}
112
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300113static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300114{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900115 /*
116 * The hists__remove_entry_filter() already folds non-filtered
117 * entries so we can assume it has 0 callchain rows.
118 */
119 browser->nr_callchain_rows = 0;
120
Namhyung Kim268397c2014-04-22 14:49:31 +0900121 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900122 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300123 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300124 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300125}
126
127static char tree__folded_sign(bool unfolded)
128{
129 return unfolded ? '-' : '+';
130}
131
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900134 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300135}
136
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300138{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900139 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300140}
141
Namhyung Kim3698dab2015-05-05 23:55:46 +0900142static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300143{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900144 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300145}
146
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148{
149 int n = 0;
150 struct rb_node *nd;
151
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300152 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300153 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
154 struct callchain_list *chain;
155 char folded_sign = ' '; /* No children */
156
157 list_for_each_entry(chain, &child->val, list) {
158 ++n;
159 /* We need this because we may not have children */
160 folded_sign = callchain_list__folded(chain);
161 if (folded_sign == '+')
162 break;
163 }
164
165 if (folded_sign == '-') /* Have children and they're unfolded */
166 n += callchain_node__count_rows_rb_tree(child);
167 }
168
169 return n;
170}
171
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900172static int callchain_node__count_flat_rows(struct callchain_node *node)
173{
174 struct callchain_list *chain;
175 char folded_sign = 0;
176 int n = 0;
177
178 list_for_each_entry(chain, &node->parent_val, list) {
179 if (!folded_sign) {
180 /* only check first chain list entry */
181 folded_sign = callchain_list__folded(chain);
182 if (folded_sign == '+')
183 return 1;
184 }
185 n++;
186 }
187
188 list_for_each_entry(chain, &node->val, list) {
189 if (!folded_sign) {
190 /* node->parent_val list might be empty */
191 folded_sign = callchain_list__folded(chain);
192 if (folded_sign == '+')
193 return 1;
194 }
195 n++;
196 }
197
198 return n;
199}
200
Namhyung Kim8c430a32015-11-09 14:45:44 +0900201static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
202{
203 return 1;
204}
205
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300206static int callchain_node__count_rows(struct callchain_node *node)
207{
208 struct callchain_list *chain;
209 bool unfolded = false;
210 int n = 0;
211
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900212 if (callchain_param.mode == CHAIN_FLAT)
213 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900214 else if (callchain_param.mode == CHAIN_FOLDED)
215 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900216
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300217 list_for_each_entry(chain, &node->val, list) {
218 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900219 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300220 }
221
222 if (unfolded)
223 n += callchain_node__count_rows_rb_tree(node);
224
225 return n;
226}
227
228static int callchain__count_rows(struct rb_root *chain)
229{
230 struct rb_node *nd;
231 int n = 0;
232
233 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
234 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
235 n += callchain_node__count_rows(node);
236 }
237
238 return n;
239}
240
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900241static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
242 bool include_children)
243{
244 int count = 0;
245 struct rb_node *node;
246 struct hist_entry *child;
247
248 if (he->leaf)
249 return callchain__count_rows(&he->sorted_chain);
250
Namhyung Kim79dded82016-02-26 21:13:19 +0900251 if (he->has_no_entry)
252 return 1;
253
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900254 node = rb_first(&he->hroot_out);
255 while (node) {
256 float percent;
257
258 child = rb_entry(node, struct hist_entry, rb_node);
259 percent = hist_entry__get_percent_limit(child);
260
261 if (!child->filtered && percent >= hb->min_pcnt) {
262 count++;
263
264 if (include_children && child->unfolded)
265 count += hierarchy_count_rows(hb, child, true);
266 }
267
268 node = rb_next(node);
269 }
270 return count;
271}
272
Namhyung Kim3698dab2015-05-05 23:55:46 +0900273static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300274{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900275 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200276 return false;
277
Namhyung Kim3698dab2015-05-05 23:55:46 +0900278 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300279 return false;
280
Namhyung Kim3698dab2015-05-05 23:55:46 +0900281 he->unfolded = !he->unfolded;
282 return true;
283}
284
285static bool callchain_list__toggle_fold(struct callchain_list *cl)
286{
287 if (!cl)
288 return false;
289
290 if (!cl->has_children)
291 return false;
292
293 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300294 return true;
295}
296
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300297static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300298{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300299 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300300
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300301 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300302 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
303 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300304 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300305
306 list_for_each_entry(chain, &child->val, list) {
307 if (first) {
308 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900309 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300310 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300311 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900312 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300313 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300314 }
315
316 callchain_node__init_have_children_rb_tree(child);
317 }
318}
319
Namhyung Kima7444af2014-11-24 17:13:27 +0900320static void callchain_node__init_have_children(struct callchain_node *node,
321 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300322{
323 struct callchain_list *chain;
324
Namhyung Kima7444af2014-11-24 17:13:27 +0900325 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900326 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900327
Andres Freund90989032016-03-30 21:02:45 +0200328 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900329 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900330 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900331 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300332
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300333 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300334}
335
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300336static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300337{
Namhyung Kima7444af2014-11-24 17:13:27 +0900338 struct rb_node *nd = rb_first(root);
339 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300340
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300341 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300342 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900343 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900344 if (callchain_param.mode == CHAIN_FLAT ||
345 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900346 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300347 }
348}
349
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300350static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300351{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900352 if (he->init_have_children)
353 return;
354
355 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900356 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300357 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900358 } else {
359 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300360 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900361
362 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363}
364
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300365static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300366{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900367 struct hist_entry *he = browser->he_selection;
368 struct map_symbol *ms = browser->selection;
369 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
370 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300371
Wang Nan4938cf02015-12-07 02:35:44 +0000372 if (!he || !ms)
373 return false;
374
Namhyung Kim3698dab2015-05-05 23:55:46 +0900375 if (ms == &he->ms)
376 has_children = hist_entry__toggle_fold(he);
377 else
378 has_children = callchain_list__toggle_fold(cl);
379
380 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900381 int child_rows = 0;
382
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300383 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900384 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900386 if (he->leaf)
387 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300388 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900389 browser->nr_hierarchy_entries -= he->nr_rows;
390
391 if (symbol_conf.report_hierarchy)
392 child_rows = hierarchy_count_rows(browser, he, true);
393
394 if (he->unfolded) {
395 if (he->leaf)
396 he->nr_rows = callchain__count_rows(&he->sorted_chain);
397 else
398 he->nr_rows = hierarchy_count_rows(browser, he, false);
399
400 /* account grand children */
401 if (symbol_conf.report_hierarchy)
402 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900403
404 if (!he->leaf && he->nr_rows == 0) {
405 he->has_no_entry = true;
406 he->nr_rows = 1;
407 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900408 } else {
409 if (symbol_conf.report_hierarchy)
410 browser->b.nr_entries -= child_rows - he->nr_rows;
411
Namhyung Kim79dded82016-02-26 21:13:19 +0900412 if (he->has_no_entry)
413 he->has_no_entry = false;
414
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300415 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900416 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900417
418 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900419
420 if (he->leaf)
421 browser->nr_callchain_rows += he->nr_rows;
422 else
423 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300424
425 return true;
426 }
427
428 /* If it doesn't have children, no toggling performed */
429 return false;
430}
431
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300432static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300433{
434 int n = 0;
435 struct rb_node *nd;
436
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300437 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300438 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
439 struct callchain_list *chain;
440 bool has_children = false;
441
442 list_for_each_entry(chain, &child->val, list) {
443 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900444 callchain_list__set_folding(chain, unfold);
445 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300446 }
447
448 if (has_children)
449 n += callchain_node__set_folding_rb_tree(child, unfold);
450 }
451
452 return n;
453}
454
455static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
456{
457 struct callchain_list *chain;
458 bool has_children = false;
459 int n = 0;
460
461 list_for_each_entry(chain, &node->val, list) {
462 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900463 callchain_list__set_folding(chain, unfold);
464 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300465 }
466
467 if (has_children)
468 n += callchain_node__set_folding_rb_tree(node, unfold);
469
470 return n;
471}
472
473static int callchain__set_folding(struct rb_root *chain, bool unfold)
474{
475 struct rb_node *nd;
476 int n = 0;
477
478 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
479 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
480 n += callchain_node__set_folding(node, unfold);
481 }
482
483 return n;
484}
485
Namhyung Kim492b1012016-02-25 00:13:44 +0900486static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
487 bool unfold __maybe_unused)
488{
489 float percent;
490 struct rb_node *nd;
491 struct hist_entry *child;
492 int n = 0;
493
494 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
495 child = rb_entry(nd, struct hist_entry, rb_node);
496 percent = hist_entry__get_percent_limit(child);
497 if (!child->filtered && percent >= hb->min_pcnt)
498 n++;
499 }
500
501 return n;
502}
503
504static void hist_entry__set_folding(struct hist_entry *he,
505 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300506{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300507 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900508 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300509
Namhyung Kim3698dab2015-05-05 23:55:46 +0900510 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900511 int n;
512
513 if (he->leaf)
514 n = callchain__set_folding(&he->sorted_chain, unfold);
515 else
516 n = hierarchy_set_folding(hb, he, unfold);
517
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300519 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300520 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300521}
522
Namhyung Kimc3b78952014-04-22 15:56:17 +0900523static void
524__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300525{
526 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900527 struct hist_entry *he;
528 double percent;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300529
Namhyung Kim492b1012016-02-25 00:13:44 +0900530 nd = rb_first(&browser->hists->entries);
531 while (nd) {
532 he = rb_entry(nd, struct hist_entry, rb_node);
533
534 /* set folding state even if it's currently folded */
535 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
536
537 hist_entry__set_folding(he, browser, unfold);
538
539 percent = hist_entry__get_percent_limit(he);
540 if (he->filtered || percent < browser->min_pcnt)
541 continue;
542
543 if (!he->depth || unfold)
544 browser->nr_hierarchy_entries++;
545 if (he->leaf)
546 browser->nr_callchain_rows += he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900547 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
548 browser->nr_hierarchy_entries++;
549 he->has_no_entry = true;
550 he->nr_rows = 1;
551 } else
552 he->has_no_entry = false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300553 }
554}
555
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300556static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300557{
Namhyung Kim492b1012016-02-25 00:13:44 +0900558 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900559 browser->nr_callchain_rows = 0;
560 __hist_browser__set_folding(browser, unfold);
561
562 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300563 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300564 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300565}
566
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200567static void ui_browser__warn_lost_events(struct ui_browser *browser)
568{
569 ui_browser__warning(browser, 4,
570 "Events are being lost, check IO/CPU overload!\n\n"
571 "You may want to run 'perf' using a RT scheduler policy:\n\n"
572 " perf top -r 80\n\n"
573 "Or reduce the sampling frequency.");
574}
575
Jiri Olsa5b91a862016-06-20 23:58:15 +0200576static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
577{
578 return browser->title ? browser->title(browser, bf, size) : 0;
579}
580
Jiri Olsadabd2012016-06-20 23:58:14 +0200581int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300582{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300583 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300584 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900585 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900586 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300587
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300588 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900589 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590
Jiri Olsa5b91a862016-06-20 23:58:15 +0200591 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592
Namhyung Kim090cff32016-01-11 19:53:14 +0900593 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300594 return -1;
595
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300596 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300597 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300598
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300599 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900600 case K_TIMER: {
601 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900602 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900603
Namhyung 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;
741 const char *str;
742
743 if (arg->row_offset != 0) {
744 arg->row_offset--;
745 return 0;
746 }
747
748 alloc_str = NULL;
749 str = callchain_list__sym_name(chain, bf, sizeof(bf),
750 browser->show_dso);
751
752 if (need_percent) {
753 char buf[64];
754
755 callchain_node__scnprintf_value(node, buf, sizeof(buf),
756 total);
757
758 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
759 str = "Not enough memory!";
760 else
761 str = alloc_str;
762 }
763
764 print(browser, chain, str, offset, row, arg);
765
766 free(alloc_str);
767 return 1;
768}
769
Namhyung Kim59c624e2016-01-28 00:40:56 +0900770static bool check_percent_display(struct rb_node *node, u64 parent_total)
771{
772 struct callchain_node *child;
773
774 if (node == NULL)
775 return false;
776
777 if (rb_next(node))
778 return true;
779
780 child = rb_entry(node, struct callchain_node, rb_node);
781 return callchain_cumul_hits(child) != parent_total;
782}
783
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900784static int hist_browser__show_callchain_flat(struct hist_browser *browser,
785 struct rb_root *root,
786 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900787 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900788 print_callchain_entry_fn print,
789 struct callchain_print_arg *arg,
790 check_output_full_fn is_output_full)
791{
792 struct rb_node *node;
793 int first_row = row, offset = LEVEL_OFFSET_STEP;
794 bool need_percent;
795
796 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900797 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900798
799 while (node) {
800 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
801 struct rb_node *next = rb_next(node);
802 struct callchain_list *chain;
803 char folded_sign = ' ';
804 int first = true;
805 int extra_offset = 0;
806
807 list_for_each_entry(chain, &child->parent_val, list) {
808 bool was_first = first;
809
810 if (first)
811 first = false;
812 else if (need_percent)
813 extra_offset = LEVEL_OFFSET_STEP;
814
815 folded_sign = callchain_list__folded(chain);
816
817 row += hist_browser__show_callchain_list(browser, child,
818 chain, row, total,
819 was_first && need_percent,
820 offset + extra_offset,
821 print, arg);
822
823 if (is_output_full(browser, row))
824 goto out;
825
826 if (folded_sign == '+')
827 goto next;
828 }
829
830 list_for_each_entry(chain, &child->val, list) {
831 bool was_first = first;
832
833 if (first)
834 first = false;
835 else if (need_percent)
836 extra_offset = LEVEL_OFFSET_STEP;
837
838 folded_sign = callchain_list__folded(chain);
839
840 row += hist_browser__show_callchain_list(browser, child,
841 chain, row, total,
842 was_first && need_percent,
843 offset + extra_offset,
844 print, arg);
845
846 if (is_output_full(browser, row))
847 goto out;
848
849 if (folded_sign == '+')
850 break;
851 }
852
853next:
854 if (is_output_full(browser, row))
855 break;
856 node = next;
857 }
858out:
859 return row - first_row;
860}
861
Namhyung Kim8c430a32015-11-09 14:45:44 +0900862static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
863 struct callchain_list *chain,
864 char *value_str, char *old_str)
865{
866 char bf[1024];
867 const char *str;
868 char *new;
869
870 str = callchain_list__sym_name(chain, bf, sizeof(bf),
871 browser->show_dso);
872 if (old_str) {
873 if (asprintf(&new, "%s%s%s", old_str,
874 symbol_conf.field_sep ?: ";", str) < 0)
875 new = NULL;
876 } else {
877 if (value_str) {
878 if (asprintf(&new, "%s %s", value_str, str) < 0)
879 new = NULL;
880 } else {
881 if (asprintf(&new, "%s", str) < 0)
882 new = NULL;
883 }
884 }
885 return new;
886}
887
888static int hist_browser__show_callchain_folded(struct hist_browser *browser,
889 struct rb_root *root,
890 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900891 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900892 print_callchain_entry_fn print,
893 struct callchain_print_arg *arg,
894 check_output_full_fn is_output_full)
895{
896 struct rb_node *node;
897 int first_row = row, offset = LEVEL_OFFSET_STEP;
898 bool need_percent;
899
900 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900901 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900902
903 while (node) {
904 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
905 struct rb_node *next = rb_next(node);
906 struct callchain_list *chain, *first_chain = NULL;
907 int first = true;
908 char *value_str = NULL, *value_str_alloc = NULL;
909 char *chain_str = NULL, *chain_str_alloc = NULL;
910
911 if (arg->row_offset != 0) {
912 arg->row_offset--;
913 goto next;
914 }
915
916 if (need_percent) {
917 char buf[64];
918
919 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
920 if (asprintf(&value_str, "%s", buf) < 0) {
921 value_str = (char *)"<...>";
922 goto do_print;
923 }
924 value_str_alloc = value_str;
925 }
926
927 list_for_each_entry(chain, &child->parent_val, list) {
928 chain_str = hist_browser__folded_callchain_str(browser,
929 chain, value_str, chain_str);
930 if (first) {
931 first = false;
932 first_chain = chain;
933 }
934
935 if (chain_str == NULL) {
936 chain_str = (char *)"Not enough memory!";
937 goto do_print;
938 }
939
940 chain_str_alloc = chain_str;
941 }
942
943 list_for_each_entry(chain, &child->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
959do_print:
960 print(browser, first_chain, chain_str, offset, row++, arg);
961 free(value_str_alloc);
962 free(chain_str_alloc);
963
964next:
965 if (is_output_full(browser, row))
966 break;
967 node = next;
968 }
969
970 return row - first_row;
971}
972
Namhyung Kim0c841c62016-01-28 00:40:54 +0900973static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900974 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900975 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900976 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900977 print_callchain_entry_fn print,
978 struct callchain_print_arg *arg,
979 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300980{
981 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900982 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +0900983 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +0900984 u64 percent_total = total;
985
986 if (callchain_param.mode == CHAIN_GRAPH_REL)
987 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300988
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900989 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900990 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +0900991
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300992 while (node) {
993 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
994 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300995 struct callchain_list *chain;
996 char folded_sign = ' ';
997 int first = true;
998 int extra_offset = 0;
999
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001000 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001001 bool was_first = first;
1002
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001003 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001004 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001005 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001006 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001007
1008 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001009
Namhyung Kim18bb8382015-11-09 14:45:42 +09001010 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001011 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001012 was_first && need_percent,
1013 offset + extra_offset,
1014 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001015
Namhyung Kim18bb8382015-11-09 14:45:42 +09001016 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001017 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001018
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001019 if (folded_sign == '+')
1020 break;
1021 }
1022
1023 if (folded_sign == '-') {
1024 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001025
Namhyung Kim0c841c62016-01-28 00:40:54 +09001026 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001027 new_level, row, total,
1028 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001029 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001030 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001031 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001032 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001033 node = next;
1034 }
1035out:
1036 return row - first_row;
1037}
1038
Namhyung Kim0c841c62016-01-28 00:40:54 +09001039static int hist_browser__show_callchain(struct hist_browser *browser,
1040 struct hist_entry *entry, int level,
1041 unsigned short row,
1042 print_callchain_entry_fn print,
1043 struct callchain_print_arg *arg,
1044 check_output_full_fn is_output_full)
1045{
1046 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001047 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001048 int printed;
1049
Namhyung Kim5eca1042016-01-28 00:40:55 +09001050 if (symbol_conf.cumulate_callchain)
1051 parent_total = entry->stat_acc->period;
1052 else
1053 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001054
1055 if (callchain_param.mode == CHAIN_FLAT) {
1056 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001057 &entry->sorted_chain, row,
1058 total, parent_total, print, arg,
1059 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001060 } else if (callchain_param.mode == CHAIN_FOLDED) {
1061 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001062 &entry->sorted_chain, row,
1063 total, parent_total, print, arg,
1064 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001065 } else {
1066 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001067 &entry->sorted_chain, level, row,
1068 total, parent_total, print, arg,
1069 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001070 }
1071
1072 if (arg->is_current_entry)
1073 browser->he_selection = entry;
1074
1075 return printed;
1076}
1077
Namhyung Kim89701462013-01-22 18:09:38 +09001078struct hpp_arg {
1079 struct ui_browser *b;
1080 char folded_sign;
1081 bool current_entry;
1082};
1083
Jiri Olsa98ba1602016-09-22 17:36:35 +02001084int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001085{
1086 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001087 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001088 va_list args;
1089 double percent;
1090
1091 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001092 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001093 percent = va_arg(args, double);
1094 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001095
Namhyung Kim89701462013-01-22 18:09:38 +09001096 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001097
Namhyung Kimd6751072014-07-31 14:47:36 +09001098 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001099 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001100
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001101 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001102}
1103
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001104#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001105static u64 __hpp_get_##_field(struct hist_entry *he) \
1106{ \
1107 return he->stat._field; \
1108} \
1109 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001110static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001111hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001112 struct perf_hpp *hpp, \
1113 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001114{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001115 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1116 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001117}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001118
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001119#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1120static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1121{ \
1122 return he->stat_acc->_field; \
1123} \
1124 \
1125static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001126hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001127 struct perf_hpp *hpp, \
1128 struct hist_entry *he) \
1129{ \
1130 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001131 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001132 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001133 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001134 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001135 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001136 \
1137 return ret; \
1138 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001139 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1140 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001141}
1142
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001143__HPP_COLOR_PERCENT_FN(overhead, period)
1144__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1145__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1146__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1147__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001148__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001149
1150#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001151#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001152
1153void hist_browser__init_hpp(void)
1154{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001155 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1156 hist_browser__hpp_color_overhead;
1157 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1158 hist_browser__hpp_color_overhead_sys;
1159 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1160 hist_browser__hpp_color_overhead_us;
1161 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1162 hist_browser__hpp_color_overhead_guest_sys;
1163 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1164 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001165 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1166 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001167}
1168
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001169static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001170 struct hist_entry *entry,
1171 unsigned short row)
1172{
Jiri Olsa12400052012-10-13 00:06:16 +02001173 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001174 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001175 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001176 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001177 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001178 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001179 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180
1181 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001182 browser->he_selection = entry;
1183 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001184 }
1185
1186 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001187 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001188 folded_sign = hist_entry__folded(entry);
1189 }
1190
1191 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001192 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001193 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001194 .folded_sign = folded_sign,
1195 .current_entry = current_entry,
1196 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001197 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001199 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001200
Jiri Olsaf0786af2016-01-18 10:24:23 +01001201 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001202 char s[2048];
1203 struct perf_hpp hpp = {
1204 .buf = s,
1205 .size = sizeof(s),
1206 .ptr = &arg,
1207 };
1208
Namhyung Kim361459f2015-12-23 02:07:08 +09001209 if (perf_hpp__should_skip(fmt, entry->hists) ||
1210 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001211 continue;
1212
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001213 if (current_entry && browser->b.navkeypressed) {
1214 ui_browser__set_color(&browser->b,
1215 HE_COLORSET_SELECTED);
1216 } else {
1217 ui_browser__set_color(&browser->b,
1218 HE_COLORSET_NORMAL);
1219 }
1220
1221 if (first) {
1222 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001223 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001224 width -= 2;
1225 }
1226 first = false;
1227 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001228 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001229 width -= 2;
1230 }
1231
Jiri Olsa12400052012-10-13 00:06:16 +02001232 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001233 int ret = fmt->color(fmt, &hpp, entry);
1234 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1235 /*
1236 * fmt->color() already used ui_browser to
1237 * print the non alignment bits, skip it (+ret):
1238 */
1239 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001240 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001241 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001242 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001243 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001244 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001245 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001246
1247 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001248 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001249 width += 1;
1250
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001251 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001252
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253 ++row;
1254 ++printed;
1255 } else
1256 --row_offset;
1257
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001258 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001259 struct callchain_print_arg arg = {
1260 .row_offset = row_offset,
1261 .is_current_entry = current_entry,
1262 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001263
Namhyung Kim0c841c62016-01-28 00:40:54 +09001264 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001265 hist_browser__show_callchain_entry, &arg,
1266 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001267 }
1268
1269 return printed;
1270}
1271
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001272static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1273 struct hist_entry *entry,
1274 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001275 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001276{
1277 int printed = 0;
1278 int width = browser->b.width;
1279 char folded_sign = ' ';
1280 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1281 off_t row_offset = entry->row_offset;
1282 bool first = true;
1283 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001284 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001285 struct hpp_arg arg = {
1286 .b = &browser->b,
1287 .current_entry = current_entry,
1288 };
1289 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001290 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001291
1292 if (current_entry) {
1293 browser->he_selection = entry;
1294 browser->selection = &entry->ms;
1295 }
1296
1297 hist_entry__init_have_children(entry);
1298 folded_sign = hist_entry__folded(entry);
1299 arg.folded_sign = folded_sign;
1300
1301 if (entry->leaf && row_offset) {
1302 row_offset--;
1303 goto show_callchain;
1304 }
1305
1306 hist_browser__gotorc(browser, row, 0);
1307
1308 if (current_entry && browser->b.navkeypressed)
1309 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1310 else
1311 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1312
1313 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1314 width -= level * HIERARCHY_INDENT;
1315
Namhyung Kima61a22f2016-03-07 16:44:50 -03001316 /* the first hpp_list_node is for overhead columns */
1317 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1318 struct perf_hpp_list_node, list);
1319 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001320 char s[2048];
1321 struct perf_hpp hpp = {
1322 .buf = s,
1323 .size = sizeof(s),
1324 .ptr = &arg,
1325 };
1326
1327 if (perf_hpp__should_skip(fmt, entry->hists) ||
1328 column++ < browser->b.horiz_scroll)
1329 continue;
1330
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001331 if (current_entry && browser->b.navkeypressed) {
1332 ui_browser__set_color(&browser->b,
1333 HE_COLORSET_SELECTED);
1334 } else {
1335 ui_browser__set_color(&browser->b,
1336 HE_COLORSET_NORMAL);
1337 }
1338
1339 if (first) {
1340 ui_browser__printf(&browser->b, "%c", folded_sign);
1341 width--;
1342 first = false;
1343 } else {
1344 ui_browser__printf(&browser->b, " ");
1345 width -= 2;
1346 }
1347
1348 if (fmt->color) {
1349 int ret = fmt->color(fmt, &hpp, entry);
1350 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1351 /*
1352 * fmt->color() already used ui_browser to
1353 * print the non alignment bits, skip it (+ret):
1354 */
1355 ui_browser__printf(&browser->b, "%s", s + ret);
1356 } else {
1357 int ret = fmt->entry(fmt, &hpp, entry);
1358 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1359 ui_browser__printf(&browser->b, "%s", s);
1360 }
1361 width -= hpp.buf - s;
1362 }
1363
1364 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1365 width -= hierarchy_indent;
1366
1367 if (column >= browser->b.horiz_scroll) {
1368 char s[2048];
1369 struct perf_hpp hpp = {
1370 .buf = s,
1371 .size = sizeof(s),
1372 .ptr = &arg,
1373 };
1374
1375 if (current_entry && browser->b.navkeypressed) {
1376 ui_browser__set_color(&browser->b,
1377 HE_COLORSET_SELECTED);
1378 } else {
1379 ui_browser__set_color(&browser->b,
1380 HE_COLORSET_NORMAL);
1381 }
1382
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001383 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1384 ui_browser__write_nstring(&browser->b, "", 2);
1385 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001386
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001387 /*
1388 * No need to call hist_entry__snprintf_alignment()
1389 * since this fmt is always the last column in the
1390 * hierarchy mode.
1391 */
1392 if (fmt->color) {
1393 width -= fmt->color(fmt, &hpp, entry);
1394 } else {
1395 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001396
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001397 width -= fmt->entry(fmt, &hpp, entry);
1398 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001399
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001400 while (isspace(s[i++]))
1401 width++;
1402 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001403 }
1404 }
1405
1406 /* The scroll bar isn't being used */
1407 if (!browser->b.navkeypressed)
1408 width += 1;
1409
1410 ui_browser__write_nstring(&browser->b, "", width);
1411
1412 ++row;
1413 ++printed;
1414
1415show_callchain:
1416 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1417 struct callchain_print_arg carg = {
1418 .row_offset = row_offset,
1419 };
1420
1421 printed += hist_browser__show_callchain(browser, entry,
1422 level + 1, row,
1423 hist_browser__show_callchain_entry, &carg,
1424 hist_browser__check_output_full);
1425 }
1426
1427 return printed;
1428}
1429
Namhyung Kim79dded82016-02-26 21:13:19 +09001430static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001431 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001432{
1433 int width = browser->b.width;
1434 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1435 bool first = true;
1436 int column = 0;
1437 int ret;
1438 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001439 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001440 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001441
1442 if (current_entry) {
1443 browser->he_selection = NULL;
1444 browser->selection = NULL;
1445 }
1446
1447 hist_browser__gotorc(browser, row, 0);
1448
1449 if (current_entry && browser->b.navkeypressed)
1450 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1451 else
1452 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1453
1454 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1455 width -= level * HIERARCHY_INDENT;
1456
Namhyung Kima61a22f2016-03-07 16:44:50 -03001457 /* the first hpp_list_node is for overhead columns */
1458 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1459 struct perf_hpp_list_node, list);
1460 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001461 if (perf_hpp__should_skip(fmt, browser->hists) ||
1462 column++ < browser->b.horiz_scroll)
1463 continue;
1464
Jiri Olsada1b0402016-06-14 20:19:20 +02001465 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001466
1467 if (first) {
1468 /* for folded sign */
1469 first = false;
1470 ret++;
1471 } else {
1472 /* space between columns */
1473 ret += 2;
1474 }
1475
1476 ui_browser__write_nstring(&browser->b, "", ret);
1477 width -= ret;
1478 }
1479
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001480 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1481 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001482
1483 if (column >= browser->b.horiz_scroll) {
1484 char buf[32];
1485
1486 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1487 ui_browser__printf(&browser->b, " %s", buf);
1488 width -= ret + 2;
1489 }
1490
1491 /* The scroll bar isn't being used */
1492 if (!browser->b.navkeypressed)
1493 width += 1;
1494
1495 ui_browser__write_nstring(&browser->b, "", width);
1496 return 1;
1497}
1498
Jiri Olsa81a888f2014-06-14 15:44:52 +02001499static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1500{
1501 advance_hpp(hpp, inc);
1502 return hpp->size <= 0;
1503}
1504
Jiri Olsa69705b32016-08-07 17:28:28 +02001505static int
1506hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1507 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001508{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001509 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001510 struct perf_hpp dummy_hpp = {
1511 .buf = buf,
1512 .size = size,
1513 };
1514 struct perf_hpp_fmt *fmt;
1515 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001516 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001517 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001518
1519 if (symbol_conf.use_callchain) {
1520 ret = scnprintf(buf, size, " ");
1521 if (advance_hpp_check(&dummy_hpp, ret))
1522 return ret;
1523 }
1524
Jiri Olsaf0786af2016-01-18 10:24:23 +01001525 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001526 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001527 continue;
1528
Jiri Olsa29659ab2016-08-07 17:28:30 +02001529 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001530 if (advance_hpp_check(&dummy_hpp, ret))
1531 break;
1532
Jiri Olsa29659ab2016-08-07 17:28:30 +02001533 if (span)
1534 continue;
1535
Jiri Olsa81a888f2014-06-14 15:44:52 +02001536 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1537 if (advance_hpp_check(&dummy_hpp, ret))
1538 break;
1539 }
1540
1541 return ret;
1542}
1543
Namhyung Kimd8b92402016-02-25 00:13:46 +09001544static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1545{
1546 struct hists *hists = browser->hists;
1547 struct perf_hpp dummy_hpp = {
1548 .buf = buf,
1549 .size = size,
1550 };
1551 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001552 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001553 size_t ret = 0;
1554 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001555 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001556 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001557
1558 ret = scnprintf(buf, size, " ");
1559 if (advance_hpp_check(&dummy_hpp, ret))
1560 return ret;
1561
Namhyung Kima61a22f2016-03-07 16:44:50 -03001562 /* the first hpp_list_node is for overhead columns */
1563 fmt_node = list_first_entry(&hists->hpp_formats,
1564 struct perf_hpp_list_node, list);
1565 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001566 if (column++ < browser->b.horiz_scroll)
1567 continue;
1568
Jiri Olsa29659ab2016-08-07 17:28:30 +02001569 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001570 if (advance_hpp_check(&dummy_hpp, ret))
1571 break;
1572
1573 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1574 if (advance_hpp_check(&dummy_hpp, ret))
1575 break;
1576 }
1577
1578 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001579 indent * HIERARCHY_INDENT, "");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001580 if (advance_hpp_check(&dummy_hpp, ret))
1581 return ret;
1582
Namhyung Kima61a22f2016-03-07 16:44:50 -03001583 first_node = true;
1584 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1585 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001586 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1587 if (advance_hpp_check(&dummy_hpp, ret))
1588 break;
1589 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001590 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001591
Namhyung Kima61a22f2016-03-07 16:44:50 -03001592 first_col = true;
1593 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1594 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001595
Namhyung Kima61a22f2016-03-07 16:44:50 -03001596 if (perf_hpp__should_skip(fmt, hists))
1597 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001598
Namhyung Kima61a22f2016-03-07 16:44:50 -03001599 if (!first_col) {
1600 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1601 if (advance_hpp_check(&dummy_hpp, ret))
1602 break;
1603 }
1604 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001605
Jiri Olsa29659ab2016-08-07 17:28:30 +02001606 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001607 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001608
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001609 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001610 ret = strlen(start);
1611
1612 if (start != dummy_hpp.buf)
1613 memmove(dummy_hpp.buf, start, ret + 1);
1614
1615 if (advance_hpp_check(&dummy_hpp, ret))
1616 break;
1617 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001618 }
1619
1620 return ret;
1621}
1622
Jiri Olsa01b47702016-06-14 20:19:13 +02001623static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001624{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001625 char headers[1024];
1626
Jiri Olsa01b47702016-06-14 20:19:13 +02001627 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1628 sizeof(headers));
1629
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001630 ui_browser__gotorc(&browser->b, 0, 0);
1631 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001632 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001633}
1634
Jiri Olsa01b47702016-06-14 20:19:13 +02001635static void hists_browser__headers(struct hist_browser *browser)
1636{
Jiri Olsa69705b32016-08-07 17:28:28 +02001637 struct hists *hists = browser->hists;
1638 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001639
Jiri Olsa69705b32016-08-07 17:28:28 +02001640 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001641
Jiri Olsa69705b32016-08-07 17:28:28 +02001642 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1643 char headers[1024];
1644
1645 hists_browser__scnprintf_headers(browser, headers,
1646 sizeof(headers), line);
1647
1648 ui_browser__gotorc(&browser->b, line, 0);
1649 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1650 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1651 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001652}
1653
1654static void hist_browser__show_headers(struct hist_browser *browser)
1655{
1656 if (symbol_conf.report_hierarchy)
1657 hists_browser__hierarchy_headers(browser);
1658 else
1659 hists_browser__headers(browser);
1660}
1661
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001662static void ui_browser__hists_init_top(struct ui_browser *browser)
1663{
1664 if (browser->top == NULL) {
1665 struct hist_browser *hb;
1666
1667 hb = container_of(browser, struct hist_browser, b);
1668 browser->top = rb_first(&hb->hists->entries);
1669 }
1670}
1671
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001672static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001673{
1674 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001675 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001676 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001677 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001678 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001679
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001680 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001681 struct perf_hpp_list *hpp_list = hists->hpp_list;
1682
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001683 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001684 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001685 }
1686
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001687 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001688 hb->he_selection = NULL;
1689 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001690
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001691 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001692 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001693 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001694
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001695 if (h->filtered) {
1696 /* let it move to sibling */
1697 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001698 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001699 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001700
Namhyung Kim14135662013-10-31 10:17:39 +09001701 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001702 if (percent < hb->min_pcnt)
1703 continue;
1704
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001705 if (symbol_conf.report_hierarchy) {
1706 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001707 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001708 if (row == browser->rows)
1709 break;
1710
1711 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001712 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001713 row++;
1714 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001715 } else {
1716 row += hist_browser__show_entry(hb, h, row);
1717 }
1718
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001719 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001720 break;
1721 }
1722
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001723 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001724}
1725
Namhyung Kim064f1982013-05-14 11:09:04 +09001726static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001727 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001728{
1729 while (nd != NULL) {
1730 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001731 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001732
Namhyung Kimc0f15272014-04-16 11:16:33 +09001733 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001734 return nd;
1735
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001736 /*
1737 * If it's filtered, its all children also were filtered.
1738 * So move to sibling node.
1739 */
1740 if (rb_next(nd))
1741 nd = rb_next(nd);
1742 else
1743 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001744 }
1745
1746 return NULL;
1747}
1748
Namhyung Kim064f1982013-05-14 11:09:04 +09001749static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001750 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001751{
1752 while (nd != NULL) {
1753 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001754 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001755
1756 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757 return nd;
1758
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001759 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001760 }
1761
1762 return NULL;
1763}
1764
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001765static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766 off_t offset, int whence)
1767{
1768 struct hist_entry *h;
1769 struct rb_node *nd;
1770 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001771 struct hist_browser *hb;
1772
1773 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001774
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001775 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001776 return;
1777
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001778 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001779
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001780 switch (whence) {
1781 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001782 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001783 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001784 break;
1785 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001786 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001787 goto do_offset;
1788 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001789 nd = rb_hierarchy_last(rb_last(browser->entries));
1790 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001791 first = false;
1792 break;
1793 default:
1794 return;
1795 }
1796
1797 /*
1798 * Moves not relative to the first visible entry invalidates its
1799 * row_offset:
1800 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001801 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001802 h->row_offset = 0;
1803
1804 /*
1805 * Here we have to check if nd is expanded (+), if it is we can't go
1806 * the next top level hist_entry, instead we must compute an offset of
1807 * what _not_ to show and not change the first visible entry.
1808 *
1809 * This offset increments when we are going from top to bottom and
1810 * decreases when we're going from bottom to top.
1811 *
1812 * As we don't have backpointers to the top level in the callchains
1813 * structure, we need to always print the whole hist_entry callchain,
1814 * skipping the first ones that are before the first visible entry
1815 * and stop when we printed enough lines to fill the screen.
1816 */
1817do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001818 if (!nd)
1819 return;
1820
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001821 if (offset > 0) {
1822 do {
1823 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001824 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001825 u16 remaining = h->nr_rows - h->row_offset;
1826 if (offset > remaining) {
1827 offset -= remaining;
1828 h->row_offset = 0;
1829 } else {
1830 h->row_offset += offset;
1831 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001832 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001833 break;
1834 }
1835 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001836 nd = hists__filter_entries(rb_hierarchy_next(nd),
1837 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001838 if (nd == NULL)
1839 break;
1840 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001841 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001842 } while (offset != 0);
1843 } else if (offset < 0) {
1844 while (1) {
1845 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001846 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001847 if (first) {
1848 if (-offset > h->row_offset) {
1849 offset += h->row_offset;
1850 h->row_offset = 0;
1851 } else {
1852 h->row_offset += offset;
1853 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001854 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001855 break;
1856 }
1857 } else {
1858 if (-offset > h->nr_rows) {
1859 offset += h->nr_rows;
1860 h->row_offset = 0;
1861 } else {
1862 h->row_offset = h->nr_rows + offset;
1863 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001864 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001865 break;
1866 }
1867 }
1868 }
1869
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001870 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001871 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001872 if (nd == NULL)
1873 break;
1874 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001875 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001876 if (offset == 0) {
1877 /*
1878 * Last unfiltered hist_entry, check if it is
1879 * unfolded, if it is then we should have
1880 * row_offset at its last entry.
1881 */
1882 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001883 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001884 h->row_offset = h->nr_rows;
1885 break;
1886 }
1887 first = false;
1888 }
1889 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001890 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001891 h = rb_entry(nd, struct hist_entry, rb_node);
1892 h->row_offset = 0;
1893 }
1894}
1895
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001896static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001897 struct hist_entry *he, FILE *fp,
1898 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001899{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001900 struct callchain_print_arg arg = {
1901 .fp = fp,
1902 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001903
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001904 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001905 hist_browser__fprintf_callchain_entry, &arg,
1906 hist_browser__check_dump_full);
1907 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001908}
1909
1910static int hist_browser__fprintf_entry(struct hist_browser *browser,
1911 struct hist_entry *he, FILE *fp)
1912{
1913 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001914 int printed = 0;
1915 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001916 struct perf_hpp hpp = {
1917 .buf = s,
1918 .size = sizeof(s),
1919 };
1920 struct perf_hpp_fmt *fmt;
1921 bool first = true;
1922 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001923
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001924 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001925 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001926 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001927 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001928
Jiri Olsaf0786af2016-01-18 10:24:23 +01001929 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001930 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001931 continue;
1932
Namhyung Kim26d8b332014-03-03 16:16:20 +09001933 if (!first) {
1934 ret = scnprintf(hpp.buf, hpp.size, " ");
1935 advance_hpp(&hpp, ret);
1936 } else
1937 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001938
Namhyung Kim26d8b332014-03-03 16:16:20 +09001939 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001940 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001941 advance_hpp(&hpp, ret);
1942 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001943 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001944
1945 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001946 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1947
1948 return printed;
1949}
1950
1951
1952static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1953 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09001954 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001955{
1956 char s[8192];
1957 int printed = 0;
1958 char folded_sign = ' ';
1959 struct perf_hpp hpp = {
1960 .buf = s,
1961 .size = sizeof(s),
1962 };
1963 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09001964 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001965 bool first = true;
1966 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09001967 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001968
1969 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1970
1971 folded_sign = hist_entry__folded(he);
1972 printed += fprintf(fp, "%c", folded_sign);
1973
Namhyung Kim325a6282016-03-09 22:47:00 +09001974 /* the first hpp_list_node is for overhead columns */
1975 fmt_node = list_first_entry(&he->hists->hpp_formats,
1976 struct perf_hpp_list_node, list);
1977 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001978 if (!first) {
1979 ret = scnprintf(hpp.buf, hpp.size, " ");
1980 advance_hpp(&hpp, ret);
1981 } else
1982 first = false;
1983
1984 ret = fmt->entry(fmt, &hpp, he);
1985 advance_hpp(&hpp, ret);
1986 }
1987
1988 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1989 advance_hpp(&hpp, ret);
1990
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001991 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1992 ret = scnprintf(hpp.buf, hpp.size, " ");
1993 advance_hpp(&hpp, ret);
1994
1995 ret = fmt->entry(fmt, &hpp, he);
1996 advance_hpp(&hpp, ret);
1997 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001998
1999 printed += fprintf(fp, "%s\n", rtrim(s));
2000
2001 if (he->leaf && folded_sign == '-') {
2002 printed += hist_browser__fprintf_callchain(browser, he, fp,
2003 he->depth + 1);
2004 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002005
2006 return printed;
2007}
2008
2009static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2010{
Namhyung Kim064f1982013-05-14 11:09:04 +09002011 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002012 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002013 int printed = 0;
2014
2015 while (nd) {
2016 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2017
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002018 if (symbol_conf.report_hierarchy) {
2019 printed += hist_browser__fprintf_hierarchy_entry(browser,
2020 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002021 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002022 } else {
2023 printed += hist_browser__fprintf_entry(browser, h, fp);
2024 }
2025
2026 nd = hists__filter_entries(rb_hierarchy_next(nd),
2027 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002028 }
2029
2030 return printed;
2031}
2032
2033static int hist_browser__dump(struct hist_browser *browser)
2034{
2035 char filename[64];
2036 FILE *fp;
2037
2038 while (1) {
2039 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2040 if (access(filename, F_OK))
2041 break;
2042 /*
2043 * XXX: Just an arbitrary lazy upper limit
2044 */
2045 if (++browser->print_seq == 8192) {
2046 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2047 return -1;
2048 }
2049 }
2050
2051 fp = fopen(filename, "w");
2052 if (fp == NULL) {
2053 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002054 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002055 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002056 return -1;
2057 }
2058
2059 ++browser->print_seq;
2060 hist_browser__fprintf(browser, fp);
2061 fclose(fp);
2062 ui_helpline__fpush("%s written!", filename);
2063
2064 return 0;
2065}
2066
Jiri Olsafcd86422016-06-20 23:58:18 +02002067void hist_browser__init(struct hist_browser *browser,
2068 struct hists *hists)
2069{
2070 struct perf_hpp_fmt *fmt;
2071
2072 browser->hists = hists;
2073 browser->b.refresh = hist_browser__refresh;
2074 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2075 browser->b.seek = ui_browser__hists_seek;
2076 browser->b.use_navkeypressed = true;
2077 browser->show_headers = symbol_conf.show_hist_headers;
2078
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002079 hists__for_each_format(hists, fmt)
Jiri Olsafcd86422016-06-20 23:58:18 +02002080 ++browser->b.columns;
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002081
2082 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002083}
2084
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002085struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002086{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002087 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002088
Jiri Olsafcd86422016-06-20 23:58:18 +02002089 if (browser)
2090 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002091
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002092 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002093}
2094
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002095static struct hist_browser *
2096perf_evsel_browser__new(struct perf_evsel *evsel,
2097 struct hist_browser_timer *hbt,
2098 struct perf_env *env)
2099{
2100 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2101
2102 if (browser) {
2103 browser->hbt = hbt;
2104 browser->env = env;
2105 browser->title = perf_evsel_browser_title;
2106 }
2107 return browser;
2108}
2109
Jiri Olsadabd2012016-06-20 23:58:14 +02002110void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002111{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002112 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002113}
2114
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002115static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002116{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002117 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002118}
2119
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002120static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002121{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002122 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002123}
2124
Taeung Song1e378eb2014-10-07 16:13:15 +09002125/* Check whether the browser is for 'top' or 'report' */
2126static inline bool is_report_browser(void *timer)
2127{
2128 return timer == NULL;
2129}
2130
Jiri Olsa5b91a862016-06-20 23:58:15 +02002131static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002132 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002133{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002134 struct hist_browser_timer *hbt = browser->hbt;
2135 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002136 char unit;
2137 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002138 const struct dso *dso = hists->dso_filter;
2139 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002140 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002141 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2142 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002143 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002144 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002145 char buf[512];
2146 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002147 char ref[30] = " show reference callgraph, ";
2148 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002149
Namhyung Kimf2148332014-01-14 11:52:48 +09002150 if (symbol_conf.filter_relative) {
2151 nr_samples = hists->stats.nr_non_filtered_samples;
2152 nr_events = hists->stats.total_non_filtered_period;
2153 }
2154
Namhyung Kim759ff492013-03-05 14:53:26 +09002155 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002156 struct perf_evsel *pos;
2157
2158 perf_evsel__group_desc(evsel, buf, buflen);
2159 ev_name = buf;
2160
2161 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002162 struct hists *pos_hists = evsel__hists(pos);
2163
Namhyung Kimf2148332014-01-14 11:52:48 +09002164 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002165 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2166 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002167 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002168 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2169 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002170 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002171 }
2172 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002173
Kan Liang9e207dd2015-08-11 06:30:49 -04002174 if (symbol_conf.show_ref_callgraph &&
2175 strstr(ev_name, "call-graph=no"))
2176 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002177 nr_samples = convert_unit(nr_samples, &unit);
2178 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002179 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2180 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002181
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002182
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002183 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002184 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002185 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002186 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002187 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002188 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002189 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002190 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002191 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002192 } else {
2193 printed += scnprintf(bf + printed, size - printed,
2194 ", Thread: %s",
2195 (thread->comm_set ? thread__comm_str(thread) : ""));
2196 }
2197 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002198 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002199 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002200 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002201 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002202 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002203 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002204 if (!is_report_browser(hbt)) {
2205 struct perf_top *top = hbt->arg;
2206
2207 if (top->zero)
2208 printed += scnprintf(bf + printed, size - printed, " [z]");
2209 }
2210
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002211 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002212}
2213
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002214static inline void free_popup_options(char **options, int n)
2215{
2216 int i;
2217
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002218 for (i = 0; i < n; ++i)
2219 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002220}
2221
Feng Tang341487ab2013-02-03 14:38:20 +08002222/*
2223 * Only runtime switching of perf data file will make "input_name" point
2224 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2225 * whether we need to call free() for current "input_name" during the switch.
2226 */
2227static bool is_input_name_malloced = false;
2228
2229static int switch_data_file(void)
2230{
2231 char *pwd, *options[32], *abs_path[32], *tmp;
2232 DIR *pwd_dir;
2233 int nr_options = 0, choice = -1, ret = -1;
2234 struct dirent *dent;
2235
2236 pwd = getenv("PWD");
2237 if (!pwd)
2238 return ret;
2239
2240 pwd_dir = opendir(pwd);
2241 if (!pwd_dir)
2242 return ret;
2243
2244 memset(options, 0, sizeof(options));
2245 memset(options, 0, sizeof(abs_path));
2246
2247 while ((dent = readdir(pwd_dir))) {
2248 char path[PATH_MAX];
2249 u64 magic;
2250 char *name = dent->d_name;
2251 FILE *file;
2252
2253 if (!(dent->d_type == DT_REG))
2254 continue;
2255
2256 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2257
2258 file = fopen(path, "r");
2259 if (!file)
2260 continue;
2261
2262 if (fread(&magic, 1, 8, file) < 8)
2263 goto close_file_and_continue;
2264
2265 if (is_perf_magic(magic)) {
2266 options[nr_options] = strdup(name);
2267 if (!options[nr_options])
2268 goto close_file_and_continue;
2269
2270 abs_path[nr_options] = strdup(path);
2271 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002272 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002273 ui__warning("Can't search all data files due to memory shortage.\n");
2274 fclose(file);
2275 break;
2276 }
2277
2278 nr_options++;
2279 }
2280
2281close_file_and_continue:
2282 fclose(file);
2283 if (nr_options >= 32) {
2284 ui__warning("Too many perf data files in PWD!\n"
2285 "Only the first 32 files will be listed.\n");
2286 break;
2287 }
2288 }
2289 closedir(pwd_dir);
2290
2291 if (nr_options) {
2292 choice = ui__popup_menu(nr_options, options);
2293 if (choice < nr_options && choice >= 0) {
2294 tmp = strdup(abs_path[choice]);
2295 if (tmp) {
2296 if (is_input_name_malloced)
2297 free((void *)input_name);
2298 input_name = tmp;
2299 is_input_name_malloced = true;
2300 ret = 0;
2301 } else
2302 ui__warning("Data switch failed due to memory shortage!\n");
2303 }
2304 }
2305
2306 free_popup_options(options, nr_options);
2307 free_popup_options(abs_path, nr_options);
2308 return ret;
2309}
2310
Namhyung Kimea7cd592015-04-22 16:18:19 +09002311struct popup_action {
2312 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002313 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002314 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002315
2316 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2317};
2318
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002319static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002320do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002321{
2322 struct perf_evsel *evsel;
2323 struct annotation *notes;
2324 struct hist_entry *he;
2325 int err;
2326
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002327 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002328 return 0;
2329
Namhyung Kimea7cd592015-04-22 16:18:19 +09002330 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002331 if (!notes->src)
2332 return 0;
2333
2334 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002335 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002336 he = hist_browser__selected_entry(browser);
2337 /*
2338 * offer option to annotate the other branch source or target
2339 * (if they exists) when returning from annotate
2340 */
2341 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2342 return 1;
2343
2344 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2345 if (err)
2346 ui_browser__handle_resize(&browser->b);
2347 return 0;
2348}
2349
2350static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002351add_annotate_opt(struct hist_browser *browser __maybe_unused,
2352 struct popup_action *act, char **optstr,
2353 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002354{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002355 if (sym == NULL || map->dso->annotate_warned)
2356 return 0;
2357
2358 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2359 return 0;
2360
2361 act->ms.map = map;
2362 act->ms.sym = sym;
2363 act->fn = do_annotate;
2364 return 1;
2365}
2366
2367static int
2368do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2369{
2370 struct thread *thread = act->thread;
2371
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002372 if ((!hists__has(browser->hists, thread) &&
2373 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002374 return 0;
2375
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002376 if (browser->hists->thread_filter) {
2377 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2378 perf_hpp__set_elide(HISTC_THREAD, false);
2379 thread__zput(browser->hists->thread_filter);
2380 ui_helpline__pop();
2381 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002382 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002383 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2384 thread->comm_set ? thread__comm_str(thread) : "",
2385 thread->tid);
2386 } else {
2387 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2388 thread->comm_set ? thread__comm_str(thread) : "");
2389 }
2390
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002391 browser->hists->thread_filter = thread__get(thread);
2392 perf_hpp__set_elide(HISTC_THREAD, false);
2393 pstack__push(browser->pstack, &browser->hists->thread_filter);
2394 }
2395
2396 hists__filter_by_thread(browser->hists);
2397 hist_browser__reset(browser);
2398 return 0;
2399}
2400
2401static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002402add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2403 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002404{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002405 int ret;
2406
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002407 if ((!hists__has(browser->hists, thread) &&
2408 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002409 return 0;
2410
Jiri Olsafa829112016-05-03 13:54:47 +02002411 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002412 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2413 browser->hists->thread_filter ? "out of" : "into",
2414 thread->comm_set ? thread__comm_str(thread) : "",
2415 thread->tid);
2416 } else {
2417 ret = asprintf(optstr, "Zoom %s %s thread",
2418 browser->hists->thread_filter ? "out of" : "into",
2419 thread->comm_set ? thread__comm_str(thread) : "");
2420 }
2421 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002422 return 0;
2423
2424 act->thread = thread;
2425 act->fn = do_zoom_thread;
2426 return 1;
2427}
2428
2429static int
2430do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2431{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002432 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002433
Jiri Olsa69849fc2016-05-03 13:54:45 +02002434 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002435 return 0;
2436
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002437 if (browser->hists->dso_filter) {
2438 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2439 perf_hpp__set_elide(HISTC_DSO, false);
2440 browser->hists->dso_filter = NULL;
2441 ui_helpline__pop();
2442 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002443 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002444 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2445 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002446 perf_hpp__set_elide(HISTC_DSO, true);
2447 pstack__push(browser->pstack, &browser->hists->dso_filter);
2448 }
2449
2450 hists__filter_by_dso(browser->hists);
2451 hist_browser__reset(browser);
2452 return 0;
2453}
2454
2455static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002456add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002457 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002458{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002459 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002460 return 0;
2461
2462 if (asprintf(optstr, "Zoom %s %s DSO",
2463 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002464 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002465 return 0;
2466
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002467 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002468 act->fn = do_zoom_dso;
2469 return 1;
2470}
2471
2472static int
2473do_browse_map(struct hist_browser *browser __maybe_unused,
2474 struct popup_action *act)
2475{
2476 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002477 return 0;
2478}
2479
2480static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002481add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002482 struct popup_action *act, char **optstr, struct map *map)
2483{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002484 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002485 return 0;
2486
2487 if (asprintf(optstr, "Browse map details") < 0)
2488 return 0;
2489
2490 act->ms.map = map;
2491 act->fn = do_browse_map;
2492 return 1;
2493}
2494
2495static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002496do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002497 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002498{
2499 char script_opt[64];
2500 memset(script_opt, 0, sizeof(script_opt));
2501
Namhyung Kimea7cd592015-04-22 16:18:19 +09002502 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002503 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002504 thread__comm_str(act->thread));
2505 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002506 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002507 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002508 }
2509
2510 script_browse(script_opt);
2511 return 0;
2512}
2513
2514static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002515add_script_opt(struct hist_browser *browser __maybe_unused,
2516 struct popup_action *act, char **optstr,
2517 struct thread *thread, struct symbol *sym)
2518{
2519 if (thread) {
2520 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2521 thread__comm_str(thread)) < 0)
2522 return 0;
2523 } else if (sym) {
2524 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2525 sym->name) < 0)
2526 return 0;
2527 } else {
2528 if (asprintf(optstr, "Run scripts for all samples") < 0)
2529 return 0;
2530 }
2531
2532 act->thread = thread;
2533 act->ms.sym = sym;
2534 act->fn = do_run_script;
2535 return 1;
2536}
2537
2538static int
2539do_switch_data(struct hist_browser *browser __maybe_unused,
2540 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002541{
2542 if (switch_data_file()) {
2543 ui__warning("Won't switch the data files due to\n"
2544 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002545 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002546 }
2547
2548 return K_SWITCH_INPUT_DATA;
2549}
2550
Namhyung Kimea7cd592015-04-22 16:18:19 +09002551static int
2552add_switch_opt(struct hist_browser *browser,
2553 struct popup_action *act, char **optstr)
2554{
2555 if (!is_report_browser(browser->hbt))
2556 return 0;
2557
2558 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2559 return 0;
2560
2561 act->fn = do_switch_data;
2562 return 1;
2563}
2564
2565static int
2566do_exit_browser(struct hist_browser *browser __maybe_unused,
2567 struct popup_action *act __maybe_unused)
2568{
2569 return 0;
2570}
2571
2572static int
2573add_exit_opt(struct hist_browser *browser __maybe_unused,
2574 struct popup_action *act, char **optstr)
2575{
2576 if (asprintf(optstr, "Exit") < 0)
2577 return 0;
2578
2579 act->fn = do_exit_browser;
2580 return 1;
2581}
2582
Kan Liang84734b02015-09-04 10:45:45 -04002583static int
2584do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2585{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002586 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002587 return 0;
2588
Kan Liang84734b02015-09-04 10:45:45 -04002589 if (browser->hists->socket_filter > -1) {
2590 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2591 browser->hists->socket_filter = -1;
2592 perf_hpp__set_elide(HISTC_SOCKET, false);
2593 } else {
2594 browser->hists->socket_filter = act->socket;
2595 perf_hpp__set_elide(HISTC_SOCKET, true);
2596 pstack__push(browser->pstack, &browser->hists->socket_filter);
2597 }
2598
2599 hists__filter_by_socket(browser->hists);
2600 hist_browser__reset(browser);
2601 return 0;
2602}
2603
2604static int
2605add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2606 char **optstr, int socket_id)
2607{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002608 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002609 return 0;
2610
2611 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2612 (browser->hists->socket_filter > -1) ? "out of" : "into",
2613 socket_id) < 0)
2614 return 0;
2615
2616 act->socket = socket_id;
2617 act->fn = do_zoom_socket;
2618 return 1;
2619}
2620
Namhyung Kim112f7612014-04-22 14:05:35 +09002621static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002622{
2623 u64 nr_entries = 0;
2624 struct rb_node *nd = rb_first(&hb->hists->entries);
2625
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002626 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002627 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2628 return;
2629 }
2630
Namhyung Kim14135662013-10-31 10:17:39 +09002631 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002632 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002633 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002634 }
2635
Namhyung Kim112f7612014-04-22 14:05:35 +09002636 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002637 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002638}
Feng Tang341487ab2013-02-03 14:38:20 +08002639
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002640static void hist_browser__update_percent_limit(struct hist_browser *hb,
2641 double percent)
2642{
2643 struct hist_entry *he;
2644 struct rb_node *nd = rb_first(&hb->hists->entries);
2645 u64 total = hists__total_period(hb->hists);
2646 u64 min_callchain_hits = total * (percent / 100);
2647
2648 hb->min_pcnt = callchain_param.min_percent = percent;
2649
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002650 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2651 he = rb_entry(nd, struct hist_entry, rb_node);
2652
Namhyung Kim79dded82016-02-26 21:13:19 +09002653 if (he->has_no_entry) {
2654 he->has_no_entry = false;
2655 he->nr_rows = 0;
2656 }
2657
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002658 if (!he->leaf || !symbol_conf.use_callchain)
2659 goto next;
2660
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002661 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2662 total = he->stat.period;
2663
2664 if (symbol_conf.cumulate_callchain)
2665 total = he->stat_acc->period;
2666
2667 min_callchain_hits = total * (percent / 100);
2668 }
2669
2670 callchain_param.sort(&he->sorted_chain, he->callchain,
2671 min_callchain_hits, &callchain_param);
2672
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002673next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002674 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002675
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002676 /* force to re-evaluate folding state of callchains */
2677 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002678 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002679 }
2680}
2681
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002682static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002683 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002684 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002685 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002686 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002687 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002688{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002689 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002690 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002691 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002692#define MAX_OPTIONS 16
2693 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002694 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002695 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002696 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002697 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002698 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002699
Namhyung Kime8e684a2013-12-26 14:37:58 +09002700#define HIST_BROWSER_HELP_COMMON \
2701 "h/?/F1 Show this window\n" \
2702 "UP/DOWN/PGUP\n" \
2703 "PGDN/SPACE Navigate\n" \
2704 "q/ESC/CTRL+C Exit browser\n\n" \
2705 "For multiple event sessions:\n\n" \
2706 "TAB/UNTAB Switch events\n\n" \
2707 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002708 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2709 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002710 "a Annotate current symbol\n" \
2711 "C Collapse all callchains\n" \
2712 "d Zoom into current DSO\n" \
2713 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002714 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002715 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002716 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002717 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002718 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002719
2720 /* help messages are sorted by lexical order of the hotkey */
2721 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002722 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002723 "P Print histograms to perf.hist.N\n"
2724 "r Run available scripts\n"
2725 "s Switch to another data file in PWD\n"
2726 "t Zoom into current Thread\n"
2727 "V Verbose (DSO names in callchains, etc)\n"
2728 "/ Filter symbol by name";
2729 const char top_help[] = HIST_BROWSER_HELP_COMMON
2730 "P Print histograms to perf.hist.N\n"
2731 "t Zoom into current Thread\n"
2732 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002733 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002734 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002735 "/ Filter symbol by name";
2736
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002737 if (browser == NULL)
2738 return -1;
2739
Namhyung Kimed426912015-05-29 21:53:44 +09002740 /* reset abort key so that it can get Ctrl-C as a key */
2741 SLang_reset_tty();
2742 SLang_init_tty(0, 0, 0);
2743
Namhyung Kim03905042015-11-28 02:32:39 +09002744 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002745 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002746 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002747
Kan Liang84734b02015-09-04 10:45:45 -04002748 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002749 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002750 goto out;
2751
2752 ui_helpline__push(helpline);
2753
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002754 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002755 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002756
Namhyung Kim5b591662014-07-31 14:47:38 +09002757 if (symbol_conf.col_width_list_str)
2758 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2759
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002760 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002761 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002762 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002763 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002764 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002765
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002766 nr_options = 0;
2767
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002768 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002769
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002770 if (browser->he_selection != NULL) {
2771 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002772 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002773 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002774 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002775 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002776 case K_TAB:
2777 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002778 if (nr_events == 1)
2779 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002780 /*
2781 * Exit the browser, let hists__browser_tree
2782 * go to the next or previous
2783 */
2784 goto out_free_stack;
2785 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002786 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002787 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002788 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002789 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002790 continue;
2791 }
2792
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002793 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002794 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002795 browser->selection->map->dso->annotate_warned)
2796 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002797
Namhyung Kimea7cd592015-04-22 16:18:19 +09002798 actions->ms.map = browser->selection->map;
2799 actions->ms.sym = browser->selection->sym;
2800 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002801 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002802 case 'P':
2803 hist_browser__dump(browser);
2804 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002805 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002806 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002807 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002808 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002809 case 'V':
2810 browser->show_dso = !browser->show_dso;
2811 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002812 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002813 actions->thread = thread;
2814 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002815 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002816 case 'S':
2817 actions->socket = socked_id;
2818 do_zoom_socket(browser, actions);
2819 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002820 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002821 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002822 "Please enter the name of symbol you want to see.\n"
2823 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002824 buf, "ENTER: OK, ESC: Cancel",
2825 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002826 hists->symbol_filter_str = *buf ? buf : NULL;
2827 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002828 hist_browser__reset(browser);
2829 }
2830 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002831 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002832 if (is_report_browser(hbt)) {
2833 actions->thread = NULL;
2834 actions->ms.sym = NULL;
2835 do_run_script(browser, actions);
2836 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002837 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002838 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002839 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002840 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002841 if (key == K_SWITCH_INPUT_DATA)
2842 goto out_free_stack;
2843 }
Feng Tang341487ab2013-02-03 14:38:20 +08002844 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002845 case 'i':
2846 /* env->arch is NULL for live-mode (i.e. perf top) */
2847 if (env->arch)
2848 tui__header_window(env);
2849 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002850 case 'F':
2851 symbol_conf.filter_relative ^= 1;
2852 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002853 case 'z':
2854 if (!is_report_browser(hbt)) {
2855 struct perf_top *top = hbt->arg;
2856
2857 top->zero = !top->zero;
2858 }
2859 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002860 case 'L':
2861 if (ui_browser__input_window("Percent Limit",
2862 "Please enter the value you want to hide entries under that percent.",
2863 buf, "ENTER: OK, ESC: Cancel",
2864 delay_secs * 2) == K_ENTER) {
2865 char *end;
2866 double new_percent = strtod(buf, &end);
2867
2868 if (new_percent < 0 || new_percent > 100) {
2869 ui_browser__warning(&browser->b, delay_secs * 2,
2870 "Invalid percent: %.2f", new_percent);
2871 continue;
2872 }
2873
2874 hist_browser__update_percent_limit(browser, new_percent);
2875 hist_browser__reset(browser);
2876 }
2877 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002878 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002879 case 'h':
2880 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002881 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002882 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002883 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002884 case K_ENTER:
2885 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002886 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002887 /* menu */
2888 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002889 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002890 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002891 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002892
Namhyung Kim01f00a12015-04-22 16:18:16 +09002893 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002894 /*
2895 * Go back to the perf_evsel_menu__run or other user
2896 */
2897 if (left_exits)
2898 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002899
2900 if (key == K_ESC &&
2901 ui_browser__dialog_yesno(&browser->b,
2902 "Do you really want to exit?"))
2903 goto out_free_stack;
2904
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002905 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002906 }
Namhyung Kim64221842015-04-24 10:15:33 +09002907 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002908 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002909 /*
2910 * No need to set actions->dso here since
2911 * it's just to remove the current filter.
2912 * Ditto for thread below.
2913 */
2914 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002915 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002916 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002917 } else if (top == &browser->hists->socket_filter) {
2918 do_zoom_socket(browser, actions);
2919 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002920 continue;
2921 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002922 case 'q':
2923 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002924 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002925 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002926 if (!is_report_browser(hbt)) {
2927 struct perf_top *top = hbt->arg;
2928
2929 perf_evlist__toggle_enable(top->evlist);
2930 /*
2931 * No need to refresh, resort/decay histogram
2932 * entries if we are not collecting samples:
2933 */
2934 if (top->evlist->enabled) {
2935 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2936 hbt->refresh = delay_secs;
2937 } else {
2938 helpline = "Press 'f' again to re-enable the events";
2939 hbt->refresh = 0;
2940 }
2941 continue;
2942 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002943 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002944 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002945 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002946 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002947 }
2948
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002949 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002950 goto skip_annotation;
2951
Namhyung Kim55369fc2013-04-01 20:35:20 +09002952 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002953 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002954
2955 if (bi == NULL)
2956 goto skip_annotation;
2957
Namhyung Kimea7cd592015-04-22 16:18:19 +09002958 nr_options += add_annotate_opt(browser,
2959 &actions[nr_options],
2960 &options[nr_options],
2961 bi->from.map,
2962 bi->from.sym);
2963 if (bi->to.sym != bi->from.sym)
2964 nr_options += add_annotate_opt(browser,
2965 &actions[nr_options],
2966 &options[nr_options],
2967 bi->to.map,
2968 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002969 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002970 nr_options += add_annotate_opt(browser,
2971 &actions[nr_options],
2972 &options[nr_options],
2973 browser->selection->map,
2974 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002975 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002976skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002977 nr_options += add_thread_opt(browser, &actions[nr_options],
2978 &options[nr_options], thread);
2979 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002980 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002981 nr_options += add_map_opt(browser, &actions[nr_options],
2982 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002983 browser->selection ?
2984 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002985 nr_options += add_socket_opt(browser, &actions[nr_options],
2986 &options[nr_options],
2987 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002988 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002989 if (!is_report_browser(hbt))
2990 goto skip_scripting;
2991
Feng Tangcdbab7c2012-10-30 11:56:06 +08002992 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02002993 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002994 nr_options += add_script_opt(browser,
2995 &actions[nr_options],
2996 &options[nr_options],
2997 thread, NULL);
2998 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002999 /*
3000 * Note that browser->selection != NULL
3001 * when browser->he_selection is not NULL,
3002 * so we don't need to check browser->selection
3003 * before fetching browser->selection->sym like what
3004 * we do before fetching browser->selection->map.
3005 *
3006 * See hist_browser__show_entry.
3007 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003008 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003009 nr_options += add_script_opt(browser,
3010 &actions[nr_options],
3011 &options[nr_options],
3012 NULL, browser->selection->sym);
3013 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003014 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003015 nr_options += add_script_opt(browser, &actions[nr_options],
3016 &options[nr_options], NULL, NULL);
3017 nr_options += add_switch_opt(browser, &actions[nr_options],
3018 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003019skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003020 nr_options += add_exit_opt(browser, &actions[nr_options],
3021 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003022
Namhyung Kimea7cd592015-04-22 16:18:19 +09003023 do {
3024 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003025
Namhyung Kimea7cd592015-04-22 16:18:19 +09003026 choice = ui__popup_menu(nr_options, options);
3027 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003028 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003029
3030 act = &actions[choice];
3031 key = act->fn(browser, act);
3032 } while (key == 1);
3033
3034 if (key == K_SWITCH_INPUT_DATA)
3035 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003036 }
3037out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003038 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003039out:
3040 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003041 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003042 return key;
3043}
3044
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003045struct perf_evsel_menu {
3046 struct ui_browser b;
3047 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003048 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003049 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003050 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003051};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003052
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003053static void perf_evsel_menu__write(struct ui_browser *browser,
3054 void *entry, int row)
3055{
3056 struct perf_evsel_menu *menu = container_of(browser,
3057 struct perf_evsel_menu, b);
3058 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003059 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003060 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003061 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003062 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003063 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003064 const char *warn = " ";
3065 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003066
3067 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3068 HE_COLORSET_NORMAL);
3069
Namhyung Kim759ff492013-03-05 14:53:26 +09003070 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003071 struct perf_evsel *pos;
3072
3073 ev_name = perf_evsel__group_name(evsel);
3074
3075 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003076 struct hists *pos_hists = evsel__hists(pos);
3077 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003078 }
3079 }
3080
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003081 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003082 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003083 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003084 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003085
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003086 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003087 if (nr_events != 0) {
3088 menu->lost_events = true;
3089 if (!current_entry)
3090 ui_browser__set_color(browser, HE_COLORSET_TOP);
3091 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003092 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3093 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003094 warn = bf;
3095 }
3096
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003097 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003098
3099 if (current_entry)
3100 menu->selection = evsel;
3101}
3102
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003103static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3104 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003105 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003106{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003107 struct perf_evlist *evlist = menu->b.priv;
3108 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003109 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003110 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003111 int key;
3112
3113 if (ui_browser__show(&menu->b, title,
3114 "ESC: exit, ENTER|->: Browse histograms") < 0)
3115 return -1;
3116
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003117 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003118 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003119
3120 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003121 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003122 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003123
3124 if (!menu->lost_events_warned && menu->lost_events) {
3125 ui_browser__warn_lost_events(&menu->b);
3126 menu->lost_events_warned = true;
3127 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003128 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003129 case K_RIGHT:
3130 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003131 if (!menu->selection)
3132 continue;
3133 pos = menu->selection;
3134browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003135 perf_evlist__set_selected(evlist, pos);
3136 /*
3137 * Give the calling tool a chance to populate the non
3138 * default evsel resorted hists tree.
3139 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003140 if (hbt)
3141 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003142 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003143 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003144 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003145 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003146 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003147 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003148 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003149 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003150 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003151 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003152 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003153 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003154 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003155 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003156 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003157 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003158 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003159 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003160 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003161 case 'q':
3162 case CTRL('c'):
3163 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003164 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003165 default:
3166 continue;
3167 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003168 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003169 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003170 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003171 if (!ui_browser__dialog_yesno(&menu->b,
3172 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003173 continue;
3174 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003175 case 'q':
3176 case CTRL('c'):
3177 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003178 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003179 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003180 }
3181 }
3182
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003183out:
3184 ui_browser__hide(&menu->b);
3185 return key;
3186}
3187
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003188static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003189 void *entry)
3190{
3191 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3192
3193 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3194 return true;
3195
3196 return false;
3197}
3198
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003199static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003200 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003201 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003202 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003203 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003204{
3205 struct perf_evsel *pos;
3206 struct perf_evsel_menu menu = {
3207 .b = {
3208 .entries = &evlist->entries,
3209 .refresh = ui_browser__list_head_refresh,
3210 .seek = ui_browser__list_head_seek,
3211 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003212 .filter = filter_group_entries,
3213 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003214 .priv = evlist,
3215 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003216 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003217 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003218 };
3219
3220 ui_helpline__push("Press ESC to exit");
3221
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003222 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003223 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003224 size_t line_len = strlen(ev_name) + 7;
3225
3226 if (menu.b.width < line_len)
3227 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003228 }
3229
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003230 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003231}
3232
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003233int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003234 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003235 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003236 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003237{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003238 int nr_entries = evlist->nr_entries;
3239
3240single_entry:
3241 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003242 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003243
3244 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003245 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003246 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003247 }
3248
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003249 if (symbol_conf.event_group) {
3250 struct perf_evsel *pos;
3251
3252 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003253 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003254 if (perf_evsel__is_group_leader(pos))
3255 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003256 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003257
3258 if (nr_entries == 1)
3259 goto single_entry;
3260 }
3261
3262 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003263 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003264}