blob: 0916575c6694edf2e1a2c3949bb188b9e0df0f47 [file] [log] [blame]
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03001#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03002#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <stdlib.h>
5#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03006#include <linux/rbtree.h>
7
Namhyung Kimaca7a942012-04-04 00:14:26 -07008#include "../../util/evsel.h"
9#include "../../util/evlist.h"
10#include "../../util/hist.h"
11#include "../../util/pstack.h"
12#include "../../util/sort.h"
13#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090014#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090015#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030016
Jiri Olsaf7589902016-06-20 23:58:13 +020017#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030018#include "../helpline.h"
19#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020020#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020022#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030023#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030024#include "string2.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030025
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030026#include "sane_ctype.h"
27
Namhyung Kimf5951d52012-09-03 11:53:09 +090028extern void hist_browser__init_hpp(void);
29
Jiri Olsa5b91a862016-06-20 23:58:15 +020030static int perf_evsel_browser_title(struct hist_browser *browser,
31 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090032static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030033
Namhyung Kimc3b78952014-04-22 15:56:17 +090034static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090035 float min_pcnt);
36
Namhyung Kim268397c2014-04-22 14:49:31 +090037static bool hist_browser__has_filter(struct hist_browser *hb)
38{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010039 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090040}
41
He Kuang4fabf3d2015-03-12 15:21:49 +080042static int hist_browser__get_folding(struct hist_browser *browser)
43{
44 struct rb_node *nd;
45 struct hists *hists = browser->hists;
46 int unfolded_rows = 0;
47
48 for (nd = rb_first(&hists->entries);
49 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090050 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080051 struct hist_entry *he =
52 rb_entry(nd, struct hist_entry, rb_node);
53
Namhyung Kimf5b763f2016-02-25 00:13:43 +090054 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080055 unfolded_rows += he->nr_rows;
56 }
57 return unfolded_rows;
58}
59
Namhyung Kimc3b78952014-04-22 15:56:17 +090060static u32 hist_browser__nr_entries(struct hist_browser *hb)
61{
62 u32 nr_entries;
63
Namhyung Kimf5b763f2016-02-25 00:13:43 +090064 if (symbol_conf.report_hierarchy)
65 nr_entries = hb->nr_hierarchy_entries;
66 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090067 nr_entries = hb->nr_non_filtered_entries;
68 else
69 nr_entries = hb->hists->nr_entries;
70
He Kuang4fabf3d2015-03-12 15:21:49 +080071 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090072 return nr_entries + hb->nr_callchain_rows;
73}
74
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020075static void hist_browser__update_rows(struct hist_browser *hb)
76{
77 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020078 struct hists *hists = hb->hists;
79 struct perf_hpp_list *hpp_list = hists->hpp_list;
80 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020081
Jiri Olsaf8e67102016-08-07 17:28:26 +020082 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020083 browser->rows = browser->height - header_offset;
84 /*
85 * Verify if we were at the last line and that line isn't
86 * visibe because we now show the header line(s).
87 */
88 index_row = browser->index - browser->top_idx;
89 if (index_row >= browser->rows)
90 browser->index -= index_row - browser->rows + 1;
91}
92
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030093static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030094{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030095 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
96
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030097 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030098 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
99 /*
100 * FIXME: Just keeping existing behaviour, but this really should be
101 * before updating browser->width, as it will invalidate the
102 * calculation above. Fix this and the fallout in another
103 * changeset.
104 */
105 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200106 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300107}
108
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300109static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
110{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200111 struct hists *hists = browser->hists;
112 struct perf_hpp_list *hpp_list = hists->hpp_list;
113 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200114
Jiri Olsaf8e67102016-08-07 17:28:26 +0200115 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200116 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300117}
118
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300119static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300120{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900121 /*
122 * The hists__remove_entry_filter() already folds non-filtered
123 * entries so we can assume it has 0 callchain rows.
124 */
125 browser->nr_callchain_rows = 0;
126
Namhyung Kim268397c2014-04-22 14:49:31 +0900127 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900128 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300129 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300130 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300131}
132
133static char tree__folded_sign(bool unfolded)
134{
135 return unfolded ? '-' : '+';
136}
137
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300138static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300139{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900140 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300141}
142
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300143static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900145 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300146}
147
Namhyung Kim3698dab2015-05-05 23:55:46 +0900148static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300149{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900150 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300151}
152
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800153static struct inline_node *inline_node__create(struct map *map, u64 ip)
154{
155 struct dso *dso;
156 struct inline_node *node;
157
158 if (map == NULL)
159 return NULL;
160
161 dso = map->dso;
162 if (dso == NULL)
163 return NULL;
164
165 if (dso->kernel != DSO_TYPE_USER)
166 return NULL;
167
168 node = dso__parse_addr_inlines(dso,
169 map__rip_2objdump(map, ip));
170
171 return node;
172}
173
174static int inline__count_rows(struct inline_node *node)
175{
176 struct inline_list *ilist;
177 int i = 0;
178
179 if (node == NULL)
180 return 0;
181
182 list_for_each_entry(ilist, &node->val, list) {
183 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
184 i++;
185 }
186
187 return i;
188}
189
190static int callchain_list__inline_rows(struct callchain_list *chain)
191{
192 struct inline_node *node;
193 int rows;
194
195 node = inline_node__create(chain->ms.map, chain->ip);
196 if (node == NULL)
197 return 0;
198
199 rows = inline__count_rows(node);
200 inline_node__delete(node);
201 return rows;
202}
203
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300204static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300205{
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800206 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300207 struct rb_node *nd;
208
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300209 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300210 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
211 struct callchain_list *chain;
212 char folded_sign = ' '; /* No children */
213
214 list_for_each_entry(chain, &child->val, list) {
215 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800216
217 if (symbol_conf.inline_name) {
218 inline_rows =
219 callchain_list__inline_rows(chain);
220 n += inline_rows;
221 }
222
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300223 /* We need this because we may not have children */
224 folded_sign = callchain_list__folded(chain);
225 if (folded_sign == '+')
226 break;
227 }
228
229 if (folded_sign == '-') /* Have children and they're unfolded */
230 n += callchain_node__count_rows_rb_tree(child);
231 }
232
233 return n;
234}
235
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900236static int callchain_node__count_flat_rows(struct callchain_node *node)
237{
238 struct callchain_list *chain;
239 char folded_sign = 0;
240 int n = 0;
241
242 list_for_each_entry(chain, &node->parent_val, list) {
243 if (!folded_sign) {
244 /* only check first chain list entry */
245 folded_sign = callchain_list__folded(chain);
246 if (folded_sign == '+')
247 return 1;
248 }
249 n++;
250 }
251
252 list_for_each_entry(chain, &node->val, list) {
253 if (!folded_sign) {
254 /* node->parent_val list might be empty */
255 folded_sign = callchain_list__folded(chain);
256 if (folded_sign == '+')
257 return 1;
258 }
259 n++;
260 }
261
262 return n;
263}
264
Namhyung Kim8c430a32015-11-09 14:45:44 +0900265static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
266{
267 return 1;
268}
269
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300270static int callchain_node__count_rows(struct callchain_node *node)
271{
272 struct callchain_list *chain;
273 bool unfolded = false;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800274 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300275
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900276 if (callchain_param.mode == CHAIN_FLAT)
277 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900278 else if (callchain_param.mode == CHAIN_FOLDED)
279 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900280
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300281 list_for_each_entry(chain, &node->val, list) {
282 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800283 if (symbol_conf.inline_name) {
284 inline_rows = callchain_list__inline_rows(chain);
285 n += inline_rows;
286 }
287
Namhyung Kim3698dab2015-05-05 23:55:46 +0900288 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300289 }
290
291 if (unfolded)
292 n += callchain_node__count_rows_rb_tree(node);
293
294 return n;
295}
296
297static int callchain__count_rows(struct rb_root *chain)
298{
299 struct rb_node *nd;
300 int n = 0;
301
302 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
303 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
304 n += callchain_node__count_rows(node);
305 }
306
307 return n;
308}
309
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900310static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
311 bool include_children)
312{
313 int count = 0;
314 struct rb_node *node;
315 struct hist_entry *child;
316
317 if (he->leaf)
318 return callchain__count_rows(&he->sorted_chain);
319
Namhyung Kim79dded82016-02-26 21:13:19 +0900320 if (he->has_no_entry)
321 return 1;
322
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900323 node = rb_first(&he->hroot_out);
324 while (node) {
325 float percent;
326
327 child = rb_entry(node, struct hist_entry, rb_node);
328 percent = hist_entry__get_percent_limit(child);
329
330 if (!child->filtered && percent >= hb->min_pcnt) {
331 count++;
332
333 if (include_children && child->unfolded)
334 count += hierarchy_count_rows(hb, child, true);
335 }
336
337 node = rb_next(node);
338 }
339 return count;
340}
341
Namhyung Kim3698dab2015-05-05 23:55:46 +0900342static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300343{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900344 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200345 return false;
346
Namhyung Kim3698dab2015-05-05 23:55:46 +0900347 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300348 return false;
349
Namhyung Kim3698dab2015-05-05 23:55:46 +0900350 he->unfolded = !he->unfolded;
351 return true;
352}
353
354static bool callchain_list__toggle_fold(struct callchain_list *cl)
355{
356 if (!cl)
357 return false;
358
359 if (!cl->has_children)
360 return false;
361
362 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363 return true;
364}
365
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300367{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300369
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300370 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300371 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
372 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300373 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300374
375 list_for_each_entry(chain, &child->val, list) {
376 if (first) {
377 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900378 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300379 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300380 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900381 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300382 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300383 }
384
385 callchain_node__init_have_children_rb_tree(child);
386 }
387}
388
Namhyung Kima7444af2014-11-24 17:13:27 +0900389static void callchain_node__init_have_children(struct callchain_node *node,
390 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300391{
392 struct callchain_list *chain;
393
Namhyung Kima7444af2014-11-24 17:13:27 +0900394 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900395 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900396
Andres Freund90989032016-03-30 21:02:45 +0200397 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900398 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900399 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900400 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300402 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300403}
404
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300405static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300406{
Namhyung Kima7444af2014-11-24 17:13:27 +0900407 struct rb_node *nd = rb_first(root);
408 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300409
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300410 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300411 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900412 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900413 if (callchain_param.mode == CHAIN_FLAT ||
414 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900415 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300416 }
417}
418
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300419static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300420{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900421 if (he->init_have_children)
422 return;
423
424 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900425 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300426 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900427 } else {
428 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300429 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900430
431 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300432}
433
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800434static void hist_entry_init_inline_node(struct hist_entry *he)
435{
436 if (he->inline_node)
437 return;
438
439 he->inline_node = inline_node__create(he->ms.map, he->ip);
440
441 if (he->inline_node == NULL)
442 return;
443
444 he->has_children = true;
445}
446
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300447static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300448{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900449 struct hist_entry *he = browser->he_selection;
450 struct map_symbol *ms = browser->selection;
451 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
452 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300453
Wang Nan4938cf02015-12-07 02:35:44 +0000454 if (!he || !ms)
455 return false;
456
Namhyung Kim3698dab2015-05-05 23:55:46 +0900457 if (ms == &he->ms)
458 has_children = hist_entry__toggle_fold(he);
459 else
460 has_children = callchain_list__toggle_fold(cl);
461
462 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900463 int child_rows = 0;
464
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300465 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900466 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300467
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900468 if (he->leaf)
469 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300470 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900471 browser->nr_hierarchy_entries -= he->nr_rows;
472
473 if (symbol_conf.report_hierarchy)
474 child_rows = hierarchy_count_rows(browser, he, true);
475
476 if (he->unfolded) {
477 if (he->leaf)
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800478 if (he->inline_node)
479 he->nr_rows = inline__count_rows(
480 he->inline_node);
481 else
482 he->nr_rows = callchain__count_rows(
483 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900484 else
485 he->nr_rows = hierarchy_count_rows(browser, he, false);
486
487 /* account grand children */
488 if (symbol_conf.report_hierarchy)
489 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900490
491 if (!he->leaf && he->nr_rows == 0) {
492 he->has_no_entry = true;
493 he->nr_rows = 1;
494 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900495 } else {
496 if (symbol_conf.report_hierarchy)
497 browser->b.nr_entries -= child_rows - he->nr_rows;
498
Namhyung Kim79dded82016-02-26 21:13:19 +0900499 if (he->has_no_entry)
500 he->has_no_entry = false;
501
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300502 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900503 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900504
505 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900506
507 if (he->leaf)
508 browser->nr_callchain_rows += he->nr_rows;
509 else
510 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300511
512 return true;
513 }
514
515 /* If it doesn't have children, no toggling performed */
516 return false;
517}
518
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300519static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300520{
521 int n = 0;
522 struct rb_node *nd;
523
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300524 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300525 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
526 struct callchain_list *chain;
527 bool has_children = false;
528
529 list_for_each_entry(chain, &child->val, list) {
530 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900531 callchain_list__set_folding(chain, unfold);
532 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300533 }
534
535 if (has_children)
536 n += callchain_node__set_folding_rb_tree(child, unfold);
537 }
538
539 return n;
540}
541
542static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
543{
544 struct callchain_list *chain;
545 bool has_children = false;
546 int n = 0;
547
548 list_for_each_entry(chain, &node->val, list) {
549 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900550 callchain_list__set_folding(chain, unfold);
551 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300552 }
553
554 if (has_children)
555 n += callchain_node__set_folding_rb_tree(node, unfold);
556
557 return n;
558}
559
560static int callchain__set_folding(struct rb_root *chain, bool unfold)
561{
562 struct rb_node *nd;
563 int n = 0;
564
565 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
566 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
567 n += callchain_node__set_folding(node, unfold);
568 }
569
570 return n;
571}
572
Namhyung Kim492b1012016-02-25 00:13:44 +0900573static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
574 bool unfold __maybe_unused)
575{
576 float percent;
577 struct rb_node *nd;
578 struct hist_entry *child;
579 int n = 0;
580
581 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
582 child = rb_entry(nd, struct hist_entry, rb_node);
583 percent = hist_entry__get_percent_limit(child);
584 if (!child->filtered && percent >= hb->min_pcnt)
585 n++;
586 }
587
588 return n;
589}
590
Jiri Olsab33f9222017-01-20 10:20:29 +0100591static void __hist_entry__set_folding(struct hist_entry *he,
592 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300593{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300594 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900595 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300596
Namhyung Kim3698dab2015-05-05 23:55:46 +0900597 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900598 int n;
599
600 if (he->leaf)
601 n = callchain__set_folding(&he->sorted_chain, unfold);
602 else
603 n = hierarchy_set_folding(hb, he, unfold);
604
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300605 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300606 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300607 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300608}
609
Jiri Olsab33f9222017-01-20 10:20:29 +0100610static void hist_entry__set_folding(struct hist_entry *he,
611 struct hist_browser *browser, bool unfold)
612{
613 double percent;
614
615 percent = hist_entry__get_percent_limit(he);
616 if (he->filtered || percent < browser->min_pcnt)
617 return;
618
619 __hist_entry__set_folding(he, browser, unfold);
620
621 if (!he->depth || unfold)
622 browser->nr_hierarchy_entries++;
623 if (he->leaf)
624 browser->nr_callchain_rows += he->nr_rows;
625 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
626 browser->nr_hierarchy_entries++;
627 he->has_no_entry = true;
628 he->nr_rows = 1;
629 } else
630 he->has_no_entry = false;
631}
632
Namhyung Kimc3b78952014-04-22 15:56:17 +0900633static void
634__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300635{
636 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900637 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300638
Namhyung Kim492b1012016-02-25 00:13:44 +0900639 nd = rb_first(&browser->hists->entries);
640 while (nd) {
641 he = rb_entry(nd, struct hist_entry, rb_node);
642
643 /* set folding state even if it's currently folded */
644 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
645
646 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300647 }
648}
649
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300650static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300651{
Namhyung Kim492b1012016-02-25 00:13:44 +0900652 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900653 browser->nr_callchain_rows = 0;
654 __hist_browser__set_folding(browser, unfold);
655
656 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300657 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300658 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300659}
660
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100661static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
662{
663 if (!browser->he_selection)
664 return;
665
666 hist_entry__set_folding(browser->he_selection, browser, unfold);
667 browser->b.nr_entries = hist_browser__nr_entries(browser);
668}
669
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200670static void ui_browser__warn_lost_events(struct ui_browser *browser)
671{
672 ui_browser__warning(browser, 4,
673 "Events are being lost, check IO/CPU overload!\n\n"
674 "You may want to run 'perf' using a RT scheduler policy:\n\n"
675 " perf top -r 80\n\n"
676 "Or reduce the sampling frequency.");
677}
678
Jiri Olsa5b91a862016-06-20 23:58:15 +0200679static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
680{
681 return browser->title ? browser->title(browser, bf, size) : 0;
682}
683
Jiri Olsadabd2012016-06-20 23:58:14 +0200684int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300685{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300686 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300687 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900688 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900689 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300690
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300691 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900692 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300693
Jiri Olsa5b91a862016-06-20 23:58:15 +0200694 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300695
Namhyung Kim090cff32016-01-11 19:53:14 +0900696 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300697 return -1;
698
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300699 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300700 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300701
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300702 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900703 case K_TIMER: {
704 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900705 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900706
Namhyung Kimc6111522016-10-07 14:04:12 +0900707 if (hist_browser__has_filter(browser) ||
708 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900709 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900710
Namhyung Kimc3b78952014-04-22 15:56:17 +0900711 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900712 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200713
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300714 if (browser->hists->stats.nr_lost_warned !=
715 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
716 browser->hists->stats.nr_lost_warned =
717 browser->hists->stats.nr_events[PERF_RECORD_LOST];
718 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200719 }
720
Jiri Olsa5b91a862016-06-20 23:58:15 +0200721 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300722 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300723 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900724 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300725 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300726 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300727 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300728 struct hist_entry, rb_node);
729 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300730 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 -0300731 seq++, browser->b.nr_entries,
732 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300733 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300734 browser->b.index,
735 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300736 h->row_offset, h->nr_rows);
737 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300738 break;
739 case 'C':
740 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300741 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300742 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100743 case 'c':
744 /* Collapse the selected entry. */
745 hist_browser__set_folding_selected(browser, false);
746 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300747 case 'E':
748 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300749 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300750 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100751 case 'e':
752 /* Expand the selected entry. */
753 hist_browser__set_folding_selected(browser, true);
754 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200755 case 'H':
756 browser->show_headers = !browser->show_headers;
757 hist_browser__update_rows(browser);
758 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200759 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300760 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300761 break;
762 /* fall thru */
763 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300764 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300765 }
766 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300767out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300768 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300769 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300770}
771
Namhyung Kim39ee5332014-08-22 09:13:21 +0900772struct callchain_print_arg {
773 /* for hists browser */
774 off_t row_offset;
775 bool is_current_entry;
776
777 /* for file dump */
778 FILE *fp;
779 int printed;
780};
781
782typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
783 struct callchain_list *chain,
784 const char *str, int offset,
785 unsigned short row,
786 struct callchain_print_arg *arg);
787
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900788static void hist_browser__show_callchain_entry(struct hist_browser *browser,
789 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900790 const char *str, int offset,
791 unsigned short row,
792 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900793{
794 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900795 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300796 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900797
798 color = HE_COLORSET_NORMAL;
799 width = browser->b.width - (offset + 2);
800 if (ui_browser__is_current_entry(&browser->b, row)) {
801 browser->selection = &chain->ms;
802 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900803 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900804 }
805
806 ui_browser__set_color(&browser->b, color);
807 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300808 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300809 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300810 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300811 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900812}
813
Namhyung Kim39ee5332014-08-22 09:13:21 +0900814static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
815 struct callchain_list *chain,
816 const char *str, int offset,
817 unsigned short row __maybe_unused,
818 struct callchain_print_arg *arg)
819{
820 char folded_sign = callchain_list__folded(chain);
821
822 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
823 folded_sign, str);
824}
825
826typedef bool (*check_output_full_fn)(struct hist_browser *browser,
827 unsigned short row);
828
829static bool hist_browser__check_output_full(struct hist_browser *browser,
830 unsigned short row)
831{
832 return browser->b.rows == row;
833}
834
835static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
836 unsigned short row __maybe_unused)
837{
838 return false;
839}
840
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300841#define LEVEL_OFFSET_STEP 3
842
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800843static int hist_browser__show_inline(struct hist_browser *browser,
844 struct inline_node *node,
845 unsigned short row,
846 int offset)
847{
848 struct inline_list *ilist;
849 char buf[1024];
850 int color, width, first_row;
851
852 first_row = row;
853 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
854 list_for_each_entry(ilist, &node->val, list) {
855 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
856 color = HE_COLORSET_NORMAL;
857 if (ui_browser__is_current_entry(&browser->b, row))
858 color = HE_COLORSET_SELECTED;
859
Milian Wolff5dfa2102017-03-18 22:49:28 +0100860 if (callchain_param.key == CCKEY_ADDRESS ||
861 callchain_param.key == CCKEY_SRCLINE) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800862 if (ilist->filename != NULL)
863 scnprintf(buf, sizeof(buf),
864 "%s:%d (inline)",
865 ilist->filename,
866 ilist->line_nr);
867 else
868 scnprintf(buf, sizeof(buf), "??");
869 } else if (ilist->funcname != NULL)
870 scnprintf(buf, sizeof(buf), "%s (inline)",
871 ilist->funcname);
872 else if (ilist->filename != NULL)
873 scnprintf(buf, sizeof(buf),
874 "%s:%d (inline)",
875 ilist->filename,
876 ilist->line_nr);
877 else
878 scnprintf(buf, sizeof(buf), "??");
879
880 ui_browser__set_color(&browser->b, color);
881 hist_browser__gotorc(browser, row, 0);
882 ui_browser__write_nstring(&browser->b, " ",
883 LEVEL_OFFSET_STEP + offset);
884 ui_browser__write_nstring(&browser->b, buf, width);
885 row++;
886 }
887 }
888
889 return row - first_row;
890}
891
892static size_t show_inline_list(struct hist_browser *browser, struct map *map,
893 u64 ip, int row, int offset)
894{
895 struct inline_node *node;
896 int ret;
897
898 node = inline_node__create(map, ip);
899 if (node == NULL)
900 return 0;
901
902 ret = hist_browser__show_inline(browser, node, row, offset);
903
904 inline_node__delete(node);
905 return ret;
906}
907
Namhyung Kim18bb8382015-11-09 14:45:42 +0900908static int hist_browser__show_callchain_list(struct hist_browser *browser,
909 struct callchain_node *node,
910 struct callchain_list *chain,
911 unsigned short row, u64 total,
912 bool need_percent, int offset,
913 print_callchain_entry_fn print,
914 struct callchain_print_arg *arg)
915{
916 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800917 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900918 const char *str;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800919 int inline_rows = 0, ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900920
921 if (arg->row_offset != 0) {
922 arg->row_offset--;
923 return 0;
924 }
925
926 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800927 alloc_str2 = NULL;
928
Namhyung Kim18bb8382015-11-09 14:45:42 +0900929 str = callchain_list__sym_name(chain, bf, sizeof(bf),
930 browser->show_dso);
931
Jin Yaofef51ec2016-10-31 09:19:53 +0800932 if (symbol_conf.show_branchflag_count) {
933 if (need_percent)
934 callchain_list_counts__printf_value(node, chain, NULL,
935 buf, sizeof(buf));
936 else
937 callchain_list_counts__printf_value(NULL, chain, NULL,
938 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900939
Jin Yaofef51ec2016-10-31 09:19:53 +0800940 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
941 str = "Not enough memory!";
942 else
943 str = alloc_str2;
944 }
945
946 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900947 callchain_node__scnprintf_value(node, buf, sizeof(buf),
948 total);
949
950 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
951 str = "Not enough memory!";
952 else
953 str = alloc_str;
954 }
955
956 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900957 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800958 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800959
960 if (symbol_conf.inline_name) {
961 inline_rows = show_inline_list(browser, chain->ms.map,
962 chain->ip, row + 1, offset);
963 }
964
965 return ret + inline_rows;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900966}
967
Namhyung Kim59c624e2016-01-28 00:40:56 +0900968static bool check_percent_display(struct rb_node *node, u64 parent_total)
969{
970 struct callchain_node *child;
971
972 if (node == NULL)
973 return false;
974
975 if (rb_next(node))
976 return true;
977
978 child = rb_entry(node, struct callchain_node, rb_node);
979 return callchain_cumul_hits(child) != parent_total;
980}
981
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900982static int hist_browser__show_callchain_flat(struct hist_browser *browser,
983 struct rb_root *root,
984 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900985 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900986 print_callchain_entry_fn print,
987 struct callchain_print_arg *arg,
988 check_output_full_fn is_output_full)
989{
990 struct rb_node *node;
991 int first_row = row, offset = LEVEL_OFFSET_STEP;
992 bool need_percent;
993
994 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900995 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900996
997 while (node) {
998 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
999 struct rb_node *next = rb_next(node);
1000 struct callchain_list *chain;
1001 char folded_sign = ' ';
1002 int first = true;
1003 int extra_offset = 0;
1004
1005 list_for_each_entry(chain, &child->parent_val, list) {
1006 bool was_first = first;
1007
1008 if (first)
1009 first = false;
1010 else if (need_percent)
1011 extra_offset = LEVEL_OFFSET_STEP;
1012
1013 folded_sign = callchain_list__folded(chain);
1014
1015 row += hist_browser__show_callchain_list(browser, child,
1016 chain, row, total,
1017 was_first && need_percent,
1018 offset + extra_offset,
1019 print, arg);
1020
1021 if (is_output_full(browser, row))
1022 goto out;
1023
1024 if (folded_sign == '+')
1025 goto next;
1026 }
1027
1028 list_for_each_entry(chain, &child->val, list) {
1029 bool was_first = first;
1030
1031 if (first)
1032 first = false;
1033 else if (need_percent)
1034 extra_offset = LEVEL_OFFSET_STEP;
1035
1036 folded_sign = callchain_list__folded(chain);
1037
1038 row += hist_browser__show_callchain_list(browser, child,
1039 chain, row, total,
1040 was_first && need_percent,
1041 offset + extra_offset,
1042 print, arg);
1043
1044 if (is_output_full(browser, row))
1045 goto out;
1046
1047 if (folded_sign == '+')
1048 break;
1049 }
1050
1051next:
1052 if (is_output_full(browser, row))
1053 break;
1054 node = next;
1055 }
1056out:
1057 return row - first_row;
1058}
1059
Namhyung Kim8c430a32015-11-09 14:45:44 +09001060static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
1061 struct callchain_list *chain,
1062 char *value_str, char *old_str)
1063{
1064 char bf[1024];
1065 const char *str;
1066 char *new;
1067
1068 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1069 browser->show_dso);
1070 if (old_str) {
1071 if (asprintf(&new, "%s%s%s", old_str,
1072 symbol_conf.field_sep ?: ";", str) < 0)
1073 new = NULL;
1074 } else {
1075 if (value_str) {
1076 if (asprintf(&new, "%s %s", value_str, str) < 0)
1077 new = NULL;
1078 } else {
1079 if (asprintf(&new, "%s", str) < 0)
1080 new = NULL;
1081 }
1082 }
1083 return new;
1084}
1085
1086static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1087 struct rb_root *root,
1088 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +09001089 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +09001090 print_callchain_entry_fn print,
1091 struct callchain_print_arg *arg,
1092 check_output_full_fn is_output_full)
1093{
1094 struct rb_node *node;
1095 int first_row = row, offset = LEVEL_OFFSET_STEP;
1096 bool need_percent;
1097
1098 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001099 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001100
1101 while (node) {
1102 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1103 struct rb_node *next = rb_next(node);
1104 struct callchain_list *chain, *first_chain = NULL;
1105 int first = true;
1106 char *value_str = NULL, *value_str_alloc = NULL;
1107 char *chain_str = NULL, *chain_str_alloc = NULL;
1108
1109 if (arg->row_offset != 0) {
1110 arg->row_offset--;
1111 goto next;
1112 }
1113
1114 if (need_percent) {
1115 char buf[64];
1116
1117 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1118 if (asprintf(&value_str, "%s", buf) < 0) {
1119 value_str = (char *)"<...>";
1120 goto do_print;
1121 }
1122 value_str_alloc = value_str;
1123 }
1124
1125 list_for_each_entry(chain, &child->parent_val, list) {
1126 chain_str = hist_browser__folded_callchain_str(browser,
1127 chain, value_str, chain_str);
1128 if (first) {
1129 first = false;
1130 first_chain = chain;
1131 }
1132
1133 if (chain_str == NULL) {
1134 chain_str = (char *)"Not enough memory!";
1135 goto do_print;
1136 }
1137
1138 chain_str_alloc = chain_str;
1139 }
1140
1141 list_for_each_entry(chain, &child->val, list) {
1142 chain_str = hist_browser__folded_callchain_str(browser,
1143 chain, value_str, chain_str);
1144 if (first) {
1145 first = false;
1146 first_chain = chain;
1147 }
1148
1149 if (chain_str == NULL) {
1150 chain_str = (char *)"Not enough memory!";
1151 goto do_print;
1152 }
1153
1154 chain_str_alloc = chain_str;
1155 }
1156
1157do_print:
1158 print(browser, first_chain, chain_str, offset, row++, arg);
1159 free(value_str_alloc);
1160 free(chain_str_alloc);
1161
1162next:
1163 if (is_output_full(browser, row))
1164 break;
1165 node = next;
1166 }
1167
1168 return row - first_row;
1169}
1170
Namhyung Kim0c841c62016-01-28 00:40:54 +09001171static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001172 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001173 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001174 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001175 print_callchain_entry_fn print,
1176 struct callchain_print_arg *arg,
1177 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001178{
1179 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001180 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001181 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001182 u64 percent_total = total;
1183
1184 if (callchain_param.mode == CHAIN_GRAPH_REL)
1185 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001186
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001187 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001188 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001189
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001190 while (node) {
1191 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1192 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001193 struct callchain_list *chain;
1194 char folded_sign = ' ';
1195 int first = true;
1196 int extra_offset = 0;
1197
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199 bool was_first = first;
1200
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001201 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001203 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001205
1206 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207
Namhyung Kim18bb8382015-11-09 14:45:42 +09001208 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001209 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001210 was_first && need_percent,
1211 offset + extra_offset,
1212 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001213
Namhyung Kim18bb8382015-11-09 14:45:42 +09001214 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001216
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001217 if (folded_sign == '+')
1218 break;
1219 }
1220
1221 if (folded_sign == '-') {
1222 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001223
Namhyung Kim0c841c62016-01-28 00:40:54 +09001224 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001225 new_level, row, total,
1226 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001227 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001228 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001229 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001230 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001231 node = next;
1232 }
1233out:
1234 return row - first_row;
1235}
1236
Namhyung Kim0c841c62016-01-28 00:40:54 +09001237static int hist_browser__show_callchain(struct hist_browser *browser,
1238 struct hist_entry *entry, int level,
1239 unsigned short row,
1240 print_callchain_entry_fn print,
1241 struct callchain_print_arg *arg,
1242 check_output_full_fn is_output_full)
1243{
1244 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001245 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001246 int printed;
1247
Namhyung Kim5eca1042016-01-28 00:40:55 +09001248 if (symbol_conf.cumulate_callchain)
1249 parent_total = entry->stat_acc->period;
1250 else
1251 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001252
1253 if (callchain_param.mode == CHAIN_FLAT) {
1254 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001255 &entry->sorted_chain, row,
1256 total, parent_total, print, arg,
1257 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001258 } else if (callchain_param.mode == CHAIN_FOLDED) {
1259 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001260 &entry->sorted_chain, row,
1261 total, parent_total, print, arg,
1262 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001263 } else {
1264 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001265 &entry->sorted_chain, level, row,
1266 total, parent_total, print, arg,
1267 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001268 }
1269
1270 if (arg->is_current_entry)
1271 browser->he_selection = entry;
1272
1273 return printed;
1274}
1275
Namhyung Kim89701462013-01-22 18:09:38 +09001276struct hpp_arg {
1277 struct ui_browser *b;
1278 char folded_sign;
1279 bool current_entry;
1280};
1281
Jiri Olsa98ba1602016-09-22 17:36:35 +02001282int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001283{
1284 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001285 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001286 va_list args;
1287 double percent;
1288
1289 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001290 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001291 percent = va_arg(args, double);
1292 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001293
Namhyung Kim89701462013-01-22 18:09:38 +09001294 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001295
Namhyung Kimd6751072014-07-31 14:47:36 +09001296 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001297 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001298
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001299 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001300}
1301
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001302#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001303static u64 __hpp_get_##_field(struct hist_entry *he) \
1304{ \
1305 return he->stat._field; \
1306} \
1307 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001308static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001309hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001310 struct perf_hpp *hpp, \
1311 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001312{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001313 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1314 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001315}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001316
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001317#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1318static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1319{ \
1320 return he->stat_acc->_field; \
1321} \
1322 \
1323static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001324hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001325 struct perf_hpp *hpp, \
1326 struct hist_entry *he) \
1327{ \
1328 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001329 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001330 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001331 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001332 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001333 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001334 \
1335 return ret; \
1336 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001337 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1338 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001339}
1340
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001341__HPP_COLOR_PERCENT_FN(overhead, period)
1342__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1343__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1344__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1345__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001346__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001347
1348#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001349#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001350
1351void hist_browser__init_hpp(void)
1352{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001353 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1354 hist_browser__hpp_color_overhead;
1355 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1356 hist_browser__hpp_color_overhead_sys;
1357 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1358 hist_browser__hpp_color_overhead_us;
1359 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1360 hist_browser__hpp_color_overhead_guest_sys;
1361 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1362 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001363 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1364 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001365}
1366
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001367static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001368 struct hist_entry *entry,
1369 unsigned short row)
1370{
Jiri Olsa12400052012-10-13 00:06:16 +02001371 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001372 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001373 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001374 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001375 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001376 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001377 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001378
1379 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001380 browser->he_selection = entry;
1381 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001382 }
1383
1384 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001385 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001386 folded_sign = hist_entry__folded(entry);
1387 }
1388
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001389 if (symbol_conf.inline_name &&
1390 (!entry->has_children)) {
1391 hist_entry_init_inline_node(entry);
1392 folded_sign = hist_entry__folded(entry);
1393 }
1394
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001395 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001396 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001397 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001398 .folded_sign = folded_sign,
1399 .current_entry = current_entry,
1400 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001401 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001402
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001403 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001404
Jiri Olsaf0786af2016-01-18 10:24:23 +01001405 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001406 char s[2048];
1407 struct perf_hpp hpp = {
1408 .buf = s,
1409 .size = sizeof(s),
1410 .ptr = &arg,
1411 };
1412
Namhyung Kim361459f2015-12-23 02:07:08 +09001413 if (perf_hpp__should_skip(fmt, entry->hists) ||
1414 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001415 continue;
1416
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001417 if (current_entry && browser->b.navkeypressed) {
1418 ui_browser__set_color(&browser->b,
1419 HE_COLORSET_SELECTED);
1420 } else {
1421 ui_browser__set_color(&browser->b,
1422 HE_COLORSET_NORMAL);
1423 }
1424
1425 if (first) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001426 if (symbol_conf.use_callchain ||
1427 symbol_conf.inline_name) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001428 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001429 width -= 2;
1430 }
1431 first = false;
1432 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001433 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001434 width -= 2;
1435 }
1436
Jiri Olsa12400052012-10-13 00:06:16 +02001437 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001438 int ret = fmt->color(fmt, &hpp, entry);
1439 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1440 /*
1441 * fmt->color() already used ui_browser to
1442 * print the non alignment bits, skip it (+ret):
1443 */
1444 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001445 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001446 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001447 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001448 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001449 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001450 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001451
1452 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001453 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001454 width += 1;
1455
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001456 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001457
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001458 ++row;
1459 ++printed;
1460 } else
1461 --row_offset;
1462
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001463 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001464 struct callchain_print_arg arg = {
1465 .row_offset = row_offset,
1466 .is_current_entry = current_entry,
1467 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001468
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001469 if (entry->inline_node)
1470 printed += hist_browser__show_inline(browser,
1471 entry->inline_node, row, 0);
1472 else
1473 printed += hist_browser__show_callchain(browser,
1474 entry, 1, row,
1475 hist_browser__show_callchain_entry,
1476 &arg,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001477 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001478 }
1479
1480 return printed;
1481}
1482
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001483static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1484 struct hist_entry *entry,
1485 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001486 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001487{
1488 int printed = 0;
1489 int width = browser->b.width;
1490 char folded_sign = ' ';
1491 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1492 off_t row_offset = entry->row_offset;
1493 bool first = true;
1494 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001495 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001496 struct hpp_arg arg = {
1497 .b = &browser->b,
1498 .current_entry = current_entry,
1499 };
1500 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001501 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001502
1503 if (current_entry) {
1504 browser->he_selection = entry;
1505 browser->selection = &entry->ms;
1506 }
1507
1508 hist_entry__init_have_children(entry);
1509 folded_sign = hist_entry__folded(entry);
1510 arg.folded_sign = folded_sign;
1511
1512 if (entry->leaf && row_offset) {
1513 row_offset--;
1514 goto show_callchain;
1515 }
1516
1517 hist_browser__gotorc(browser, row, 0);
1518
1519 if (current_entry && browser->b.navkeypressed)
1520 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1521 else
1522 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1523
1524 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1525 width -= level * HIERARCHY_INDENT;
1526
Namhyung Kima61a22f2016-03-07 16:44:50 -03001527 /* the first hpp_list_node is for overhead columns */
1528 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1529 struct perf_hpp_list_node, list);
1530 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001531 char s[2048];
1532 struct perf_hpp hpp = {
1533 .buf = s,
1534 .size = sizeof(s),
1535 .ptr = &arg,
1536 };
1537
1538 if (perf_hpp__should_skip(fmt, entry->hists) ||
1539 column++ < browser->b.horiz_scroll)
1540 continue;
1541
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001542 if (current_entry && browser->b.navkeypressed) {
1543 ui_browser__set_color(&browser->b,
1544 HE_COLORSET_SELECTED);
1545 } else {
1546 ui_browser__set_color(&browser->b,
1547 HE_COLORSET_NORMAL);
1548 }
1549
1550 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001551 ui_browser__printf(&browser->b, "%c ", folded_sign);
1552 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001553 first = false;
1554 } else {
1555 ui_browser__printf(&browser->b, " ");
1556 width -= 2;
1557 }
1558
1559 if (fmt->color) {
1560 int ret = fmt->color(fmt, &hpp, entry);
1561 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1562 /*
1563 * fmt->color() already used ui_browser to
1564 * print the non alignment bits, skip it (+ret):
1565 */
1566 ui_browser__printf(&browser->b, "%s", s + ret);
1567 } else {
1568 int ret = fmt->entry(fmt, &hpp, entry);
1569 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1570 ui_browser__printf(&browser->b, "%s", s);
1571 }
1572 width -= hpp.buf - s;
1573 }
1574
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001575 if (!first) {
1576 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1577 width -= hierarchy_indent;
1578 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001579
1580 if (column >= browser->b.horiz_scroll) {
1581 char s[2048];
1582 struct perf_hpp hpp = {
1583 .buf = s,
1584 .size = sizeof(s),
1585 .ptr = &arg,
1586 };
1587
1588 if (current_entry && browser->b.navkeypressed) {
1589 ui_browser__set_color(&browser->b,
1590 HE_COLORSET_SELECTED);
1591 } else {
1592 ui_browser__set_color(&browser->b,
1593 HE_COLORSET_NORMAL);
1594 }
1595
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001596 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001597 if (first) {
1598 ui_browser__printf(&browser->b, "%c ", folded_sign);
1599 first = false;
1600 } else {
1601 ui_browser__write_nstring(&browser->b, "", 2);
1602 }
1603
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001604 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001605
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001606 /*
1607 * No need to call hist_entry__snprintf_alignment()
1608 * since this fmt is always the last column in the
1609 * hierarchy mode.
1610 */
1611 if (fmt->color) {
1612 width -= fmt->color(fmt, &hpp, entry);
1613 } else {
1614 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001615
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001616 width -= fmt->entry(fmt, &hpp, entry);
1617 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001618
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001619 while (isspace(s[i++]))
1620 width++;
1621 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001622 }
1623 }
1624
1625 /* The scroll bar isn't being used */
1626 if (!browser->b.navkeypressed)
1627 width += 1;
1628
1629 ui_browser__write_nstring(&browser->b, "", width);
1630
1631 ++row;
1632 ++printed;
1633
1634show_callchain:
1635 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1636 struct callchain_print_arg carg = {
1637 .row_offset = row_offset,
1638 };
1639
1640 printed += hist_browser__show_callchain(browser, entry,
1641 level + 1, row,
1642 hist_browser__show_callchain_entry, &carg,
1643 hist_browser__check_output_full);
1644 }
1645
1646 return printed;
1647}
1648
Namhyung Kim79dded82016-02-26 21:13:19 +09001649static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001650 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001651{
1652 int width = browser->b.width;
1653 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1654 bool first = true;
1655 int column = 0;
1656 int ret;
1657 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001658 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001659 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001660
1661 if (current_entry) {
1662 browser->he_selection = NULL;
1663 browser->selection = NULL;
1664 }
1665
1666 hist_browser__gotorc(browser, row, 0);
1667
1668 if (current_entry && browser->b.navkeypressed)
1669 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1670 else
1671 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1672
1673 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1674 width -= level * HIERARCHY_INDENT;
1675
Namhyung Kima61a22f2016-03-07 16:44:50 -03001676 /* the first hpp_list_node is for overhead columns */
1677 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1678 struct perf_hpp_list_node, list);
1679 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001680 if (perf_hpp__should_skip(fmt, browser->hists) ||
1681 column++ < browser->b.horiz_scroll)
1682 continue;
1683
Jiri Olsada1b0402016-06-14 20:19:20 +02001684 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001685
1686 if (first) {
1687 /* for folded sign */
1688 first = false;
1689 ret++;
1690 } else {
1691 /* space between columns */
1692 ret += 2;
1693 }
1694
1695 ui_browser__write_nstring(&browser->b, "", ret);
1696 width -= ret;
1697 }
1698
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001699 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1700 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001701
1702 if (column >= browser->b.horiz_scroll) {
1703 char buf[32];
1704
1705 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1706 ui_browser__printf(&browser->b, " %s", buf);
1707 width -= ret + 2;
1708 }
1709
1710 /* The scroll bar isn't being used */
1711 if (!browser->b.navkeypressed)
1712 width += 1;
1713
1714 ui_browser__write_nstring(&browser->b, "", width);
1715 return 1;
1716}
1717
Jiri Olsa81a888f2014-06-14 15:44:52 +02001718static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1719{
1720 advance_hpp(hpp, inc);
1721 return hpp->size <= 0;
1722}
1723
Jiri Olsa69705b32016-08-07 17:28:28 +02001724static int
1725hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1726 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001727{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001728 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001729 struct perf_hpp dummy_hpp = {
1730 .buf = buf,
1731 .size = size,
1732 };
1733 struct perf_hpp_fmt *fmt;
1734 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001735 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001736 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001737
1738 if (symbol_conf.use_callchain) {
1739 ret = scnprintf(buf, size, " ");
1740 if (advance_hpp_check(&dummy_hpp, ret))
1741 return ret;
1742 }
1743
Jiri Olsaf0786af2016-01-18 10:24:23 +01001744 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001745 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001746 continue;
1747
Jiri Olsa29659ab2016-08-07 17:28:30 +02001748 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001749 if (advance_hpp_check(&dummy_hpp, ret))
1750 break;
1751
Jiri Olsa29659ab2016-08-07 17:28:30 +02001752 if (span)
1753 continue;
1754
Jiri Olsa81a888f2014-06-14 15:44:52 +02001755 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1756 if (advance_hpp_check(&dummy_hpp, ret))
1757 break;
1758 }
1759
1760 return ret;
1761}
1762
Namhyung Kimd8b92402016-02-25 00:13:46 +09001763static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1764{
1765 struct hists *hists = browser->hists;
1766 struct perf_hpp dummy_hpp = {
1767 .buf = buf,
1768 .size = size,
1769 };
1770 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001771 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001772 size_t ret = 0;
1773 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001774 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001775 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001776
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001777 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001778 if (advance_hpp_check(&dummy_hpp, ret))
1779 return ret;
1780
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001781 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001782 /* the first hpp_list_node is for overhead columns */
1783 fmt_node = list_first_entry(&hists->hpp_formats,
1784 struct perf_hpp_list_node, list);
1785 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001786 if (column++ < browser->b.horiz_scroll)
1787 continue;
1788
Jiri Olsa29659ab2016-08-07 17:28:30 +02001789 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001790 if (advance_hpp_check(&dummy_hpp, ret))
1791 break;
1792
1793 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1794 if (advance_hpp_check(&dummy_hpp, ret))
1795 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001796
1797 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001798 }
1799
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001800 if (!first_node) {
1801 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1802 indent * HIERARCHY_INDENT, "");
1803 if (advance_hpp_check(&dummy_hpp, ret))
1804 return ret;
1805 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001806
Namhyung Kima61a22f2016-03-07 16:44:50 -03001807 first_node = true;
1808 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1809 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001810 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1811 if (advance_hpp_check(&dummy_hpp, ret))
1812 break;
1813 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001814 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001815
Namhyung Kima61a22f2016-03-07 16:44:50 -03001816 first_col = true;
1817 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1818 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001819
Namhyung Kima61a22f2016-03-07 16:44:50 -03001820 if (perf_hpp__should_skip(fmt, hists))
1821 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001822
Namhyung Kima61a22f2016-03-07 16:44:50 -03001823 if (!first_col) {
1824 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1825 if (advance_hpp_check(&dummy_hpp, ret))
1826 break;
1827 }
1828 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001829
Jiri Olsa29659ab2016-08-07 17:28:30 +02001830 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001831 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001832
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001833 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001834 ret = strlen(start);
1835
1836 if (start != dummy_hpp.buf)
1837 memmove(dummy_hpp.buf, start, ret + 1);
1838
1839 if (advance_hpp_check(&dummy_hpp, ret))
1840 break;
1841 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001842 }
1843
1844 return ret;
1845}
1846
Jiri Olsa01b47702016-06-14 20:19:13 +02001847static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001848{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001849 char headers[1024];
1850
Jiri Olsa01b47702016-06-14 20:19:13 +02001851 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1852 sizeof(headers));
1853
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001854 ui_browser__gotorc(&browser->b, 0, 0);
1855 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001856 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001857}
1858
Jiri Olsa01b47702016-06-14 20:19:13 +02001859static void hists_browser__headers(struct hist_browser *browser)
1860{
Jiri Olsa69705b32016-08-07 17:28:28 +02001861 struct hists *hists = browser->hists;
1862 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001863
Jiri Olsa69705b32016-08-07 17:28:28 +02001864 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001865
Jiri Olsa69705b32016-08-07 17:28:28 +02001866 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1867 char headers[1024];
1868
1869 hists_browser__scnprintf_headers(browser, headers,
1870 sizeof(headers), line);
1871
1872 ui_browser__gotorc(&browser->b, line, 0);
1873 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1874 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1875 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001876}
1877
1878static void hist_browser__show_headers(struct hist_browser *browser)
1879{
1880 if (symbol_conf.report_hierarchy)
1881 hists_browser__hierarchy_headers(browser);
1882 else
1883 hists_browser__headers(browser);
1884}
1885
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001886static void ui_browser__hists_init_top(struct ui_browser *browser)
1887{
1888 if (browser->top == NULL) {
1889 struct hist_browser *hb;
1890
1891 hb = container_of(browser, struct hist_browser, b);
1892 browser->top = rb_first(&hb->hists->entries);
1893 }
1894}
1895
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001896static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001897{
1898 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001899 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001900 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001901 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001902 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001903
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001904 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001905 struct perf_hpp_list *hpp_list = hists->hpp_list;
1906
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001907 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001908 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001909 }
1910
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001911 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001912 hb->he_selection = NULL;
1913 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001914
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001915 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001916 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001917 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001918
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001919 if (h->filtered) {
1920 /* let it move to sibling */
1921 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001922 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001923 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001924
Namhyung Kim14135662013-10-31 10:17:39 +09001925 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001926 if (percent < hb->min_pcnt)
1927 continue;
1928
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001929 if (symbol_conf.report_hierarchy) {
1930 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001931 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001932 if (row == browser->rows)
1933 break;
1934
1935 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001936 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001937 row++;
1938 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001939 } else {
1940 row += hist_browser__show_entry(hb, h, row);
1941 }
1942
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001943 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001944 break;
1945 }
1946
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001947 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001948}
1949
Namhyung Kim064f1982013-05-14 11:09:04 +09001950static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001951 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001952{
1953 while (nd != NULL) {
1954 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001955 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001956
Namhyung Kimc0f15272014-04-16 11:16:33 +09001957 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001958 return nd;
1959
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001960 /*
1961 * If it's filtered, its all children also were filtered.
1962 * So move to sibling node.
1963 */
1964 if (rb_next(nd))
1965 nd = rb_next(nd);
1966 else
1967 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001968 }
1969
1970 return NULL;
1971}
1972
Namhyung Kim064f1982013-05-14 11:09:04 +09001973static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001974 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001975{
1976 while (nd != NULL) {
1977 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001978 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001979
1980 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001981 return nd;
1982
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001983 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001984 }
1985
1986 return NULL;
1987}
1988
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001989static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001990 off_t offset, int whence)
1991{
1992 struct hist_entry *h;
1993 struct rb_node *nd;
1994 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001995 struct hist_browser *hb;
1996
1997 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001998
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001999 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002000 return;
2001
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002002 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03002003
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002004 switch (whence) {
2005 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09002006 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09002007 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002008 break;
2009 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002010 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002011 goto do_offset;
2012 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002013 nd = rb_hierarchy_last(rb_last(browser->entries));
2014 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002015 first = false;
2016 break;
2017 default:
2018 return;
2019 }
2020
2021 /*
2022 * Moves not relative to the first visible entry invalidates its
2023 * row_offset:
2024 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002025 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002026 h->row_offset = 0;
2027
2028 /*
2029 * Here we have to check if nd is expanded (+), if it is we can't go
2030 * the next top level hist_entry, instead we must compute an offset of
2031 * what _not_ to show and not change the first visible entry.
2032 *
2033 * This offset increments when we are going from top to bottom and
2034 * decreases when we're going from bottom to top.
2035 *
2036 * As we don't have backpointers to the top level in the callchains
2037 * structure, we need to always print the whole hist_entry callchain,
2038 * skipping the first ones that are before the first visible entry
2039 * and stop when we printed enough lines to fill the screen.
2040 */
2041do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00002042 if (!nd)
2043 return;
2044
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002045 if (offset > 0) {
2046 do {
2047 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002048 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002049 u16 remaining = h->nr_rows - h->row_offset;
2050 if (offset > remaining) {
2051 offset -= remaining;
2052 h->row_offset = 0;
2053 } else {
2054 h->row_offset += offset;
2055 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002056 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002057 break;
2058 }
2059 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002060 nd = hists__filter_entries(rb_hierarchy_next(nd),
2061 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002062 if (nd == NULL)
2063 break;
2064 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002065 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002066 } while (offset != 0);
2067 } else if (offset < 0) {
2068 while (1) {
2069 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002070 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002071 if (first) {
2072 if (-offset > h->row_offset) {
2073 offset += h->row_offset;
2074 h->row_offset = 0;
2075 } else {
2076 h->row_offset += offset;
2077 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002078 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002079 break;
2080 }
2081 } else {
2082 if (-offset > h->nr_rows) {
2083 offset += h->nr_rows;
2084 h->row_offset = 0;
2085 } else {
2086 h->row_offset = h->nr_rows + offset;
2087 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002088 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002089 break;
2090 }
2091 }
2092 }
2093
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002094 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09002095 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002096 if (nd == NULL)
2097 break;
2098 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002099 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002100 if (offset == 0) {
2101 /*
2102 * Last unfiltered hist_entry, check if it is
2103 * unfolded, if it is then we should have
2104 * row_offset at its last entry.
2105 */
2106 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002107 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002108 h->row_offset = h->nr_rows;
2109 break;
2110 }
2111 first = false;
2112 }
2113 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002114 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002115 h = rb_entry(nd, struct hist_entry, rb_node);
2116 h->row_offset = 0;
2117 }
2118}
2119
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002120static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002121 struct hist_entry *he, FILE *fp,
2122 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002123{
Namhyung Kim39ee5332014-08-22 09:13:21 +09002124 struct callchain_print_arg arg = {
2125 .fp = fp,
2126 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002127
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002128 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09002129 hist_browser__fprintf_callchain_entry, &arg,
2130 hist_browser__check_dump_full);
2131 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002132}
2133
2134static int hist_browser__fprintf_entry(struct hist_browser *browser,
2135 struct hist_entry *he, FILE *fp)
2136{
2137 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002138 int printed = 0;
2139 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09002140 struct perf_hpp hpp = {
2141 .buf = s,
2142 .size = sizeof(s),
2143 };
2144 struct perf_hpp_fmt *fmt;
2145 bool first = true;
2146 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002147
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002148 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002149 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002150 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002151 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002152
Jiri Olsaf0786af2016-01-18 10:24:23 +01002153 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002154 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002155 continue;
2156
Namhyung Kim26d8b332014-03-03 16:16:20 +09002157 if (!first) {
2158 ret = scnprintf(hpp.buf, hpp.size, " ");
2159 advance_hpp(&hpp, ret);
2160 } else
2161 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002162
Namhyung Kim26d8b332014-03-03 16:16:20 +09002163 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002164 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002165 advance_hpp(&hpp, ret);
2166 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002167 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002168
2169 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002170 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2171
2172 return printed;
2173}
2174
2175
2176static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2177 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002178 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002179{
2180 char s[8192];
2181 int printed = 0;
2182 char folded_sign = ' ';
2183 struct perf_hpp hpp = {
2184 .buf = s,
2185 .size = sizeof(s),
2186 };
2187 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002188 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002189 bool first = true;
2190 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002191 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002192
2193 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2194
2195 folded_sign = hist_entry__folded(he);
2196 printed += fprintf(fp, "%c", folded_sign);
2197
Namhyung Kim325a6282016-03-09 22:47:00 +09002198 /* the first hpp_list_node is for overhead columns */
2199 fmt_node = list_first_entry(&he->hists->hpp_formats,
2200 struct perf_hpp_list_node, list);
2201 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002202 if (!first) {
2203 ret = scnprintf(hpp.buf, hpp.size, " ");
2204 advance_hpp(&hpp, ret);
2205 } else
2206 first = false;
2207
2208 ret = fmt->entry(fmt, &hpp, he);
2209 advance_hpp(&hpp, ret);
2210 }
2211
2212 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2213 advance_hpp(&hpp, ret);
2214
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002215 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2216 ret = scnprintf(hpp.buf, hpp.size, " ");
2217 advance_hpp(&hpp, ret);
2218
2219 ret = fmt->entry(fmt, &hpp, he);
2220 advance_hpp(&hpp, ret);
2221 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002222
2223 printed += fprintf(fp, "%s\n", rtrim(s));
2224
2225 if (he->leaf && folded_sign == '-') {
2226 printed += hist_browser__fprintf_callchain(browser, he, fp,
2227 he->depth + 1);
2228 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002229
2230 return printed;
2231}
2232
2233static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2234{
Namhyung Kim064f1982013-05-14 11:09:04 +09002235 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002236 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002237 int printed = 0;
2238
2239 while (nd) {
2240 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2241
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002242 if (symbol_conf.report_hierarchy) {
2243 printed += hist_browser__fprintf_hierarchy_entry(browser,
2244 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002245 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002246 } else {
2247 printed += hist_browser__fprintf_entry(browser, h, fp);
2248 }
2249
2250 nd = hists__filter_entries(rb_hierarchy_next(nd),
2251 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002252 }
2253
2254 return printed;
2255}
2256
2257static int hist_browser__dump(struct hist_browser *browser)
2258{
2259 char filename[64];
2260 FILE *fp;
2261
2262 while (1) {
2263 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2264 if (access(filename, F_OK))
2265 break;
2266 /*
2267 * XXX: Just an arbitrary lazy upper limit
2268 */
2269 if (++browser->print_seq == 8192) {
2270 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2271 return -1;
2272 }
2273 }
2274
2275 fp = fopen(filename, "w");
2276 if (fp == NULL) {
2277 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002278 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002279 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002280 return -1;
2281 }
2282
2283 ++browser->print_seq;
2284 hist_browser__fprintf(browser, fp);
2285 fclose(fp);
2286 ui_helpline__fpush("%s written!", filename);
2287
2288 return 0;
2289}
2290
Jiri Olsafcd86422016-06-20 23:58:18 +02002291void hist_browser__init(struct hist_browser *browser,
2292 struct hists *hists)
2293{
2294 struct perf_hpp_fmt *fmt;
2295
2296 browser->hists = hists;
2297 browser->b.refresh = hist_browser__refresh;
2298 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2299 browser->b.seek = ui_browser__hists_seek;
2300 browser->b.use_navkeypressed = true;
2301 browser->show_headers = symbol_conf.show_hist_headers;
2302
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002303 if (symbol_conf.report_hierarchy) {
2304 struct perf_hpp_list_node *fmt_node;
2305
2306 /* count overhead columns (in the first node) */
2307 fmt_node = list_first_entry(&hists->hpp_formats,
2308 struct perf_hpp_list_node, list);
2309 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2310 ++browser->b.columns;
2311
2312 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002313 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002314 } else {
2315 hists__for_each_format(hists, fmt)
2316 ++browser->b.columns;
2317 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002318
2319 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002320}
2321
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002322struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002323{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002324 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002325
Jiri Olsafcd86422016-06-20 23:58:18 +02002326 if (browser)
2327 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002328
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002329 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002330}
2331
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002332static struct hist_browser *
2333perf_evsel_browser__new(struct perf_evsel *evsel,
2334 struct hist_browser_timer *hbt,
2335 struct perf_env *env)
2336{
2337 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2338
2339 if (browser) {
2340 browser->hbt = hbt;
2341 browser->env = env;
2342 browser->title = perf_evsel_browser_title;
2343 }
2344 return browser;
2345}
2346
Jiri Olsadabd2012016-06-20 23:58:14 +02002347void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002348{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002349 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002350}
2351
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002352static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002353{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002354 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002355}
2356
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002357static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002358{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002359 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002360}
2361
Taeung Song1e378eb2014-10-07 16:13:15 +09002362/* Check whether the browser is for 'top' or 'report' */
2363static inline bool is_report_browser(void *timer)
2364{
2365 return timer == NULL;
2366}
2367
Jiri Olsa5b91a862016-06-20 23:58:15 +02002368static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002369 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002370{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002371 struct hist_browser_timer *hbt = browser->hbt;
2372 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002373 char unit;
2374 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002375 const struct dso *dso = hists->dso_filter;
2376 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002377 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002378 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2379 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002380 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002381 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002382 char buf[512];
2383 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002384 char ref[30] = " show reference callgraph, ";
2385 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002386
Namhyung Kimf2148332014-01-14 11:52:48 +09002387 if (symbol_conf.filter_relative) {
2388 nr_samples = hists->stats.nr_non_filtered_samples;
2389 nr_events = hists->stats.total_non_filtered_period;
2390 }
2391
Namhyung Kim759ff492013-03-05 14:53:26 +09002392 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002393 struct perf_evsel *pos;
2394
2395 perf_evsel__group_desc(evsel, buf, buflen);
2396 ev_name = buf;
2397
2398 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002399 struct hists *pos_hists = evsel__hists(pos);
2400
Namhyung Kimf2148332014-01-14 11:52:48 +09002401 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002402 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2403 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002404 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002405 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2406 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002407 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002408 }
2409 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002410
Kan Liang9e207dd2015-08-11 06:30:49 -04002411 if (symbol_conf.show_ref_callgraph &&
2412 strstr(ev_name, "call-graph=no"))
2413 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002414 nr_samples = convert_unit(nr_samples, &unit);
2415 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002416 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2417 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002418
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002419
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002420 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002421 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002422 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002423 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002424 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002425 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002426 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002427 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002428 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002429 } else {
2430 printed += scnprintf(bf + printed, size - printed,
2431 ", Thread: %s",
2432 (thread->comm_set ? thread__comm_str(thread) : ""));
2433 }
2434 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002435 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002436 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002437 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002438 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002439 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002440 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002441 if (!is_report_browser(hbt)) {
2442 struct perf_top *top = hbt->arg;
2443
2444 if (top->zero)
2445 printed += scnprintf(bf + printed, size - printed, " [z]");
2446 }
2447
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002448 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002449}
2450
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002451static inline void free_popup_options(char **options, int n)
2452{
2453 int i;
2454
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002455 for (i = 0; i < n; ++i)
2456 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002457}
2458
Feng Tang341487ab2013-02-03 14:38:20 +08002459/*
2460 * Only runtime switching of perf data file will make "input_name" point
2461 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2462 * whether we need to call free() for current "input_name" during the switch.
2463 */
2464static bool is_input_name_malloced = false;
2465
2466static int switch_data_file(void)
2467{
2468 char *pwd, *options[32], *abs_path[32], *tmp;
2469 DIR *pwd_dir;
2470 int nr_options = 0, choice = -1, ret = -1;
2471 struct dirent *dent;
2472
2473 pwd = getenv("PWD");
2474 if (!pwd)
2475 return ret;
2476
2477 pwd_dir = opendir(pwd);
2478 if (!pwd_dir)
2479 return ret;
2480
2481 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002482 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002483
2484 while ((dent = readdir(pwd_dir))) {
2485 char path[PATH_MAX];
2486 u64 magic;
2487 char *name = dent->d_name;
2488 FILE *file;
2489
2490 if (!(dent->d_type == DT_REG))
2491 continue;
2492
2493 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2494
2495 file = fopen(path, "r");
2496 if (!file)
2497 continue;
2498
2499 if (fread(&magic, 1, 8, file) < 8)
2500 goto close_file_and_continue;
2501
2502 if (is_perf_magic(magic)) {
2503 options[nr_options] = strdup(name);
2504 if (!options[nr_options])
2505 goto close_file_and_continue;
2506
2507 abs_path[nr_options] = strdup(path);
2508 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002509 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002510 ui__warning("Can't search all data files due to memory shortage.\n");
2511 fclose(file);
2512 break;
2513 }
2514
2515 nr_options++;
2516 }
2517
2518close_file_and_continue:
2519 fclose(file);
2520 if (nr_options >= 32) {
2521 ui__warning("Too many perf data files in PWD!\n"
2522 "Only the first 32 files will be listed.\n");
2523 break;
2524 }
2525 }
2526 closedir(pwd_dir);
2527
2528 if (nr_options) {
2529 choice = ui__popup_menu(nr_options, options);
2530 if (choice < nr_options && choice >= 0) {
2531 tmp = strdup(abs_path[choice]);
2532 if (tmp) {
2533 if (is_input_name_malloced)
2534 free((void *)input_name);
2535 input_name = tmp;
2536 is_input_name_malloced = true;
2537 ret = 0;
2538 } else
2539 ui__warning("Data switch failed due to memory shortage!\n");
2540 }
2541 }
2542
2543 free_popup_options(options, nr_options);
2544 free_popup_options(abs_path, nr_options);
2545 return ret;
2546}
2547
Namhyung Kimea7cd592015-04-22 16:18:19 +09002548struct popup_action {
2549 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002550 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002551 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002552
2553 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2554};
2555
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002556static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002557do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002558{
2559 struct perf_evsel *evsel;
2560 struct annotation *notes;
2561 struct hist_entry *he;
2562 int err;
2563
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002564 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002565 return 0;
2566
Namhyung Kimea7cd592015-04-22 16:18:19 +09002567 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002568 if (!notes->src)
2569 return 0;
2570
2571 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002572 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002573 he = hist_browser__selected_entry(browser);
2574 /*
2575 * offer option to annotate the other branch source or target
2576 * (if they exists) when returning from annotate
2577 */
2578 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2579 return 1;
2580
2581 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2582 if (err)
2583 ui_browser__handle_resize(&browser->b);
2584 return 0;
2585}
2586
2587static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002588add_annotate_opt(struct hist_browser *browser __maybe_unused,
2589 struct popup_action *act, char **optstr,
2590 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002591{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002592 if (sym == NULL || map->dso->annotate_warned)
2593 return 0;
2594
2595 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2596 return 0;
2597
2598 act->ms.map = map;
2599 act->ms.sym = sym;
2600 act->fn = do_annotate;
2601 return 1;
2602}
2603
2604static int
2605do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2606{
2607 struct thread *thread = act->thread;
2608
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002609 if ((!hists__has(browser->hists, thread) &&
2610 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002611 return 0;
2612
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002613 if (browser->hists->thread_filter) {
2614 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2615 perf_hpp__set_elide(HISTC_THREAD, false);
2616 thread__zput(browser->hists->thread_filter);
2617 ui_helpline__pop();
2618 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002619 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002620 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2621 thread->comm_set ? thread__comm_str(thread) : "",
2622 thread->tid);
2623 } else {
2624 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2625 thread->comm_set ? thread__comm_str(thread) : "");
2626 }
2627
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002628 browser->hists->thread_filter = thread__get(thread);
2629 perf_hpp__set_elide(HISTC_THREAD, false);
2630 pstack__push(browser->pstack, &browser->hists->thread_filter);
2631 }
2632
2633 hists__filter_by_thread(browser->hists);
2634 hist_browser__reset(browser);
2635 return 0;
2636}
2637
2638static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002639add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2640 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002641{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002642 int ret;
2643
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002644 if ((!hists__has(browser->hists, thread) &&
2645 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002646 return 0;
2647
Jiri Olsafa829112016-05-03 13:54:47 +02002648 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002649 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2650 browser->hists->thread_filter ? "out of" : "into",
2651 thread->comm_set ? thread__comm_str(thread) : "",
2652 thread->tid);
2653 } else {
2654 ret = asprintf(optstr, "Zoom %s %s thread",
2655 browser->hists->thread_filter ? "out of" : "into",
2656 thread->comm_set ? thread__comm_str(thread) : "");
2657 }
2658 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002659 return 0;
2660
2661 act->thread = thread;
2662 act->fn = do_zoom_thread;
2663 return 1;
2664}
2665
2666static int
2667do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2668{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002669 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002670
Jiri Olsa69849fc2016-05-03 13:54:45 +02002671 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002672 return 0;
2673
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002674 if (browser->hists->dso_filter) {
2675 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2676 perf_hpp__set_elide(HISTC_DSO, false);
2677 browser->hists->dso_filter = NULL;
2678 ui_helpline__pop();
2679 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002680 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002681 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2682 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002683 perf_hpp__set_elide(HISTC_DSO, true);
2684 pstack__push(browser->pstack, &browser->hists->dso_filter);
2685 }
2686
2687 hists__filter_by_dso(browser->hists);
2688 hist_browser__reset(browser);
2689 return 0;
2690}
2691
2692static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002693add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002694 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002695{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002696 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002697 return 0;
2698
2699 if (asprintf(optstr, "Zoom %s %s DSO",
2700 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002701 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002702 return 0;
2703
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002704 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002705 act->fn = do_zoom_dso;
2706 return 1;
2707}
2708
2709static int
2710do_browse_map(struct hist_browser *browser __maybe_unused,
2711 struct popup_action *act)
2712{
2713 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002714 return 0;
2715}
2716
2717static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002718add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002719 struct popup_action *act, char **optstr, struct map *map)
2720{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002721 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002722 return 0;
2723
2724 if (asprintf(optstr, "Browse map details") < 0)
2725 return 0;
2726
2727 act->ms.map = map;
2728 act->fn = do_browse_map;
2729 return 1;
2730}
2731
2732static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002733do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002734 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002735{
2736 char script_opt[64];
2737 memset(script_opt, 0, sizeof(script_opt));
2738
Namhyung Kimea7cd592015-04-22 16:18:19 +09002739 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002740 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002741 thread__comm_str(act->thread));
2742 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002743 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002744 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002745 }
2746
2747 script_browse(script_opt);
2748 return 0;
2749}
2750
2751static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002752add_script_opt(struct hist_browser *browser __maybe_unused,
2753 struct popup_action *act, char **optstr,
2754 struct thread *thread, struct symbol *sym)
2755{
2756 if (thread) {
2757 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2758 thread__comm_str(thread)) < 0)
2759 return 0;
2760 } else if (sym) {
2761 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2762 sym->name) < 0)
2763 return 0;
2764 } else {
2765 if (asprintf(optstr, "Run scripts for all samples") < 0)
2766 return 0;
2767 }
2768
2769 act->thread = thread;
2770 act->ms.sym = sym;
2771 act->fn = do_run_script;
2772 return 1;
2773}
2774
2775static int
2776do_switch_data(struct hist_browser *browser __maybe_unused,
2777 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002778{
2779 if (switch_data_file()) {
2780 ui__warning("Won't switch the data files due to\n"
2781 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002782 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002783 }
2784
2785 return K_SWITCH_INPUT_DATA;
2786}
2787
Namhyung Kimea7cd592015-04-22 16:18:19 +09002788static int
2789add_switch_opt(struct hist_browser *browser,
2790 struct popup_action *act, char **optstr)
2791{
2792 if (!is_report_browser(browser->hbt))
2793 return 0;
2794
2795 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2796 return 0;
2797
2798 act->fn = do_switch_data;
2799 return 1;
2800}
2801
2802static int
2803do_exit_browser(struct hist_browser *browser __maybe_unused,
2804 struct popup_action *act __maybe_unused)
2805{
2806 return 0;
2807}
2808
2809static int
2810add_exit_opt(struct hist_browser *browser __maybe_unused,
2811 struct popup_action *act, char **optstr)
2812{
2813 if (asprintf(optstr, "Exit") < 0)
2814 return 0;
2815
2816 act->fn = do_exit_browser;
2817 return 1;
2818}
2819
Kan Liang84734b02015-09-04 10:45:45 -04002820static int
2821do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2822{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002823 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002824 return 0;
2825
Kan Liang84734b02015-09-04 10:45:45 -04002826 if (browser->hists->socket_filter > -1) {
2827 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2828 browser->hists->socket_filter = -1;
2829 perf_hpp__set_elide(HISTC_SOCKET, false);
2830 } else {
2831 browser->hists->socket_filter = act->socket;
2832 perf_hpp__set_elide(HISTC_SOCKET, true);
2833 pstack__push(browser->pstack, &browser->hists->socket_filter);
2834 }
2835
2836 hists__filter_by_socket(browser->hists);
2837 hist_browser__reset(browser);
2838 return 0;
2839}
2840
2841static int
2842add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2843 char **optstr, int socket_id)
2844{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002845 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002846 return 0;
2847
2848 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2849 (browser->hists->socket_filter > -1) ? "out of" : "into",
2850 socket_id) < 0)
2851 return 0;
2852
2853 act->socket = socket_id;
2854 act->fn = do_zoom_socket;
2855 return 1;
2856}
2857
Namhyung Kim112f7612014-04-22 14:05:35 +09002858static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002859{
2860 u64 nr_entries = 0;
2861 struct rb_node *nd = rb_first(&hb->hists->entries);
2862
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002863 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002864 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2865 return;
2866 }
2867
Namhyung Kim14135662013-10-31 10:17:39 +09002868 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002869 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002870 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002871 }
2872
Namhyung Kim112f7612014-04-22 14:05:35 +09002873 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002874 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002875}
Feng Tang341487ab2013-02-03 14:38:20 +08002876
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002877static void hist_browser__update_percent_limit(struct hist_browser *hb,
2878 double percent)
2879{
2880 struct hist_entry *he;
2881 struct rb_node *nd = rb_first(&hb->hists->entries);
2882 u64 total = hists__total_period(hb->hists);
2883 u64 min_callchain_hits = total * (percent / 100);
2884
2885 hb->min_pcnt = callchain_param.min_percent = percent;
2886
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002887 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2888 he = rb_entry(nd, struct hist_entry, rb_node);
2889
Namhyung Kim79dded82016-02-26 21:13:19 +09002890 if (he->has_no_entry) {
2891 he->has_no_entry = false;
2892 he->nr_rows = 0;
2893 }
2894
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002895 if (!he->leaf || !symbol_conf.use_callchain)
2896 goto next;
2897
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002898 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2899 total = he->stat.period;
2900
2901 if (symbol_conf.cumulate_callchain)
2902 total = he->stat_acc->period;
2903
2904 min_callchain_hits = total * (percent / 100);
2905 }
2906
2907 callchain_param.sort(&he->sorted_chain, he->callchain,
2908 min_callchain_hits, &callchain_param);
2909
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002910next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002911 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002912
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002913 /* force to re-evaluate folding state of callchains */
2914 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002915 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002916 }
2917}
2918
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002919static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002920 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002921 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002922 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002923 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002924 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002925{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002926 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002927 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002928 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002929#define MAX_OPTIONS 16
2930 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002931 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002932 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002933 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002934 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002935 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002936
Namhyung Kime8e684a2013-12-26 14:37:58 +09002937#define HIST_BROWSER_HELP_COMMON \
2938 "h/?/F1 Show this window\n" \
2939 "UP/DOWN/PGUP\n" \
2940 "PGDN/SPACE Navigate\n" \
2941 "q/ESC/CTRL+C Exit browser\n\n" \
2942 "For multiple event sessions:\n\n" \
2943 "TAB/UNTAB Switch events\n\n" \
2944 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002945 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2946 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002947 "a Annotate current symbol\n" \
2948 "C Collapse all callchains\n" \
2949 "d Zoom into current DSO\n" \
2950 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002951 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002952 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002953 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002954 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002955 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002956
2957 /* help messages are sorted by lexical order of the hotkey */
2958 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002959 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002960 "P Print histograms to perf.hist.N\n"
2961 "r Run available scripts\n"
2962 "s Switch to another data file in PWD\n"
2963 "t Zoom into current Thread\n"
2964 "V Verbose (DSO names in callchains, etc)\n"
2965 "/ Filter symbol by name";
2966 const char top_help[] = HIST_BROWSER_HELP_COMMON
2967 "P Print histograms to perf.hist.N\n"
2968 "t Zoom into current Thread\n"
2969 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002970 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002971 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002972 "/ Filter symbol by name";
2973
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002974 if (browser == NULL)
2975 return -1;
2976
Namhyung Kimed426912015-05-29 21:53:44 +09002977 /* reset abort key so that it can get Ctrl-C as a key */
2978 SLang_reset_tty();
2979 SLang_init_tty(0, 0, 0);
2980
Namhyung Kim03905042015-11-28 02:32:39 +09002981 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002982 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002983 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002984
Kan Liang84734b02015-09-04 10:45:45 -04002985 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002986 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002987 goto out;
2988
2989 ui_helpline__push(helpline);
2990
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002991 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002992 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002993
Namhyung Kim5b591662014-07-31 14:47:38 +09002994 if (symbol_conf.col_width_list_str)
2995 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2996
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002997 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002998 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002999 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003000 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04003001 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003002
Stephane Eranian24bff2d2012-03-12 16:13:30 +01003003 nr_options = 0;
3004
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03003005 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003006
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003007 if (browser->he_selection != NULL) {
3008 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003009 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04003010 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003011 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003012 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003013 case K_TAB:
3014 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06003015 if (nr_events == 1)
3016 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003017 /*
3018 * Exit the browser, let hists__browser_tree
3019 * go to the next or previous
3020 */
3021 goto out_free_stack;
3022 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003023 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003024 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003025 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003026 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003027 continue;
3028 }
3029
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003030 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08003031 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003032 browser->selection->map->dso->annotate_warned)
3033 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003034
Namhyung Kimea7cd592015-04-22 16:18:19 +09003035 actions->ms.map = browser->selection->map;
3036 actions->ms.sym = browser->selection->sym;
3037 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003038 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03003039 case 'P':
3040 hist_browser__dump(browser);
3041 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003042 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03003043 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003044 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003045 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003046 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02003047 verbose = (verbose + 1) % 4;
3048 browser->show_dso = verbose > 0;
3049 ui_helpline__fpush("Verbosity level set to %d\n",
3050 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003051 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003052 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003053 actions->thread = thread;
3054 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003055 continue;
Kan Liang84734b02015-09-04 10:45:45 -04003056 case 'S':
3057 actions->socket = socked_id;
3058 do_zoom_socket(browser, actions);
3059 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03003060 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09003061 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03003062 "Please enter the name of symbol you want to see.\n"
3063 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09003064 buf, "ENTER: OK, ESC: Cancel",
3065 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03003066 hists->symbol_filter_str = *buf ? buf : NULL;
3067 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09003068 hist_browser__reset(browser);
3069 }
3070 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08003071 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003072 if (is_report_browser(hbt)) {
3073 actions->thread = NULL;
3074 actions->ms.sym = NULL;
3075 do_run_script(browser, actions);
3076 }
Feng Tangc77d8d72012-11-01 00:00:55 +08003077 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08003078 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003079 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003080 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003081 if (key == K_SWITCH_INPUT_DATA)
3082 goto out_free_stack;
3083 }
Feng Tang341487ab2013-02-03 14:38:20 +08003084 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09003085 case 'i':
3086 /* env->arch is NULL for live-mode (i.e. perf top) */
3087 if (env->arch)
3088 tui__header_window(env);
3089 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09003090 case 'F':
3091 symbol_conf.filter_relative ^= 1;
3092 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09003093 case 'z':
3094 if (!is_report_browser(hbt)) {
3095 struct perf_top *top = hbt->arg;
3096
3097 top->zero = !top->zero;
3098 }
3099 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003100 case 'L':
3101 if (ui_browser__input_window("Percent Limit",
3102 "Please enter the value you want to hide entries under that percent.",
3103 buf, "ENTER: OK, ESC: Cancel",
3104 delay_secs * 2) == K_ENTER) {
3105 char *end;
3106 double new_percent = strtod(buf, &end);
3107
3108 if (new_percent < 0 || new_percent > 100) {
3109 ui_browser__warning(&browser->b, delay_secs * 2,
3110 "Invalid percent: %.2f", new_percent);
3111 continue;
3112 }
3113
3114 hist_browser__update_percent_limit(browser, new_percent);
3115 hist_browser__reset(browser);
3116 }
3117 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003118 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003119 case 'h':
3120 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003121 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003122 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003123 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003124 case K_ENTER:
3125 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003126 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003127 /* menu */
3128 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003129 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003130 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003131 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003132
Namhyung Kim01f00a12015-04-22 16:18:16 +09003133 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003134 /*
3135 * Go back to the perf_evsel_menu__run or other user
3136 */
3137 if (left_exits)
3138 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003139
3140 if (key == K_ESC &&
3141 ui_browser__dialog_yesno(&browser->b,
3142 "Do you really want to exit?"))
3143 goto out_free_stack;
3144
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003145 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003146 }
Namhyung Kim64221842015-04-24 10:15:33 +09003147 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003148 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003149 /*
3150 * No need to set actions->dso here since
3151 * it's just to remove the current filter.
3152 * Ditto for thread below.
3153 */
3154 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003155 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003156 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003157 } else if (top == &browser->hists->socket_filter) {
3158 do_zoom_socket(browser, actions);
3159 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003160 continue;
3161 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003162 case 'q':
3163 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003164 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003165 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003166 if (!is_report_browser(hbt)) {
3167 struct perf_top *top = hbt->arg;
3168
3169 perf_evlist__toggle_enable(top->evlist);
3170 /*
3171 * No need to refresh, resort/decay histogram
3172 * entries if we are not collecting samples:
3173 */
3174 if (top->evlist->enabled) {
3175 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3176 hbt->refresh = delay_secs;
3177 } else {
3178 helpline = "Press 'f' again to re-enable the events";
3179 hbt->refresh = 0;
3180 }
3181 continue;
3182 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003183 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003184 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003185 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003186 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003187 }
3188
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003189 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003190 goto skip_annotation;
3191
Namhyung Kim55369fc2013-04-01 20:35:20 +09003192 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003193 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003194
3195 if (bi == NULL)
3196 goto skip_annotation;
3197
Namhyung Kimea7cd592015-04-22 16:18:19 +09003198 nr_options += add_annotate_opt(browser,
3199 &actions[nr_options],
3200 &options[nr_options],
3201 bi->from.map,
3202 bi->from.sym);
3203 if (bi->to.sym != bi->from.sym)
3204 nr_options += add_annotate_opt(browser,
3205 &actions[nr_options],
3206 &options[nr_options],
3207 bi->to.map,
3208 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003209 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003210 nr_options += add_annotate_opt(browser,
3211 &actions[nr_options],
3212 &options[nr_options],
3213 browser->selection->map,
3214 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003215 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003216skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003217 nr_options += add_thread_opt(browser, &actions[nr_options],
3218 &options[nr_options], thread);
3219 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003220 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003221 nr_options += add_map_opt(browser, &actions[nr_options],
3222 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003223 browser->selection ?
3224 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003225 nr_options += add_socket_opt(browser, &actions[nr_options],
3226 &options[nr_options],
3227 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003228 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003229 if (!is_report_browser(hbt))
3230 goto skip_scripting;
3231
Feng Tangcdbab7c2012-10-30 11:56:06 +08003232 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003233 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003234 nr_options += add_script_opt(browser,
3235 &actions[nr_options],
3236 &options[nr_options],
3237 thread, NULL);
3238 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003239 /*
3240 * Note that browser->selection != NULL
3241 * when browser->he_selection is not NULL,
3242 * so we don't need to check browser->selection
3243 * before fetching browser->selection->sym like what
3244 * we do before fetching browser->selection->map.
3245 *
3246 * See hist_browser__show_entry.
3247 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003248 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003249 nr_options += add_script_opt(browser,
3250 &actions[nr_options],
3251 &options[nr_options],
3252 NULL, browser->selection->sym);
3253 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003254 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003255 nr_options += add_script_opt(browser, &actions[nr_options],
3256 &options[nr_options], NULL, NULL);
3257 nr_options += add_switch_opt(browser, &actions[nr_options],
3258 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003259skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003260 nr_options += add_exit_opt(browser, &actions[nr_options],
3261 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003262
Namhyung Kimea7cd592015-04-22 16:18:19 +09003263 do {
3264 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003265
Namhyung Kimea7cd592015-04-22 16:18:19 +09003266 choice = ui__popup_menu(nr_options, options);
3267 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003268 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003269
3270 act = &actions[choice];
3271 key = act->fn(browser, act);
3272 } while (key == 1);
3273
3274 if (key == K_SWITCH_INPUT_DATA)
3275 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003276 }
3277out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003278 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003279out:
3280 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003281 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003282 return key;
3283}
3284
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003285struct perf_evsel_menu {
3286 struct ui_browser b;
3287 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003288 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003289 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003290 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003291};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003292
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003293static void perf_evsel_menu__write(struct ui_browser *browser,
3294 void *entry, int row)
3295{
3296 struct perf_evsel_menu *menu = container_of(browser,
3297 struct perf_evsel_menu, b);
3298 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003299 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003300 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003301 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003302 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003303 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003304 const char *warn = " ";
3305 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003306
3307 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3308 HE_COLORSET_NORMAL);
3309
Namhyung Kim759ff492013-03-05 14:53:26 +09003310 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003311 struct perf_evsel *pos;
3312
3313 ev_name = perf_evsel__group_name(evsel);
3314
3315 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003316 struct hists *pos_hists = evsel__hists(pos);
3317 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003318 }
3319 }
3320
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003321 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003322 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003323 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003324 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003325
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003326 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003327 if (nr_events != 0) {
3328 menu->lost_events = true;
3329 if (!current_entry)
3330 ui_browser__set_color(browser, HE_COLORSET_TOP);
3331 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003332 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3333 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003334 warn = bf;
3335 }
3336
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003337 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003338
3339 if (current_entry)
3340 menu->selection = evsel;
3341}
3342
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003343static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3344 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003345 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003346{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003347 struct perf_evlist *evlist = menu->b.priv;
3348 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003349 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003350 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003351 int key;
3352
3353 if (ui_browser__show(&menu->b, title,
3354 "ESC: exit, ENTER|->: Browse histograms") < 0)
3355 return -1;
3356
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003357 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003358 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003359
3360 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003361 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003362 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003363
3364 if (!menu->lost_events_warned && menu->lost_events) {
3365 ui_browser__warn_lost_events(&menu->b);
3366 menu->lost_events_warned = true;
3367 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003368 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003369 case K_RIGHT:
3370 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003371 if (!menu->selection)
3372 continue;
3373 pos = menu->selection;
3374browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003375 perf_evlist__set_selected(evlist, pos);
3376 /*
3377 * Give the calling tool a chance to populate the non
3378 * default evsel resorted hists tree.
3379 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003380 if (hbt)
3381 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003382 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003383 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003384 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003385 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003386 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003387 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003388 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003389 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003390 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003391 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003392 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003393 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003394 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003395 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003396 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003397 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003398 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003399 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003400 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003401 case 'q':
3402 case CTRL('c'):
3403 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003404 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003405 default:
3406 continue;
3407 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003408 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003409 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003410 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003411 if (!ui_browser__dialog_yesno(&menu->b,
3412 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003413 continue;
3414 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003415 case 'q':
3416 case CTRL('c'):
3417 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003418 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003419 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003420 }
3421 }
3422
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003423out:
3424 ui_browser__hide(&menu->b);
3425 return key;
3426}
3427
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003428static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003429 void *entry)
3430{
3431 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3432
3433 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3434 return true;
3435
3436 return false;
3437}
3438
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003439static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003440 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003441 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003442 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003443 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003444{
3445 struct perf_evsel *pos;
3446 struct perf_evsel_menu menu = {
3447 .b = {
3448 .entries = &evlist->entries,
3449 .refresh = ui_browser__list_head_refresh,
3450 .seek = ui_browser__list_head_seek,
3451 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003452 .filter = filter_group_entries,
3453 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003454 .priv = evlist,
3455 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003456 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003457 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003458 };
3459
3460 ui_helpline__push("Press ESC to exit");
3461
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003462 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003463 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003464 size_t line_len = strlen(ev_name) + 7;
3465
3466 if (menu.b.width < line_len)
3467 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003468 }
3469
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003470 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003471}
3472
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003473int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003474 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003475 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003476 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003477{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003478 int nr_entries = evlist->nr_entries;
3479
3480single_entry:
3481 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003482 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003483
3484 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003485 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003486 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003487 }
3488
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003489 if (symbol_conf.event_group) {
3490 struct perf_evsel *pos;
3491
3492 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003493 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003494 if (perf_evsel__is_group_leader(pos))
3495 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003496 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003497
3498 if (nr_entries == 1)
3499 goto single_entry;
3500 }
3501
3502 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003503 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003504}