blob: 69f4570bd4f941bee8a67fc48741994ce41a127e [file] [log] [blame]
Arnaldo Carvalho de Melo76b31a22017-04-18 12:26:44 -03001#include <dirent.h>
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03002#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03003#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <stdlib.h>
6#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03007#include <linux/rbtree.h>
Arnaldo Carvalho de Melob0742e92017-04-18 11:08:10 -03008#include <sys/ttydefaults.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03009
Namhyung Kimaca7a942012-04-04 00:14:26 -070010#include "../../util/evsel.h"
11#include "../../util/evlist.h"
12#include "../../util/hist.h"
13#include "../../util/pstack.h"
14#include "../../util/sort.h"
15#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090016#include "../../util/top.h"
Arnaldo Carvalho de Meloe7ff8922017-04-19 21:34:35 -030017#include "../../util/thread.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090018#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019
Jiri Olsaf7589902016-06-20 23:58:13 +020020#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021#include "../helpline.h"
22#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020023#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030024#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020025#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030026#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030027#include "string2.h"
Arnaldo Carvalho de Melo58db1d62017-04-19 16:05:56 -030028#include "units.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030029
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030030#include "sane_ctype.h"
31
Namhyung Kimf5951d52012-09-03 11:53:09 +090032extern void hist_browser__init_hpp(void);
33
Jiri Olsa5b91a862016-06-20 23:58:15 +020034static int perf_evsel_browser_title(struct hist_browser *browser,
35 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090036static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030037
Namhyung Kimc3b78952014-04-22 15:56:17 +090038static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090039 float min_pcnt);
40
Namhyung Kim268397c2014-04-22 14:49:31 +090041static bool hist_browser__has_filter(struct hist_browser *hb)
42{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010043 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090044}
45
He Kuang4fabf3d2015-03-12 15:21:49 +080046static int hist_browser__get_folding(struct hist_browser *browser)
47{
48 struct rb_node *nd;
49 struct hists *hists = browser->hists;
50 int unfolded_rows = 0;
51
52 for (nd = rb_first(&hists->entries);
53 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090054 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080055 struct hist_entry *he =
56 rb_entry(nd, struct hist_entry, rb_node);
57
Namhyung Kimf5b763f2016-02-25 00:13:43 +090058 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080059 unfolded_rows += he->nr_rows;
60 }
61 return unfolded_rows;
62}
63
Namhyung Kimc3b78952014-04-22 15:56:17 +090064static u32 hist_browser__nr_entries(struct hist_browser *hb)
65{
66 u32 nr_entries;
67
Namhyung Kimf5b763f2016-02-25 00:13:43 +090068 if (symbol_conf.report_hierarchy)
69 nr_entries = hb->nr_hierarchy_entries;
70 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090071 nr_entries = hb->nr_non_filtered_entries;
72 else
73 nr_entries = hb->hists->nr_entries;
74
He Kuang4fabf3d2015-03-12 15:21:49 +080075 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090076 return nr_entries + hb->nr_callchain_rows;
77}
78
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020079static void hist_browser__update_rows(struct hist_browser *hb)
80{
81 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020082 struct hists *hists = hb->hists;
83 struct perf_hpp_list *hpp_list = hists->hpp_list;
84 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020085
Jiri Olsaf8e67102016-08-07 17:28:26 +020086 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020087 browser->rows = browser->height - header_offset;
88 /*
89 * Verify if we were at the last line and that line isn't
90 * visibe because we now show the header line(s).
91 */
92 index_row = browser->index - browser->top_idx;
93 if (index_row >= browser->rows)
94 browser->index -= index_row - browser->rows + 1;
95}
96
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030097static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030098{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030099 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
100
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300102 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
103 /*
104 * FIXME: Just keeping existing behaviour, but this really should be
105 * before updating browser->width, as it will invalidate the
106 * calculation above. Fix this and the fallout in another
107 * changeset.
108 */
109 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200110 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300111}
112
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300113static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
114{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200115 struct hists *hists = browser->hists;
116 struct perf_hpp_list *hpp_list = hists->hpp_list;
117 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200118
Jiri Olsaf8e67102016-08-07 17:28:26 +0200119 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200120 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300121}
122
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300123static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300124{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900125 /*
126 * The hists__remove_entry_filter() already folds non-filtered
127 * entries so we can assume it has 0 callchain rows.
128 */
129 browser->nr_callchain_rows = 0;
130
Namhyung Kim268397c2014-04-22 14:49:31 +0900131 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900132 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300133 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300134 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300135}
136
137static char tree__folded_sign(bool unfolded)
138{
139 return unfolded ? '-' : '+';
140}
141
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300142static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900144 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145}
146
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900149 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300150}
151
Namhyung Kim3698dab2015-05-05 23:55:46 +0900152static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300153{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900154 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300155}
156
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800157static struct inline_node *inline_node__create(struct map *map, u64 ip)
158{
159 struct dso *dso;
160 struct inline_node *node;
161
162 if (map == NULL)
163 return NULL;
164
165 dso = map->dso;
166 if (dso == NULL)
167 return NULL;
168
169 if (dso->kernel != DSO_TYPE_USER)
170 return NULL;
171
172 node = dso__parse_addr_inlines(dso,
173 map__rip_2objdump(map, ip));
174
175 return node;
176}
177
178static int inline__count_rows(struct inline_node *node)
179{
180 struct inline_list *ilist;
181 int i = 0;
182
183 if (node == NULL)
184 return 0;
185
186 list_for_each_entry(ilist, &node->val, list) {
187 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
188 i++;
189 }
190
191 return i;
192}
193
194static int callchain_list__inline_rows(struct callchain_list *chain)
195{
196 struct inline_node *node;
197 int rows;
198
199 node = inline_node__create(chain->ms.map, chain->ip);
200 if (node == NULL)
201 return 0;
202
203 rows = inline__count_rows(node);
204 inline_node__delete(node);
205 return rows;
206}
207
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300208static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300209{
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800210 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300211 struct rb_node *nd;
212
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300213 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300214 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
215 struct callchain_list *chain;
216 char folded_sign = ' '; /* No children */
217
218 list_for_each_entry(chain, &child->val, list) {
219 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800220
221 if (symbol_conf.inline_name) {
222 inline_rows =
223 callchain_list__inline_rows(chain);
224 n += inline_rows;
225 }
226
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300227 /* We need this because we may not have children */
228 folded_sign = callchain_list__folded(chain);
229 if (folded_sign == '+')
230 break;
231 }
232
233 if (folded_sign == '-') /* Have children and they're unfolded */
234 n += callchain_node__count_rows_rb_tree(child);
235 }
236
237 return n;
238}
239
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900240static int callchain_node__count_flat_rows(struct callchain_node *node)
241{
242 struct callchain_list *chain;
243 char folded_sign = 0;
244 int n = 0;
245
246 list_for_each_entry(chain, &node->parent_val, list) {
247 if (!folded_sign) {
248 /* only check first chain list entry */
249 folded_sign = callchain_list__folded(chain);
250 if (folded_sign == '+')
251 return 1;
252 }
253 n++;
254 }
255
256 list_for_each_entry(chain, &node->val, list) {
257 if (!folded_sign) {
258 /* node->parent_val list might be empty */
259 folded_sign = callchain_list__folded(chain);
260 if (folded_sign == '+')
261 return 1;
262 }
263 n++;
264 }
265
266 return n;
267}
268
Namhyung Kim8c430a32015-11-09 14:45:44 +0900269static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
270{
271 return 1;
272}
273
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300274static int callchain_node__count_rows(struct callchain_node *node)
275{
276 struct callchain_list *chain;
277 bool unfolded = false;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800278 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300279
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900280 if (callchain_param.mode == CHAIN_FLAT)
281 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900282 else if (callchain_param.mode == CHAIN_FOLDED)
283 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900284
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300285 list_for_each_entry(chain, &node->val, list) {
286 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800287 if (symbol_conf.inline_name) {
288 inline_rows = callchain_list__inline_rows(chain);
289 n += inline_rows;
290 }
291
Namhyung Kim3698dab2015-05-05 23:55:46 +0900292 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300293 }
294
295 if (unfolded)
296 n += callchain_node__count_rows_rb_tree(node);
297
298 return n;
299}
300
301static int callchain__count_rows(struct rb_root *chain)
302{
303 struct rb_node *nd;
304 int n = 0;
305
306 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
307 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
308 n += callchain_node__count_rows(node);
309 }
310
311 return n;
312}
313
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900314static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
315 bool include_children)
316{
317 int count = 0;
318 struct rb_node *node;
319 struct hist_entry *child;
320
321 if (he->leaf)
322 return callchain__count_rows(&he->sorted_chain);
323
Namhyung Kim79dded82016-02-26 21:13:19 +0900324 if (he->has_no_entry)
325 return 1;
326
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900327 node = rb_first(&he->hroot_out);
328 while (node) {
329 float percent;
330
331 child = rb_entry(node, struct hist_entry, rb_node);
332 percent = hist_entry__get_percent_limit(child);
333
334 if (!child->filtered && percent >= hb->min_pcnt) {
335 count++;
336
337 if (include_children && child->unfolded)
338 count += hierarchy_count_rows(hb, child, true);
339 }
340
341 node = rb_next(node);
342 }
343 return count;
344}
345
Namhyung Kim3698dab2015-05-05 23:55:46 +0900346static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300347{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900348 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200349 return false;
350
Namhyung Kim3698dab2015-05-05 23:55:46 +0900351 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300352 return false;
353
Namhyung Kim3698dab2015-05-05 23:55:46 +0900354 he->unfolded = !he->unfolded;
355 return true;
356}
357
358static bool callchain_list__toggle_fold(struct callchain_list *cl)
359{
360 if (!cl)
361 return false;
362
363 if (!cl->has_children)
364 return false;
365
366 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300367 return true;
368}
369
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300370static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300371{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300372 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300373
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300374 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300375 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
376 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300377 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300378
379 list_for_each_entry(chain, &child->val, list) {
380 if (first) {
381 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900382 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300383 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300384 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900385 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300386 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300387 }
388
389 callchain_node__init_have_children_rb_tree(child);
390 }
391}
392
Namhyung Kima7444af2014-11-24 17:13:27 +0900393static void callchain_node__init_have_children(struct callchain_node *node,
394 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300395{
396 struct callchain_list *chain;
397
Namhyung Kima7444af2014-11-24 17:13:27 +0900398 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900399 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900400
Andres Freund90989032016-03-30 21:02:45 +0200401 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900402 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900403 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900404 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300405
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300406 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300407}
408
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300409static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300410{
Namhyung Kima7444af2014-11-24 17:13:27 +0900411 struct rb_node *nd = rb_first(root);
412 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300413
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300414 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300415 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900416 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900417 if (callchain_param.mode == CHAIN_FLAT ||
418 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900419 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300420 }
421}
422
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300423static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300424{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900425 if (he->init_have_children)
426 return;
427
428 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900429 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300430 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900431 } else {
432 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300433 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900434
435 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300436}
437
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800438static void hist_entry_init_inline_node(struct hist_entry *he)
439{
440 if (he->inline_node)
441 return;
442
443 he->inline_node = inline_node__create(he->ms.map, he->ip);
444
445 if (he->inline_node == NULL)
446 return;
447
448 he->has_children = true;
449}
450
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300451static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300452{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900453 struct hist_entry *he = browser->he_selection;
454 struct map_symbol *ms = browser->selection;
455 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
456 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300457
Wang Nan4938cf02015-12-07 02:35:44 +0000458 if (!he || !ms)
459 return false;
460
Namhyung Kim3698dab2015-05-05 23:55:46 +0900461 if (ms == &he->ms)
462 has_children = hist_entry__toggle_fold(he);
463 else
464 has_children = callchain_list__toggle_fold(cl);
465
466 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900467 int child_rows = 0;
468
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300469 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900470 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300471
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900472 if (he->leaf)
473 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300474 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900475 browser->nr_hierarchy_entries -= he->nr_rows;
476
477 if (symbol_conf.report_hierarchy)
478 child_rows = hierarchy_count_rows(browser, he, true);
479
480 if (he->unfolded) {
481 if (he->leaf)
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800482 if (he->inline_node)
483 he->nr_rows = inline__count_rows(
484 he->inline_node);
485 else
486 he->nr_rows = callchain__count_rows(
487 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900488 else
489 he->nr_rows = hierarchy_count_rows(browser, he, false);
490
491 /* account grand children */
492 if (symbol_conf.report_hierarchy)
493 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900494
495 if (!he->leaf && he->nr_rows == 0) {
496 he->has_no_entry = true;
497 he->nr_rows = 1;
498 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900499 } else {
500 if (symbol_conf.report_hierarchy)
501 browser->b.nr_entries -= child_rows - he->nr_rows;
502
Namhyung Kim79dded82016-02-26 21:13:19 +0900503 if (he->has_no_entry)
504 he->has_no_entry = false;
505
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300506 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900507 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900508
509 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900510
511 if (he->leaf)
512 browser->nr_callchain_rows += he->nr_rows;
513 else
514 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300515
516 return true;
517 }
518
519 /* If it doesn't have children, no toggling performed */
520 return false;
521}
522
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300523static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300524{
525 int n = 0;
526 struct rb_node *nd;
527
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300528 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300529 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
530 struct callchain_list *chain;
531 bool has_children = false;
532
533 list_for_each_entry(chain, &child->val, list) {
534 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900535 callchain_list__set_folding(chain, unfold);
536 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300537 }
538
539 if (has_children)
540 n += callchain_node__set_folding_rb_tree(child, unfold);
541 }
542
543 return n;
544}
545
546static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
547{
548 struct callchain_list *chain;
549 bool has_children = false;
550 int n = 0;
551
552 list_for_each_entry(chain, &node->val, list) {
553 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900554 callchain_list__set_folding(chain, unfold);
555 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300556 }
557
558 if (has_children)
559 n += callchain_node__set_folding_rb_tree(node, unfold);
560
561 return n;
562}
563
564static int callchain__set_folding(struct rb_root *chain, bool unfold)
565{
566 struct rb_node *nd;
567 int n = 0;
568
569 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
570 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
571 n += callchain_node__set_folding(node, unfold);
572 }
573
574 return n;
575}
576
Namhyung Kim492b1012016-02-25 00:13:44 +0900577static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
578 bool unfold __maybe_unused)
579{
580 float percent;
581 struct rb_node *nd;
582 struct hist_entry *child;
583 int n = 0;
584
585 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
586 child = rb_entry(nd, struct hist_entry, rb_node);
587 percent = hist_entry__get_percent_limit(child);
588 if (!child->filtered && percent >= hb->min_pcnt)
589 n++;
590 }
591
592 return n;
593}
594
Jiri Olsab33f9222017-01-20 10:20:29 +0100595static void __hist_entry__set_folding(struct hist_entry *he,
596 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300597{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300598 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900599 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300600
Namhyung Kim3698dab2015-05-05 23:55:46 +0900601 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900602 int n;
603
604 if (he->leaf)
605 n = callchain__set_folding(&he->sorted_chain, unfold);
606 else
607 n = hierarchy_set_folding(hb, he, unfold);
608
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300609 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300610 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300611 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300612}
613
Jiri Olsab33f9222017-01-20 10:20:29 +0100614static void hist_entry__set_folding(struct hist_entry *he,
615 struct hist_browser *browser, bool unfold)
616{
617 double percent;
618
619 percent = hist_entry__get_percent_limit(he);
620 if (he->filtered || percent < browser->min_pcnt)
621 return;
622
623 __hist_entry__set_folding(he, browser, unfold);
624
625 if (!he->depth || unfold)
626 browser->nr_hierarchy_entries++;
627 if (he->leaf)
628 browser->nr_callchain_rows += he->nr_rows;
629 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
630 browser->nr_hierarchy_entries++;
631 he->has_no_entry = true;
632 he->nr_rows = 1;
633 } else
634 he->has_no_entry = false;
635}
636
Namhyung Kimc3b78952014-04-22 15:56:17 +0900637static void
638__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300639{
640 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900641 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300642
Namhyung Kim492b1012016-02-25 00:13:44 +0900643 nd = rb_first(&browser->hists->entries);
644 while (nd) {
645 he = rb_entry(nd, struct hist_entry, rb_node);
646
647 /* set folding state even if it's currently folded */
648 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
649
650 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300651 }
652}
653
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300654static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300655{
Namhyung Kim492b1012016-02-25 00:13:44 +0900656 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900657 browser->nr_callchain_rows = 0;
658 __hist_browser__set_folding(browser, unfold);
659
660 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300661 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300662 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300663}
664
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100665static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
666{
667 if (!browser->he_selection)
668 return;
669
670 hist_entry__set_folding(browser->he_selection, browser, unfold);
671 browser->b.nr_entries = hist_browser__nr_entries(browser);
672}
673
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200674static void ui_browser__warn_lost_events(struct ui_browser *browser)
675{
676 ui_browser__warning(browser, 4,
677 "Events are being lost, check IO/CPU overload!\n\n"
678 "You may want to run 'perf' using a RT scheduler policy:\n\n"
679 " perf top -r 80\n\n"
680 "Or reduce the sampling frequency.");
681}
682
Jiri Olsa5b91a862016-06-20 23:58:15 +0200683static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
684{
685 return browser->title ? browser->title(browser, bf, size) : 0;
686}
687
Jiri Olsadabd2012016-06-20 23:58:14 +0200688int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300689{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300690 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300691 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900692 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900693 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300694
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300695 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900696 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300697
Jiri Olsa5b91a862016-06-20 23:58:15 +0200698 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300699
Namhyung Kim090cff32016-01-11 19:53:14 +0900700 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300701 return -1;
702
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300703 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300704 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300705
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300706 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900707 case K_TIMER: {
708 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900709 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900710
Namhyung Kimc6111522016-10-07 14:04:12 +0900711 if (hist_browser__has_filter(browser) ||
712 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900713 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900714
Namhyung Kimc3b78952014-04-22 15:56:17 +0900715 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900716 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200717
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300718 if (browser->hists->stats.nr_lost_warned !=
719 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
720 browser->hists->stats.nr_lost_warned =
721 browser->hists->stats.nr_events[PERF_RECORD_LOST];
722 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200723 }
724
Jiri Olsa5b91a862016-06-20 23:58:15 +0200725 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300726 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300727 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900728 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300729 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300730 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300731 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300732 struct hist_entry, rb_node);
733 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300734 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 -0300735 seq++, browser->b.nr_entries,
736 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300737 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300738 browser->b.index,
739 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300740 h->row_offset, h->nr_rows);
741 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300742 break;
743 case 'C':
744 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300745 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300746 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100747 case 'c':
748 /* Collapse the selected entry. */
749 hist_browser__set_folding_selected(browser, false);
750 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300751 case 'E':
752 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300753 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300754 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100755 case 'e':
756 /* Expand the selected entry. */
757 hist_browser__set_folding_selected(browser, true);
758 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200759 case 'H':
760 browser->show_headers = !browser->show_headers;
761 hist_browser__update_rows(browser);
762 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200763 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300764 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300765 break;
766 /* fall thru */
767 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300768 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300769 }
770 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300771out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300772 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300773 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300774}
775
Namhyung Kim39ee5332014-08-22 09:13:21 +0900776struct callchain_print_arg {
777 /* for hists browser */
778 off_t row_offset;
779 bool is_current_entry;
780
781 /* for file dump */
782 FILE *fp;
783 int printed;
784};
785
786typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
787 struct callchain_list *chain,
788 const char *str, int offset,
789 unsigned short row,
790 struct callchain_print_arg *arg);
791
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900792static void hist_browser__show_callchain_entry(struct hist_browser *browser,
793 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900794 const char *str, int offset,
795 unsigned short row,
796 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900797{
798 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900799 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300800 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900801
802 color = HE_COLORSET_NORMAL;
803 width = browser->b.width - (offset + 2);
804 if (ui_browser__is_current_entry(&browser->b, row)) {
805 browser->selection = &chain->ms;
806 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900807 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900808 }
809
810 ui_browser__set_color(&browser->b, color);
811 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300812 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300813 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300814 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300815 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900816}
817
Namhyung Kim39ee5332014-08-22 09:13:21 +0900818static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
819 struct callchain_list *chain,
820 const char *str, int offset,
821 unsigned short row __maybe_unused,
822 struct callchain_print_arg *arg)
823{
824 char folded_sign = callchain_list__folded(chain);
825
826 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
827 folded_sign, str);
828}
829
830typedef bool (*check_output_full_fn)(struct hist_browser *browser,
831 unsigned short row);
832
833static bool hist_browser__check_output_full(struct hist_browser *browser,
834 unsigned short row)
835{
836 return browser->b.rows == row;
837}
838
839static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
840 unsigned short row __maybe_unused)
841{
842 return false;
843}
844
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300845#define LEVEL_OFFSET_STEP 3
846
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800847static int hist_browser__show_inline(struct hist_browser *browser,
848 struct inline_node *node,
849 unsigned short row,
850 int offset)
851{
852 struct inline_list *ilist;
853 char buf[1024];
854 int color, width, first_row;
855
856 first_row = row;
857 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
858 list_for_each_entry(ilist, &node->val, list) {
859 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
860 color = HE_COLORSET_NORMAL;
861 if (ui_browser__is_current_entry(&browser->b, row))
862 color = HE_COLORSET_SELECTED;
863
Milian Wolff5dfa2102017-03-18 22:49:28 +0100864 if (callchain_param.key == CCKEY_ADDRESS ||
865 callchain_param.key == CCKEY_SRCLINE) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800866 if (ilist->filename != NULL)
867 scnprintf(buf, sizeof(buf),
868 "%s:%d (inline)",
869 ilist->filename,
870 ilist->line_nr);
871 else
872 scnprintf(buf, sizeof(buf), "??");
873 } else if (ilist->funcname != NULL)
874 scnprintf(buf, sizeof(buf), "%s (inline)",
875 ilist->funcname);
876 else if (ilist->filename != NULL)
877 scnprintf(buf, sizeof(buf),
878 "%s:%d (inline)",
879 ilist->filename,
880 ilist->line_nr);
881 else
882 scnprintf(buf, sizeof(buf), "??");
883
884 ui_browser__set_color(&browser->b, color);
885 hist_browser__gotorc(browser, row, 0);
886 ui_browser__write_nstring(&browser->b, " ",
887 LEVEL_OFFSET_STEP + offset);
888 ui_browser__write_nstring(&browser->b, buf, width);
889 row++;
890 }
891 }
892
893 return row - first_row;
894}
895
896static size_t show_inline_list(struct hist_browser *browser, struct map *map,
897 u64 ip, int row, int offset)
898{
899 struct inline_node *node;
900 int ret;
901
902 node = inline_node__create(map, ip);
903 if (node == NULL)
904 return 0;
905
906 ret = hist_browser__show_inline(browser, node, row, offset);
907
908 inline_node__delete(node);
909 return ret;
910}
911
Namhyung Kim18bb8382015-11-09 14:45:42 +0900912static int hist_browser__show_callchain_list(struct hist_browser *browser,
913 struct callchain_node *node,
914 struct callchain_list *chain,
915 unsigned short row, u64 total,
916 bool need_percent, int offset,
917 print_callchain_entry_fn print,
918 struct callchain_print_arg *arg)
919{
920 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800921 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900922 const char *str;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800923 int inline_rows = 0, ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900924
925 if (arg->row_offset != 0) {
926 arg->row_offset--;
927 return 0;
928 }
929
930 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800931 alloc_str2 = NULL;
932
Namhyung Kim18bb8382015-11-09 14:45:42 +0900933 str = callchain_list__sym_name(chain, bf, sizeof(bf),
934 browser->show_dso);
935
Jin Yaofef51ec2016-10-31 09:19:53 +0800936 if (symbol_conf.show_branchflag_count) {
937 if (need_percent)
938 callchain_list_counts__printf_value(node, chain, NULL,
939 buf, sizeof(buf));
940 else
941 callchain_list_counts__printf_value(NULL, chain, NULL,
942 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900943
Jin Yaofef51ec2016-10-31 09:19:53 +0800944 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
945 str = "Not enough memory!";
946 else
947 str = alloc_str2;
948 }
949
950 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900951 callchain_node__scnprintf_value(node, buf, sizeof(buf),
952 total);
953
954 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
955 str = "Not enough memory!";
956 else
957 str = alloc_str;
958 }
959
960 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900961 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800962 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800963
964 if (symbol_conf.inline_name) {
965 inline_rows = show_inline_list(browser, chain->ms.map,
966 chain->ip, row + 1, offset);
967 }
968
969 return ret + inline_rows;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900970}
971
Namhyung Kim59c624e2016-01-28 00:40:56 +0900972static bool check_percent_display(struct rb_node *node, u64 parent_total)
973{
974 struct callchain_node *child;
975
976 if (node == NULL)
977 return false;
978
979 if (rb_next(node))
980 return true;
981
982 child = rb_entry(node, struct callchain_node, rb_node);
983 return callchain_cumul_hits(child) != parent_total;
984}
985
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900986static int hist_browser__show_callchain_flat(struct hist_browser *browser,
987 struct rb_root *root,
988 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900989 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900990 print_callchain_entry_fn print,
991 struct callchain_print_arg *arg,
992 check_output_full_fn is_output_full)
993{
994 struct rb_node *node;
995 int first_row = row, offset = LEVEL_OFFSET_STEP;
996 bool need_percent;
997
998 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900999 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001000
1001 while (node) {
1002 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1003 struct rb_node *next = rb_next(node);
1004 struct callchain_list *chain;
1005 char folded_sign = ' ';
1006 int first = true;
1007 int extra_offset = 0;
1008
1009 list_for_each_entry(chain, &child->parent_val, list) {
1010 bool was_first = first;
1011
1012 if (first)
1013 first = false;
1014 else if (need_percent)
1015 extra_offset = LEVEL_OFFSET_STEP;
1016
1017 folded_sign = callchain_list__folded(chain);
1018
1019 row += hist_browser__show_callchain_list(browser, child,
1020 chain, row, total,
1021 was_first && need_percent,
1022 offset + extra_offset,
1023 print, arg);
1024
1025 if (is_output_full(browser, row))
1026 goto out;
1027
1028 if (folded_sign == '+')
1029 goto next;
1030 }
1031
1032 list_for_each_entry(chain, &child->val, list) {
1033 bool was_first = first;
1034
1035 if (first)
1036 first = false;
1037 else if (need_percent)
1038 extra_offset = LEVEL_OFFSET_STEP;
1039
1040 folded_sign = callchain_list__folded(chain);
1041
1042 row += hist_browser__show_callchain_list(browser, child,
1043 chain, row, total,
1044 was_first && need_percent,
1045 offset + extra_offset,
1046 print, arg);
1047
1048 if (is_output_full(browser, row))
1049 goto out;
1050
1051 if (folded_sign == '+')
1052 break;
1053 }
1054
1055next:
1056 if (is_output_full(browser, row))
1057 break;
1058 node = next;
1059 }
1060out:
1061 return row - first_row;
1062}
1063
Namhyung Kim8c430a32015-11-09 14:45:44 +09001064static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
1065 struct callchain_list *chain,
1066 char *value_str, char *old_str)
1067{
1068 char bf[1024];
1069 const char *str;
1070 char *new;
1071
1072 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1073 browser->show_dso);
1074 if (old_str) {
1075 if (asprintf(&new, "%s%s%s", old_str,
1076 symbol_conf.field_sep ?: ";", str) < 0)
1077 new = NULL;
1078 } else {
1079 if (value_str) {
1080 if (asprintf(&new, "%s %s", value_str, str) < 0)
1081 new = NULL;
1082 } else {
1083 if (asprintf(&new, "%s", str) < 0)
1084 new = NULL;
1085 }
1086 }
1087 return new;
1088}
1089
1090static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1091 struct rb_root *root,
1092 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +09001093 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +09001094 print_callchain_entry_fn print,
1095 struct callchain_print_arg *arg,
1096 check_output_full_fn is_output_full)
1097{
1098 struct rb_node *node;
1099 int first_row = row, offset = LEVEL_OFFSET_STEP;
1100 bool need_percent;
1101
1102 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001103 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001104
1105 while (node) {
1106 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1107 struct rb_node *next = rb_next(node);
1108 struct callchain_list *chain, *first_chain = NULL;
1109 int first = true;
1110 char *value_str = NULL, *value_str_alloc = NULL;
1111 char *chain_str = NULL, *chain_str_alloc = NULL;
1112
1113 if (arg->row_offset != 0) {
1114 arg->row_offset--;
1115 goto next;
1116 }
1117
1118 if (need_percent) {
1119 char buf[64];
1120
1121 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1122 if (asprintf(&value_str, "%s", buf) < 0) {
1123 value_str = (char *)"<...>";
1124 goto do_print;
1125 }
1126 value_str_alloc = value_str;
1127 }
1128
1129 list_for_each_entry(chain, &child->parent_val, list) {
1130 chain_str = hist_browser__folded_callchain_str(browser,
1131 chain, value_str, chain_str);
1132 if (first) {
1133 first = false;
1134 first_chain = chain;
1135 }
1136
1137 if (chain_str == NULL) {
1138 chain_str = (char *)"Not enough memory!";
1139 goto do_print;
1140 }
1141
1142 chain_str_alloc = chain_str;
1143 }
1144
1145 list_for_each_entry(chain, &child->val, list) {
1146 chain_str = hist_browser__folded_callchain_str(browser,
1147 chain, value_str, chain_str);
1148 if (first) {
1149 first = false;
1150 first_chain = chain;
1151 }
1152
1153 if (chain_str == NULL) {
1154 chain_str = (char *)"Not enough memory!";
1155 goto do_print;
1156 }
1157
1158 chain_str_alloc = chain_str;
1159 }
1160
1161do_print:
1162 print(browser, first_chain, chain_str, offset, row++, arg);
1163 free(value_str_alloc);
1164 free(chain_str_alloc);
1165
1166next:
1167 if (is_output_full(browser, row))
1168 break;
1169 node = next;
1170 }
1171
1172 return row - first_row;
1173}
1174
Namhyung Kim0c841c62016-01-28 00:40:54 +09001175static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001176 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001177 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001178 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001179 print_callchain_entry_fn print,
1180 struct callchain_print_arg *arg,
1181 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001182{
1183 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001184 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001185 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001186 u64 percent_total = total;
1187
1188 if (callchain_param.mode == CHAIN_GRAPH_REL)
1189 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001190
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001191 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001192 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001193
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001194 while (node) {
1195 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1196 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001197 struct callchain_list *chain;
1198 char folded_sign = ' ';
1199 int first = true;
1200 int extra_offset = 0;
1201
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001203 bool was_first = first;
1204
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001205 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001207 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001208 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001209
1210 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001211
Namhyung Kim18bb8382015-11-09 14:45:42 +09001212 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001213 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001214 was_first && need_percent,
1215 offset + extra_offset,
1216 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001217
Namhyung Kim18bb8382015-11-09 14:45:42 +09001218 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001220
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001221 if (folded_sign == '+')
1222 break;
1223 }
1224
1225 if (folded_sign == '-') {
1226 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001227
Namhyung Kim0c841c62016-01-28 00:40:54 +09001228 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001229 new_level, row, total,
1230 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001231 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001232 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001233 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001234 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001235 node = next;
1236 }
1237out:
1238 return row - first_row;
1239}
1240
Namhyung Kim0c841c62016-01-28 00:40:54 +09001241static int hist_browser__show_callchain(struct hist_browser *browser,
1242 struct hist_entry *entry, int level,
1243 unsigned short row,
1244 print_callchain_entry_fn print,
1245 struct callchain_print_arg *arg,
1246 check_output_full_fn is_output_full)
1247{
1248 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001249 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001250 int printed;
1251
Namhyung Kim5eca1042016-01-28 00:40:55 +09001252 if (symbol_conf.cumulate_callchain)
1253 parent_total = entry->stat_acc->period;
1254 else
1255 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001256
1257 if (callchain_param.mode == CHAIN_FLAT) {
1258 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001259 &entry->sorted_chain, row,
1260 total, parent_total, print, arg,
1261 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001262 } else if (callchain_param.mode == CHAIN_FOLDED) {
1263 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001264 &entry->sorted_chain, row,
1265 total, parent_total, print, arg,
1266 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001267 } else {
1268 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001269 &entry->sorted_chain, level, row,
1270 total, parent_total, print, arg,
1271 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001272 }
1273
1274 if (arg->is_current_entry)
1275 browser->he_selection = entry;
1276
1277 return printed;
1278}
1279
Namhyung Kim89701462013-01-22 18:09:38 +09001280struct hpp_arg {
1281 struct ui_browser *b;
1282 char folded_sign;
1283 bool current_entry;
1284};
1285
Jiri Olsa98ba1602016-09-22 17:36:35 +02001286int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001287{
1288 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001289 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001290 va_list args;
1291 double percent;
1292
1293 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001294 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001295 percent = va_arg(args, double);
1296 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001297
Namhyung Kim89701462013-01-22 18:09:38 +09001298 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001299
Namhyung Kimd6751072014-07-31 14:47:36 +09001300 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001301 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001302
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001303 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001304}
1305
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001306#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001307static u64 __hpp_get_##_field(struct hist_entry *he) \
1308{ \
1309 return he->stat._field; \
1310} \
1311 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001312static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001313hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001314 struct perf_hpp *hpp, \
1315 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001316{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001317 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1318 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001319}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001320
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001321#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1322static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1323{ \
1324 return he->stat_acc->_field; \
1325} \
1326 \
1327static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001328hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001329 struct perf_hpp *hpp, \
1330 struct hist_entry *he) \
1331{ \
1332 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001333 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001334 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001335 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001336 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001337 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001338 \
1339 return ret; \
1340 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001341 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1342 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001343}
1344
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001345__HPP_COLOR_PERCENT_FN(overhead, period)
1346__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1347__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1348__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1349__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001350__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001351
1352#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001353#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001354
1355void hist_browser__init_hpp(void)
1356{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001357 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1358 hist_browser__hpp_color_overhead;
1359 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1360 hist_browser__hpp_color_overhead_sys;
1361 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1362 hist_browser__hpp_color_overhead_us;
1363 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1364 hist_browser__hpp_color_overhead_guest_sys;
1365 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1366 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001367 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1368 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001369}
1370
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001371static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001372 struct hist_entry *entry,
1373 unsigned short row)
1374{
Jiri Olsa12400052012-10-13 00:06:16 +02001375 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001376 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001377 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001378 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001379 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001380 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001381 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001382
1383 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001384 browser->he_selection = entry;
1385 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001386 }
1387
1388 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001389 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001390 folded_sign = hist_entry__folded(entry);
1391 }
1392
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001393 if (symbol_conf.inline_name &&
1394 (!entry->has_children)) {
1395 hist_entry_init_inline_node(entry);
1396 folded_sign = hist_entry__folded(entry);
1397 }
1398
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001399 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001400 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001401 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001402 .folded_sign = folded_sign,
1403 .current_entry = current_entry,
1404 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001405 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001406
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001407 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001408
Jiri Olsaf0786af2016-01-18 10:24:23 +01001409 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001410 char s[2048];
1411 struct perf_hpp hpp = {
1412 .buf = s,
1413 .size = sizeof(s),
1414 .ptr = &arg,
1415 };
1416
Namhyung Kim361459f2015-12-23 02:07:08 +09001417 if (perf_hpp__should_skip(fmt, entry->hists) ||
1418 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001419 continue;
1420
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001421 if (current_entry && browser->b.navkeypressed) {
1422 ui_browser__set_color(&browser->b,
1423 HE_COLORSET_SELECTED);
1424 } else {
1425 ui_browser__set_color(&browser->b,
1426 HE_COLORSET_NORMAL);
1427 }
1428
1429 if (first) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001430 if (symbol_conf.use_callchain ||
1431 symbol_conf.inline_name) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001432 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001433 width -= 2;
1434 }
1435 first = false;
1436 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001437 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001438 width -= 2;
1439 }
1440
Jiri Olsa12400052012-10-13 00:06:16 +02001441 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001442 int ret = fmt->color(fmt, &hpp, entry);
1443 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1444 /*
1445 * fmt->color() already used ui_browser to
1446 * print the non alignment bits, skip it (+ret):
1447 */
1448 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001449 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001450 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001451 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001452 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001453 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001454 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001455
1456 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001457 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001458 width += 1;
1459
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001460 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001461
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001462 ++row;
1463 ++printed;
1464 } else
1465 --row_offset;
1466
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001467 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001468 struct callchain_print_arg arg = {
1469 .row_offset = row_offset,
1470 .is_current_entry = current_entry,
1471 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001472
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001473 if (entry->inline_node)
1474 printed += hist_browser__show_inline(browser,
1475 entry->inline_node, row, 0);
1476 else
1477 printed += hist_browser__show_callchain(browser,
1478 entry, 1, row,
1479 hist_browser__show_callchain_entry,
1480 &arg,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001481 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001482 }
1483
1484 return printed;
1485}
1486
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001487static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1488 struct hist_entry *entry,
1489 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001490 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001491{
1492 int printed = 0;
1493 int width = browser->b.width;
1494 char folded_sign = ' ';
1495 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1496 off_t row_offset = entry->row_offset;
1497 bool first = true;
1498 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001499 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001500 struct hpp_arg arg = {
1501 .b = &browser->b,
1502 .current_entry = current_entry,
1503 };
1504 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001505 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001506
1507 if (current_entry) {
1508 browser->he_selection = entry;
1509 browser->selection = &entry->ms;
1510 }
1511
1512 hist_entry__init_have_children(entry);
1513 folded_sign = hist_entry__folded(entry);
1514 arg.folded_sign = folded_sign;
1515
1516 if (entry->leaf && row_offset) {
1517 row_offset--;
1518 goto show_callchain;
1519 }
1520
1521 hist_browser__gotorc(browser, row, 0);
1522
1523 if (current_entry && browser->b.navkeypressed)
1524 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1525 else
1526 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1527
1528 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1529 width -= level * HIERARCHY_INDENT;
1530
Namhyung Kima61a22f2016-03-07 16:44:50 -03001531 /* the first hpp_list_node is for overhead columns */
1532 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1533 struct perf_hpp_list_node, list);
1534 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001535 char s[2048];
1536 struct perf_hpp hpp = {
1537 .buf = s,
1538 .size = sizeof(s),
1539 .ptr = &arg,
1540 };
1541
1542 if (perf_hpp__should_skip(fmt, entry->hists) ||
1543 column++ < browser->b.horiz_scroll)
1544 continue;
1545
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001546 if (current_entry && browser->b.navkeypressed) {
1547 ui_browser__set_color(&browser->b,
1548 HE_COLORSET_SELECTED);
1549 } else {
1550 ui_browser__set_color(&browser->b,
1551 HE_COLORSET_NORMAL);
1552 }
1553
1554 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001555 ui_browser__printf(&browser->b, "%c ", folded_sign);
1556 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001557 first = false;
1558 } else {
1559 ui_browser__printf(&browser->b, " ");
1560 width -= 2;
1561 }
1562
1563 if (fmt->color) {
1564 int ret = fmt->color(fmt, &hpp, entry);
1565 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1566 /*
1567 * fmt->color() already used ui_browser to
1568 * print the non alignment bits, skip it (+ret):
1569 */
1570 ui_browser__printf(&browser->b, "%s", s + ret);
1571 } else {
1572 int ret = fmt->entry(fmt, &hpp, entry);
1573 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1574 ui_browser__printf(&browser->b, "%s", s);
1575 }
1576 width -= hpp.buf - s;
1577 }
1578
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001579 if (!first) {
1580 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1581 width -= hierarchy_indent;
1582 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001583
1584 if (column >= browser->b.horiz_scroll) {
1585 char s[2048];
1586 struct perf_hpp hpp = {
1587 .buf = s,
1588 .size = sizeof(s),
1589 .ptr = &arg,
1590 };
1591
1592 if (current_entry && browser->b.navkeypressed) {
1593 ui_browser__set_color(&browser->b,
1594 HE_COLORSET_SELECTED);
1595 } else {
1596 ui_browser__set_color(&browser->b,
1597 HE_COLORSET_NORMAL);
1598 }
1599
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001600 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001601 if (first) {
1602 ui_browser__printf(&browser->b, "%c ", folded_sign);
1603 first = false;
1604 } else {
1605 ui_browser__write_nstring(&browser->b, "", 2);
1606 }
1607
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001608 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001609
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001610 /*
1611 * No need to call hist_entry__snprintf_alignment()
1612 * since this fmt is always the last column in the
1613 * hierarchy mode.
1614 */
1615 if (fmt->color) {
1616 width -= fmt->color(fmt, &hpp, entry);
1617 } else {
1618 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001619
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001620 width -= fmt->entry(fmt, &hpp, entry);
1621 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001622
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001623 while (isspace(s[i++]))
1624 width++;
1625 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001626 }
1627 }
1628
1629 /* The scroll bar isn't being used */
1630 if (!browser->b.navkeypressed)
1631 width += 1;
1632
1633 ui_browser__write_nstring(&browser->b, "", width);
1634
1635 ++row;
1636 ++printed;
1637
1638show_callchain:
1639 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1640 struct callchain_print_arg carg = {
1641 .row_offset = row_offset,
1642 };
1643
1644 printed += hist_browser__show_callchain(browser, entry,
1645 level + 1, row,
1646 hist_browser__show_callchain_entry, &carg,
1647 hist_browser__check_output_full);
1648 }
1649
1650 return printed;
1651}
1652
Namhyung Kim79dded82016-02-26 21:13:19 +09001653static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001654 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001655{
1656 int width = browser->b.width;
1657 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1658 bool first = true;
1659 int column = 0;
1660 int ret;
1661 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001662 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001663 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001664
1665 if (current_entry) {
1666 browser->he_selection = NULL;
1667 browser->selection = NULL;
1668 }
1669
1670 hist_browser__gotorc(browser, row, 0);
1671
1672 if (current_entry && browser->b.navkeypressed)
1673 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1674 else
1675 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1676
1677 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1678 width -= level * HIERARCHY_INDENT;
1679
Namhyung Kima61a22f2016-03-07 16:44:50 -03001680 /* the first hpp_list_node is for overhead columns */
1681 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1682 struct perf_hpp_list_node, list);
1683 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001684 if (perf_hpp__should_skip(fmt, browser->hists) ||
1685 column++ < browser->b.horiz_scroll)
1686 continue;
1687
Jiri Olsada1b0402016-06-14 20:19:20 +02001688 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001689
1690 if (first) {
1691 /* for folded sign */
1692 first = false;
1693 ret++;
1694 } else {
1695 /* space between columns */
1696 ret += 2;
1697 }
1698
1699 ui_browser__write_nstring(&browser->b, "", ret);
1700 width -= ret;
1701 }
1702
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001703 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1704 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001705
1706 if (column >= browser->b.horiz_scroll) {
1707 char buf[32];
1708
1709 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1710 ui_browser__printf(&browser->b, " %s", buf);
1711 width -= ret + 2;
1712 }
1713
1714 /* The scroll bar isn't being used */
1715 if (!browser->b.navkeypressed)
1716 width += 1;
1717
1718 ui_browser__write_nstring(&browser->b, "", width);
1719 return 1;
1720}
1721
Jiri Olsa81a888f2014-06-14 15:44:52 +02001722static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1723{
1724 advance_hpp(hpp, inc);
1725 return hpp->size <= 0;
1726}
1727
Jiri Olsa69705b32016-08-07 17:28:28 +02001728static int
1729hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1730 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001731{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001732 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001733 struct perf_hpp dummy_hpp = {
1734 .buf = buf,
1735 .size = size,
1736 };
1737 struct perf_hpp_fmt *fmt;
1738 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001739 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001740 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001741
1742 if (symbol_conf.use_callchain) {
1743 ret = scnprintf(buf, size, " ");
1744 if (advance_hpp_check(&dummy_hpp, ret))
1745 return ret;
1746 }
1747
Jiri Olsaf0786af2016-01-18 10:24:23 +01001748 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001749 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001750 continue;
1751
Jiri Olsa29659ab2016-08-07 17:28:30 +02001752 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001753 if (advance_hpp_check(&dummy_hpp, ret))
1754 break;
1755
Jiri Olsa29659ab2016-08-07 17:28:30 +02001756 if (span)
1757 continue;
1758
Jiri Olsa81a888f2014-06-14 15:44:52 +02001759 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1760 if (advance_hpp_check(&dummy_hpp, ret))
1761 break;
1762 }
1763
1764 return ret;
1765}
1766
Namhyung Kimd8b92402016-02-25 00:13:46 +09001767static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1768{
1769 struct hists *hists = browser->hists;
1770 struct perf_hpp dummy_hpp = {
1771 .buf = buf,
1772 .size = size,
1773 };
1774 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001775 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001776 size_t ret = 0;
1777 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001778 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001779 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001780
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001781 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001782 if (advance_hpp_check(&dummy_hpp, ret))
1783 return ret;
1784
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001785 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001786 /* the first hpp_list_node is for overhead columns */
1787 fmt_node = list_first_entry(&hists->hpp_formats,
1788 struct perf_hpp_list_node, list);
1789 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001790 if (column++ < browser->b.horiz_scroll)
1791 continue;
1792
Jiri Olsa29659ab2016-08-07 17:28:30 +02001793 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001794 if (advance_hpp_check(&dummy_hpp, ret))
1795 break;
1796
1797 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1798 if (advance_hpp_check(&dummy_hpp, ret))
1799 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001800
1801 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001802 }
1803
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001804 if (!first_node) {
1805 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1806 indent * HIERARCHY_INDENT, "");
1807 if (advance_hpp_check(&dummy_hpp, ret))
1808 return ret;
1809 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001810
Namhyung Kima61a22f2016-03-07 16:44:50 -03001811 first_node = true;
1812 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1813 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001814 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1815 if (advance_hpp_check(&dummy_hpp, ret))
1816 break;
1817 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001818 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001819
Namhyung Kima61a22f2016-03-07 16:44:50 -03001820 first_col = true;
1821 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1822 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001823
Namhyung Kima61a22f2016-03-07 16:44:50 -03001824 if (perf_hpp__should_skip(fmt, hists))
1825 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001826
Namhyung Kima61a22f2016-03-07 16:44:50 -03001827 if (!first_col) {
1828 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1829 if (advance_hpp_check(&dummy_hpp, ret))
1830 break;
1831 }
1832 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001833
Jiri Olsa29659ab2016-08-07 17:28:30 +02001834 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001835 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001836
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001837 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001838 ret = strlen(start);
1839
1840 if (start != dummy_hpp.buf)
1841 memmove(dummy_hpp.buf, start, ret + 1);
1842
1843 if (advance_hpp_check(&dummy_hpp, ret))
1844 break;
1845 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001846 }
1847
1848 return ret;
1849}
1850
Jiri Olsa01b47702016-06-14 20:19:13 +02001851static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001852{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001853 char headers[1024];
1854
Jiri Olsa01b47702016-06-14 20:19:13 +02001855 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1856 sizeof(headers));
1857
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001858 ui_browser__gotorc(&browser->b, 0, 0);
1859 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001860 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001861}
1862
Jiri Olsa01b47702016-06-14 20:19:13 +02001863static void hists_browser__headers(struct hist_browser *browser)
1864{
Jiri Olsa69705b32016-08-07 17:28:28 +02001865 struct hists *hists = browser->hists;
1866 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001867
Jiri Olsa69705b32016-08-07 17:28:28 +02001868 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001869
Jiri Olsa69705b32016-08-07 17:28:28 +02001870 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1871 char headers[1024];
1872
1873 hists_browser__scnprintf_headers(browser, headers,
1874 sizeof(headers), line);
1875
1876 ui_browser__gotorc(&browser->b, line, 0);
1877 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1878 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1879 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001880}
1881
1882static void hist_browser__show_headers(struct hist_browser *browser)
1883{
1884 if (symbol_conf.report_hierarchy)
1885 hists_browser__hierarchy_headers(browser);
1886 else
1887 hists_browser__headers(browser);
1888}
1889
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001890static void ui_browser__hists_init_top(struct ui_browser *browser)
1891{
1892 if (browser->top == NULL) {
1893 struct hist_browser *hb;
1894
1895 hb = container_of(browser, struct hist_browser, b);
1896 browser->top = rb_first(&hb->hists->entries);
1897 }
1898}
1899
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001900static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001901{
1902 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001903 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001904 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001905 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001906 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001907
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001908 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001909 struct perf_hpp_list *hpp_list = hists->hpp_list;
1910
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001911 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001912 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001913 }
1914
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001915 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001916 hb->he_selection = NULL;
1917 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001918
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001919 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001920 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001921 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001922
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001923 if (h->filtered) {
1924 /* let it move to sibling */
1925 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001926 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001927 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001928
Namhyung Kim14135662013-10-31 10:17:39 +09001929 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001930 if (percent < hb->min_pcnt)
1931 continue;
1932
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001933 if (symbol_conf.report_hierarchy) {
1934 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001935 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001936 if (row == browser->rows)
1937 break;
1938
1939 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001940 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001941 row++;
1942 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001943 } else {
1944 row += hist_browser__show_entry(hb, h, row);
1945 }
1946
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001947 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001948 break;
1949 }
1950
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001951 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001952}
1953
Namhyung Kim064f1982013-05-14 11:09:04 +09001954static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001955 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001956{
1957 while (nd != NULL) {
1958 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001959 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001960
Namhyung Kimc0f15272014-04-16 11:16:33 +09001961 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001962 return nd;
1963
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001964 /*
1965 * If it's filtered, its all children also were filtered.
1966 * So move to sibling node.
1967 */
1968 if (rb_next(nd))
1969 nd = rb_next(nd);
1970 else
1971 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001972 }
1973
1974 return NULL;
1975}
1976
Namhyung Kim064f1982013-05-14 11:09:04 +09001977static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001978 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001979{
1980 while (nd != NULL) {
1981 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001982 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001983
1984 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001985 return nd;
1986
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001987 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001988 }
1989
1990 return NULL;
1991}
1992
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001993static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001994 off_t offset, int whence)
1995{
1996 struct hist_entry *h;
1997 struct rb_node *nd;
1998 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001999 struct hist_browser *hb;
2000
2001 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002002
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002003 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002004 return;
2005
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002006 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03002007
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002008 switch (whence) {
2009 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09002010 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09002011 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002012 break;
2013 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002014 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002015 goto do_offset;
2016 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002017 nd = rb_hierarchy_last(rb_last(browser->entries));
2018 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002019 first = false;
2020 break;
2021 default:
2022 return;
2023 }
2024
2025 /*
2026 * Moves not relative to the first visible entry invalidates its
2027 * row_offset:
2028 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002029 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002030 h->row_offset = 0;
2031
2032 /*
2033 * Here we have to check if nd is expanded (+), if it is we can't go
2034 * the next top level hist_entry, instead we must compute an offset of
2035 * what _not_ to show and not change the first visible entry.
2036 *
2037 * This offset increments when we are going from top to bottom and
2038 * decreases when we're going from bottom to top.
2039 *
2040 * As we don't have backpointers to the top level in the callchains
2041 * structure, we need to always print the whole hist_entry callchain,
2042 * skipping the first ones that are before the first visible entry
2043 * and stop when we printed enough lines to fill the screen.
2044 */
2045do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00002046 if (!nd)
2047 return;
2048
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002049 if (offset > 0) {
2050 do {
2051 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002052 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002053 u16 remaining = h->nr_rows - h->row_offset;
2054 if (offset > remaining) {
2055 offset -= remaining;
2056 h->row_offset = 0;
2057 } else {
2058 h->row_offset += offset;
2059 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002060 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002061 break;
2062 }
2063 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002064 nd = hists__filter_entries(rb_hierarchy_next(nd),
2065 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002066 if (nd == NULL)
2067 break;
2068 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002069 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002070 } while (offset != 0);
2071 } else if (offset < 0) {
2072 while (1) {
2073 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002074 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002075 if (first) {
2076 if (-offset > h->row_offset) {
2077 offset += h->row_offset;
2078 h->row_offset = 0;
2079 } else {
2080 h->row_offset += offset;
2081 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002082 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002083 break;
2084 }
2085 } else {
2086 if (-offset > h->nr_rows) {
2087 offset += h->nr_rows;
2088 h->row_offset = 0;
2089 } else {
2090 h->row_offset = h->nr_rows + offset;
2091 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002092 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002093 break;
2094 }
2095 }
2096 }
2097
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002098 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09002099 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002100 if (nd == NULL)
2101 break;
2102 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002103 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002104 if (offset == 0) {
2105 /*
2106 * Last unfiltered hist_entry, check if it is
2107 * unfolded, if it is then we should have
2108 * row_offset at its last entry.
2109 */
2110 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002111 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002112 h->row_offset = h->nr_rows;
2113 break;
2114 }
2115 first = false;
2116 }
2117 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002118 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002119 h = rb_entry(nd, struct hist_entry, rb_node);
2120 h->row_offset = 0;
2121 }
2122}
2123
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002124static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002125 struct hist_entry *he, FILE *fp,
2126 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002127{
Namhyung Kim39ee5332014-08-22 09:13:21 +09002128 struct callchain_print_arg arg = {
2129 .fp = fp,
2130 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002131
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002132 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09002133 hist_browser__fprintf_callchain_entry, &arg,
2134 hist_browser__check_dump_full);
2135 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002136}
2137
2138static int hist_browser__fprintf_entry(struct hist_browser *browser,
2139 struct hist_entry *he, FILE *fp)
2140{
2141 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002142 int printed = 0;
2143 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09002144 struct perf_hpp hpp = {
2145 .buf = s,
2146 .size = sizeof(s),
2147 };
2148 struct perf_hpp_fmt *fmt;
2149 bool first = true;
2150 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002151
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002152 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002153 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002154 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002155 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002156
Jiri Olsaf0786af2016-01-18 10:24:23 +01002157 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002158 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002159 continue;
2160
Namhyung Kim26d8b332014-03-03 16:16:20 +09002161 if (!first) {
2162 ret = scnprintf(hpp.buf, hpp.size, " ");
2163 advance_hpp(&hpp, ret);
2164 } else
2165 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002166
Namhyung Kim26d8b332014-03-03 16:16:20 +09002167 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002168 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002169 advance_hpp(&hpp, ret);
2170 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002171 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002172
2173 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002174 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2175
2176 return printed;
2177}
2178
2179
2180static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2181 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002182 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002183{
2184 char s[8192];
2185 int printed = 0;
2186 char folded_sign = ' ';
2187 struct perf_hpp hpp = {
2188 .buf = s,
2189 .size = sizeof(s),
2190 };
2191 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002192 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002193 bool first = true;
2194 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002195 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002196
2197 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2198
2199 folded_sign = hist_entry__folded(he);
2200 printed += fprintf(fp, "%c", folded_sign);
2201
Namhyung Kim325a6282016-03-09 22:47:00 +09002202 /* the first hpp_list_node is for overhead columns */
2203 fmt_node = list_first_entry(&he->hists->hpp_formats,
2204 struct perf_hpp_list_node, list);
2205 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002206 if (!first) {
2207 ret = scnprintf(hpp.buf, hpp.size, " ");
2208 advance_hpp(&hpp, ret);
2209 } else
2210 first = false;
2211
2212 ret = fmt->entry(fmt, &hpp, he);
2213 advance_hpp(&hpp, ret);
2214 }
2215
2216 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2217 advance_hpp(&hpp, ret);
2218
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002219 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2220 ret = scnprintf(hpp.buf, hpp.size, " ");
2221 advance_hpp(&hpp, ret);
2222
2223 ret = fmt->entry(fmt, &hpp, he);
2224 advance_hpp(&hpp, ret);
2225 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002226
2227 printed += fprintf(fp, "%s\n", rtrim(s));
2228
2229 if (he->leaf && folded_sign == '-') {
2230 printed += hist_browser__fprintf_callchain(browser, he, fp,
2231 he->depth + 1);
2232 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002233
2234 return printed;
2235}
2236
2237static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2238{
Namhyung Kim064f1982013-05-14 11:09:04 +09002239 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002240 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002241 int printed = 0;
2242
2243 while (nd) {
2244 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2245
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002246 if (symbol_conf.report_hierarchy) {
2247 printed += hist_browser__fprintf_hierarchy_entry(browser,
2248 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002249 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002250 } else {
2251 printed += hist_browser__fprintf_entry(browser, h, fp);
2252 }
2253
2254 nd = hists__filter_entries(rb_hierarchy_next(nd),
2255 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002256 }
2257
2258 return printed;
2259}
2260
2261static int hist_browser__dump(struct hist_browser *browser)
2262{
2263 char filename[64];
2264 FILE *fp;
2265
2266 while (1) {
2267 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2268 if (access(filename, F_OK))
2269 break;
2270 /*
2271 * XXX: Just an arbitrary lazy upper limit
2272 */
2273 if (++browser->print_seq == 8192) {
2274 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2275 return -1;
2276 }
2277 }
2278
2279 fp = fopen(filename, "w");
2280 if (fp == NULL) {
2281 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002282 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002283 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002284 return -1;
2285 }
2286
2287 ++browser->print_seq;
2288 hist_browser__fprintf(browser, fp);
2289 fclose(fp);
2290 ui_helpline__fpush("%s written!", filename);
2291
2292 return 0;
2293}
2294
Jiri Olsafcd86422016-06-20 23:58:18 +02002295void hist_browser__init(struct hist_browser *browser,
2296 struct hists *hists)
2297{
2298 struct perf_hpp_fmt *fmt;
2299
2300 browser->hists = hists;
2301 browser->b.refresh = hist_browser__refresh;
2302 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2303 browser->b.seek = ui_browser__hists_seek;
2304 browser->b.use_navkeypressed = true;
2305 browser->show_headers = symbol_conf.show_hist_headers;
2306
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002307 if (symbol_conf.report_hierarchy) {
2308 struct perf_hpp_list_node *fmt_node;
2309
2310 /* count overhead columns (in the first node) */
2311 fmt_node = list_first_entry(&hists->hpp_formats,
2312 struct perf_hpp_list_node, list);
2313 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2314 ++browser->b.columns;
2315
2316 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002317 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002318 } else {
2319 hists__for_each_format(hists, fmt)
2320 ++browser->b.columns;
2321 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002322
2323 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002324}
2325
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002326struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002327{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002328 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002329
Jiri Olsafcd86422016-06-20 23:58:18 +02002330 if (browser)
2331 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002332
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002333 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002334}
2335
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002336static struct hist_browser *
2337perf_evsel_browser__new(struct perf_evsel *evsel,
2338 struct hist_browser_timer *hbt,
2339 struct perf_env *env)
2340{
2341 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2342
2343 if (browser) {
2344 browser->hbt = hbt;
2345 browser->env = env;
2346 browser->title = perf_evsel_browser_title;
2347 }
2348 return browser;
2349}
2350
Jiri Olsadabd2012016-06-20 23:58:14 +02002351void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002352{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002353 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002354}
2355
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002356static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002357{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002358 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002359}
2360
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002361static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002362{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002363 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002364}
2365
Taeung Song1e378eb2014-10-07 16:13:15 +09002366/* Check whether the browser is for 'top' or 'report' */
2367static inline bool is_report_browser(void *timer)
2368{
2369 return timer == NULL;
2370}
2371
Jiri Olsa5b91a862016-06-20 23:58:15 +02002372static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002373 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002374{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002375 struct hist_browser_timer *hbt = browser->hbt;
2376 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002377 char unit;
2378 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002379 const struct dso *dso = hists->dso_filter;
2380 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002381 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002382 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2383 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002384 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002385 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002386 char buf[512];
2387 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002388 char ref[30] = " show reference callgraph, ";
2389 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002390
Namhyung Kimf2148332014-01-14 11:52:48 +09002391 if (symbol_conf.filter_relative) {
2392 nr_samples = hists->stats.nr_non_filtered_samples;
2393 nr_events = hists->stats.total_non_filtered_period;
2394 }
2395
Namhyung Kim759ff492013-03-05 14:53:26 +09002396 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002397 struct perf_evsel *pos;
2398
2399 perf_evsel__group_desc(evsel, buf, buflen);
2400 ev_name = buf;
2401
2402 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002403 struct hists *pos_hists = evsel__hists(pos);
2404
Namhyung Kimf2148332014-01-14 11:52:48 +09002405 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002406 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2407 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002408 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002409 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2410 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002411 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002412 }
2413 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002414
Kan Liang9e207dd2015-08-11 06:30:49 -04002415 if (symbol_conf.show_ref_callgraph &&
2416 strstr(ev_name, "call-graph=no"))
2417 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002418 nr_samples = convert_unit(nr_samples, &unit);
2419 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002420 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2421 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002422
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002423
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002424 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002425 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002426 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002427 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002428 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002429 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002430 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002431 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002432 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002433 } else {
2434 printed += scnprintf(bf + printed, size - printed,
2435 ", Thread: %s",
2436 (thread->comm_set ? thread__comm_str(thread) : ""));
2437 }
2438 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002439 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002440 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002441 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002442 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002443 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002444 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002445 if (!is_report_browser(hbt)) {
2446 struct perf_top *top = hbt->arg;
2447
2448 if (top->zero)
2449 printed += scnprintf(bf + printed, size - printed, " [z]");
2450 }
2451
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002452 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002453}
2454
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002455static inline void free_popup_options(char **options, int n)
2456{
2457 int i;
2458
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002459 for (i = 0; i < n; ++i)
2460 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002461}
2462
Feng Tang341487ab2013-02-03 14:38:20 +08002463/*
2464 * Only runtime switching of perf data file will make "input_name" point
2465 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2466 * whether we need to call free() for current "input_name" during the switch.
2467 */
2468static bool is_input_name_malloced = false;
2469
2470static int switch_data_file(void)
2471{
2472 char *pwd, *options[32], *abs_path[32], *tmp;
2473 DIR *pwd_dir;
2474 int nr_options = 0, choice = -1, ret = -1;
2475 struct dirent *dent;
2476
2477 pwd = getenv("PWD");
2478 if (!pwd)
2479 return ret;
2480
2481 pwd_dir = opendir(pwd);
2482 if (!pwd_dir)
2483 return ret;
2484
2485 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002486 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002487
2488 while ((dent = readdir(pwd_dir))) {
2489 char path[PATH_MAX];
2490 u64 magic;
2491 char *name = dent->d_name;
2492 FILE *file;
2493
2494 if (!(dent->d_type == DT_REG))
2495 continue;
2496
2497 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2498
2499 file = fopen(path, "r");
2500 if (!file)
2501 continue;
2502
2503 if (fread(&magic, 1, 8, file) < 8)
2504 goto close_file_and_continue;
2505
2506 if (is_perf_magic(magic)) {
2507 options[nr_options] = strdup(name);
2508 if (!options[nr_options])
2509 goto close_file_and_continue;
2510
2511 abs_path[nr_options] = strdup(path);
2512 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002513 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002514 ui__warning("Can't search all data files due to memory shortage.\n");
2515 fclose(file);
2516 break;
2517 }
2518
2519 nr_options++;
2520 }
2521
2522close_file_and_continue:
2523 fclose(file);
2524 if (nr_options >= 32) {
2525 ui__warning("Too many perf data files in PWD!\n"
2526 "Only the first 32 files will be listed.\n");
2527 break;
2528 }
2529 }
2530 closedir(pwd_dir);
2531
2532 if (nr_options) {
2533 choice = ui__popup_menu(nr_options, options);
2534 if (choice < nr_options && choice >= 0) {
2535 tmp = strdup(abs_path[choice]);
2536 if (tmp) {
2537 if (is_input_name_malloced)
2538 free((void *)input_name);
2539 input_name = tmp;
2540 is_input_name_malloced = true;
2541 ret = 0;
2542 } else
2543 ui__warning("Data switch failed due to memory shortage!\n");
2544 }
2545 }
2546
2547 free_popup_options(options, nr_options);
2548 free_popup_options(abs_path, nr_options);
2549 return ret;
2550}
2551
Namhyung Kimea7cd592015-04-22 16:18:19 +09002552struct popup_action {
2553 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002554 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002555 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002556
2557 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2558};
2559
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002560static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002561do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002562{
2563 struct perf_evsel *evsel;
2564 struct annotation *notes;
2565 struct hist_entry *he;
2566 int err;
2567
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002568 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002569 return 0;
2570
Namhyung Kimea7cd592015-04-22 16:18:19 +09002571 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002572 if (!notes->src)
2573 return 0;
2574
2575 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002576 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002577 he = hist_browser__selected_entry(browser);
2578 /*
2579 * offer option to annotate the other branch source or target
2580 * (if they exists) when returning from annotate
2581 */
2582 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2583 return 1;
2584
2585 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2586 if (err)
2587 ui_browser__handle_resize(&browser->b);
2588 return 0;
2589}
2590
2591static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002592add_annotate_opt(struct hist_browser *browser __maybe_unused,
2593 struct popup_action *act, char **optstr,
2594 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002595{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002596 if (sym == NULL || map->dso->annotate_warned)
2597 return 0;
2598
2599 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2600 return 0;
2601
2602 act->ms.map = map;
2603 act->ms.sym = sym;
2604 act->fn = do_annotate;
2605 return 1;
2606}
2607
2608static int
2609do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2610{
2611 struct thread *thread = act->thread;
2612
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002613 if ((!hists__has(browser->hists, thread) &&
2614 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002615 return 0;
2616
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002617 if (browser->hists->thread_filter) {
2618 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2619 perf_hpp__set_elide(HISTC_THREAD, false);
2620 thread__zput(browser->hists->thread_filter);
2621 ui_helpline__pop();
2622 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002623 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002624 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2625 thread->comm_set ? thread__comm_str(thread) : "",
2626 thread->tid);
2627 } else {
2628 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2629 thread->comm_set ? thread__comm_str(thread) : "");
2630 }
2631
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002632 browser->hists->thread_filter = thread__get(thread);
2633 perf_hpp__set_elide(HISTC_THREAD, false);
2634 pstack__push(browser->pstack, &browser->hists->thread_filter);
2635 }
2636
2637 hists__filter_by_thread(browser->hists);
2638 hist_browser__reset(browser);
2639 return 0;
2640}
2641
2642static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002643add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2644 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002645{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002646 int ret;
2647
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002648 if ((!hists__has(browser->hists, thread) &&
2649 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002650 return 0;
2651
Jiri Olsafa829112016-05-03 13:54:47 +02002652 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002653 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2654 browser->hists->thread_filter ? "out of" : "into",
2655 thread->comm_set ? thread__comm_str(thread) : "",
2656 thread->tid);
2657 } else {
2658 ret = asprintf(optstr, "Zoom %s %s thread",
2659 browser->hists->thread_filter ? "out of" : "into",
2660 thread->comm_set ? thread__comm_str(thread) : "");
2661 }
2662 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002663 return 0;
2664
2665 act->thread = thread;
2666 act->fn = do_zoom_thread;
2667 return 1;
2668}
2669
2670static int
2671do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2672{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002673 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002674
Jiri Olsa69849fc2016-05-03 13:54:45 +02002675 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002676 return 0;
2677
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002678 if (browser->hists->dso_filter) {
2679 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2680 perf_hpp__set_elide(HISTC_DSO, false);
2681 browser->hists->dso_filter = NULL;
2682 ui_helpline__pop();
2683 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002684 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002685 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2686 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002687 perf_hpp__set_elide(HISTC_DSO, true);
2688 pstack__push(browser->pstack, &browser->hists->dso_filter);
2689 }
2690
2691 hists__filter_by_dso(browser->hists);
2692 hist_browser__reset(browser);
2693 return 0;
2694}
2695
2696static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002697add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002698 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002699{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002700 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002701 return 0;
2702
2703 if (asprintf(optstr, "Zoom %s %s DSO",
2704 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002705 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002706 return 0;
2707
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002708 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002709 act->fn = do_zoom_dso;
2710 return 1;
2711}
2712
2713static int
2714do_browse_map(struct hist_browser *browser __maybe_unused,
2715 struct popup_action *act)
2716{
2717 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002718 return 0;
2719}
2720
2721static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002722add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002723 struct popup_action *act, char **optstr, struct map *map)
2724{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002725 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002726 return 0;
2727
2728 if (asprintf(optstr, "Browse map details") < 0)
2729 return 0;
2730
2731 act->ms.map = map;
2732 act->fn = do_browse_map;
2733 return 1;
2734}
2735
2736static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002737do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002738 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002739{
2740 char script_opt[64];
2741 memset(script_opt, 0, sizeof(script_opt));
2742
Namhyung Kimea7cd592015-04-22 16:18:19 +09002743 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002744 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002745 thread__comm_str(act->thread));
2746 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002747 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002748 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002749 }
2750
2751 script_browse(script_opt);
2752 return 0;
2753}
2754
2755static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002756add_script_opt(struct hist_browser *browser __maybe_unused,
2757 struct popup_action *act, char **optstr,
2758 struct thread *thread, struct symbol *sym)
2759{
2760 if (thread) {
2761 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2762 thread__comm_str(thread)) < 0)
2763 return 0;
2764 } else if (sym) {
2765 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2766 sym->name) < 0)
2767 return 0;
2768 } else {
2769 if (asprintf(optstr, "Run scripts for all samples") < 0)
2770 return 0;
2771 }
2772
2773 act->thread = thread;
2774 act->ms.sym = sym;
2775 act->fn = do_run_script;
2776 return 1;
2777}
2778
2779static int
2780do_switch_data(struct hist_browser *browser __maybe_unused,
2781 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002782{
2783 if (switch_data_file()) {
2784 ui__warning("Won't switch the data files due to\n"
2785 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002786 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002787 }
2788
2789 return K_SWITCH_INPUT_DATA;
2790}
2791
Namhyung Kimea7cd592015-04-22 16:18:19 +09002792static int
2793add_switch_opt(struct hist_browser *browser,
2794 struct popup_action *act, char **optstr)
2795{
2796 if (!is_report_browser(browser->hbt))
2797 return 0;
2798
2799 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2800 return 0;
2801
2802 act->fn = do_switch_data;
2803 return 1;
2804}
2805
2806static int
2807do_exit_browser(struct hist_browser *browser __maybe_unused,
2808 struct popup_action *act __maybe_unused)
2809{
2810 return 0;
2811}
2812
2813static int
2814add_exit_opt(struct hist_browser *browser __maybe_unused,
2815 struct popup_action *act, char **optstr)
2816{
2817 if (asprintf(optstr, "Exit") < 0)
2818 return 0;
2819
2820 act->fn = do_exit_browser;
2821 return 1;
2822}
2823
Kan Liang84734b02015-09-04 10:45:45 -04002824static int
2825do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2826{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002827 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002828 return 0;
2829
Kan Liang84734b02015-09-04 10:45:45 -04002830 if (browser->hists->socket_filter > -1) {
2831 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2832 browser->hists->socket_filter = -1;
2833 perf_hpp__set_elide(HISTC_SOCKET, false);
2834 } else {
2835 browser->hists->socket_filter = act->socket;
2836 perf_hpp__set_elide(HISTC_SOCKET, true);
2837 pstack__push(browser->pstack, &browser->hists->socket_filter);
2838 }
2839
2840 hists__filter_by_socket(browser->hists);
2841 hist_browser__reset(browser);
2842 return 0;
2843}
2844
2845static int
2846add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2847 char **optstr, int socket_id)
2848{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002849 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002850 return 0;
2851
2852 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2853 (browser->hists->socket_filter > -1) ? "out of" : "into",
2854 socket_id) < 0)
2855 return 0;
2856
2857 act->socket = socket_id;
2858 act->fn = do_zoom_socket;
2859 return 1;
2860}
2861
Namhyung Kim112f7612014-04-22 14:05:35 +09002862static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002863{
2864 u64 nr_entries = 0;
2865 struct rb_node *nd = rb_first(&hb->hists->entries);
2866
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002867 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002868 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2869 return;
2870 }
2871
Namhyung Kim14135662013-10-31 10:17:39 +09002872 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002873 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002874 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002875 }
2876
Namhyung Kim112f7612014-04-22 14:05:35 +09002877 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002878 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002879}
Feng Tang341487ab2013-02-03 14:38:20 +08002880
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002881static void hist_browser__update_percent_limit(struct hist_browser *hb,
2882 double percent)
2883{
2884 struct hist_entry *he;
2885 struct rb_node *nd = rb_first(&hb->hists->entries);
2886 u64 total = hists__total_period(hb->hists);
2887 u64 min_callchain_hits = total * (percent / 100);
2888
2889 hb->min_pcnt = callchain_param.min_percent = percent;
2890
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002891 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2892 he = rb_entry(nd, struct hist_entry, rb_node);
2893
Namhyung Kim79dded82016-02-26 21:13:19 +09002894 if (he->has_no_entry) {
2895 he->has_no_entry = false;
2896 he->nr_rows = 0;
2897 }
2898
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002899 if (!he->leaf || !symbol_conf.use_callchain)
2900 goto next;
2901
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002902 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2903 total = he->stat.period;
2904
2905 if (symbol_conf.cumulate_callchain)
2906 total = he->stat_acc->period;
2907
2908 min_callchain_hits = total * (percent / 100);
2909 }
2910
2911 callchain_param.sort(&he->sorted_chain, he->callchain,
2912 min_callchain_hits, &callchain_param);
2913
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002914next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002915 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002916
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002917 /* force to re-evaluate folding state of callchains */
2918 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002919 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002920 }
2921}
2922
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002923static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002924 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002925 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002926 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002927 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002928 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002929{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002930 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002931 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002932 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002933#define MAX_OPTIONS 16
2934 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002935 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002936 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002937 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002938 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002939 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002940
Namhyung Kime8e684a2013-12-26 14:37:58 +09002941#define HIST_BROWSER_HELP_COMMON \
2942 "h/?/F1 Show this window\n" \
2943 "UP/DOWN/PGUP\n" \
2944 "PGDN/SPACE Navigate\n" \
2945 "q/ESC/CTRL+C Exit browser\n\n" \
2946 "For multiple event sessions:\n\n" \
2947 "TAB/UNTAB Switch events\n\n" \
2948 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002949 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2950 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002951 "a Annotate current symbol\n" \
2952 "C Collapse all callchains\n" \
2953 "d Zoom into current DSO\n" \
2954 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002955 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002956 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002957 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002958 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002959 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002960
2961 /* help messages are sorted by lexical order of the hotkey */
2962 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002963 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002964 "P Print histograms to perf.hist.N\n"
2965 "r Run available scripts\n"
2966 "s Switch to another data file in PWD\n"
2967 "t Zoom into current Thread\n"
2968 "V Verbose (DSO names in callchains, etc)\n"
2969 "/ Filter symbol by name";
2970 const char top_help[] = HIST_BROWSER_HELP_COMMON
2971 "P Print histograms to perf.hist.N\n"
2972 "t Zoom into current Thread\n"
2973 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002974 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002975 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002976 "/ Filter symbol by name";
2977
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002978 if (browser == NULL)
2979 return -1;
2980
Namhyung Kimed426912015-05-29 21:53:44 +09002981 /* reset abort key so that it can get Ctrl-C as a key */
2982 SLang_reset_tty();
2983 SLang_init_tty(0, 0, 0);
2984
Namhyung Kim03905042015-11-28 02:32:39 +09002985 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002986 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002987 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002988
Kan Liang84734b02015-09-04 10:45:45 -04002989 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002990 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002991 goto out;
2992
2993 ui_helpline__push(helpline);
2994
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002995 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002996 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002997
Namhyung Kim5b591662014-07-31 14:47:38 +09002998 if (symbol_conf.col_width_list_str)
2999 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
3000
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003001 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03003002 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003003 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003004 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04003005 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003006
Stephane Eranian24bff2d2012-03-12 16:13:30 +01003007 nr_options = 0;
3008
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03003009 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003010
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003011 if (browser->he_selection != NULL) {
3012 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003013 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04003014 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003015 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003016 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003017 case K_TAB:
3018 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06003019 if (nr_events == 1)
3020 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003021 /*
3022 * Exit the browser, let hists__browser_tree
3023 * go to the next or previous
3024 */
3025 goto out_free_stack;
3026 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003027 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003028 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003029 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003030 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003031 continue;
3032 }
3033
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003034 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08003035 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003036 browser->selection->map->dso->annotate_warned)
3037 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003038
Namhyung Kimea7cd592015-04-22 16:18:19 +09003039 actions->ms.map = browser->selection->map;
3040 actions->ms.sym = browser->selection->sym;
3041 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003042 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03003043 case 'P':
3044 hist_browser__dump(browser);
3045 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003046 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03003047 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003048 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003049 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003050 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02003051 verbose = (verbose + 1) % 4;
3052 browser->show_dso = verbose > 0;
3053 ui_helpline__fpush("Verbosity level set to %d\n",
3054 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003055 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003056 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003057 actions->thread = thread;
3058 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003059 continue;
Kan Liang84734b02015-09-04 10:45:45 -04003060 case 'S':
3061 actions->socket = socked_id;
3062 do_zoom_socket(browser, actions);
3063 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03003064 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09003065 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03003066 "Please enter the name of symbol you want to see.\n"
3067 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09003068 buf, "ENTER: OK, ESC: Cancel",
3069 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03003070 hists->symbol_filter_str = *buf ? buf : NULL;
3071 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09003072 hist_browser__reset(browser);
3073 }
3074 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08003075 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003076 if (is_report_browser(hbt)) {
3077 actions->thread = NULL;
3078 actions->ms.sym = NULL;
3079 do_run_script(browser, actions);
3080 }
Feng Tangc77d8d72012-11-01 00:00:55 +08003081 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08003082 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003083 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003084 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003085 if (key == K_SWITCH_INPUT_DATA)
3086 goto out_free_stack;
3087 }
Feng Tang341487ab2013-02-03 14:38:20 +08003088 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09003089 case 'i':
3090 /* env->arch is NULL for live-mode (i.e. perf top) */
3091 if (env->arch)
3092 tui__header_window(env);
3093 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09003094 case 'F':
3095 symbol_conf.filter_relative ^= 1;
3096 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09003097 case 'z':
3098 if (!is_report_browser(hbt)) {
3099 struct perf_top *top = hbt->arg;
3100
3101 top->zero = !top->zero;
3102 }
3103 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003104 case 'L':
3105 if (ui_browser__input_window("Percent Limit",
3106 "Please enter the value you want to hide entries under that percent.",
3107 buf, "ENTER: OK, ESC: Cancel",
3108 delay_secs * 2) == K_ENTER) {
3109 char *end;
3110 double new_percent = strtod(buf, &end);
3111
3112 if (new_percent < 0 || new_percent > 100) {
3113 ui_browser__warning(&browser->b, delay_secs * 2,
3114 "Invalid percent: %.2f", new_percent);
3115 continue;
3116 }
3117
3118 hist_browser__update_percent_limit(browser, new_percent);
3119 hist_browser__reset(browser);
3120 }
3121 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003122 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003123 case 'h':
3124 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003125 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003126 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003127 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003128 case K_ENTER:
3129 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003130 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003131 /* menu */
3132 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003133 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003134 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003135 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003136
Namhyung Kim01f00a12015-04-22 16:18:16 +09003137 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003138 /*
3139 * Go back to the perf_evsel_menu__run or other user
3140 */
3141 if (left_exits)
3142 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003143
3144 if (key == K_ESC &&
3145 ui_browser__dialog_yesno(&browser->b,
3146 "Do you really want to exit?"))
3147 goto out_free_stack;
3148
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003149 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003150 }
Namhyung Kim64221842015-04-24 10:15:33 +09003151 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003152 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003153 /*
3154 * No need to set actions->dso here since
3155 * it's just to remove the current filter.
3156 * Ditto for thread below.
3157 */
3158 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003159 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003160 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003161 } else if (top == &browser->hists->socket_filter) {
3162 do_zoom_socket(browser, actions);
3163 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003164 continue;
3165 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003166 case 'q':
3167 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003168 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003169 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003170 if (!is_report_browser(hbt)) {
3171 struct perf_top *top = hbt->arg;
3172
3173 perf_evlist__toggle_enable(top->evlist);
3174 /*
3175 * No need to refresh, resort/decay histogram
3176 * entries if we are not collecting samples:
3177 */
3178 if (top->evlist->enabled) {
3179 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3180 hbt->refresh = delay_secs;
3181 } else {
3182 helpline = "Press 'f' again to re-enable the events";
3183 hbt->refresh = 0;
3184 }
3185 continue;
3186 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003187 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003188 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003189 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003190 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003191 }
3192
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003193 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003194 goto skip_annotation;
3195
Namhyung Kim55369fc2013-04-01 20:35:20 +09003196 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003197 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003198
3199 if (bi == NULL)
3200 goto skip_annotation;
3201
Namhyung Kimea7cd592015-04-22 16:18:19 +09003202 nr_options += add_annotate_opt(browser,
3203 &actions[nr_options],
3204 &options[nr_options],
3205 bi->from.map,
3206 bi->from.sym);
3207 if (bi->to.sym != bi->from.sym)
3208 nr_options += add_annotate_opt(browser,
3209 &actions[nr_options],
3210 &options[nr_options],
3211 bi->to.map,
3212 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003213 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003214 nr_options += add_annotate_opt(browser,
3215 &actions[nr_options],
3216 &options[nr_options],
3217 browser->selection->map,
3218 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003219 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003220skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003221 nr_options += add_thread_opt(browser, &actions[nr_options],
3222 &options[nr_options], thread);
3223 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003224 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003225 nr_options += add_map_opt(browser, &actions[nr_options],
3226 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003227 browser->selection ?
3228 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003229 nr_options += add_socket_opt(browser, &actions[nr_options],
3230 &options[nr_options],
3231 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003232 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003233 if (!is_report_browser(hbt))
3234 goto skip_scripting;
3235
Feng Tangcdbab7c2012-10-30 11:56:06 +08003236 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003237 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003238 nr_options += add_script_opt(browser,
3239 &actions[nr_options],
3240 &options[nr_options],
3241 thread, NULL);
3242 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003243 /*
3244 * Note that browser->selection != NULL
3245 * when browser->he_selection is not NULL,
3246 * so we don't need to check browser->selection
3247 * before fetching browser->selection->sym like what
3248 * we do before fetching browser->selection->map.
3249 *
3250 * See hist_browser__show_entry.
3251 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003252 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003253 nr_options += add_script_opt(browser,
3254 &actions[nr_options],
3255 &options[nr_options],
3256 NULL, browser->selection->sym);
3257 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003258 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003259 nr_options += add_script_opt(browser, &actions[nr_options],
3260 &options[nr_options], NULL, NULL);
3261 nr_options += add_switch_opt(browser, &actions[nr_options],
3262 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003263skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003264 nr_options += add_exit_opt(browser, &actions[nr_options],
3265 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003266
Namhyung Kimea7cd592015-04-22 16:18:19 +09003267 do {
3268 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003269
Namhyung Kimea7cd592015-04-22 16:18:19 +09003270 choice = ui__popup_menu(nr_options, options);
3271 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003272 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003273
3274 act = &actions[choice];
3275 key = act->fn(browser, act);
3276 } while (key == 1);
3277
3278 if (key == K_SWITCH_INPUT_DATA)
3279 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003280 }
3281out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003282 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003283out:
3284 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003285 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003286 return key;
3287}
3288
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003289struct perf_evsel_menu {
3290 struct ui_browser b;
3291 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003292 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003293 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003294 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003295};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003296
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003297static void perf_evsel_menu__write(struct ui_browser *browser,
3298 void *entry, int row)
3299{
3300 struct perf_evsel_menu *menu = container_of(browser,
3301 struct perf_evsel_menu, b);
3302 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003303 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003304 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003305 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003306 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003307 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003308 const char *warn = " ";
3309 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003310
3311 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3312 HE_COLORSET_NORMAL);
3313
Namhyung Kim759ff492013-03-05 14:53:26 +09003314 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003315 struct perf_evsel *pos;
3316
3317 ev_name = perf_evsel__group_name(evsel);
3318
3319 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003320 struct hists *pos_hists = evsel__hists(pos);
3321 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003322 }
3323 }
3324
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003325 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003326 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003327 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003328 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003329
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003330 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003331 if (nr_events != 0) {
3332 menu->lost_events = true;
3333 if (!current_entry)
3334 ui_browser__set_color(browser, HE_COLORSET_TOP);
3335 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003336 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3337 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003338 warn = bf;
3339 }
3340
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003341 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003342
3343 if (current_entry)
3344 menu->selection = evsel;
3345}
3346
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003347static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3348 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003349 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003350{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003351 struct perf_evlist *evlist = menu->b.priv;
3352 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003353 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003354 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003355 int key;
3356
3357 if (ui_browser__show(&menu->b, title,
3358 "ESC: exit, ENTER|->: Browse histograms") < 0)
3359 return -1;
3360
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003361 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003362 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003363
3364 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003365 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003366 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003367
3368 if (!menu->lost_events_warned && menu->lost_events) {
3369 ui_browser__warn_lost_events(&menu->b);
3370 menu->lost_events_warned = true;
3371 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003372 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003373 case K_RIGHT:
3374 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003375 if (!menu->selection)
3376 continue;
3377 pos = menu->selection;
3378browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003379 perf_evlist__set_selected(evlist, pos);
3380 /*
3381 * Give the calling tool a chance to populate the non
3382 * default evsel resorted hists tree.
3383 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003384 if (hbt)
3385 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003386 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003387 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003388 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003389 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003390 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003391 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003392 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003393 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003394 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003395 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003396 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003397 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003398 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003399 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003400 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003401 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003402 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003403 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003404 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003405 case 'q':
3406 case CTRL('c'):
3407 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003408 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003409 default:
3410 continue;
3411 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003412 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003413 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003414 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003415 if (!ui_browser__dialog_yesno(&menu->b,
3416 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003417 continue;
3418 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003419 case 'q':
3420 case CTRL('c'):
3421 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003422 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003423 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003424 }
3425 }
3426
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003427out:
3428 ui_browser__hide(&menu->b);
3429 return key;
3430}
3431
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003432static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003433 void *entry)
3434{
3435 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3436
3437 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3438 return true;
3439
3440 return false;
3441}
3442
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003443static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003444 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003445 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003446 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003447 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003448{
3449 struct perf_evsel *pos;
3450 struct perf_evsel_menu menu = {
3451 .b = {
3452 .entries = &evlist->entries,
3453 .refresh = ui_browser__list_head_refresh,
3454 .seek = ui_browser__list_head_seek,
3455 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003456 .filter = filter_group_entries,
3457 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003458 .priv = evlist,
3459 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003460 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003461 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003462 };
3463
3464 ui_helpline__push("Press ESC to exit");
3465
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003466 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003467 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003468 size_t line_len = strlen(ev_name) + 7;
3469
3470 if (menu.b.width < line_len)
3471 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003472 }
3473
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003474 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003475}
3476
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003477int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003478 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003479 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003480 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003481{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003482 int nr_entries = evlist->nr_entries;
3483
3484single_entry:
3485 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003486 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003487
3488 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003489 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003490 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003491 }
3492
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003493 if (symbol_conf.event_group) {
3494 struct perf_evsel *pos;
3495
3496 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003497 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003498 if (perf_evsel__is_group_leader(pos))
3499 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003500 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003501
3502 if (nr_entries == 1)
3503 goto single_entry;
3504 }
3505
3506 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003507 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003508}