blob: ac7f6a3e4a86b4cc77773df93d45661cbc25d149 [file] [log] [blame]
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03001#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003#include <stdlib.h>
4#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <linux/rbtree.h>
6
Namhyung Kimaca7a942012-04-04 00:14:26 -07007#include "../../util/evsel.h"
8#include "../../util/evlist.h"
9#include "../../util/hist.h"
10#include "../../util/pstack.h"
11#include "../../util/sort.h"
12#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090013#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090014#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030015
Jiri Olsaf7589902016-06-20 23:58:13 +020016#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030017#include "../helpline.h"
18#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020019#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030020#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020021#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030022#include "srcline.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030023
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030024#include "sane_ctype.h"
25
Namhyung Kimf5951d52012-09-03 11:53:09 +090026extern void hist_browser__init_hpp(void);
27
Jiri Olsa5b91a862016-06-20 23:58:15 +020028static int perf_evsel_browser_title(struct hist_browser *browser,
29 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090030static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030031
Namhyung Kimc3b78952014-04-22 15:56:17 +090032static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090033 float min_pcnt);
34
Namhyung Kim268397c2014-04-22 14:49:31 +090035static bool hist_browser__has_filter(struct hist_browser *hb)
36{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010037 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090038}
39
He Kuang4fabf3d2015-03-12 15:21:49 +080040static int hist_browser__get_folding(struct hist_browser *browser)
41{
42 struct rb_node *nd;
43 struct hists *hists = browser->hists;
44 int unfolded_rows = 0;
45
46 for (nd = rb_first(&hists->entries);
47 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090048 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080049 struct hist_entry *he =
50 rb_entry(nd, struct hist_entry, rb_node);
51
Namhyung Kimf5b763f2016-02-25 00:13:43 +090052 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080053 unfolded_rows += he->nr_rows;
54 }
55 return unfolded_rows;
56}
57
Namhyung Kimc3b78952014-04-22 15:56:17 +090058static u32 hist_browser__nr_entries(struct hist_browser *hb)
59{
60 u32 nr_entries;
61
Namhyung Kimf5b763f2016-02-25 00:13:43 +090062 if (symbol_conf.report_hierarchy)
63 nr_entries = hb->nr_hierarchy_entries;
64 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090065 nr_entries = hb->nr_non_filtered_entries;
66 else
67 nr_entries = hb->hists->nr_entries;
68
He Kuang4fabf3d2015-03-12 15:21:49 +080069 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090070 return nr_entries + hb->nr_callchain_rows;
71}
72
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020073static void hist_browser__update_rows(struct hist_browser *hb)
74{
75 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020076 struct hists *hists = hb->hists;
77 struct perf_hpp_list *hpp_list = hists->hpp_list;
78 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020079
Jiri Olsaf8e67102016-08-07 17:28:26 +020080 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020081 browser->rows = browser->height - header_offset;
82 /*
83 * Verify if we were at the last line and that line isn't
84 * visibe because we now show the header line(s).
85 */
86 index_row = browser->index - browser->top_idx;
87 if (index_row >= browser->rows)
88 browser->index -= index_row - browser->rows + 1;
89}
90
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030091static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030092{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030093 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
94
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030095 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030096 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
97 /*
98 * FIXME: Just keeping existing behaviour, but this really should be
99 * before updating browser->width, as it will invalidate the
100 * calculation above. Fix this and the fallout in another
101 * changeset.
102 */
103 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200104 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300105}
106
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300107static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
108{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200109 struct hists *hists = browser->hists;
110 struct perf_hpp_list *hpp_list = hists->hpp_list;
111 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200112
Jiri Olsaf8e67102016-08-07 17:28:26 +0200113 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200114 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300115}
116
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300117static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300118{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900119 /*
120 * The hists__remove_entry_filter() already folds non-filtered
121 * entries so we can assume it has 0 callchain rows.
122 */
123 browser->nr_callchain_rows = 0;
124
Namhyung Kim268397c2014-04-22 14:49:31 +0900125 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900126 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300127 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300128 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300129}
130
131static char tree__folded_sign(bool unfolded)
132{
133 return unfolded ? '-' : '+';
134}
135
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300136static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300137{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900138 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300139}
140
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300141static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300142{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900143 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144}
145
Namhyung Kim3698dab2015-05-05 23:55:46 +0900146static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300147{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900148 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300149}
150
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800151static struct inline_node *inline_node__create(struct map *map, u64 ip)
152{
153 struct dso *dso;
154 struct inline_node *node;
155
156 if (map == NULL)
157 return NULL;
158
159 dso = map->dso;
160 if (dso == NULL)
161 return NULL;
162
163 if (dso->kernel != DSO_TYPE_USER)
164 return NULL;
165
166 node = dso__parse_addr_inlines(dso,
167 map__rip_2objdump(map, ip));
168
169 return node;
170}
171
172static int inline__count_rows(struct inline_node *node)
173{
174 struct inline_list *ilist;
175 int i = 0;
176
177 if (node == NULL)
178 return 0;
179
180 list_for_each_entry(ilist, &node->val, list) {
181 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
182 i++;
183 }
184
185 return i;
186}
187
188static int callchain_list__inline_rows(struct callchain_list *chain)
189{
190 struct inline_node *node;
191 int rows;
192
193 node = inline_node__create(chain->ms.map, chain->ip);
194 if (node == NULL)
195 return 0;
196
197 rows = inline__count_rows(node);
198 inline_node__delete(node);
199 return rows;
200}
201
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300202static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300203{
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800204 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300205 struct rb_node *nd;
206
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300207 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300208 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
209 struct callchain_list *chain;
210 char folded_sign = ' '; /* No children */
211
212 list_for_each_entry(chain, &child->val, list) {
213 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800214
215 if (symbol_conf.inline_name) {
216 inline_rows =
217 callchain_list__inline_rows(chain);
218 n += inline_rows;
219 }
220
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300221 /* We need this because we may not have children */
222 folded_sign = callchain_list__folded(chain);
223 if (folded_sign == '+')
224 break;
225 }
226
227 if (folded_sign == '-') /* Have children and they're unfolded */
228 n += callchain_node__count_rows_rb_tree(child);
229 }
230
231 return n;
232}
233
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900234static int callchain_node__count_flat_rows(struct callchain_node *node)
235{
236 struct callchain_list *chain;
237 char folded_sign = 0;
238 int n = 0;
239
240 list_for_each_entry(chain, &node->parent_val, list) {
241 if (!folded_sign) {
242 /* only check first chain list entry */
243 folded_sign = callchain_list__folded(chain);
244 if (folded_sign == '+')
245 return 1;
246 }
247 n++;
248 }
249
250 list_for_each_entry(chain, &node->val, list) {
251 if (!folded_sign) {
252 /* node->parent_val list might be empty */
253 folded_sign = callchain_list__folded(chain);
254 if (folded_sign == '+')
255 return 1;
256 }
257 n++;
258 }
259
260 return n;
261}
262
Namhyung Kim8c430a32015-11-09 14:45:44 +0900263static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
264{
265 return 1;
266}
267
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300268static int callchain_node__count_rows(struct callchain_node *node)
269{
270 struct callchain_list *chain;
271 bool unfolded = false;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800272 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300273
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900274 if (callchain_param.mode == CHAIN_FLAT)
275 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900276 else if (callchain_param.mode == CHAIN_FOLDED)
277 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900278
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300279 list_for_each_entry(chain, &node->val, list) {
280 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800281 if (symbol_conf.inline_name) {
282 inline_rows = callchain_list__inline_rows(chain);
283 n += inline_rows;
284 }
285
Namhyung Kim3698dab2015-05-05 23:55:46 +0900286 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300287 }
288
289 if (unfolded)
290 n += callchain_node__count_rows_rb_tree(node);
291
292 return n;
293}
294
295static int callchain__count_rows(struct rb_root *chain)
296{
297 struct rb_node *nd;
298 int n = 0;
299
300 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
301 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
302 n += callchain_node__count_rows(node);
303 }
304
305 return n;
306}
307
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900308static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
309 bool include_children)
310{
311 int count = 0;
312 struct rb_node *node;
313 struct hist_entry *child;
314
315 if (he->leaf)
316 return callchain__count_rows(&he->sorted_chain);
317
Namhyung Kim79dded82016-02-26 21:13:19 +0900318 if (he->has_no_entry)
319 return 1;
320
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900321 node = rb_first(&he->hroot_out);
322 while (node) {
323 float percent;
324
325 child = rb_entry(node, struct hist_entry, rb_node);
326 percent = hist_entry__get_percent_limit(child);
327
328 if (!child->filtered && percent >= hb->min_pcnt) {
329 count++;
330
331 if (include_children && child->unfolded)
332 count += hierarchy_count_rows(hb, child, true);
333 }
334
335 node = rb_next(node);
336 }
337 return count;
338}
339
Namhyung Kim3698dab2015-05-05 23:55:46 +0900340static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300341{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900342 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200343 return false;
344
Namhyung Kim3698dab2015-05-05 23:55:46 +0900345 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300346 return false;
347
Namhyung Kim3698dab2015-05-05 23:55:46 +0900348 he->unfolded = !he->unfolded;
349 return true;
350}
351
352static bool callchain_list__toggle_fold(struct callchain_list *cl)
353{
354 if (!cl)
355 return false;
356
357 if (!cl->has_children)
358 return false;
359
360 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300361 return true;
362}
363
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300364static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300365{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300366 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300367
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300369 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
370 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300371 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372
373 list_for_each_entry(chain, &child->val, list) {
374 if (first) {
375 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900376 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300377 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300378 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900379 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300380 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300381 }
382
383 callchain_node__init_have_children_rb_tree(child);
384 }
385}
386
Namhyung Kima7444af2014-11-24 17:13:27 +0900387static void callchain_node__init_have_children(struct callchain_node *node,
388 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300389{
390 struct callchain_list *chain;
391
Namhyung Kima7444af2014-11-24 17:13:27 +0900392 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900393 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900394
Andres Freund90989032016-03-30 21:02:45 +0200395 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900396 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900397 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900398 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300399
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300400 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401}
402
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300403static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300404{
Namhyung Kima7444af2014-11-24 17:13:27 +0900405 struct rb_node *nd = rb_first(root);
406 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300407
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300408 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300409 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900410 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900411 if (callchain_param.mode == CHAIN_FLAT ||
412 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900413 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300414 }
415}
416
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300417static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300418{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900419 if (he->init_have_children)
420 return;
421
422 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900423 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300424 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900425 } else {
426 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300427 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900428
429 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300430}
431
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800432static void hist_entry_init_inline_node(struct hist_entry *he)
433{
434 if (he->inline_node)
435 return;
436
437 he->inline_node = inline_node__create(he->ms.map, he->ip);
438
439 if (he->inline_node == NULL)
440 return;
441
442 he->has_children = true;
443}
444
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300445static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300446{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900447 struct hist_entry *he = browser->he_selection;
448 struct map_symbol *ms = browser->selection;
449 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
450 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300451
Wang Nan4938cf02015-12-07 02:35:44 +0000452 if (!he || !ms)
453 return false;
454
Namhyung Kim3698dab2015-05-05 23:55:46 +0900455 if (ms == &he->ms)
456 has_children = hist_entry__toggle_fold(he);
457 else
458 has_children = callchain_list__toggle_fold(cl);
459
460 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900461 int child_rows = 0;
462
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300463 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900464 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300465
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900466 if (he->leaf)
467 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300468 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900469 browser->nr_hierarchy_entries -= he->nr_rows;
470
471 if (symbol_conf.report_hierarchy)
472 child_rows = hierarchy_count_rows(browser, he, true);
473
474 if (he->unfolded) {
475 if (he->leaf)
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800476 if (he->inline_node)
477 he->nr_rows = inline__count_rows(
478 he->inline_node);
479 else
480 he->nr_rows = callchain__count_rows(
481 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900482 else
483 he->nr_rows = hierarchy_count_rows(browser, he, false);
484
485 /* account grand children */
486 if (symbol_conf.report_hierarchy)
487 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900488
489 if (!he->leaf && he->nr_rows == 0) {
490 he->has_no_entry = true;
491 he->nr_rows = 1;
492 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900493 } else {
494 if (symbol_conf.report_hierarchy)
495 browser->b.nr_entries -= child_rows - he->nr_rows;
496
Namhyung Kim79dded82016-02-26 21:13:19 +0900497 if (he->has_no_entry)
498 he->has_no_entry = false;
499
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300500 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900501 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900502
503 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900504
505 if (he->leaf)
506 browser->nr_callchain_rows += he->nr_rows;
507 else
508 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300509
510 return true;
511 }
512
513 /* If it doesn't have children, no toggling performed */
514 return false;
515}
516
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300517static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300518{
519 int n = 0;
520 struct rb_node *nd;
521
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300522 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300523 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
524 struct callchain_list *chain;
525 bool has_children = false;
526
527 list_for_each_entry(chain, &child->val, list) {
528 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900529 callchain_list__set_folding(chain, unfold);
530 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300531 }
532
533 if (has_children)
534 n += callchain_node__set_folding_rb_tree(child, unfold);
535 }
536
537 return n;
538}
539
540static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
541{
542 struct callchain_list *chain;
543 bool has_children = false;
544 int n = 0;
545
546 list_for_each_entry(chain, &node->val, list) {
547 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900548 callchain_list__set_folding(chain, unfold);
549 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300550 }
551
552 if (has_children)
553 n += callchain_node__set_folding_rb_tree(node, unfold);
554
555 return n;
556}
557
558static int callchain__set_folding(struct rb_root *chain, bool unfold)
559{
560 struct rb_node *nd;
561 int n = 0;
562
563 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
564 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
565 n += callchain_node__set_folding(node, unfold);
566 }
567
568 return n;
569}
570
Namhyung Kim492b1012016-02-25 00:13:44 +0900571static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
572 bool unfold __maybe_unused)
573{
574 float percent;
575 struct rb_node *nd;
576 struct hist_entry *child;
577 int n = 0;
578
579 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
580 child = rb_entry(nd, struct hist_entry, rb_node);
581 percent = hist_entry__get_percent_limit(child);
582 if (!child->filtered && percent >= hb->min_pcnt)
583 n++;
584 }
585
586 return n;
587}
588
Jiri Olsab33f9222017-01-20 10:20:29 +0100589static void __hist_entry__set_folding(struct hist_entry *he,
590 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300591{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300592 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900593 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300594
Namhyung Kim3698dab2015-05-05 23:55:46 +0900595 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900596 int n;
597
598 if (he->leaf)
599 n = callchain__set_folding(&he->sorted_chain, unfold);
600 else
601 n = hierarchy_set_folding(hb, he, unfold);
602
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300603 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300604 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300605 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300606}
607
Jiri Olsab33f9222017-01-20 10:20:29 +0100608static void hist_entry__set_folding(struct hist_entry *he,
609 struct hist_browser *browser, bool unfold)
610{
611 double percent;
612
613 percent = hist_entry__get_percent_limit(he);
614 if (he->filtered || percent < browser->min_pcnt)
615 return;
616
617 __hist_entry__set_folding(he, browser, unfold);
618
619 if (!he->depth || unfold)
620 browser->nr_hierarchy_entries++;
621 if (he->leaf)
622 browser->nr_callchain_rows += he->nr_rows;
623 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
624 browser->nr_hierarchy_entries++;
625 he->has_no_entry = true;
626 he->nr_rows = 1;
627 } else
628 he->has_no_entry = false;
629}
630
Namhyung Kimc3b78952014-04-22 15:56:17 +0900631static void
632__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300633{
634 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900635 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300636
Namhyung Kim492b1012016-02-25 00:13:44 +0900637 nd = rb_first(&browser->hists->entries);
638 while (nd) {
639 he = rb_entry(nd, struct hist_entry, rb_node);
640
641 /* set folding state even if it's currently folded */
642 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
643
644 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300645 }
646}
647
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300648static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300649{
Namhyung Kim492b1012016-02-25 00:13:44 +0900650 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900651 browser->nr_callchain_rows = 0;
652 __hist_browser__set_folding(browser, unfold);
653
654 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300655 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300656 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300657}
658
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100659static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
660{
661 if (!browser->he_selection)
662 return;
663
664 hist_entry__set_folding(browser->he_selection, browser, unfold);
665 browser->b.nr_entries = hist_browser__nr_entries(browser);
666}
667
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200668static void ui_browser__warn_lost_events(struct ui_browser *browser)
669{
670 ui_browser__warning(browser, 4,
671 "Events are being lost, check IO/CPU overload!\n\n"
672 "You may want to run 'perf' using a RT scheduler policy:\n\n"
673 " perf top -r 80\n\n"
674 "Or reduce the sampling frequency.");
675}
676
Jiri Olsa5b91a862016-06-20 23:58:15 +0200677static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
678{
679 return browser->title ? browser->title(browser, bf, size) : 0;
680}
681
Jiri Olsadabd2012016-06-20 23:58:14 +0200682int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300683{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300684 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300685 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900686 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900687 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300688
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300689 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900690 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300691
Jiri Olsa5b91a862016-06-20 23:58:15 +0200692 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300693
Namhyung Kim090cff32016-01-11 19:53:14 +0900694 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300695 return -1;
696
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300697 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300698 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300699
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300700 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900701 case K_TIMER: {
702 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900703 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900704
Namhyung Kimc6111522016-10-07 14:04:12 +0900705 if (hist_browser__has_filter(browser) ||
706 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900707 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900708
Namhyung Kimc3b78952014-04-22 15:56:17 +0900709 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900710 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200711
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300712 if (browser->hists->stats.nr_lost_warned !=
713 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
714 browser->hists->stats.nr_lost_warned =
715 browser->hists->stats.nr_events[PERF_RECORD_LOST];
716 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200717 }
718
Jiri Olsa5b91a862016-06-20 23:58:15 +0200719 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300720 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300721 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900722 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300723 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300724 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300725 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300726 struct hist_entry, rb_node);
727 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300728 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 -0300729 seq++, browser->b.nr_entries,
730 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300731 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300732 browser->b.index,
733 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300734 h->row_offset, h->nr_rows);
735 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300736 break;
737 case 'C':
738 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300739 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300740 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100741 case 'c':
742 /* Collapse the selected entry. */
743 hist_browser__set_folding_selected(browser, false);
744 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300745 case 'E':
746 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300747 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300748 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100749 case 'e':
750 /* Expand the selected entry. */
751 hist_browser__set_folding_selected(browser, true);
752 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200753 case 'H':
754 browser->show_headers = !browser->show_headers;
755 hist_browser__update_rows(browser);
756 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200757 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300758 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300759 break;
760 /* fall thru */
761 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300762 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300763 }
764 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300765out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300766 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300767 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300768}
769
Namhyung Kim39ee5332014-08-22 09:13:21 +0900770struct callchain_print_arg {
771 /* for hists browser */
772 off_t row_offset;
773 bool is_current_entry;
774
775 /* for file dump */
776 FILE *fp;
777 int printed;
778};
779
780typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
781 struct callchain_list *chain,
782 const char *str, int offset,
783 unsigned short row,
784 struct callchain_print_arg *arg);
785
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900786static void hist_browser__show_callchain_entry(struct hist_browser *browser,
787 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900788 const char *str, int offset,
789 unsigned short row,
790 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900791{
792 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900793 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300794 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900795
796 color = HE_COLORSET_NORMAL;
797 width = browser->b.width - (offset + 2);
798 if (ui_browser__is_current_entry(&browser->b, row)) {
799 browser->selection = &chain->ms;
800 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900801 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900802 }
803
804 ui_browser__set_color(&browser->b, color);
805 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300806 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300807 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300808 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300809 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900810}
811
Namhyung Kim39ee5332014-08-22 09:13:21 +0900812static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
813 struct callchain_list *chain,
814 const char *str, int offset,
815 unsigned short row __maybe_unused,
816 struct callchain_print_arg *arg)
817{
818 char folded_sign = callchain_list__folded(chain);
819
820 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
821 folded_sign, str);
822}
823
824typedef bool (*check_output_full_fn)(struct hist_browser *browser,
825 unsigned short row);
826
827static bool hist_browser__check_output_full(struct hist_browser *browser,
828 unsigned short row)
829{
830 return browser->b.rows == row;
831}
832
833static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
834 unsigned short row __maybe_unused)
835{
836 return false;
837}
838
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300839#define LEVEL_OFFSET_STEP 3
840
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800841static int hist_browser__show_inline(struct hist_browser *browser,
842 struct inline_node *node,
843 unsigned short row,
844 int offset)
845{
846 struct inline_list *ilist;
847 char buf[1024];
848 int color, width, first_row;
849
850 first_row = row;
851 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
852 list_for_each_entry(ilist, &node->val, list) {
853 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
854 color = HE_COLORSET_NORMAL;
855 if (ui_browser__is_current_entry(&browser->b, row))
856 color = HE_COLORSET_SELECTED;
857
Milian Wolff5dfa2102017-03-18 22:49:28 +0100858 if (callchain_param.key == CCKEY_ADDRESS ||
859 callchain_param.key == CCKEY_SRCLINE) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800860 if (ilist->filename != NULL)
861 scnprintf(buf, sizeof(buf),
862 "%s:%d (inline)",
863 ilist->filename,
864 ilist->line_nr);
865 else
866 scnprintf(buf, sizeof(buf), "??");
867 } else if (ilist->funcname != NULL)
868 scnprintf(buf, sizeof(buf), "%s (inline)",
869 ilist->funcname);
870 else if (ilist->filename != NULL)
871 scnprintf(buf, sizeof(buf),
872 "%s:%d (inline)",
873 ilist->filename,
874 ilist->line_nr);
875 else
876 scnprintf(buf, sizeof(buf), "??");
877
878 ui_browser__set_color(&browser->b, color);
879 hist_browser__gotorc(browser, row, 0);
880 ui_browser__write_nstring(&browser->b, " ",
881 LEVEL_OFFSET_STEP + offset);
882 ui_browser__write_nstring(&browser->b, buf, width);
883 row++;
884 }
885 }
886
887 return row - first_row;
888}
889
890static size_t show_inline_list(struct hist_browser *browser, struct map *map,
891 u64 ip, int row, int offset)
892{
893 struct inline_node *node;
894 int ret;
895
896 node = inline_node__create(map, ip);
897 if (node == NULL)
898 return 0;
899
900 ret = hist_browser__show_inline(browser, node, row, offset);
901
902 inline_node__delete(node);
903 return ret;
904}
905
Namhyung Kim18bb8382015-11-09 14:45:42 +0900906static int hist_browser__show_callchain_list(struct hist_browser *browser,
907 struct callchain_node *node,
908 struct callchain_list *chain,
909 unsigned short row, u64 total,
910 bool need_percent, int offset,
911 print_callchain_entry_fn print,
912 struct callchain_print_arg *arg)
913{
914 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800915 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900916 const char *str;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800917 int inline_rows = 0, ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900918
919 if (arg->row_offset != 0) {
920 arg->row_offset--;
921 return 0;
922 }
923
924 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800925 alloc_str2 = NULL;
926
Namhyung Kim18bb8382015-11-09 14:45:42 +0900927 str = callchain_list__sym_name(chain, bf, sizeof(bf),
928 browser->show_dso);
929
Jin Yaofef51ec2016-10-31 09:19:53 +0800930 if (symbol_conf.show_branchflag_count) {
931 if (need_percent)
932 callchain_list_counts__printf_value(node, chain, NULL,
933 buf, sizeof(buf));
934 else
935 callchain_list_counts__printf_value(NULL, chain, NULL,
936 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900937
Jin Yaofef51ec2016-10-31 09:19:53 +0800938 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
939 str = "Not enough memory!";
940 else
941 str = alloc_str2;
942 }
943
944 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900945 callchain_node__scnprintf_value(node, buf, sizeof(buf),
946 total);
947
948 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
949 str = "Not enough memory!";
950 else
951 str = alloc_str;
952 }
953
954 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900955 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800956 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800957
958 if (symbol_conf.inline_name) {
959 inline_rows = show_inline_list(browser, chain->ms.map,
960 chain->ip, row + 1, offset);
961 }
962
963 return ret + inline_rows;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900964}
965
Namhyung Kim59c624e2016-01-28 00:40:56 +0900966static bool check_percent_display(struct rb_node *node, u64 parent_total)
967{
968 struct callchain_node *child;
969
970 if (node == NULL)
971 return false;
972
973 if (rb_next(node))
974 return true;
975
976 child = rb_entry(node, struct callchain_node, rb_node);
977 return callchain_cumul_hits(child) != parent_total;
978}
979
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900980static int hist_browser__show_callchain_flat(struct hist_browser *browser,
981 struct rb_root *root,
982 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900983 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900984 print_callchain_entry_fn print,
985 struct callchain_print_arg *arg,
986 check_output_full_fn is_output_full)
987{
988 struct rb_node *node;
989 int first_row = row, offset = LEVEL_OFFSET_STEP;
990 bool need_percent;
991
992 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900993 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900994
995 while (node) {
996 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
997 struct rb_node *next = rb_next(node);
998 struct callchain_list *chain;
999 char folded_sign = ' ';
1000 int first = true;
1001 int extra_offset = 0;
1002
1003 list_for_each_entry(chain, &child->parent_val, list) {
1004 bool was_first = first;
1005
1006 if (first)
1007 first = false;
1008 else if (need_percent)
1009 extra_offset = LEVEL_OFFSET_STEP;
1010
1011 folded_sign = callchain_list__folded(chain);
1012
1013 row += hist_browser__show_callchain_list(browser, child,
1014 chain, row, total,
1015 was_first && need_percent,
1016 offset + extra_offset,
1017 print, arg);
1018
1019 if (is_output_full(browser, row))
1020 goto out;
1021
1022 if (folded_sign == '+')
1023 goto next;
1024 }
1025
1026 list_for_each_entry(chain, &child->val, list) {
1027 bool was_first = first;
1028
1029 if (first)
1030 first = false;
1031 else if (need_percent)
1032 extra_offset = LEVEL_OFFSET_STEP;
1033
1034 folded_sign = callchain_list__folded(chain);
1035
1036 row += hist_browser__show_callchain_list(browser, child,
1037 chain, row, total,
1038 was_first && need_percent,
1039 offset + extra_offset,
1040 print, arg);
1041
1042 if (is_output_full(browser, row))
1043 goto out;
1044
1045 if (folded_sign == '+')
1046 break;
1047 }
1048
1049next:
1050 if (is_output_full(browser, row))
1051 break;
1052 node = next;
1053 }
1054out:
1055 return row - first_row;
1056}
1057
Namhyung Kim8c430a32015-11-09 14:45:44 +09001058static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
1059 struct callchain_list *chain,
1060 char *value_str, char *old_str)
1061{
1062 char bf[1024];
1063 const char *str;
1064 char *new;
1065
1066 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1067 browser->show_dso);
1068 if (old_str) {
1069 if (asprintf(&new, "%s%s%s", old_str,
1070 symbol_conf.field_sep ?: ";", str) < 0)
1071 new = NULL;
1072 } else {
1073 if (value_str) {
1074 if (asprintf(&new, "%s %s", value_str, str) < 0)
1075 new = NULL;
1076 } else {
1077 if (asprintf(&new, "%s", str) < 0)
1078 new = NULL;
1079 }
1080 }
1081 return new;
1082}
1083
1084static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1085 struct rb_root *root,
1086 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +09001087 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +09001088 print_callchain_entry_fn print,
1089 struct callchain_print_arg *arg,
1090 check_output_full_fn is_output_full)
1091{
1092 struct rb_node *node;
1093 int first_row = row, offset = LEVEL_OFFSET_STEP;
1094 bool need_percent;
1095
1096 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001097 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001098
1099 while (node) {
1100 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1101 struct rb_node *next = rb_next(node);
1102 struct callchain_list *chain, *first_chain = NULL;
1103 int first = true;
1104 char *value_str = NULL, *value_str_alloc = NULL;
1105 char *chain_str = NULL, *chain_str_alloc = NULL;
1106
1107 if (arg->row_offset != 0) {
1108 arg->row_offset--;
1109 goto next;
1110 }
1111
1112 if (need_percent) {
1113 char buf[64];
1114
1115 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1116 if (asprintf(&value_str, "%s", buf) < 0) {
1117 value_str = (char *)"<...>";
1118 goto do_print;
1119 }
1120 value_str_alloc = value_str;
1121 }
1122
1123 list_for_each_entry(chain, &child->parent_val, list) {
1124 chain_str = hist_browser__folded_callchain_str(browser,
1125 chain, value_str, chain_str);
1126 if (first) {
1127 first = false;
1128 first_chain = chain;
1129 }
1130
1131 if (chain_str == NULL) {
1132 chain_str = (char *)"Not enough memory!";
1133 goto do_print;
1134 }
1135
1136 chain_str_alloc = chain_str;
1137 }
1138
1139 list_for_each_entry(chain, &child->val, list) {
1140 chain_str = hist_browser__folded_callchain_str(browser,
1141 chain, value_str, chain_str);
1142 if (first) {
1143 first = false;
1144 first_chain = chain;
1145 }
1146
1147 if (chain_str == NULL) {
1148 chain_str = (char *)"Not enough memory!";
1149 goto do_print;
1150 }
1151
1152 chain_str_alloc = chain_str;
1153 }
1154
1155do_print:
1156 print(browser, first_chain, chain_str, offset, row++, arg);
1157 free(value_str_alloc);
1158 free(chain_str_alloc);
1159
1160next:
1161 if (is_output_full(browser, row))
1162 break;
1163 node = next;
1164 }
1165
1166 return row - first_row;
1167}
1168
Namhyung Kim0c841c62016-01-28 00:40:54 +09001169static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001170 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001171 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001172 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001173 print_callchain_entry_fn print,
1174 struct callchain_print_arg *arg,
1175 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001176{
1177 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001178 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001179 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001180 u64 percent_total = total;
1181
1182 if (callchain_param.mode == CHAIN_GRAPH_REL)
1183 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001184
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001185 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001186 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001187
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001188 while (node) {
1189 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1190 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001191 struct callchain_list *chain;
1192 char folded_sign = ' ';
1193 int first = true;
1194 int extra_offset = 0;
1195
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001197 bool was_first = first;
1198
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001199 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001201 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001203
1204 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001205
Namhyung Kim18bb8382015-11-09 14:45:42 +09001206 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001207 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001208 was_first && need_percent,
1209 offset + extra_offset,
1210 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001211
Namhyung Kim18bb8382015-11-09 14:45:42 +09001212 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001213 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001214
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001215 if (folded_sign == '+')
1216 break;
1217 }
1218
1219 if (folded_sign == '-') {
1220 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001221
Namhyung Kim0c841c62016-01-28 00:40:54 +09001222 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001223 new_level, row, total,
1224 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001225 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001226 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001227 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001228 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001229 node = next;
1230 }
1231out:
1232 return row - first_row;
1233}
1234
Namhyung Kim0c841c62016-01-28 00:40:54 +09001235static int hist_browser__show_callchain(struct hist_browser *browser,
1236 struct hist_entry *entry, int level,
1237 unsigned short row,
1238 print_callchain_entry_fn print,
1239 struct callchain_print_arg *arg,
1240 check_output_full_fn is_output_full)
1241{
1242 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001243 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001244 int printed;
1245
Namhyung Kim5eca1042016-01-28 00:40:55 +09001246 if (symbol_conf.cumulate_callchain)
1247 parent_total = entry->stat_acc->period;
1248 else
1249 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001250
1251 if (callchain_param.mode == CHAIN_FLAT) {
1252 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001253 &entry->sorted_chain, row,
1254 total, parent_total, print, arg,
1255 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001256 } else if (callchain_param.mode == CHAIN_FOLDED) {
1257 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001258 &entry->sorted_chain, row,
1259 total, parent_total, print, arg,
1260 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001261 } else {
1262 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001263 &entry->sorted_chain, level, row,
1264 total, parent_total, print, arg,
1265 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001266 }
1267
1268 if (arg->is_current_entry)
1269 browser->he_selection = entry;
1270
1271 return printed;
1272}
1273
Namhyung Kim89701462013-01-22 18:09:38 +09001274struct hpp_arg {
1275 struct ui_browser *b;
1276 char folded_sign;
1277 bool current_entry;
1278};
1279
Jiri Olsa98ba1602016-09-22 17:36:35 +02001280int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001281{
1282 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd675107c2014-07-31 14:47:36 +09001283 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001284 va_list args;
1285 double percent;
1286
1287 va_start(args, fmt);
Namhyung Kimd675107c2014-07-31 14:47:36 +09001288 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001289 percent = va_arg(args, double);
1290 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001291
Namhyung Kim89701462013-01-22 18:09:38 +09001292 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001293
Namhyung Kimd675107c2014-07-31 14:47:36 +09001294 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001295 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001296
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001297 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001298}
1299
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001300#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001301static u64 __hpp_get_##_field(struct hist_entry *he) \
1302{ \
1303 return he->stat._field; \
1304} \
1305 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001306static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001307hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001308 struct perf_hpp *hpp, \
1309 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001310{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001311 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1312 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001313}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001314
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001315#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1316static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1317{ \
1318 return he->stat_acc->_field; \
1319} \
1320 \
1321static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001322hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001323 struct perf_hpp *hpp, \
1324 struct hist_entry *he) \
1325{ \
1326 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001327 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001328 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd675107c2014-07-31 14:47:36 +09001329 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001330 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001331 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001332 \
1333 return ret; \
1334 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001335 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1336 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001337}
1338
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001339__HPP_COLOR_PERCENT_FN(overhead, period)
1340__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1341__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1342__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1343__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001344__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001345
1346#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001347#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001348
1349void hist_browser__init_hpp(void)
1350{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001351 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1352 hist_browser__hpp_color_overhead;
1353 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1354 hist_browser__hpp_color_overhead_sys;
1355 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1356 hist_browser__hpp_color_overhead_us;
1357 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1358 hist_browser__hpp_color_overhead_guest_sys;
1359 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1360 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001361 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1362 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001363}
1364
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001365static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001366 struct hist_entry *entry,
1367 unsigned short row)
1368{
Jiri Olsa12400052012-10-13 00:06:16 +02001369 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001370 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001371 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001372 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001373 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001374 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001375 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001376
1377 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001378 browser->he_selection = entry;
1379 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001380 }
1381
1382 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001383 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001384 folded_sign = hist_entry__folded(entry);
1385 }
1386
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001387 if (symbol_conf.inline_name &&
1388 (!entry->has_children)) {
1389 hist_entry_init_inline_node(entry);
1390 folded_sign = hist_entry__folded(entry);
1391 }
1392
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001393 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001394 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001395 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001396 .folded_sign = folded_sign,
1397 .current_entry = current_entry,
1398 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001399 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001400
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001401 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001402
Jiri Olsaf0786af2016-01-18 10:24:23 +01001403 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001404 char s[2048];
1405 struct perf_hpp hpp = {
1406 .buf = s,
1407 .size = sizeof(s),
1408 .ptr = &arg,
1409 };
1410
Namhyung Kim361459f2015-12-23 02:07:08 +09001411 if (perf_hpp__should_skip(fmt, entry->hists) ||
1412 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001413 continue;
1414
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001415 if (current_entry && browser->b.navkeypressed) {
1416 ui_browser__set_color(&browser->b,
1417 HE_COLORSET_SELECTED);
1418 } else {
1419 ui_browser__set_color(&browser->b,
1420 HE_COLORSET_NORMAL);
1421 }
1422
1423 if (first) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001424 if (symbol_conf.use_callchain ||
1425 symbol_conf.inline_name) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001426 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001427 width -= 2;
1428 }
1429 first = false;
1430 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001431 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001432 width -= 2;
1433 }
1434
Jiri Olsa12400052012-10-13 00:06:16 +02001435 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001436 int ret = fmt->color(fmt, &hpp, entry);
1437 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1438 /*
1439 * fmt->color() already used ui_browser to
1440 * print the non alignment bits, skip it (+ret):
1441 */
1442 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001443 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001444 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001445 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001446 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001447 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001448 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001449
1450 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001451 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001452 width += 1;
1453
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001454 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001455
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001456 ++row;
1457 ++printed;
1458 } else
1459 --row_offset;
1460
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001461 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001462 struct callchain_print_arg arg = {
1463 .row_offset = row_offset,
1464 .is_current_entry = current_entry,
1465 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001466
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001467 if (entry->inline_node)
1468 printed += hist_browser__show_inline(browser,
1469 entry->inline_node, row, 0);
1470 else
1471 printed += hist_browser__show_callchain(browser,
1472 entry, 1, row,
1473 hist_browser__show_callchain_entry,
1474 &arg,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001475 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001476 }
1477
1478 return printed;
1479}
1480
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001481static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1482 struct hist_entry *entry,
1483 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001484 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001485{
1486 int printed = 0;
1487 int width = browser->b.width;
1488 char folded_sign = ' ';
1489 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1490 off_t row_offset = entry->row_offset;
1491 bool first = true;
1492 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001493 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001494 struct hpp_arg arg = {
1495 .b = &browser->b,
1496 .current_entry = current_entry,
1497 };
1498 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001499 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001500
1501 if (current_entry) {
1502 browser->he_selection = entry;
1503 browser->selection = &entry->ms;
1504 }
1505
1506 hist_entry__init_have_children(entry);
1507 folded_sign = hist_entry__folded(entry);
1508 arg.folded_sign = folded_sign;
1509
1510 if (entry->leaf && row_offset) {
1511 row_offset--;
1512 goto show_callchain;
1513 }
1514
1515 hist_browser__gotorc(browser, row, 0);
1516
1517 if (current_entry && browser->b.navkeypressed)
1518 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1519 else
1520 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1521
1522 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1523 width -= level * HIERARCHY_INDENT;
1524
Namhyung Kima61a22f2016-03-07 16:44:50 -03001525 /* the first hpp_list_node is for overhead columns */
1526 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1527 struct perf_hpp_list_node, list);
1528 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001529 char s[2048];
1530 struct perf_hpp hpp = {
1531 .buf = s,
1532 .size = sizeof(s),
1533 .ptr = &arg,
1534 };
1535
1536 if (perf_hpp__should_skip(fmt, entry->hists) ||
1537 column++ < browser->b.horiz_scroll)
1538 continue;
1539
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001540 if (current_entry && browser->b.navkeypressed) {
1541 ui_browser__set_color(&browser->b,
1542 HE_COLORSET_SELECTED);
1543 } else {
1544 ui_browser__set_color(&browser->b,
1545 HE_COLORSET_NORMAL);
1546 }
1547
1548 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001549 ui_browser__printf(&browser->b, "%c ", folded_sign);
1550 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001551 first = false;
1552 } else {
1553 ui_browser__printf(&browser->b, " ");
1554 width -= 2;
1555 }
1556
1557 if (fmt->color) {
1558 int ret = fmt->color(fmt, &hpp, entry);
1559 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1560 /*
1561 * fmt->color() already used ui_browser to
1562 * print the non alignment bits, skip it (+ret):
1563 */
1564 ui_browser__printf(&browser->b, "%s", s + ret);
1565 } else {
1566 int ret = fmt->entry(fmt, &hpp, entry);
1567 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1568 ui_browser__printf(&browser->b, "%s", s);
1569 }
1570 width -= hpp.buf - s;
1571 }
1572
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001573 if (!first) {
1574 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1575 width -= hierarchy_indent;
1576 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001577
1578 if (column >= browser->b.horiz_scroll) {
1579 char s[2048];
1580 struct perf_hpp hpp = {
1581 .buf = s,
1582 .size = sizeof(s),
1583 .ptr = &arg,
1584 };
1585
1586 if (current_entry && browser->b.navkeypressed) {
1587 ui_browser__set_color(&browser->b,
1588 HE_COLORSET_SELECTED);
1589 } else {
1590 ui_browser__set_color(&browser->b,
1591 HE_COLORSET_NORMAL);
1592 }
1593
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001594 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001595 if (first) {
1596 ui_browser__printf(&browser->b, "%c ", folded_sign);
1597 first = false;
1598 } else {
1599 ui_browser__write_nstring(&browser->b, "", 2);
1600 }
1601
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001602 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001603
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001604 /*
1605 * No need to call hist_entry__snprintf_alignment()
1606 * since this fmt is always the last column in the
1607 * hierarchy mode.
1608 */
1609 if (fmt->color) {
1610 width -= fmt->color(fmt, &hpp, entry);
1611 } else {
1612 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001613
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001614 width -= fmt->entry(fmt, &hpp, entry);
1615 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001616
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001617 while (isspace(s[i++]))
1618 width++;
1619 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001620 }
1621 }
1622
1623 /* The scroll bar isn't being used */
1624 if (!browser->b.navkeypressed)
1625 width += 1;
1626
1627 ui_browser__write_nstring(&browser->b, "", width);
1628
1629 ++row;
1630 ++printed;
1631
1632show_callchain:
1633 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1634 struct callchain_print_arg carg = {
1635 .row_offset = row_offset,
1636 };
1637
1638 printed += hist_browser__show_callchain(browser, entry,
1639 level + 1, row,
1640 hist_browser__show_callchain_entry, &carg,
1641 hist_browser__check_output_full);
1642 }
1643
1644 return printed;
1645}
1646
Namhyung Kim79dded82016-02-26 21:13:19 +09001647static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001648 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001649{
1650 int width = browser->b.width;
1651 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1652 bool first = true;
1653 int column = 0;
1654 int ret;
1655 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001656 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001657 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001658
1659 if (current_entry) {
1660 browser->he_selection = NULL;
1661 browser->selection = NULL;
1662 }
1663
1664 hist_browser__gotorc(browser, row, 0);
1665
1666 if (current_entry && browser->b.navkeypressed)
1667 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1668 else
1669 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1670
1671 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1672 width -= level * HIERARCHY_INDENT;
1673
Namhyung Kima61a22f2016-03-07 16:44:50 -03001674 /* the first hpp_list_node is for overhead columns */
1675 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1676 struct perf_hpp_list_node, list);
1677 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001678 if (perf_hpp__should_skip(fmt, browser->hists) ||
1679 column++ < browser->b.horiz_scroll)
1680 continue;
1681
Jiri Olsada1b0402016-06-14 20:19:20 +02001682 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001683
1684 if (first) {
1685 /* for folded sign */
1686 first = false;
1687 ret++;
1688 } else {
1689 /* space between columns */
1690 ret += 2;
1691 }
1692
1693 ui_browser__write_nstring(&browser->b, "", ret);
1694 width -= ret;
1695 }
1696
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001697 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1698 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001699
1700 if (column >= browser->b.horiz_scroll) {
1701 char buf[32];
1702
1703 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1704 ui_browser__printf(&browser->b, " %s", buf);
1705 width -= ret + 2;
1706 }
1707
1708 /* The scroll bar isn't being used */
1709 if (!browser->b.navkeypressed)
1710 width += 1;
1711
1712 ui_browser__write_nstring(&browser->b, "", width);
1713 return 1;
1714}
1715
Jiri Olsa81a888f2014-06-14 15:44:52 +02001716static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1717{
1718 advance_hpp(hpp, inc);
1719 return hpp->size <= 0;
1720}
1721
Jiri Olsa69705b32016-08-07 17:28:28 +02001722static int
1723hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1724 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001725{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001726 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001727 struct perf_hpp dummy_hpp = {
1728 .buf = buf,
1729 .size = size,
1730 };
1731 struct perf_hpp_fmt *fmt;
1732 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001733 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001734 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001735
1736 if (symbol_conf.use_callchain) {
1737 ret = scnprintf(buf, size, " ");
1738 if (advance_hpp_check(&dummy_hpp, ret))
1739 return ret;
1740 }
1741
Jiri Olsaf0786af2016-01-18 10:24:23 +01001742 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001743 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001744 continue;
1745
Jiri Olsa29659ab2016-08-07 17:28:30 +02001746 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001747 if (advance_hpp_check(&dummy_hpp, ret))
1748 break;
1749
Jiri Olsa29659ab2016-08-07 17:28:30 +02001750 if (span)
1751 continue;
1752
Jiri Olsa81a888f2014-06-14 15:44:52 +02001753 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1754 if (advance_hpp_check(&dummy_hpp, ret))
1755 break;
1756 }
1757
1758 return ret;
1759}
1760
Namhyung Kimd8b92402016-02-25 00:13:46 +09001761static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1762{
1763 struct hists *hists = browser->hists;
1764 struct perf_hpp dummy_hpp = {
1765 .buf = buf,
1766 .size = size,
1767 };
1768 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001769 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001770 size_t ret = 0;
1771 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001772 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001773 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001774
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001775 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001776 if (advance_hpp_check(&dummy_hpp, ret))
1777 return ret;
1778
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001779 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001780 /* the first hpp_list_node is for overhead columns */
1781 fmt_node = list_first_entry(&hists->hpp_formats,
1782 struct perf_hpp_list_node, list);
1783 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001784 if (column++ < browser->b.horiz_scroll)
1785 continue;
1786
Jiri Olsa29659ab2016-08-07 17:28:30 +02001787 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001788 if (advance_hpp_check(&dummy_hpp, ret))
1789 break;
1790
1791 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1792 if (advance_hpp_check(&dummy_hpp, ret))
1793 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001794
1795 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001796 }
1797
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001798 if (!first_node) {
1799 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1800 indent * HIERARCHY_INDENT, "");
1801 if (advance_hpp_check(&dummy_hpp, ret))
1802 return ret;
1803 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001804
Namhyung Kima61a22f2016-03-07 16:44:50 -03001805 first_node = true;
1806 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1807 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001808 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1809 if (advance_hpp_check(&dummy_hpp, ret))
1810 break;
1811 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001812 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001813
Namhyung Kima61a22f2016-03-07 16:44:50 -03001814 first_col = true;
1815 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1816 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001817
Namhyung Kima61a22f2016-03-07 16:44:50 -03001818 if (perf_hpp__should_skip(fmt, hists))
1819 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001820
Namhyung Kima61a22f2016-03-07 16:44:50 -03001821 if (!first_col) {
1822 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1823 if (advance_hpp_check(&dummy_hpp, ret))
1824 break;
1825 }
1826 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001827
Jiri Olsa29659ab2016-08-07 17:28:30 +02001828 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001829 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001830
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001831 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001832 ret = strlen(start);
1833
1834 if (start != dummy_hpp.buf)
1835 memmove(dummy_hpp.buf, start, ret + 1);
1836
1837 if (advance_hpp_check(&dummy_hpp, ret))
1838 break;
1839 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001840 }
1841
1842 return ret;
1843}
1844
Jiri Olsa01b47702016-06-14 20:19:13 +02001845static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001846{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001847 char headers[1024];
1848
Jiri Olsa01b47702016-06-14 20:19:13 +02001849 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1850 sizeof(headers));
1851
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001852 ui_browser__gotorc(&browser->b, 0, 0);
1853 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001854 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001855}
1856
Jiri Olsa01b47702016-06-14 20:19:13 +02001857static void hists_browser__headers(struct hist_browser *browser)
1858{
Jiri Olsa69705b32016-08-07 17:28:28 +02001859 struct hists *hists = browser->hists;
1860 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001861
Jiri Olsa69705b32016-08-07 17:28:28 +02001862 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001863
Jiri Olsa69705b32016-08-07 17:28:28 +02001864 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1865 char headers[1024];
1866
1867 hists_browser__scnprintf_headers(browser, headers,
1868 sizeof(headers), line);
1869
1870 ui_browser__gotorc(&browser->b, line, 0);
1871 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1872 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1873 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001874}
1875
1876static void hist_browser__show_headers(struct hist_browser *browser)
1877{
1878 if (symbol_conf.report_hierarchy)
1879 hists_browser__hierarchy_headers(browser);
1880 else
1881 hists_browser__headers(browser);
1882}
1883
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001884static void ui_browser__hists_init_top(struct ui_browser *browser)
1885{
1886 if (browser->top == NULL) {
1887 struct hist_browser *hb;
1888
1889 hb = container_of(browser, struct hist_browser, b);
1890 browser->top = rb_first(&hb->hists->entries);
1891 }
1892}
1893
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001894static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001895{
1896 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001897 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001898 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001899 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001900 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001901
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001902 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001903 struct perf_hpp_list *hpp_list = hists->hpp_list;
1904
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001905 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001906 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001907 }
1908
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001909 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001910 hb->he_selection = NULL;
1911 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001912
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001913 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001914 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001915 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001916
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001917 if (h->filtered) {
1918 /* let it move to sibling */
1919 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001920 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001921 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001922
Namhyung Kim14135662013-10-31 10:17:39 +09001923 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001924 if (percent < hb->min_pcnt)
1925 continue;
1926
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001927 if (symbol_conf.report_hierarchy) {
1928 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001929 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001930 if (row == browser->rows)
1931 break;
1932
1933 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001934 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001935 row++;
1936 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001937 } else {
1938 row += hist_browser__show_entry(hb, h, row);
1939 }
1940
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001941 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001942 break;
1943 }
1944
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001945 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001946}
1947
Namhyung Kim064f1982013-05-14 11:09:04 +09001948static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001949 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001950{
1951 while (nd != NULL) {
1952 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001953 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001954
Namhyung Kimc0f15272014-04-16 11:16:33 +09001955 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001956 return nd;
1957
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001958 /*
1959 * If it's filtered, its all children also were filtered.
1960 * So move to sibling node.
1961 */
1962 if (rb_next(nd))
1963 nd = rb_next(nd);
1964 else
1965 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001966 }
1967
1968 return NULL;
1969}
1970
Namhyung Kim064f1982013-05-14 11:09:04 +09001971static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001972 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001973{
1974 while (nd != NULL) {
1975 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001976 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001977
1978 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001979 return nd;
1980
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001981 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001982 }
1983
1984 return NULL;
1985}
1986
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001987static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001988 off_t offset, int whence)
1989{
1990 struct hist_entry *h;
1991 struct rb_node *nd;
1992 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001993 struct hist_browser *hb;
1994
1995 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001996
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001997 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001998 return;
1999
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002000 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03002001
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002002 switch (whence) {
2003 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09002004 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09002005 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002006 break;
2007 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002008 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002009 goto do_offset;
2010 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002011 nd = rb_hierarchy_last(rb_last(browser->entries));
2012 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002013 first = false;
2014 break;
2015 default:
2016 return;
2017 }
2018
2019 /*
2020 * Moves not relative to the first visible entry invalidates its
2021 * row_offset:
2022 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002023 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002024 h->row_offset = 0;
2025
2026 /*
2027 * Here we have to check if nd is expanded (+), if it is we can't go
2028 * the next top level hist_entry, instead we must compute an offset of
2029 * what _not_ to show and not change the first visible entry.
2030 *
2031 * This offset increments when we are going from top to bottom and
2032 * decreases when we're going from bottom to top.
2033 *
2034 * As we don't have backpointers to the top level in the callchains
2035 * structure, we need to always print the whole hist_entry callchain,
2036 * skipping the first ones that are before the first visible entry
2037 * and stop when we printed enough lines to fill the screen.
2038 */
2039do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00002040 if (!nd)
2041 return;
2042
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002043 if (offset > 0) {
2044 do {
2045 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002046 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002047 u16 remaining = h->nr_rows - h->row_offset;
2048 if (offset > remaining) {
2049 offset -= remaining;
2050 h->row_offset = 0;
2051 } else {
2052 h->row_offset += offset;
2053 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002054 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002055 break;
2056 }
2057 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002058 nd = hists__filter_entries(rb_hierarchy_next(nd),
2059 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002060 if (nd == NULL)
2061 break;
2062 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002063 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002064 } while (offset != 0);
2065 } else if (offset < 0) {
2066 while (1) {
2067 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002068 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002069 if (first) {
2070 if (-offset > h->row_offset) {
2071 offset += h->row_offset;
2072 h->row_offset = 0;
2073 } else {
2074 h->row_offset += offset;
2075 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002076 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002077 break;
2078 }
2079 } else {
2080 if (-offset > h->nr_rows) {
2081 offset += h->nr_rows;
2082 h->row_offset = 0;
2083 } else {
2084 h->row_offset = h->nr_rows + offset;
2085 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002086 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002087 break;
2088 }
2089 }
2090 }
2091
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002092 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09002093 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002094 if (nd == NULL)
2095 break;
2096 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002097 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002098 if (offset == 0) {
2099 /*
2100 * Last unfiltered hist_entry, check if it is
2101 * unfolded, if it is then we should have
2102 * row_offset at its last entry.
2103 */
2104 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002105 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002106 h->row_offset = h->nr_rows;
2107 break;
2108 }
2109 first = false;
2110 }
2111 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002112 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002113 h = rb_entry(nd, struct hist_entry, rb_node);
2114 h->row_offset = 0;
2115 }
2116}
2117
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002118static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002119 struct hist_entry *he, FILE *fp,
2120 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002121{
Namhyung Kim39ee5332014-08-22 09:13:21 +09002122 struct callchain_print_arg arg = {
2123 .fp = fp,
2124 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002125
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002126 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09002127 hist_browser__fprintf_callchain_entry, &arg,
2128 hist_browser__check_dump_full);
2129 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002130}
2131
2132static int hist_browser__fprintf_entry(struct hist_browser *browser,
2133 struct hist_entry *he, FILE *fp)
2134{
2135 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002136 int printed = 0;
2137 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09002138 struct perf_hpp hpp = {
2139 .buf = s,
2140 .size = sizeof(s),
2141 };
2142 struct perf_hpp_fmt *fmt;
2143 bool first = true;
2144 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002145
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002146 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002147 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002148 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002149 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002150
Jiri Olsaf0786af2016-01-18 10:24:23 +01002151 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002152 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002153 continue;
2154
Namhyung Kim26d8b332014-03-03 16:16:20 +09002155 if (!first) {
2156 ret = scnprintf(hpp.buf, hpp.size, " ");
2157 advance_hpp(&hpp, ret);
2158 } else
2159 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002160
Namhyung Kim26d8b332014-03-03 16:16:20 +09002161 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002162 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002163 advance_hpp(&hpp, ret);
2164 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002165 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002166
2167 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002168 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2169
2170 return printed;
2171}
2172
2173
2174static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2175 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002176 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002177{
2178 char s[8192];
2179 int printed = 0;
2180 char folded_sign = ' ';
2181 struct perf_hpp hpp = {
2182 .buf = s,
2183 .size = sizeof(s),
2184 };
2185 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002186 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002187 bool first = true;
2188 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002189 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002190
2191 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2192
2193 folded_sign = hist_entry__folded(he);
2194 printed += fprintf(fp, "%c", folded_sign);
2195
Namhyung Kim325a6282016-03-09 22:47:00 +09002196 /* the first hpp_list_node is for overhead columns */
2197 fmt_node = list_first_entry(&he->hists->hpp_formats,
2198 struct perf_hpp_list_node, list);
2199 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002200 if (!first) {
2201 ret = scnprintf(hpp.buf, hpp.size, " ");
2202 advance_hpp(&hpp, ret);
2203 } else
2204 first = false;
2205
2206 ret = fmt->entry(fmt, &hpp, he);
2207 advance_hpp(&hpp, ret);
2208 }
2209
2210 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2211 advance_hpp(&hpp, ret);
2212
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002213 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2214 ret = scnprintf(hpp.buf, hpp.size, " ");
2215 advance_hpp(&hpp, ret);
2216
2217 ret = fmt->entry(fmt, &hpp, he);
2218 advance_hpp(&hpp, ret);
2219 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002220
2221 printed += fprintf(fp, "%s\n", rtrim(s));
2222
2223 if (he->leaf && folded_sign == '-') {
2224 printed += hist_browser__fprintf_callchain(browser, he, fp,
2225 he->depth + 1);
2226 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002227
2228 return printed;
2229}
2230
2231static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2232{
Namhyung Kim064f1982013-05-14 11:09:04 +09002233 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002234 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002235 int printed = 0;
2236
2237 while (nd) {
2238 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2239
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002240 if (symbol_conf.report_hierarchy) {
2241 printed += hist_browser__fprintf_hierarchy_entry(browser,
2242 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002243 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002244 } else {
2245 printed += hist_browser__fprintf_entry(browser, h, fp);
2246 }
2247
2248 nd = hists__filter_entries(rb_hierarchy_next(nd),
2249 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002250 }
2251
2252 return printed;
2253}
2254
2255static int hist_browser__dump(struct hist_browser *browser)
2256{
2257 char filename[64];
2258 FILE *fp;
2259
2260 while (1) {
2261 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2262 if (access(filename, F_OK))
2263 break;
2264 /*
2265 * XXX: Just an arbitrary lazy upper limit
2266 */
2267 if (++browser->print_seq == 8192) {
2268 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2269 return -1;
2270 }
2271 }
2272
2273 fp = fopen(filename, "w");
2274 if (fp == NULL) {
2275 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002276 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002277 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002278 return -1;
2279 }
2280
2281 ++browser->print_seq;
2282 hist_browser__fprintf(browser, fp);
2283 fclose(fp);
2284 ui_helpline__fpush("%s written!", filename);
2285
2286 return 0;
2287}
2288
Jiri Olsafcd86422016-06-20 23:58:18 +02002289void hist_browser__init(struct hist_browser *browser,
2290 struct hists *hists)
2291{
2292 struct perf_hpp_fmt *fmt;
2293
2294 browser->hists = hists;
2295 browser->b.refresh = hist_browser__refresh;
2296 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2297 browser->b.seek = ui_browser__hists_seek;
2298 browser->b.use_navkeypressed = true;
2299 browser->show_headers = symbol_conf.show_hist_headers;
2300
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002301 if (symbol_conf.report_hierarchy) {
2302 struct perf_hpp_list_node *fmt_node;
2303
2304 /* count overhead columns (in the first node) */
2305 fmt_node = list_first_entry(&hists->hpp_formats,
2306 struct perf_hpp_list_node, list);
2307 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2308 ++browser->b.columns;
2309
2310 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002311 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002312 } else {
2313 hists__for_each_format(hists, fmt)
2314 ++browser->b.columns;
2315 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002316
2317 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002318}
2319
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002320struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002321{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002322 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002323
Jiri Olsafcd86422016-06-20 23:58:18 +02002324 if (browser)
2325 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002326
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002327 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002328}
2329
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002330static struct hist_browser *
2331perf_evsel_browser__new(struct perf_evsel *evsel,
2332 struct hist_browser_timer *hbt,
2333 struct perf_env *env)
2334{
2335 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2336
2337 if (browser) {
2338 browser->hbt = hbt;
2339 browser->env = env;
2340 browser->title = perf_evsel_browser_title;
2341 }
2342 return browser;
2343}
2344
Jiri Olsadabd2012016-06-20 23:58:14 +02002345void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002346{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002347 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002348}
2349
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002350static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002351{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002352 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002353}
2354
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002355static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002356{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002357 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002358}
2359
Taeung Song1e378eb2014-10-07 16:13:15 +09002360/* Check whether the browser is for 'top' or 'report' */
2361static inline bool is_report_browser(void *timer)
2362{
2363 return timer == NULL;
2364}
2365
Jiri Olsa5b91a862016-06-20 23:58:15 +02002366static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002367 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002368{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002369 struct hist_browser_timer *hbt = browser->hbt;
2370 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002371 char unit;
2372 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002373 const struct dso *dso = hists->dso_filter;
2374 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002375 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002376 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2377 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002378 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002379 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002380 char buf[512];
2381 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002382 char ref[30] = " show reference callgraph, ";
2383 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002384
Namhyung Kimf2148332014-01-14 11:52:48 +09002385 if (symbol_conf.filter_relative) {
2386 nr_samples = hists->stats.nr_non_filtered_samples;
2387 nr_events = hists->stats.total_non_filtered_period;
2388 }
2389
Namhyung Kim759ff492013-03-05 14:53:26 +09002390 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002391 struct perf_evsel *pos;
2392
2393 perf_evsel__group_desc(evsel, buf, buflen);
2394 ev_name = buf;
2395
2396 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002397 struct hists *pos_hists = evsel__hists(pos);
2398
Namhyung Kimf2148332014-01-14 11:52:48 +09002399 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002400 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2401 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002402 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002403 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2404 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002405 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002406 }
2407 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002408
Kan Liang9e207dd2015-08-11 06:30:49 -04002409 if (symbol_conf.show_ref_callgraph &&
2410 strstr(ev_name, "call-graph=no"))
2411 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002412 nr_samples = convert_unit(nr_samples, &unit);
2413 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002414 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2415 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002416
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002417
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002418 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002419 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002420 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002421 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002422 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002423 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002424 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002425 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002426 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002427 } else {
2428 printed += scnprintf(bf + printed, size - printed,
2429 ", Thread: %s",
2430 (thread->comm_set ? thread__comm_str(thread) : ""));
2431 }
2432 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002433 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002434 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002435 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002436 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002437 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002438 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002439 if (!is_report_browser(hbt)) {
2440 struct perf_top *top = hbt->arg;
2441
2442 if (top->zero)
2443 printed += scnprintf(bf + printed, size - printed, " [z]");
2444 }
2445
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002446 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002447}
2448
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002449static inline void free_popup_options(char **options, int n)
2450{
2451 int i;
2452
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002453 for (i = 0; i < n; ++i)
2454 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002455}
2456
Feng Tang341487ab2013-02-03 14:38:20 +08002457/*
2458 * Only runtime switching of perf data file will make "input_name" point
2459 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2460 * whether we need to call free() for current "input_name" during the switch.
2461 */
2462static bool is_input_name_malloced = false;
2463
2464static int switch_data_file(void)
2465{
2466 char *pwd, *options[32], *abs_path[32], *tmp;
2467 DIR *pwd_dir;
2468 int nr_options = 0, choice = -1, ret = -1;
2469 struct dirent *dent;
2470
2471 pwd = getenv("PWD");
2472 if (!pwd)
2473 return ret;
2474
2475 pwd_dir = opendir(pwd);
2476 if (!pwd_dir)
2477 return ret;
2478
2479 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002480 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002481
2482 while ((dent = readdir(pwd_dir))) {
2483 char path[PATH_MAX];
2484 u64 magic;
2485 char *name = dent->d_name;
2486 FILE *file;
2487
2488 if (!(dent->d_type == DT_REG))
2489 continue;
2490
2491 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2492
2493 file = fopen(path, "r");
2494 if (!file)
2495 continue;
2496
2497 if (fread(&magic, 1, 8, file) < 8)
2498 goto close_file_and_continue;
2499
2500 if (is_perf_magic(magic)) {
2501 options[nr_options] = strdup(name);
2502 if (!options[nr_options])
2503 goto close_file_and_continue;
2504
2505 abs_path[nr_options] = strdup(path);
2506 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002507 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002508 ui__warning("Can't search all data files due to memory shortage.\n");
2509 fclose(file);
2510 break;
2511 }
2512
2513 nr_options++;
2514 }
2515
2516close_file_and_continue:
2517 fclose(file);
2518 if (nr_options >= 32) {
2519 ui__warning("Too many perf data files in PWD!\n"
2520 "Only the first 32 files will be listed.\n");
2521 break;
2522 }
2523 }
2524 closedir(pwd_dir);
2525
2526 if (nr_options) {
2527 choice = ui__popup_menu(nr_options, options);
2528 if (choice < nr_options && choice >= 0) {
2529 tmp = strdup(abs_path[choice]);
2530 if (tmp) {
2531 if (is_input_name_malloced)
2532 free((void *)input_name);
2533 input_name = tmp;
2534 is_input_name_malloced = true;
2535 ret = 0;
2536 } else
2537 ui__warning("Data switch failed due to memory shortage!\n");
2538 }
2539 }
2540
2541 free_popup_options(options, nr_options);
2542 free_popup_options(abs_path, nr_options);
2543 return ret;
2544}
2545
Namhyung Kimea7cd592015-04-22 16:18:19 +09002546struct popup_action {
2547 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002548 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002549 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002550
2551 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2552};
2553
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002554static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002555do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002556{
2557 struct perf_evsel *evsel;
2558 struct annotation *notes;
2559 struct hist_entry *he;
2560 int err;
2561
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002562 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002563 return 0;
2564
Namhyung Kimea7cd592015-04-22 16:18:19 +09002565 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002566 if (!notes->src)
2567 return 0;
2568
2569 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002570 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002571 he = hist_browser__selected_entry(browser);
2572 /*
2573 * offer option to annotate the other branch source or target
2574 * (if they exists) when returning from annotate
2575 */
2576 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2577 return 1;
2578
2579 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2580 if (err)
2581 ui_browser__handle_resize(&browser->b);
2582 return 0;
2583}
2584
2585static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002586add_annotate_opt(struct hist_browser *browser __maybe_unused,
2587 struct popup_action *act, char **optstr,
2588 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002589{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002590 if (sym == NULL || map->dso->annotate_warned)
2591 return 0;
2592
2593 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2594 return 0;
2595
2596 act->ms.map = map;
2597 act->ms.sym = sym;
2598 act->fn = do_annotate;
2599 return 1;
2600}
2601
2602static int
2603do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2604{
2605 struct thread *thread = act->thread;
2606
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002607 if ((!hists__has(browser->hists, thread) &&
2608 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002609 return 0;
2610
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002611 if (browser->hists->thread_filter) {
2612 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2613 perf_hpp__set_elide(HISTC_THREAD, false);
2614 thread__zput(browser->hists->thread_filter);
2615 ui_helpline__pop();
2616 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002617 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002618 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2619 thread->comm_set ? thread__comm_str(thread) : "",
2620 thread->tid);
2621 } else {
2622 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2623 thread->comm_set ? thread__comm_str(thread) : "");
2624 }
2625
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002626 browser->hists->thread_filter = thread__get(thread);
2627 perf_hpp__set_elide(HISTC_THREAD, false);
2628 pstack__push(browser->pstack, &browser->hists->thread_filter);
2629 }
2630
2631 hists__filter_by_thread(browser->hists);
2632 hist_browser__reset(browser);
2633 return 0;
2634}
2635
2636static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002637add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2638 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002639{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002640 int ret;
2641
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002642 if ((!hists__has(browser->hists, thread) &&
2643 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002644 return 0;
2645
Jiri Olsafa829112016-05-03 13:54:47 +02002646 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002647 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2648 browser->hists->thread_filter ? "out of" : "into",
2649 thread->comm_set ? thread__comm_str(thread) : "",
2650 thread->tid);
2651 } else {
2652 ret = asprintf(optstr, "Zoom %s %s thread",
2653 browser->hists->thread_filter ? "out of" : "into",
2654 thread->comm_set ? thread__comm_str(thread) : "");
2655 }
2656 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002657 return 0;
2658
2659 act->thread = thread;
2660 act->fn = do_zoom_thread;
2661 return 1;
2662}
2663
2664static int
2665do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2666{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002667 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002668
Jiri Olsa69849fc2016-05-03 13:54:45 +02002669 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002670 return 0;
2671
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002672 if (browser->hists->dso_filter) {
2673 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2674 perf_hpp__set_elide(HISTC_DSO, false);
2675 browser->hists->dso_filter = NULL;
2676 ui_helpline__pop();
2677 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002678 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002679 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2680 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002681 perf_hpp__set_elide(HISTC_DSO, true);
2682 pstack__push(browser->pstack, &browser->hists->dso_filter);
2683 }
2684
2685 hists__filter_by_dso(browser->hists);
2686 hist_browser__reset(browser);
2687 return 0;
2688}
2689
2690static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002691add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002692 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002693{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002694 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002695 return 0;
2696
2697 if (asprintf(optstr, "Zoom %s %s DSO",
2698 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002699 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002700 return 0;
2701
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002702 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002703 act->fn = do_zoom_dso;
2704 return 1;
2705}
2706
2707static int
2708do_browse_map(struct hist_browser *browser __maybe_unused,
2709 struct popup_action *act)
2710{
2711 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002712 return 0;
2713}
2714
2715static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002716add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002717 struct popup_action *act, char **optstr, struct map *map)
2718{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002719 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002720 return 0;
2721
2722 if (asprintf(optstr, "Browse map details") < 0)
2723 return 0;
2724
2725 act->ms.map = map;
2726 act->fn = do_browse_map;
2727 return 1;
2728}
2729
2730static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002731do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002732 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002733{
2734 char script_opt[64];
2735 memset(script_opt, 0, sizeof(script_opt));
2736
Namhyung Kimea7cd592015-04-22 16:18:19 +09002737 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002738 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002739 thread__comm_str(act->thread));
2740 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002741 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002742 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002743 }
2744
2745 script_browse(script_opt);
2746 return 0;
2747}
2748
2749static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002750add_script_opt(struct hist_browser *browser __maybe_unused,
2751 struct popup_action *act, char **optstr,
2752 struct thread *thread, struct symbol *sym)
2753{
2754 if (thread) {
2755 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2756 thread__comm_str(thread)) < 0)
2757 return 0;
2758 } else if (sym) {
2759 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2760 sym->name) < 0)
2761 return 0;
2762 } else {
2763 if (asprintf(optstr, "Run scripts for all samples") < 0)
2764 return 0;
2765 }
2766
2767 act->thread = thread;
2768 act->ms.sym = sym;
2769 act->fn = do_run_script;
2770 return 1;
2771}
2772
2773static int
2774do_switch_data(struct hist_browser *browser __maybe_unused,
2775 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002776{
2777 if (switch_data_file()) {
2778 ui__warning("Won't switch the data files due to\n"
2779 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002780 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002781 }
2782
2783 return K_SWITCH_INPUT_DATA;
2784}
2785
Namhyung Kimea7cd592015-04-22 16:18:19 +09002786static int
2787add_switch_opt(struct hist_browser *browser,
2788 struct popup_action *act, char **optstr)
2789{
2790 if (!is_report_browser(browser->hbt))
2791 return 0;
2792
2793 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2794 return 0;
2795
2796 act->fn = do_switch_data;
2797 return 1;
2798}
2799
2800static int
2801do_exit_browser(struct hist_browser *browser __maybe_unused,
2802 struct popup_action *act __maybe_unused)
2803{
2804 return 0;
2805}
2806
2807static int
2808add_exit_opt(struct hist_browser *browser __maybe_unused,
2809 struct popup_action *act, char **optstr)
2810{
2811 if (asprintf(optstr, "Exit") < 0)
2812 return 0;
2813
2814 act->fn = do_exit_browser;
2815 return 1;
2816}
2817
Kan Liang84734b02015-09-04 10:45:45 -04002818static int
2819do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2820{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002821 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002822 return 0;
2823
Kan Liang84734b02015-09-04 10:45:45 -04002824 if (browser->hists->socket_filter > -1) {
2825 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2826 browser->hists->socket_filter = -1;
2827 perf_hpp__set_elide(HISTC_SOCKET, false);
2828 } else {
2829 browser->hists->socket_filter = act->socket;
2830 perf_hpp__set_elide(HISTC_SOCKET, true);
2831 pstack__push(browser->pstack, &browser->hists->socket_filter);
2832 }
2833
2834 hists__filter_by_socket(browser->hists);
2835 hist_browser__reset(browser);
2836 return 0;
2837}
2838
2839static int
2840add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2841 char **optstr, int socket_id)
2842{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002843 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002844 return 0;
2845
2846 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2847 (browser->hists->socket_filter > -1) ? "out of" : "into",
2848 socket_id) < 0)
2849 return 0;
2850
2851 act->socket = socket_id;
2852 act->fn = do_zoom_socket;
2853 return 1;
2854}
2855
Namhyung Kim112f7612014-04-22 14:05:35 +09002856static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002857{
2858 u64 nr_entries = 0;
2859 struct rb_node *nd = rb_first(&hb->hists->entries);
2860
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002861 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002862 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2863 return;
2864 }
2865
Namhyung Kim14135662013-10-31 10:17:39 +09002866 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002867 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002868 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002869 }
2870
Namhyung Kim112f7612014-04-22 14:05:35 +09002871 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002872 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002873}
Feng Tang341487ab2013-02-03 14:38:20 +08002874
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002875static void hist_browser__update_percent_limit(struct hist_browser *hb,
2876 double percent)
2877{
2878 struct hist_entry *he;
2879 struct rb_node *nd = rb_first(&hb->hists->entries);
2880 u64 total = hists__total_period(hb->hists);
2881 u64 min_callchain_hits = total * (percent / 100);
2882
2883 hb->min_pcnt = callchain_param.min_percent = percent;
2884
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002885 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2886 he = rb_entry(nd, struct hist_entry, rb_node);
2887
Namhyung Kim79dded82016-02-26 21:13:19 +09002888 if (he->has_no_entry) {
2889 he->has_no_entry = false;
2890 he->nr_rows = 0;
2891 }
2892
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002893 if (!he->leaf || !symbol_conf.use_callchain)
2894 goto next;
2895
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002896 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2897 total = he->stat.period;
2898
2899 if (symbol_conf.cumulate_callchain)
2900 total = he->stat_acc->period;
2901
2902 min_callchain_hits = total * (percent / 100);
2903 }
2904
2905 callchain_param.sort(&he->sorted_chain, he->callchain,
2906 min_callchain_hits, &callchain_param);
2907
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002908next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002909 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002910
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002911 /* force to re-evaluate folding state of callchains */
2912 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002913 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002914 }
2915}
2916
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002917static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002918 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002919 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002920 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002921 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002922 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002923{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002924 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002925 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002926 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002927#define MAX_OPTIONS 16
2928 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002929 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002930 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002931 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002932 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002933 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002934
Namhyung Kime8e684a2013-12-26 14:37:58 +09002935#define HIST_BROWSER_HELP_COMMON \
2936 "h/?/F1 Show this window\n" \
2937 "UP/DOWN/PGUP\n" \
2938 "PGDN/SPACE Navigate\n" \
2939 "q/ESC/CTRL+C Exit browser\n\n" \
2940 "For multiple event sessions:\n\n" \
2941 "TAB/UNTAB Switch events\n\n" \
2942 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002943 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2944 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002945 "a Annotate current symbol\n" \
2946 "C Collapse all callchains\n" \
2947 "d Zoom into current DSO\n" \
2948 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002949 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002950 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002951 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002952 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002953 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002954
2955 /* help messages are sorted by lexical order of the hotkey */
2956 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002957 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002958 "P Print histograms to perf.hist.N\n"
2959 "r Run available scripts\n"
2960 "s Switch to another data file in PWD\n"
2961 "t Zoom into current Thread\n"
2962 "V Verbose (DSO names in callchains, etc)\n"
2963 "/ Filter symbol by name";
2964 const char top_help[] = HIST_BROWSER_HELP_COMMON
2965 "P Print histograms to perf.hist.N\n"
2966 "t Zoom into current Thread\n"
2967 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002968 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002969 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002970 "/ Filter symbol by name";
2971
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002972 if (browser == NULL)
2973 return -1;
2974
Namhyung Kimed426912015-05-29 21:53:44 +09002975 /* reset abort key so that it can get Ctrl-C as a key */
2976 SLang_reset_tty();
2977 SLang_init_tty(0, 0, 0);
2978
Namhyung Kim03905042015-11-28 02:32:39 +09002979 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002980 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002981 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002982
Kan Liang84734b02015-09-04 10:45:45 -04002983 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002984 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002985 goto out;
2986
2987 ui_helpline__push(helpline);
2988
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002989 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002990 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002991
Namhyung Kim5b591662014-07-31 14:47:38 +09002992 if (symbol_conf.col_width_list_str)
2993 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2994
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002995 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002996 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002997 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002998 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002999 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003000
Stephane Eranian24bff2d2012-03-12 16:13:30 +01003001 nr_options = 0;
3002
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03003003 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003004
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003005 if (browser->he_selection != NULL) {
3006 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003007 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04003008 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003009 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003010 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003011 case K_TAB:
3012 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06003013 if (nr_events == 1)
3014 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003015 /*
3016 * Exit the browser, let hists__browser_tree
3017 * go to the next or previous
3018 */
3019 goto out_free_stack;
3020 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003021 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003022 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003023 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003024 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003025 continue;
3026 }
3027
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003028 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08003029 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003030 browser->selection->map->dso->annotate_warned)
3031 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003032
Namhyung Kimea7cd592015-04-22 16:18:19 +09003033 actions->ms.map = browser->selection->map;
3034 actions->ms.sym = browser->selection->sym;
3035 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003036 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03003037 case 'P':
3038 hist_browser__dump(browser);
3039 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003040 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03003041 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003042 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003043 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003044 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02003045 verbose = (verbose + 1) % 4;
3046 browser->show_dso = verbose > 0;
3047 ui_helpline__fpush("Verbosity level set to %d\n",
3048 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003049 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003050 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003051 actions->thread = thread;
3052 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003053 continue;
Kan Liang84734b02015-09-04 10:45:45 -04003054 case 'S':
3055 actions->socket = socked_id;
3056 do_zoom_socket(browser, actions);
3057 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03003058 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09003059 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03003060 "Please enter the name of symbol you want to see.\n"
3061 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09003062 buf, "ENTER: OK, ESC: Cancel",
3063 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03003064 hists->symbol_filter_str = *buf ? buf : NULL;
3065 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09003066 hist_browser__reset(browser);
3067 }
3068 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08003069 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003070 if (is_report_browser(hbt)) {
3071 actions->thread = NULL;
3072 actions->ms.sym = NULL;
3073 do_run_script(browser, actions);
3074 }
Feng Tangc77d8d72012-11-01 00:00:55 +08003075 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08003076 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003077 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003078 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003079 if (key == K_SWITCH_INPUT_DATA)
3080 goto out_free_stack;
3081 }
Feng Tang341487ab2013-02-03 14:38:20 +08003082 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09003083 case 'i':
3084 /* env->arch is NULL for live-mode (i.e. perf top) */
3085 if (env->arch)
3086 tui__header_window(env);
3087 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09003088 case 'F':
3089 symbol_conf.filter_relative ^= 1;
3090 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09003091 case 'z':
3092 if (!is_report_browser(hbt)) {
3093 struct perf_top *top = hbt->arg;
3094
3095 top->zero = !top->zero;
3096 }
3097 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003098 case 'L':
3099 if (ui_browser__input_window("Percent Limit",
3100 "Please enter the value you want to hide entries under that percent.",
3101 buf, "ENTER: OK, ESC: Cancel",
3102 delay_secs * 2) == K_ENTER) {
3103 char *end;
3104 double new_percent = strtod(buf, &end);
3105
3106 if (new_percent < 0 || new_percent > 100) {
3107 ui_browser__warning(&browser->b, delay_secs * 2,
3108 "Invalid percent: %.2f", new_percent);
3109 continue;
3110 }
3111
3112 hist_browser__update_percent_limit(browser, new_percent);
3113 hist_browser__reset(browser);
3114 }
3115 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003116 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003117 case 'h':
3118 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003119 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003120 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003121 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003122 case K_ENTER:
3123 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003124 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003125 /* menu */
3126 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003127 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003128 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003129 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003130
Namhyung Kim01f00a12015-04-22 16:18:16 +09003131 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003132 /*
3133 * Go back to the perf_evsel_menu__run or other user
3134 */
3135 if (left_exits)
3136 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003137
3138 if (key == K_ESC &&
3139 ui_browser__dialog_yesno(&browser->b,
3140 "Do you really want to exit?"))
3141 goto out_free_stack;
3142
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003143 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003144 }
Namhyung Kim64221842015-04-24 10:15:33 +09003145 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003146 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003147 /*
3148 * No need to set actions->dso here since
3149 * it's just to remove the current filter.
3150 * Ditto for thread below.
3151 */
3152 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003153 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003154 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003155 } else if (top == &browser->hists->socket_filter) {
3156 do_zoom_socket(browser, actions);
3157 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003158 continue;
3159 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003160 case 'q':
3161 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003162 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003163 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003164 if (!is_report_browser(hbt)) {
3165 struct perf_top *top = hbt->arg;
3166
3167 perf_evlist__toggle_enable(top->evlist);
3168 /*
3169 * No need to refresh, resort/decay histogram
3170 * entries if we are not collecting samples:
3171 */
3172 if (top->evlist->enabled) {
3173 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3174 hbt->refresh = delay_secs;
3175 } else {
3176 helpline = "Press 'f' again to re-enable the events";
3177 hbt->refresh = 0;
3178 }
3179 continue;
3180 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003181 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003182 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003183 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003184 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003185 }
3186
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003187 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003188 goto skip_annotation;
3189
Namhyung Kim55369fc2013-04-01 20:35:20 +09003190 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003191 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003192
3193 if (bi == NULL)
3194 goto skip_annotation;
3195
Namhyung Kimea7cd592015-04-22 16:18:19 +09003196 nr_options += add_annotate_opt(browser,
3197 &actions[nr_options],
3198 &options[nr_options],
3199 bi->from.map,
3200 bi->from.sym);
3201 if (bi->to.sym != bi->from.sym)
3202 nr_options += add_annotate_opt(browser,
3203 &actions[nr_options],
3204 &options[nr_options],
3205 bi->to.map,
3206 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003207 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003208 nr_options += add_annotate_opt(browser,
3209 &actions[nr_options],
3210 &options[nr_options],
3211 browser->selection->map,
3212 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003213 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003214skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003215 nr_options += add_thread_opt(browser, &actions[nr_options],
3216 &options[nr_options], thread);
3217 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003218 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003219 nr_options += add_map_opt(browser, &actions[nr_options],
3220 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003221 browser->selection ?
3222 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003223 nr_options += add_socket_opt(browser, &actions[nr_options],
3224 &options[nr_options],
3225 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003226 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003227 if (!is_report_browser(hbt))
3228 goto skip_scripting;
3229
Feng Tangcdbab7c2012-10-30 11:56:06 +08003230 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003231 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003232 nr_options += add_script_opt(browser,
3233 &actions[nr_options],
3234 &options[nr_options],
3235 thread, NULL);
3236 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003237 /*
3238 * Note that browser->selection != NULL
3239 * when browser->he_selection is not NULL,
3240 * so we don't need to check browser->selection
3241 * before fetching browser->selection->sym like what
3242 * we do before fetching browser->selection->map.
3243 *
3244 * See hist_browser__show_entry.
3245 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003246 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003247 nr_options += add_script_opt(browser,
3248 &actions[nr_options],
3249 &options[nr_options],
3250 NULL, browser->selection->sym);
3251 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003252 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003253 nr_options += add_script_opt(browser, &actions[nr_options],
3254 &options[nr_options], NULL, NULL);
3255 nr_options += add_switch_opt(browser, &actions[nr_options],
3256 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003257skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003258 nr_options += add_exit_opt(browser, &actions[nr_options],
3259 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003260
Namhyung Kimea7cd592015-04-22 16:18:19 +09003261 do {
3262 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003263
Namhyung Kimea7cd592015-04-22 16:18:19 +09003264 choice = ui__popup_menu(nr_options, options);
3265 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003266 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003267
3268 act = &actions[choice];
3269 key = act->fn(browser, act);
3270 } while (key == 1);
3271
3272 if (key == K_SWITCH_INPUT_DATA)
3273 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003274 }
3275out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003276 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003277out:
3278 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003279 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003280 return key;
3281}
3282
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003283struct perf_evsel_menu {
3284 struct ui_browser b;
3285 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003286 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003287 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003288 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003289};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003290
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003291static void perf_evsel_menu__write(struct ui_browser *browser,
3292 void *entry, int row)
3293{
3294 struct perf_evsel_menu *menu = container_of(browser,
3295 struct perf_evsel_menu, b);
3296 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003297 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003298 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003299 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003300 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003301 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003302 const char *warn = " ";
3303 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003304
3305 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3306 HE_COLORSET_NORMAL);
3307
Namhyung Kim759ff492013-03-05 14:53:26 +09003308 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003309 struct perf_evsel *pos;
3310
3311 ev_name = perf_evsel__group_name(evsel);
3312
3313 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003314 struct hists *pos_hists = evsel__hists(pos);
3315 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003316 }
3317 }
3318
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003319 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003320 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003321 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003322 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003323
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003324 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003325 if (nr_events != 0) {
3326 menu->lost_events = true;
3327 if (!current_entry)
3328 ui_browser__set_color(browser, HE_COLORSET_TOP);
3329 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003330 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3331 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003332 warn = bf;
3333 }
3334
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003335 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003336
3337 if (current_entry)
3338 menu->selection = evsel;
3339}
3340
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003341static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3342 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003343 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003344{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003345 struct perf_evlist *evlist = menu->b.priv;
3346 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003347 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003348 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003349 int key;
3350
3351 if (ui_browser__show(&menu->b, title,
3352 "ESC: exit, ENTER|->: Browse histograms") < 0)
3353 return -1;
3354
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003355 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003356 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003357
3358 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003359 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003360 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003361
3362 if (!menu->lost_events_warned && menu->lost_events) {
3363 ui_browser__warn_lost_events(&menu->b);
3364 menu->lost_events_warned = true;
3365 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003366 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003367 case K_RIGHT:
3368 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003369 if (!menu->selection)
3370 continue;
3371 pos = menu->selection;
3372browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003373 perf_evlist__set_selected(evlist, pos);
3374 /*
3375 * Give the calling tool a chance to populate the non
3376 * default evsel resorted hists tree.
3377 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003378 if (hbt)
3379 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003380 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003381 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003382 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003383 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003384 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003385 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003386 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003387 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003388 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003389 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003390 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003391 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003392 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003393 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003394 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003395 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003396 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003397 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003398 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003399 case 'q':
3400 case CTRL('c'):
3401 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003402 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003403 default:
3404 continue;
3405 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003406 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003407 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003408 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003409 if (!ui_browser__dialog_yesno(&menu->b,
3410 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003411 continue;
3412 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003413 case 'q':
3414 case CTRL('c'):
3415 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003416 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003417 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003418 }
3419 }
3420
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003421out:
3422 ui_browser__hide(&menu->b);
3423 return key;
3424}
3425
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003426static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003427 void *entry)
3428{
3429 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3430
3431 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3432 return true;
3433
3434 return false;
3435}
3436
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003437static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003438 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003439 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003440 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003441 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003442{
3443 struct perf_evsel *pos;
3444 struct perf_evsel_menu menu = {
3445 .b = {
3446 .entries = &evlist->entries,
3447 .refresh = ui_browser__list_head_refresh,
3448 .seek = ui_browser__list_head_seek,
3449 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003450 .filter = filter_group_entries,
3451 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003452 .priv = evlist,
3453 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003454 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003455 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003456 };
3457
3458 ui_helpline__push("Press ESC to exit");
3459
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003460 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003461 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003462 size_t line_len = strlen(ev_name) + 7;
3463
3464 if (menu.b.width < line_len)
3465 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003466 }
3467
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003468 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003469}
3470
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003471int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003472 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003473 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003474 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003475{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003476 int nr_entries = evlist->nr_entries;
3477
3478single_entry:
3479 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003480 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003481
3482 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003483 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003484 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003485 }
3486
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003487 if (symbol_conf.event_group) {
3488 struct perf_evsel *pos;
3489
3490 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003491 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003492 if (perf_evsel__is_group_leader(pos))
3493 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003494 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003495
3496 if (nr_entries == 1)
3497 goto single_entry;
3498 }
3499
3500 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003501 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003502}