blob: bc397bbbc3a7d28a1b9e51bc52ee35898361d078 [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 Meloa0675582017-04-17 16:51:59 -030023#include "string2.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030024
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030025#include "sane_ctype.h"
26
Namhyung Kimf5951d52012-09-03 11:53:09 +090027extern void hist_browser__init_hpp(void);
28
Jiri Olsa5b91a862016-06-20 23:58:15 +020029static int perf_evsel_browser_title(struct hist_browser *browser,
30 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090031static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030032
Namhyung Kimc3b78952014-04-22 15:56:17 +090033static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090034 float min_pcnt);
35
Namhyung Kim268397c2014-04-22 14:49:31 +090036static bool hist_browser__has_filter(struct hist_browser *hb)
37{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010038 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090039}
40
He Kuang4fabf3d2015-03-12 15:21:49 +080041static int hist_browser__get_folding(struct hist_browser *browser)
42{
43 struct rb_node *nd;
44 struct hists *hists = browser->hists;
45 int unfolded_rows = 0;
46
47 for (nd = rb_first(&hists->entries);
48 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090049 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080050 struct hist_entry *he =
51 rb_entry(nd, struct hist_entry, rb_node);
52
Namhyung Kimf5b763f2016-02-25 00:13:43 +090053 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080054 unfolded_rows += he->nr_rows;
55 }
56 return unfolded_rows;
57}
58
Namhyung Kimc3b78952014-04-22 15:56:17 +090059static u32 hist_browser__nr_entries(struct hist_browser *hb)
60{
61 u32 nr_entries;
62
Namhyung Kimf5b763f2016-02-25 00:13:43 +090063 if (symbol_conf.report_hierarchy)
64 nr_entries = hb->nr_hierarchy_entries;
65 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090066 nr_entries = hb->nr_non_filtered_entries;
67 else
68 nr_entries = hb->hists->nr_entries;
69
He Kuang4fabf3d2015-03-12 15:21:49 +080070 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090071 return nr_entries + hb->nr_callchain_rows;
72}
73
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020074static void hist_browser__update_rows(struct hist_browser *hb)
75{
76 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020077 struct hists *hists = hb->hists;
78 struct perf_hpp_list *hpp_list = hists->hpp_list;
79 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020080
Jiri Olsaf8e67102016-08-07 17:28:26 +020081 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020082 browser->rows = browser->height - header_offset;
83 /*
84 * Verify if we were at the last line and that line isn't
85 * visibe because we now show the header line(s).
86 */
87 index_row = browser->index - browser->top_idx;
88 if (index_row >= browser->rows)
89 browser->index -= index_row - browser->rows + 1;
90}
91
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030092static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030093{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030094 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
95
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030096 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030097 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
98 /*
99 * FIXME: Just keeping existing behaviour, but this really should be
100 * before updating browser->width, as it will invalidate the
101 * calculation above. Fix this and the fallout in another
102 * changeset.
103 */
104 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200105 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300106}
107
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300108static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
109{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200110 struct hists *hists = browser->hists;
111 struct perf_hpp_list *hpp_list = hists->hpp_list;
112 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200113
Jiri Olsaf8e67102016-08-07 17:28:26 +0200114 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200115 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300116}
117
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300118static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300119{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900120 /*
121 * The hists__remove_entry_filter() already folds non-filtered
122 * entries so we can assume it has 0 callchain rows.
123 */
124 browser->nr_callchain_rows = 0;
125
Namhyung Kim268397c2014-04-22 14:49:31 +0900126 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900127 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300128 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300129 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300130}
131
132static char tree__folded_sign(bool unfolded)
133{
134 return unfolded ? '-' : '+';
135}
136
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300138{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900139 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300140}
141
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300142static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900144 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145}
146
Namhyung Kim3698dab2015-05-05 23:55:46 +0900147static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300148{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900149 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300150}
151
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800152static struct inline_node *inline_node__create(struct map *map, u64 ip)
153{
154 struct dso *dso;
155 struct inline_node *node;
156
157 if (map == NULL)
158 return NULL;
159
160 dso = map->dso;
161 if (dso == NULL)
162 return NULL;
163
164 if (dso->kernel != DSO_TYPE_USER)
165 return NULL;
166
167 node = dso__parse_addr_inlines(dso,
168 map__rip_2objdump(map, ip));
169
170 return node;
171}
172
173static int inline__count_rows(struct inline_node *node)
174{
175 struct inline_list *ilist;
176 int i = 0;
177
178 if (node == NULL)
179 return 0;
180
181 list_for_each_entry(ilist, &node->val, list) {
182 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
183 i++;
184 }
185
186 return i;
187}
188
189static int callchain_list__inline_rows(struct callchain_list *chain)
190{
191 struct inline_node *node;
192 int rows;
193
194 node = inline_node__create(chain->ms.map, chain->ip);
195 if (node == NULL)
196 return 0;
197
198 rows = inline__count_rows(node);
199 inline_node__delete(node);
200 return rows;
201}
202
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300203static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300204{
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800205 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300206 struct rb_node *nd;
207
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300208 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300209 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
210 struct callchain_list *chain;
211 char folded_sign = ' '; /* No children */
212
213 list_for_each_entry(chain, &child->val, list) {
214 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800215
216 if (symbol_conf.inline_name) {
217 inline_rows =
218 callchain_list__inline_rows(chain);
219 n += inline_rows;
220 }
221
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300222 /* We need this because we may not have children */
223 folded_sign = callchain_list__folded(chain);
224 if (folded_sign == '+')
225 break;
226 }
227
228 if (folded_sign == '-') /* Have children and they're unfolded */
229 n += callchain_node__count_rows_rb_tree(child);
230 }
231
232 return n;
233}
234
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900235static int callchain_node__count_flat_rows(struct callchain_node *node)
236{
237 struct callchain_list *chain;
238 char folded_sign = 0;
239 int n = 0;
240
241 list_for_each_entry(chain, &node->parent_val, list) {
242 if (!folded_sign) {
243 /* only check first chain list entry */
244 folded_sign = callchain_list__folded(chain);
245 if (folded_sign == '+')
246 return 1;
247 }
248 n++;
249 }
250
251 list_for_each_entry(chain, &node->val, list) {
252 if (!folded_sign) {
253 /* node->parent_val list might be empty */
254 folded_sign = callchain_list__folded(chain);
255 if (folded_sign == '+')
256 return 1;
257 }
258 n++;
259 }
260
261 return n;
262}
263
Namhyung Kim8c430a32015-11-09 14:45:44 +0900264static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
265{
266 return 1;
267}
268
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300269static int callchain_node__count_rows(struct callchain_node *node)
270{
271 struct callchain_list *chain;
272 bool unfolded = false;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800273 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300274
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900275 if (callchain_param.mode == CHAIN_FLAT)
276 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900277 else if (callchain_param.mode == CHAIN_FOLDED)
278 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900279
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300280 list_for_each_entry(chain, &node->val, list) {
281 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800282 if (symbol_conf.inline_name) {
283 inline_rows = callchain_list__inline_rows(chain);
284 n += inline_rows;
285 }
286
Namhyung Kim3698dab2015-05-05 23:55:46 +0900287 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300288 }
289
290 if (unfolded)
291 n += callchain_node__count_rows_rb_tree(node);
292
293 return n;
294}
295
296static int callchain__count_rows(struct rb_root *chain)
297{
298 struct rb_node *nd;
299 int n = 0;
300
301 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
302 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
303 n += callchain_node__count_rows(node);
304 }
305
306 return n;
307}
308
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900309static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
310 bool include_children)
311{
312 int count = 0;
313 struct rb_node *node;
314 struct hist_entry *child;
315
316 if (he->leaf)
317 return callchain__count_rows(&he->sorted_chain);
318
Namhyung Kim79dded82016-02-26 21:13:19 +0900319 if (he->has_no_entry)
320 return 1;
321
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900322 node = rb_first(&he->hroot_out);
323 while (node) {
324 float percent;
325
326 child = rb_entry(node, struct hist_entry, rb_node);
327 percent = hist_entry__get_percent_limit(child);
328
329 if (!child->filtered && percent >= hb->min_pcnt) {
330 count++;
331
332 if (include_children && child->unfolded)
333 count += hierarchy_count_rows(hb, child, true);
334 }
335
336 node = rb_next(node);
337 }
338 return count;
339}
340
Namhyung Kim3698dab2015-05-05 23:55:46 +0900341static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300342{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900343 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200344 return false;
345
Namhyung Kim3698dab2015-05-05 23:55:46 +0900346 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300347 return false;
348
Namhyung Kim3698dab2015-05-05 23:55:46 +0900349 he->unfolded = !he->unfolded;
350 return true;
351}
352
353static bool callchain_list__toggle_fold(struct callchain_list *cl)
354{
355 if (!cl)
356 return false;
357
358 if (!cl->has_children)
359 return false;
360
361 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300362 return true;
363}
364
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300365static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300366{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300367 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300368
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300369 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300370 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
371 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300372 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300373
374 list_for_each_entry(chain, &child->val, list) {
375 if (first) {
376 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900377 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300378 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300379 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900380 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300381 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300382 }
383
384 callchain_node__init_have_children_rb_tree(child);
385 }
386}
387
Namhyung Kima7444af2014-11-24 17:13:27 +0900388static void callchain_node__init_have_children(struct callchain_node *node,
389 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300390{
391 struct callchain_list *chain;
392
Namhyung Kima7444af2014-11-24 17:13:27 +0900393 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900394 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900395
Andres Freund90989032016-03-30 21:02:45 +0200396 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900397 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900398 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900399 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300400
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300401 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300402}
403
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300404static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300405{
Namhyung Kima7444af2014-11-24 17:13:27 +0900406 struct rb_node *nd = rb_first(root);
407 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300408
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300409 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300410 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900411 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900412 if (callchain_param.mode == CHAIN_FLAT ||
413 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900414 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300415 }
416}
417
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300418static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300419{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900420 if (he->init_have_children)
421 return;
422
423 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900424 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300425 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900426 } else {
427 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900429
430 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300431}
432
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800433static void hist_entry_init_inline_node(struct hist_entry *he)
434{
435 if (he->inline_node)
436 return;
437
438 he->inline_node = inline_node__create(he->ms.map, he->ip);
439
440 if (he->inline_node == NULL)
441 return;
442
443 he->has_children = true;
444}
445
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300446static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300447{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900448 struct hist_entry *he = browser->he_selection;
449 struct map_symbol *ms = browser->selection;
450 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
451 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300452
Wang Nan4938cf02015-12-07 02:35:44 +0000453 if (!he || !ms)
454 return false;
455
Namhyung Kim3698dab2015-05-05 23:55:46 +0900456 if (ms == &he->ms)
457 has_children = hist_entry__toggle_fold(he);
458 else
459 has_children = callchain_list__toggle_fold(cl);
460
461 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900462 int child_rows = 0;
463
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300464 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900465 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300466
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900467 if (he->leaf)
468 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300469 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900470 browser->nr_hierarchy_entries -= he->nr_rows;
471
472 if (symbol_conf.report_hierarchy)
473 child_rows = hierarchy_count_rows(browser, he, true);
474
475 if (he->unfolded) {
476 if (he->leaf)
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800477 if (he->inline_node)
478 he->nr_rows = inline__count_rows(
479 he->inline_node);
480 else
481 he->nr_rows = callchain__count_rows(
482 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900483 else
484 he->nr_rows = hierarchy_count_rows(browser, he, false);
485
486 /* account grand children */
487 if (symbol_conf.report_hierarchy)
488 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900489
490 if (!he->leaf && he->nr_rows == 0) {
491 he->has_no_entry = true;
492 he->nr_rows = 1;
493 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900494 } else {
495 if (symbol_conf.report_hierarchy)
496 browser->b.nr_entries -= child_rows - he->nr_rows;
497
Namhyung Kim79dded82016-02-26 21:13:19 +0900498 if (he->has_no_entry)
499 he->has_no_entry = false;
500
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300501 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900502 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900503
504 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900505
506 if (he->leaf)
507 browser->nr_callchain_rows += he->nr_rows;
508 else
509 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300510
511 return true;
512 }
513
514 /* If it doesn't have children, no toggling performed */
515 return false;
516}
517
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300519{
520 int n = 0;
521 struct rb_node *nd;
522
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300523 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300524 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
525 struct callchain_list *chain;
526 bool has_children = false;
527
528 list_for_each_entry(chain, &child->val, list) {
529 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900530 callchain_list__set_folding(chain, unfold);
531 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300532 }
533
534 if (has_children)
535 n += callchain_node__set_folding_rb_tree(child, unfold);
536 }
537
538 return n;
539}
540
541static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
542{
543 struct callchain_list *chain;
544 bool has_children = false;
545 int n = 0;
546
547 list_for_each_entry(chain, &node->val, list) {
548 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900549 callchain_list__set_folding(chain, unfold);
550 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300551 }
552
553 if (has_children)
554 n += callchain_node__set_folding_rb_tree(node, unfold);
555
556 return n;
557}
558
559static int callchain__set_folding(struct rb_root *chain, bool unfold)
560{
561 struct rb_node *nd;
562 int n = 0;
563
564 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
565 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
566 n += callchain_node__set_folding(node, unfold);
567 }
568
569 return n;
570}
571
Namhyung Kim492b1012016-02-25 00:13:44 +0900572static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
573 bool unfold __maybe_unused)
574{
575 float percent;
576 struct rb_node *nd;
577 struct hist_entry *child;
578 int n = 0;
579
580 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
581 child = rb_entry(nd, struct hist_entry, rb_node);
582 percent = hist_entry__get_percent_limit(child);
583 if (!child->filtered && percent >= hb->min_pcnt)
584 n++;
585 }
586
587 return n;
588}
589
Jiri Olsab33f9222017-01-20 10:20:29 +0100590static void __hist_entry__set_folding(struct hist_entry *he,
591 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300592{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300593 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900594 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300595
Namhyung Kim3698dab2015-05-05 23:55:46 +0900596 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900597 int n;
598
599 if (he->leaf)
600 n = callchain__set_folding(&he->sorted_chain, unfold);
601 else
602 n = hierarchy_set_folding(hb, he, unfold);
603
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300604 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300605 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300606 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300607}
608
Jiri Olsab33f9222017-01-20 10:20:29 +0100609static void hist_entry__set_folding(struct hist_entry *he,
610 struct hist_browser *browser, bool unfold)
611{
612 double percent;
613
614 percent = hist_entry__get_percent_limit(he);
615 if (he->filtered || percent < browser->min_pcnt)
616 return;
617
618 __hist_entry__set_folding(he, browser, unfold);
619
620 if (!he->depth || unfold)
621 browser->nr_hierarchy_entries++;
622 if (he->leaf)
623 browser->nr_callchain_rows += he->nr_rows;
624 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
625 browser->nr_hierarchy_entries++;
626 he->has_no_entry = true;
627 he->nr_rows = 1;
628 } else
629 he->has_no_entry = false;
630}
631
Namhyung Kimc3b78952014-04-22 15:56:17 +0900632static void
633__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300634{
635 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900636 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300637
Namhyung Kim492b1012016-02-25 00:13:44 +0900638 nd = rb_first(&browser->hists->entries);
639 while (nd) {
640 he = rb_entry(nd, struct hist_entry, rb_node);
641
642 /* set folding state even if it's currently folded */
643 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
644
645 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300646 }
647}
648
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300649static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300650{
Namhyung Kim492b1012016-02-25 00:13:44 +0900651 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900652 browser->nr_callchain_rows = 0;
653 __hist_browser__set_folding(browser, unfold);
654
655 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300656 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300657 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300658}
659
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100660static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
661{
662 if (!browser->he_selection)
663 return;
664
665 hist_entry__set_folding(browser->he_selection, browser, unfold);
666 browser->b.nr_entries = hist_browser__nr_entries(browser);
667}
668
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200669static void ui_browser__warn_lost_events(struct ui_browser *browser)
670{
671 ui_browser__warning(browser, 4,
672 "Events are being lost, check IO/CPU overload!\n\n"
673 "You may want to run 'perf' using a RT scheduler policy:\n\n"
674 " perf top -r 80\n\n"
675 "Or reduce the sampling frequency.");
676}
677
Jiri Olsa5b91a862016-06-20 23:58:15 +0200678static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
679{
680 return browser->title ? browser->title(browser, bf, size) : 0;
681}
682
Jiri Olsadabd2012016-06-20 23:58:14 +0200683int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300684{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300685 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300686 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900687 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900688 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300689
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300690 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900691 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300692
Jiri Olsa5b91a862016-06-20 23:58:15 +0200693 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300694
Namhyung Kim090cff32016-01-11 19:53:14 +0900695 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300696 return -1;
697
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300698 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300699 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300700
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300701 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900702 case K_TIMER: {
703 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900704 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900705
Namhyung Kimc6111522016-10-07 14:04:12 +0900706 if (hist_browser__has_filter(browser) ||
707 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900708 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900709
Namhyung Kimc3b78952014-04-22 15:56:17 +0900710 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900711 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200712
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300713 if (browser->hists->stats.nr_lost_warned !=
714 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
715 browser->hists->stats.nr_lost_warned =
716 browser->hists->stats.nr_events[PERF_RECORD_LOST];
717 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200718 }
719
Jiri Olsa5b91a862016-06-20 23:58:15 +0200720 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300721 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300722 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900723 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300724 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300725 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300726 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300727 struct hist_entry, rb_node);
728 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300729 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 -0300730 seq++, browser->b.nr_entries,
731 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300732 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300733 browser->b.index,
734 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300735 h->row_offset, h->nr_rows);
736 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300737 break;
738 case 'C':
739 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300740 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300741 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100742 case 'c':
743 /* Collapse the selected entry. */
744 hist_browser__set_folding_selected(browser, false);
745 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300746 case 'E':
747 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300748 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300749 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100750 case 'e':
751 /* Expand the selected entry. */
752 hist_browser__set_folding_selected(browser, true);
753 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200754 case 'H':
755 browser->show_headers = !browser->show_headers;
756 hist_browser__update_rows(browser);
757 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200758 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300759 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300760 break;
761 /* fall thru */
762 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300763 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300764 }
765 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300766out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300767 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300768 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300769}
770
Namhyung Kim39ee5332014-08-22 09:13:21 +0900771struct callchain_print_arg {
772 /* for hists browser */
773 off_t row_offset;
774 bool is_current_entry;
775
776 /* for file dump */
777 FILE *fp;
778 int printed;
779};
780
781typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
782 struct callchain_list *chain,
783 const char *str, int offset,
784 unsigned short row,
785 struct callchain_print_arg *arg);
786
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900787static void hist_browser__show_callchain_entry(struct hist_browser *browser,
788 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900789 const char *str, int offset,
790 unsigned short row,
791 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900792{
793 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900794 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300795 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900796
797 color = HE_COLORSET_NORMAL;
798 width = browser->b.width - (offset + 2);
799 if (ui_browser__is_current_entry(&browser->b, row)) {
800 browser->selection = &chain->ms;
801 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900802 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900803 }
804
805 ui_browser__set_color(&browser->b, color);
806 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300807 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300808 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300809 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300810 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900811}
812
Namhyung Kim39ee5332014-08-22 09:13:21 +0900813static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
814 struct callchain_list *chain,
815 const char *str, int offset,
816 unsigned short row __maybe_unused,
817 struct callchain_print_arg *arg)
818{
819 char folded_sign = callchain_list__folded(chain);
820
821 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
822 folded_sign, str);
823}
824
825typedef bool (*check_output_full_fn)(struct hist_browser *browser,
826 unsigned short row);
827
828static bool hist_browser__check_output_full(struct hist_browser *browser,
829 unsigned short row)
830{
831 return browser->b.rows == row;
832}
833
834static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
835 unsigned short row __maybe_unused)
836{
837 return false;
838}
839
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300840#define LEVEL_OFFSET_STEP 3
841
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800842static int hist_browser__show_inline(struct hist_browser *browser,
843 struct inline_node *node,
844 unsigned short row,
845 int offset)
846{
847 struct inline_list *ilist;
848 char buf[1024];
849 int color, width, first_row;
850
851 first_row = row;
852 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
853 list_for_each_entry(ilist, &node->val, list) {
854 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
855 color = HE_COLORSET_NORMAL;
856 if (ui_browser__is_current_entry(&browser->b, row))
857 color = HE_COLORSET_SELECTED;
858
Milian Wolff5dfa2102017-03-18 22:49:28 +0100859 if (callchain_param.key == CCKEY_ADDRESS ||
860 callchain_param.key == CCKEY_SRCLINE) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800861 if (ilist->filename != NULL)
862 scnprintf(buf, sizeof(buf),
863 "%s:%d (inline)",
864 ilist->filename,
865 ilist->line_nr);
866 else
867 scnprintf(buf, sizeof(buf), "??");
868 } else if (ilist->funcname != NULL)
869 scnprintf(buf, sizeof(buf), "%s (inline)",
870 ilist->funcname);
871 else if (ilist->filename != NULL)
872 scnprintf(buf, sizeof(buf),
873 "%s:%d (inline)",
874 ilist->filename,
875 ilist->line_nr);
876 else
877 scnprintf(buf, sizeof(buf), "??");
878
879 ui_browser__set_color(&browser->b, color);
880 hist_browser__gotorc(browser, row, 0);
881 ui_browser__write_nstring(&browser->b, " ",
882 LEVEL_OFFSET_STEP + offset);
883 ui_browser__write_nstring(&browser->b, buf, width);
884 row++;
885 }
886 }
887
888 return row - first_row;
889}
890
891static size_t show_inline_list(struct hist_browser *browser, struct map *map,
892 u64 ip, int row, int offset)
893{
894 struct inline_node *node;
895 int ret;
896
897 node = inline_node__create(map, ip);
898 if (node == NULL)
899 return 0;
900
901 ret = hist_browser__show_inline(browser, node, row, offset);
902
903 inline_node__delete(node);
904 return ret;
905}
906
Namhyung Kim18bb8382015-11-09 14:45:42 +0900907static int hist_browser__show_callchain_list(struct hist_browser *browser,
908 struct callchain_node *node,
909 struct callchain_list *chain,
910 unsigned short row, u64 total,
911 bool need_percent, int offset,
912 print_callchain_entry_fn print,
913 struct callchain_print_arg *arg)
914{
915 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800916 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900917 const char *str;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800918 int inline_rows = 0, ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900919
920 if (arg->row_offset != 0) {
921 arg->row_offset--;
922 return 0;
923 }
924
925 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800926 alloc_str2 = NULL;
927
Namhyung Kim18bb8382015-11-09 14:45:42 +0900928 str = callchain_list__sym_name(chain, bf, sizeof(bf),
929 browser->show_dso);
930
Jin Yaofef51ec2016-10-31 09:19:53 +0800931 if (symbol_conf.show_branchflag_count) {
932 if (need_percent)
933 callchain_list_counts__printf_value(node, chain, NULL,
934 buf, sizeof(buf));
935 else
936 callchain_list_counts__printf_value(NULL, chain, NULL,
937 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900938
Jin Yaofef51ec2016-10-31 09:19:53 +0800939 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
940 str = "Not enough memory!";
941 else
942 str = alloc_str2;
943 }
944
945 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900946 callchain_node__scnprintf_value(node, buf, sizeof(buf),
947 total);
948
949 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
950 str = "Not enough memory!";
951 else
952 str = alloc_str;
953 }
954
955 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900956 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800957 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800958
959 if (symbol_conf.inline_name) {
960 inline_rows = show_inline_list(browser, chain->ms.map,
961 chain->ip, row + 1, offset);
962 }
963
964 return ret + inline_rows;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900965}
966
Namhyung Kim59c624e2016-01-28 00:40:56 +0900967static bool check_percent_display(struct rb_node *node, u64 parent_total)
968{
969 struct callchain_node *child;
970
971 if (node == NULL)
972 return false;
973
974 if (rb_next(node))
975 return true;
976
977 child = rb_entry(node, struct callchain_node, rb_node);
978 return callchain_cumul_hits(child) != parent_total;
979}
980
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900981static int hist_browser__show_callchain_flat(struct hist_browser *browser,
982 struct rb_root *root,
983 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900984 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900985 print_callchain_entry_fn print,
986 struct callchain_print_arg *arg,
987 check_output_full_fn is_output_full)
988{
989 struct rb_node *node;
990 int first_row = row, offset = LEVEL_OFFSET_STEP;
991 bool need_percent;
992
993 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900994 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900995
996 while (node) {
997 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
998 struct rb_node *next = rb_next(node);
999 struct callchain_list *chain;
1000 char folded_sign = ' ';
1001 int first = true;
1002 int extra_offset = 0;
1003
1004 list_for_each_entry(chain, &child->parent_val, list) {
1005 bool was_first = first;
1006
1007 if (first)
1008 first = false;
1009 else if (need_percent)
1010 extra_offset = LEVEL_OFFSET_STEP;
1011
1012 folded_sign = callchain_list__folded(chain);
1013
1014 row += hist_browser__show_callchain_list(browser, child,
1015 chain, row, total,
1016 was_first && need_percent,
1017 offset + extra_offset,
1018 print, arg);
1019
1020 if (is_output_full(browser, row))
1021 goto out;
1022
1023 if (folded_sign == '+')
1024 goto next;
1025 }
1026
1027 list_for_each_entry(chain, &child->val, list) {
1028 bool was_first = first;
1029
1030 if (first)
1031 first = false;
1032 else if (need_percent)
1033 extra_offset = LEVEL_OFFSET_STEP;
1034
1035 folded_sign = callchain_list__folded(chain);
1036
1037 row += hist_browser__show_callchain_list(browser, child,
1038 chain, row, total,
1039 was_first && need_percent,
1040 offset + extra_offset,
1041 print, arg);
1042
1043 if (is_output_full(browser, row))
1044 goto out;
1045
1046 if (folded_sign == '+')
1047 break;
1048 }
1049
1050next:
1051 if (is_output_full(browser, row))
1052 break;
1053 node = next;
1054 }
1055out:
1056 return row - first_row;
1057}
1058
Namhyung Kim8c430a32015-11-09 14:45:44 +09001059static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
1060 struct callchain_list *chain,
1061 char *value_str, char *old_str)
1062{
1063 char bf[1024];
1064 const char *str;
1065 char *new;
1066
1067 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1068 browser->show_dso);
1069 if (old_str) {
1070 if (asprintf(&new, "%s%s%s", old_str,
1071 symbol_conf.field_sep ?: ";", str) < 0)
1072 new = NULL;
1073 } else {
1074 if (value_str) {
1075 if (asprintf(&new, "%s %s", value_str, str) < 0)
1076 new = NULL;
1077 } else {
1078 if (asprintf(&new, "%s", str) < 0)
1079 new = NULL;
1080 }
1081 }
1082 return new;
1083}
1084
1085static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1086 struct rb_root *root,
1087 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +09001088 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +09001089 print_callchain_entry_fn print,
1090 struct callchain_print_arg *arg,
1091 check_output_full_fn is_output_full)
1092{
1093 struct rb_node *node;
1094 int first_row = row, offset = LEVEL_OFFSET_STEP;
1095 bool need_percent;
1096
1097 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001098 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001099
1100 while (node) {
1101 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1102 struct rb_node *next = rb_next(node);
1103 struct callchain_list *chain, *first_chain = NULL;
1104 int first = true;
1105 char *value_str = NULL, *value_str_alloc = NULL;
1106 char *chain_str = NULL, *chain_str_alloc = NULL;
1107
1108 if (arg->row_offset != 0) {
1109 arg->row_offset--;
1110 goto next;
1111 }
1112
1113 if (need_percent) {
1114 char buf[64];
1115
1116 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1117 if (asprintf(&value_str, "%s", buf) < 0) {
1118 value_str = (char *)"<...>";
1119 goto do_print;
1120 }
1121 value_str_alloc = value_str;
1122 }
1123
1124 list_for_each_entry(chain, &child->parent_val, list) {
1125 chain_str = hist_browser__folded_callchain_str(browser,
1126 chain, value_str, chain_str);
1127 if (first) {
1128 first = false;
1129 first_chain = chain;
1130 }
1131
1132 if (chain_str == NULL) {
1133 chain_str = (char *)"Not enough memory!";
1134 goto do_print;
1135 }
1136
1137 chain_str_alloc = chain_str;
1138 }
1139
1140 list_for_each_entry(chain, &child->val, list) {
1141 chain_str = hist_browser__folded_callchain_str(browser,
1142 chain, value_str, chain_str);
1143 if (first) {
1144 first = false;
1145 first_chain = chain;
1146 }
1147
1148 if (chain_str == NULL) {
1149 chain_str = (char *)"Not enough memory!";
1150 goto do_print;
1151 }
1152
1153 chain_str_alloc = chain_str;
1154 }
1155
1156do_print:
1157 print(browser, first_chain, chain_str, offset, row++, arg);
1158 free(value_str_alloc);
1159 free(chain_str_alloc);
1160
1161next:
1162 if (is_output_full(browser, row))
1163 break;
1164 node = next;
1165 }
1166
1167 return row - first_row;
1168}
1169
Namhyung Kim0c841c62016-01-28 00:40:54 +09001170static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001171 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001172 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001173 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001174 print_callchain_entry_fn print,
1175 struct callchain_print_arg *arg,
1176 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001177{
1178 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001179 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001180 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001181 u64 percent_total = total;
1182
1183 if (callchain_param.mode == CHAIN_GRAPH_REL)
1184 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001185
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001186 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001187 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001188
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001189 while (node) {
1190 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1191 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001192 struct callchain_list *chain;
1193 char folded_sign = ' ';
1194 int first = true;
1195 int extra_offset = 0;
1196
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001197 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198 bool was_first = first;
1199
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001200 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001202 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001203 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204
1205 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206
Namhyung Kim18bb8382015-11-09 14:45:42 +09001207 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001208 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001209 was_first && need_percent,
1210 offset + extra_offset,
1211 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001212
Namhyung Kim18bb8382015-11-09 14:45:42 +09001213 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001214 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001215
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001216 if (folded_sign == '+')
1217 break;
1218 }
1219
1220 if (folded_sign == '-') {
1221 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001222
Namhyung Kim0c841c62016-01-28 00:40:54 +09001223 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001224 new_level, row, total,
1225 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001226 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001227 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001228 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001229 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001230 node = next;
1231 }
1232out:
1233 return row - first_row;
1234}
1235
Namhyung Kim0c841c62016-01-28 00:40:54 +09001236static int hist_browser__show_callchain(struct hist_browser *browser,
1237 struct hist_entry *entry, int level,
1238 unsigned short row,
1239 print_callchain_entry_fn print,
1240 struct callchain_print_arg *arg,
1241 check_output_full_fn is_output_full)
1242{
1243 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001244 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001245 int printed;
1246
Namhyung Kim5eca1042016-01-28 00:40:55 +09001247 if (symbol_conf.cumulate_callchain)
1248 parent_total = entry->stat_acc->period;
1249 else
1250 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001251
1252 if (callchain_param.mode == CHAIN_FLAT) {
1253 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001254 &entry->sorted_chain, row,
1255 total, parent_total, print, arg,
1256 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001257 } else if (callchain_param.mode == CHAIN_FOLDED) {
1258 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001259 &entry->sorted_chain, row,
1260 total, parent_total, print, arg,
1261 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001262 } else {
1263 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001264 &entry->sorted_chain, level, row,
1265 total, parent_total, print, arg,
1266 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001267 }
1268
1269 if (arg->is_current_entry)
1270 browser->he_selection = entry;
1271
1272 return printed;
1273}
1274
Namhyung Kim89701462013-01-22 18:09:38 +09001275struct hpp_arg {
1276 struct ui_browser *b;
1277 char folded_sign;
1278 bool current_entry;
1279};
1280
Jiri Olsa98ba1602016-09-22 17:36:35 +02001281int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001282{
1283 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001284 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001285 va_list args;
1286 double percent;
1287
1288 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001289 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001290 percent = va_arg(args, double);
1291 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001292
Namhyung Kim89701462013-01-22 18:09:38 +09001293 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001294
Namhyung Kimd6751072014-07-31 14:47:36 +09001295 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001296 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001297
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001298 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001299}
1300
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001301#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001302static u64 __hpp_get_##_field(struct hist_entry *he) \
1303{ \
1304 return he->stat._field; \
1305} \
1306 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001307static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001308hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001309 struct perf_hpp *hpp, \
1310 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001311{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001312 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1313 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001314}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001315
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001316#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1317static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1318{ \
1319 return he->stat_acc->_field; \
1320} \
1321 \
1322static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001323hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001324 struct perf_hpp *hpp, \
1325 struct hist_entry *he) \
1326{ \
1327 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001328 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001329 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001330 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001331 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001332 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001333 \
1334 return ret; \
1335 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001336 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1337 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001338}
1339
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001340__HPP_COLOR_PERCENT_FN(overhead, period)
1341__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1342__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1343__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1344__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001345__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001346
1347#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001348#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001349
1350void hist_browser__init_hpp(void)
1351{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001352 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1353 hist_browser__hpp_color_overhead;
1354 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1355 hist_browser__hpp_color_overhead_sys;
1356 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1357 hist_browser__hpp_color_overhead_us;
1358 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1359 hist_browser__hpp_color_overhead_guest_sys;
1360 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1361 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001362 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1363 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001364}
1365
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001366static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001367 struct hist_entry *entry,
1368 unsigned short row)
1369{
Jiri Olsa12400052012-10-13 00:06:16 +02001370 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001371 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001372 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001373 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001374 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001375 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001376 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001377
1378 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001379 browser->he_selection = entry;
1380 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001381 }
1382
1383 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001384 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001385 folded_sign = hist_entry__folded(entry);
1386 }
1387
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001388 if (symbol_conf.inline_name &&
1389 (!entry->has_children)) {
1390 hist_entry_init_inline_node(entry);
1391 folded_sign = hist_entry__folded(entry);
1392 }
1393
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001394 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001395 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001396 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001397 .folded_sign = folded_sign,
1398 .current_entry = current_entry,
1399 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001400 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001401
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001402 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001403
Jiri Olsaf0786af2016-01-18 10:24:23 +01001404 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001405 char s[2048];
1406 struct perf_hpp hpp = {
1407 .buf = s,
1408 .size = sizeof(s),
1409 .ptr = &arg,
1410 };
1411
Namhyung Kim361459f2015-12-23 02:07:08 +09001412 if (perf_hpp__should_skip(fmt, entry->hists) ||
1413 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001414 continue;
1415
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001416 if (current_entry && browser->b.navkeypressed) {
1417 ui_browser__set_color(&browser->b,
1418 HE_COLORSET_SELECTED);
1419 } else {
1420 ui_browser__set_color(&browser->b,
1421 HE_COLORSET_NORMAL);
1422 }
1423
1424 if (first) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001425 if (symbol_conf.use_callchain ||
1426 symbol_conf.inline_name) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001427 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001428 width -= 2;
1429 }
1430 first = false;
1431 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001432 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001433 width -= 2;
1434 }
1435
Jiri Olsa12400052012-10-13 00:06:16 +02001436 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001437 int ret = fmt->color(fmt, &hpp, entry);
1438 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1439 /*
1440 * fmt->color() already used ui_browser to
1441 * print the non alignment bits, skip it (+ret):
1442 */
1443 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001444 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001445 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001446 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001447 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001448 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001449 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001450
1451 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001452 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001453 width += 1;
1454
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001455 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001456
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001457 ++row;
1458 ++printed;
1459 } else
1460 --row_offset;
1461
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001462 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001463 struct callchain_print_arg arg = {
1464 .row_offset = row_offset,
1465 .is_current_entry = current_entry,
1466 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001467
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001468 if (entry->inline_node)
1469 printed += hist_browser__show_inline(browser,
1470 entry->inline_node, row, 0);
1471 else
1472 printed += hist_browser__show_callchain(browser,
1473 entry, 1, row,
1474 hist_browser__show_callchain_entry,
1475 &arg,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001476 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001477 }
1478
1479 return printed;
1480}
1481
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001482static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1483 struct hist_entry *entry,
1484 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001485 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001486{
1487 int printed = 0;
1488 int width = browser->b.width;
1489 char folded_sign = ' ';
1490 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1491 off_t row_offset = entry->row_offset;
1492 bool first = true;
1493 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001494 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001495 struct hpp_arg arg = {
1496 .b = &browser->b,
1497 .current_entry = current_entry,
1498 };
1499 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001500 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001501
1502 if (current_entry) {
1503 browser->he_selection = entry;
1504 browser->selection = &entry->ms;
1505 }
1506
1507 hist_entry__init_have_children(entry);
1508 folded_sign = hist_entry__folded(entry);
1509 arg.folded_sign = folded_sign;
1510
1511 if (entry->leaf && row_offset) {
1512 row_offset--;
1513 goto show_callchain;
1514 }
1515
1516 hist_browser__gotorc(browser, row, 0);
1517
1518 if (current_entry && browser->b.navkeypressed)
1519 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1520 else
1521 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1522
1523 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1524 width -= level * HIERARCHY_INDENT;
1525
Namhyung Kima61a22f2016-03-07 16:44:50 -03001526 /* the first hpp_list_node is for overhead columns */
1527 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1528 struct perf_hpp_list_node, list);
1529 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001530 char s[2048];
1531 struct perf_hpp hpp = {
1532 .buf = s,
1533 .size = sizeof(s),
1534 .ptr = &arg,
1535 };
1536
1537 if (perf_hpp__should_skip(fmt, entry->hists) ||
1538 column++ < browser->b.horiz_scroll)
1539 continue;
1540
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001541 if (current_entry && browser->b.navkeypressed) {
1542 ui_browser__set_color(&browser->b,
1543 HE_COLORSET_SELECTED);
1544 } else {
1545 ui_browser__set_color(&browser->b,
1546 HE_COLORSET_NORMAL);
1547 }
1548
1549 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001550 ui_browser__printf(&browser->b, "%c ", folded_sign);
1551 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001552 first = false;
1553 } else {
1554 ui_browser__printf(&browser->b, " ");
1555 width -= 2;
1556 }
1557
1558 if (fmt->color) {
1559 int ret = fmt->color(fmt, &hpp, entry);
1560 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1561 /*
1562 * fmt->color() already used ui_browser to
1563 * print the non alignment bits, skip it (+ret):
1564 */
1565 ui_browser__printf(&browser->b, "%s", s + ret);
1566 } else {
1567 int ret = fmt->entry(fmt, &hpp, entry);
1568 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1569 ui_browser__printf(&browser->b, "%s", s);
1570 }
1571 width -= hpp.buf - s;
1572 }
1573
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001574 if (!first) {
1575 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1576 width -= hierarchy_indent;
1577 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001578
1579 if (column >= browser->b.horiz_scroll) {
1580 char s[2048];
1581 struct perf_hpp hpp = {
1582 .buf = s,
1583 .size = sizeof(s),
1584 .ptr = &arg,
1585 };
1586
1587 if (current_entry && browser->b.navkeypressed) {
1588 ui_browser__set_color(&browser->b,
1589 HE_COLORSET_SELECTED);
1590 } else {
1591 ui_browser__set_color(&browser->b,
1592 HE_COLORSET_NORMAL);
1593 }
1594
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001595 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001596 if (first) {
1597 ui_browser__printf(&browser->b, "%c ", folded_sign);
1598 first = false;
1599 } else {
1600 ui_browser__write_nstring(&browser->b, "", 2);
1601 }
1602
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001603 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001604
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001605 /*
1606 * No need to call hist_entry__snprintf_alignment()
1607 * since this fmt is always the last column in the
1608 * hierarchy mode.
1609 */
1610 if (fmt->color) {
1611 width -= fmt->color(fmt, &hpp, entry);
1612 } else {
1613 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001614
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001615 width -= fmt->entry(fmt, &hpp, entry);
1616 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001617
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001618 while (isspace(s[i++]))
1619 width++;
1620 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001621 }
1622 }
1623
1624 /* The scroll bar isn't being used */
1625 if (!browser->b.navkeypressed)
1626 width += 1;
1627
1628 ui_browser__write_nstring(&browser->b, "", width);
1629
1630 ++row;
1631 ++printed;
1632
1633show_callchain:
1634 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1635 struct callchain_print_arg carg = {
1636 .row_offset = row_offset,
1637 };
1638
1639 printed += hist_browser__show_callchain(browser, entry,
1640 level + 1, row,
1641 hist_browser__show_callchain_entry, &carg,
1642 hist_browser__check_output_full);
1643 }
1644
1645 return printed;
1646}
1647
Namhyung Kim79dded82016-02-26 21:13:19 +09001648static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001649 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001650{
1651 int width = browser->b.width;
1652 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1653 bool first = true;
1654 int column = 0;
1655 int ret;
1656 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001657 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001658 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001659
1660 if (current_entry) {
1661 browser->he_selection = NULL;
1662 browser->selection = NULL;
1663 }
1664
1665 hist_browser__gotorc(browser, row, 0);
1666
1667 if (current_entry && browser->b.navkeypressed)
1668 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1669 else
1670 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1671
1672 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1673 width -= level * HIERARCHY_INDENT;
1674
Namhyung Kima61a22f2016-03-07 16:44:50 -03001675 /* the first hpp_list_node is for overhead columns */
1676 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1677 struct perf_hpp_list_node, list);
1678 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001679 if (perf_hpp__should_skip(fmt, browser->hists) ||
1680 column++ < browser->b.horiz_scroll)
1681 continue;
1682
Jiri Olsada1b0402016-06-14 20:19:20 +02001683 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001684
1685 if (first) {
1686 /* for folded sign */
1687 first = false;
1688 ret++;
1689 } else {
1690 /* space between columns */
1691 ret += 2;
1692 }
1693
1694 ui_browser__write_nstring(&browser->b, "", ret);
1695 width -= ret;
1696 }
1697
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001698 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1699 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001700
1701 if (column >= browser->b.horiz_scroll) {
1702 char buf[32];
1703
1704 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1705 ui_browser__printf(&browser->b, " %s", buf);
1706 width -= ret + 2;
1707 }
1708
1709 /* The scroll bar isn't being used */
1710 if (!browser->b.navkeypressed)
1711 width += 1;
1712
1713 ui_browser__write_nstring(&browser->b, "", width);
1714 return 1;
1715}
1716
Jiri Olsa81a888f2014-06-14 15:44:52 +02001717static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1718{
1719 advance_hpp(hpp, inc);
1720 return hpp->size <= 0;
1721}
1722
Jiri Olsa69705b32016-08-07 17:28:28 +02001723static int
1724hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1725 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001726{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001727 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001728 struct perf_hpp dummy_hpp = {
1729 .buf = buf,
1730 .size = size,
1731 };
1732 struct perf_hpp_fmt *fmt;
1733 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001734 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001735 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001736
1737 if (symbol_conf.use_callchain) {
1738 ret = scnprintf(buf, size, " ");
1739 if (advance_hpp_check(&dummy_hpp, ret))
1740 return ret;
1741 }
1742
Jiri Olsaf0786af2016-01-18 10:24:23 +01001743 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001744 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001745 continue;
1746
Jiri Olsa29659ab2016-08-07 17:28:30 +02001747 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001748 if (advance_hpp_check(&dummy_hpp, ret))
1749 break;
1750
Jiri Olsa29659ab2016-08-07 17:28:30 +02001751 if (span)
1752 continue;
1753
Jiri Olsa81a888f2014-06-14 15:44:52 +02001754 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1755 if (advance_hpp_check(&dummy_hpp, ret))
1756 break;
1757 }
1758
1759 return ret;
1760}
1761
Namhyung Kimd8b92402016-02-25 00:13:46 +09001762static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1763{
1764 struct hists *hists = browser->hists;
1765 struct perf_hpp dummy_hpp = {
1766 .buf = buf,
1767 .size = size,
1768 };
1769 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001770 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001771 size_t ret = 0;
1772 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001773 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001774 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001775
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001776 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001777 if (advance_hpp_check(&dummy_hpp, ret))
1778 return ret;
1779
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001780 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001781 /* the first hpp_list_node is for overhead columns */
1782 fmt_node = list_first_entry(&hists->hpp_formats,
1783 struct perf_hpp_list_node, list);
1784 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001785 if (column++ < browser->b.horiz_scroll)
1786 continue;
1787
Jiri Olsa29659ab2016-08-07 17:28:30 +02001788 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001789 if (advance_hpp_check(&dummy_hpp, ret))
1790 break;
1791
1792 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1793 if (advance_hpp_check(&dummy_hpp, ret))
1794 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001795
1796 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001797 }
1798
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001799 if (!first_node) {
1800 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1801 indent * HIERARCHY_INDENT, "");
1802 if (advance_hpp_check(&dummy_hpp, ret))
1803 return ret;
1804 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001805
Namhyung Kima61a22f2016-03-07 16:44:50 -03001806 first_node = true;
1807 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1808 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001809 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1810 if (advance_hpp_check(&dummy_hpp, ret))
1811 break;
1812 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001813 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001814
Namhyung Kima61a22f2016-03-07 16:44:50 -03001815 first_col = true;
1816 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1817 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001818
Namhyung Kima61a22f2016-03-07 16:44:50 -03001819 if (perf_hpp__should_skip(fmt, hists))
1820 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001821
Namhyung Kima61a22f2016-03-07 16:44:50 -03001822 if (!first_col) {
1823 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1824 if (advance_hpp_check(&dummy_hpp, ret))
1825 break;
1826 }
1827 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001828
Jiri Olsa29659ab2016-08-07 17:28:30 +02001829 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001830 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001831
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001832 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001833 ret = strlen(start);
1834
1835 if (start != dummy_hpp.buf)
1836 memmove(dummy_hpp.buf, start, ret + 1);
1837
1838 if (advance_hpp_check(&dummy_hpp, ret))
1839 break;
1840 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001841 }
1842
1843 return ret;
1844}
1845
Jiri Olsa01b47702016-06-14 20:19:13 +02001846static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001847{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001848 char headers[1024];
1849
Jiri Olsa01b47702016-06-14 20:19:13 +02001850 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1851 sizeof(headers));
1852
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001853 ui_browser__gotorc(&browser->b, 0, 0);
1854 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001855 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001856}
1857
Jiri Olsa01b47702016-06-14 20:19:13 +02001858static void hists_browser__headers(struct hist_browser *browser)
1859{
Jiri Olsa69705b32016-08-07 17:28:28 +02001860 struct hists *hists = browser->hists;
1861 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001862
Jiri Olsa69705b32016-08-07 17:28:28 +02001863 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001864
Jiri Olsa69705b32016-08-07 17:28:28 +02001865 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1866 char headers[1024];
1867
1868 hists_browser__scnprintf_headers(browser, headers,
1869 sizeof(headers), line);
1870
1871 ui_browser__gotorc(&browser->b, line, 0);
1872 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1873 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1874 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001875}
1876
1877static void hist_browser__show_headers(struct hist_browser *browser)
1878{
1879 if (symbol_conf.report_hierarchy)
1880 hists_browser__hierarchy_headers(browser);
1881 else
1882 hists_browser__headers(browser);
1883}
1884
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001885static void ui_browser__hists_init_top(struct ui_browser *browser)
1886{
1887 if (browser->top == NULL) {
1888 struct hist_browser *hb;
1889
1890 hb = container_of(browser, struct hist_browser, b);
1891 browser->top = rb_first(&hb->hists->entries);
1892 }
1893}
1894
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001895static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001896{
1897 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001898 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001899 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001900 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001901 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001902
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001903 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001904 struct perf_hpp_list *hpp_list = hists->hpp_list;
1905
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001906 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001907 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001908 }
1909
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001910 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001911 hb->he_selection = NULL;
1912 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001913
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001914 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001915 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001916 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001917
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001918 if (h->filtered) {
1919 /* let it move to sibling */
1920 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001921 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001922 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001923
Namhyung Kim14135662013-10-31 10:17:39 +09001924 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001925 if (percent < hb->min_pcnt)
1926 continue;
1927
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001928 if (symbol_conf.report_hierarchy) {
1929 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001930 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001931 if (row == browser->rows)
1932 break;
1933
1934 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001935 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001936 row++;
1937 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001938 } else {
1939 row += hist_browser__show_entry(hb, h, row);
1940 }
1941
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001942 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001943 break;
1944 }
1945
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001946 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001947}
1948
Namhyung Kim064f1982013-05-14 11:09:04 +09001949static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001950 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001951{
1952 while (nd != NULL) {
1953 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001954 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001955
Namhyung Kimc0f15272014-04-16 11:16:33 +09001956 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001957 return nd;
1958
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001959 /*
1960 * If it's filtered, its all children also were filtered.
1961 * So move to sibling node.
1962 */
1963 if (rb_next(nd))
1964 nd = rb_next(nd);
1965 else
1966 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001967 }
1968
1969 return NULL;
1970}
1971
Namhyung Kim064f1982013-05-14 11:09:04 +09001972static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001973 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001974{
1975 while (nd != NULL) {
1976 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001977 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001978
1979 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001980 return nd;
1981
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001982 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001983 }
1984
1985 return NULL;
1986}
1987
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001988static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001989 off_t offset, int whence)
1990{
1991 struct hist_entry *h;
1992 struct rb_node *nd;
1993 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001994 struct hist_browser *hb;
1995
1996 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001997
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001998 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001999 return;
2000
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002001 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03002002
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002003 switch (whence) {
2004 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09002005 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09002006 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002007 break;
2008 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002009 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002010 goto do_offset;
2011 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002012 nd = rb_hierarchy_last(rb_last(browser->entries));
2013 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002014 first = false;
2015 break;
2016 default:
2017 return;
2018 }
2019
2020 /*
2021 * Moves not relative to the first visible entry invalidates its
2022 * row_offset:
2023 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002024 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002025 h->row_offset = 0;
2026
2027 /*
2028 * Here we have to check if nd is expanded (+), if it is we can't go
2029 * the next top level hist_entry, instead we must compute an offset of
2030 * what _not_ to show and not change the first visible entry.
2031 *
2032 * This offset increments when we are going from top to bottom and
2033 * decreases when we're going from bottom to top.
2034 *
2035 * As we don't have backpointers to the top level in the callchains
2036 * structure, we need to always print the whole hist_entry callchain,
2037 * skipping the first ones that are before the first visible entry
2038 * and stop when we printed enough lines to fill the screen.
2039 */
2040do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00002041 if (!nd)
2042 return;
2043
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002044 if (offset > 0) {
2045 do {
2046 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002047 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002048 u16 remaining = h->nr_rows - h->row_offset;
2049 if (offset > remaining) {
2050 offset -= remaining;
2051 h->row_offset = 0;
2052 } else {
2053 h->row_offset += offset;
2054 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002055 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002056 break;
2057 }
2058 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002059 nd = hists__filter_entries(rb_hierarchy_next(nd),
2060 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002061 if (nd == NULL)
2062 break;
2063 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002064 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002065 } while (offset != 0);
2066 } else if (offset < 0) {
2067 while (1) {
2068 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002069 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002070 if (first) {
2071 if (-offset > h->row_offset) {
2072 offset += h->row_offset;
2073 h->row_offset = 0;
2074 } else {
2075 h->row_offset += offset;
2076 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002077 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002078 break;
2079 }
2080 } else {
2081 if (-offset > h->nr_rows) {
2082 offset += h->nr_rows;
2083 h->row_offset = 0;
2084 } else {
2085 h->row_offset = h->nr_rows + offset;
2086 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002087 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002088 break;
2089 }
2090 }
2091 }
2092
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002093 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09002094 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002095 if (nd == NULL)
2096 break;
2097 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002098 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002099 if (offset == 0) {
2100 /*
2101 * Last unfiltered hist_entry, check if it is
2102 * unfolded, if it is then we should have
2103 * row_offset at its last entry.
2104 */
2105 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002106 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002107 h->row_offset = h->nr_rows;
2108 break;
2109 }
2110 first = false;
2111 }
2112 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002113 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002114 h = rb_entry(nd, struct hist_entry, rb_node);
2115 h->row_offset = 0;
2116 }
2117}
2118
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002119static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002120 struct hist_entry *he, FILE *fp,
2121 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002122{
Namhyung Kim39ee5332014-08-22 09:13:21 +09002123 struct callchain_print_arg arg = {
2124 .fp = fp,
2125 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002126
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002127 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09002128 hist_browser__fprintf_callchain_entry, &arg,
2129 hist_browser__check_dump_full);
2130 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002131}
2132
2133static int hist_browser__fprintf_entry(struct hist_browser *browser,
2134 struct hist_entry *he, FILE *fp)
2135{
2136 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002137 int printed = 0;
2138 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09002139 struct perf_hpp hpp = {
2140 .buf = s,
2141 .size = sizeof(s),
2142 };
2143 struct perf_hpp_fmt *fmt;
2144 bool first = true;
2145 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002146
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002147 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002148 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002149 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002150 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002151
Jiri Olsaf0786af2016-01-18 10:24:23 +01002152 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002153 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002154 continue;
2155
Namhyung Kim26d8b332014-03-03 16:16:20 +09002156 if (!first) {
2157 ret = scnprintf(hpp.buf, hpp.size, " ");
2158 advance_hpp(&hpp, ret);
2159 } else
2160 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002161
Namhyung Kim26d8b332014-03-03 16:16:20 +09002162 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002163 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002164 advance_hpp(&hpp, ret);
2165 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002166 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002167
2168 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002169 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2170
2171 return printed;
2172}
2173
2174
2175static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2176 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002177 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002178{
2179 char s[8192];
2180 int printed = 0;
2181 char folded_sign = ' ';
2182 struct perf_hpp hpp = {
2183 .buf = s,
2184 .size = sizeof(s),
2185 };
2186 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002187 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002188 bool first = true;
2189 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002190 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002191
2192 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2193
2194 folded_sign = hist_entry__folded(he);
2195 printed += fprintf(fp, "%c", folded_sign);
2196
Namhyung Kim325a6282016-03-09 22:47:00 +09002197 /* the first hpp_list_node is for overhead columns */
2198 fmt_node = list_first_entry(&he->hists->hpp_formats,
2199 struct perf_hpp_list_node, list);
2200 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002201 if (!first) {
2202 ret = scnprintf(hpp.buf, hpp.size, " ");
2203 advance_hpp(&hpp, ret);
2204 } else
2205 first = false;
2206
2207 ret = fmt->entry(fmt, &hpp, he);
2208 advance_hpp(&hpp, ret);
2209 }
2210
2211 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2212 advance_hpp(&hpp, ret);
2213
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002214 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2215 ret = scnprintf(hpp.buf, hpp.size, " ");
2216 advance_hpp(&hpp, ret);
2217
2218 ret = fmt->entry(fmt, &hpp, he);
2219 advance_hpp(&hpp, ret);
2220 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002221
2222 printed += fprintf(fp, "%s\n", rtrim(s));
2223
2224 if (he->leaf && folded_sign == '-') {
2225 printed += hist_browser__fprintf_callchain(browser, he, fp,
2226 he->depth + 1);
2227 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002228
2229 return printed;
2230}
2231
2232static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2233{
Namhyung Kim064f1982013-05-14 11:09:04 +09002234 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002235 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002236 int printed = 0;
2237
2238 while (nd) {
2239 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2240
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002241 if (symbol_conf.report_hierarchy) {
2242 printed += hist_browser__fprintf_hierarchy_entry(browser,
2243 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002244 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002245 } else {
2246 printed += hist_browser__fprintf_entry(browser, h, fp);
2247 }
2248
2249 nd = hists__filter_entries(rb_hierarchy_next(nd),
2250 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002251 }
2252
2253 return printed;
2254}
2255
2256static int hist_browser__dump(struct hist_browser *browser)
2257{
2258 char filename[64];
2259 FILE *fp;
2260
2261 while (1) {
2262 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2263 if (access(filename, F_OK))
2264 break;
2265 /*
2266 * XXX: Just an arbitrary lazy upper limit
2267 */
2268 if (++browser->print_seq == 8192) {
2269 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2270 return -1;
2271 }
2272 }
2273
2274 fp = fopen(filename, "w");
2275 if (fp == NULL) {
2276 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002277 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002278 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002279 return -1;
2280 }
2281
2282 ++browser->print_seq;
2283 hist_browser__fprintf(browser, fp);
2284 fclose(fp);
2285 ui_helpline__fpush("%s written!", filename);
2286
2287 return 0;
2288}
2289
Jiri Olsafcd86422016-06-20 23:58:18 +02002290void hist_browser__init(struct hist_browser *browser,
2291 struct hists *hists)
2292{
2293 struct perf_hpp_fmt *fmt;
2294
2295 browser->hists = hists;
2296 browser->b.refresh = hist_browser__refresh;
2297 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2298 browser->b.seek = ui_browser__hists_seek;
2299 browser->b.use_navkeypressed = true;
2300 browser->show_headers = symbol_conf.show_hist_headers;
2301
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002302 if (symbol_conf.report_hierarchy) {
2303 struct perf_hpp_list_node *fmt_node;
2304
2305 /* count overhead columns (in the first node) */
2306 fmt_node = list_first_entry(&hists->hpp_formats,
2307 struct perf_hpp_list_node, list);
2308 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2309 ++browser->b.columns;
2310
2311 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002312 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002313 } else {
2314 hists__for_each_format(hists, fmt)
2315 ++browser->b.columns;
2316 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002317
2318 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002319}
2320
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002321struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002322{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002323 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002324
Jiri Olsafcd86422016-06-20 23:58:18 +02002325 if (browser)
2326 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002327
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002328 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002329}
2330
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002331static struct hist_browser *
2332perf_evsel_browser__new(struct perf_evsel *evsel,
2333 struct hist_browser_timer *hbt,
2334 struct perf_env *env)
2335{
2336 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2337
2338 if (browser) {
2339 browser->hbt = hbt;
2340 browser->env = env;
2341 browser->title = perf_evsel_browser_title;
2342 }
2343 return browser;
2344}
2345
Jiri Olsadabd2012016-06-20 23:58:14 +02002346void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002347{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002348 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002349}
2350
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002351static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002352{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002353 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002354}
2355
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002356static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002357{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002358 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002359}
2360
Taeung Song1e378eb2014-10-07 16:13:15 +09002361/* Check whether the browser is for 'top' or 'report' */
2362static inline bool is_report_browser(void *timer)
2363{
2364 return timer == NULL;
2365}
2366
Jiri Olsa5b91a862016-06-20 23:58:15 +02002367static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002368 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002369{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002370 struct hist_browser_timer *hbt = browser->hbt;
2371 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002372 char unit;
2373 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002374 const struct dso *dso = hists->dso_filter;
2375 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002376 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002377 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2378 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002379 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002380 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002381 char buf[512];
2382 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002383 char ref[30] = " show reference callgraph, ";
2384 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002385
Namhyung Kimf2148332014-01-14 11:52:48 +09002386 if (symbol_conf.filter_relative) {
2387 nr_samples = hists->stats.nr_non_filtered_samples;
2388 nr_events = hists->stats.total_non_filtered_period;
2389 }
2390
Namhyung Kim759ff492013-03-05 14:53:26 +09002391 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002392 struct perf_evsel *pos;
2393
2394 perf_evsel__group_desc(evsel, buf, buflen);
2395 ev_name = buf;
2396
2397 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002398 struct hists *pos_hists = evsel__hists(pos);
2399
Namhyung Kimf2148332014-01-14 11:52:48 +09002400 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002401 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2402 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002403 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002404 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2405 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002406 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002407 }
2408 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002409
Kan Liang9e207dd2015-08-11 06:30:49 -04002410 if (symbol_conf.show_ref_callgraph &&
2411 strstr(ev_name, "call-graph=no"))
2412 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002413 nr_samples = convert_unit(nr_samples, &unit);
2414 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002415 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2416 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002417
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002418
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002419 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002420 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002421 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002422 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002423 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002424 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002425 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002426 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002427 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002428 } else {
2429 printed += scnprintf(bf + printed, size - printed,
2430 ", Thread: %s",
2431 (thread->comm_set ? thread__comm_str(thread) : ""));
2432 }
2433 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002434 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002435 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002436 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002437 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002438 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002439 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002440 if (!is_report_browser(hbt)) {
2441 struct perf_top *top = hbt->arg;
2442
2443 if (top->zero)
2444 printed += scnprintf(bf + printed, size - printed, " [z]");
2445 }
2446
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002447 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002448}
2449
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002450static inline void free_popup_options(char **options, int n)
2451{
2452 int i;
2453
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002454 for (i = 0; i < n; ++i)
2455 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002456}
2457
Feng Tang341487ab2013-02-03 14:38:20 +08002458/*
2459 * Only runtime switching of perf data file will make "input_name" point
2460 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2461 * whether we need to call free() for current "input_name" during the switch.
2462 */
2463static bool is_input_name_malloced = false;
2464
2465static int switch_data_file(void)
2466{
2467 char *pwd, *options[32], *abs_path[32], *tmp;
2468 DIR *pwd_dir;
2469 int nr_options = 0, choice = -1, ret = -1;
2470 struct dirent *dent;
2471
2472 pwd = getenv("PWD");
2473 if (!pwd)
2474 return ret;
2475
2476 pwd_dir = opendir(pwd);
2477 if (!pwd_dir)
2478 return ret;
2479
2480 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002481 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002482
2483 while ((dent = readdir(pwd_dir))) {
2484 char path[PATH_MAX];
2485 u64 magic;
2486 char *name = dent->d_name;
2487 FILE *file;
2488
2489 if (!(dent->d_type == DT_REG))
2490 continue;
2491
2492 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2493
2494 file = fopen(path, "r");
2495 if (!file)
2496 continue;
2497
2498 if (fread(&magic, 1, 8, file) < 8)
2499 goto close_file_and_continue;
2500
2501 if (is_perf_magic(magic)) {
2502 options[nr_options] = strdup(name);
2503 if (!options[nr_options])
2504 goto close_file_and_continue;
2505
2506 abs_path[nr_options] = strdup(path);
2507 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002508 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002509 ui__warning("Can't search all data files due to memory shortage.\n");
2510 fclose(file);
2511 break;
2512 }
2513
2514 nr_options++;
2515 }
2516
2517close_file_and_continue:
2518 fclose(file);
2519 if (nr_options >= 32) {
2520 ui__warning("Too many perf data files in PWD!\n"
2521 "Only the first 32 files will be listed.\n");
2522 break;
2523 }
2524 }
2525 closedir(pwd_dir);
2526
2527 if (nr_options) {
2528 choice = ui__popup_menu(nr_options, options);
2529 if (choice < nr_options && choice >= 0) {
2530 tmp = strdup(abs_path[choice]);
2531 if (tmp) {
2532 if (is_input_name_malloced)
2533 free((void *)input_name);
2534 input_name = tmp;
2535 is_input_name_malloced = true;
2536 ret = 0;
2537 } else
2538 ui__warning("Data switch failed due to memory shortage!\n");
2539 }
2540 }
2541
2542 free_popup_options(options, nr_options);
2543 free_popup_options(abs_path, nr_options);
2544 return ret;
2545}
2546
Namhyung Kimea7cd592015-04-22 16:18:19 +09002547struct popup_action {
2548 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002549 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002550 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002551
2552 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2553};
2554
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002555static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002556do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002557{
2558 struct perf_evsel *evsel;
2559 struct annotation *notes;
2560 struct hist_entry *he;
2561 int err;
2562
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002563 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002564 return 0;
2565
Namhyung Kimea7cd592015-04-22 16:18:19 +09002566 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002567 if (!notes->src)
2568 return 0;
2569
2570 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002571 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002572 he = hist_browser__selected_entry(browser);
2573 /*
2574 * offer option to annotate the other branch source or target
2575 * (if they exists) when returning from annotate
2576 */
2577 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2578 return 1;
2579
2580 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2581 if (err)
2582 ui_browser__handle_resize(&browser->b);
2583 return 0;
2584}
2585
2586static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002587add_annotate_opt(struct hist_browser *browser __maybe_unused,
2588 struct popup_action *act, char **optstr,
2589 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002590{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002591 if (sym == NULL || map->dso->annotate_warned)
2592 return 0;
2593
2594 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2595 return 0;
2596
2597 act->ms.map = map;
2598 act->ms.sym = sym;
2599 act->fn = do_annotate;
2600 return 1;
2601}
2602
2603static int
2604do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2605{
2606 struct thread *thread = act->thread;
2607
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002608 if ((!hists__has(browser->hists, thread) &&
2609 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002610 return 0;
2611
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002612 if (browser->hists->thread_filter) {
2613 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2614 perf_hpp__set_elide(HISTC_THREAD, false);
2615 thread__zput(browser->hists->thread_filter);
2616 ui_helpline__pop();
2617 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002618 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002619 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2620 thread->comm_set ? thread__comm_str(thread) : "",
2621 thread->tid);
2622 } else {
2623 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2624 thread->comm_set ? thread__comm_str(thread) : "");
2625 }
2626
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002627 browser->hists->thread_filter = thread__get(thread);
2628 perf_hpp__set_elide(HISTC_THREAD, false);
2629 pstack__push(browser->pstack, &browser->hists->thread_filter);
2630 }
2631
2632 hists__filter_by_thread(browser->hists);
2633 hist_browser__reset(browser);
2634 return 0;
2635}
2636
2637static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002638add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2639 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002640{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002641 int ret;
2642
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002643 if ((!hists__has(browser->hists, thread) &&
2644 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002645 return 0;
2646
Jiri Olsafa829112016-05-03 13:54:47 +02002647 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002648 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2649 browser->hists->thread_filter ? "out of" : "into",
2650 thread->comm_set ? thread__comm_str(thread) : "",
2651 thread->tid);
2652 } else {
2653 ret = asprintf(optstr, "Zoom %s %s thread",
2654 browser->hists->thread_filter ? "out of" : "into",
2655 thread->comm_set ? thread__comm_str(thread) : "");
2656 }
2657 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002658 return 0;
2659
2660 act->thread = thread;
2661 act->fn = do_zoom_thread;
2662 return 1;
2663}
2664
2665static int
2666do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2667{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002668 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002669
Jiri Olsa69849fc2016-05-03 13:54:45 +02002670 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002671 return 0;
2672
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002673 if (browser->hists->dso_filter) {
2674 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2675 perf_hpp__set_elide(HISTC_DSO, false);
2676 browser->hists->dso_filter = NULL;
2677 ui_helpline__pop();
2678 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002679 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002680 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2681 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002682 perf_hpp__set_elide(HISTC_DSO, true);
2683 pstack__push(browser->pstack, &browser->hists->dso_filter);
2684 }
2685
2686 hists__filter_by_dso(browser->hists);
2687 hist_browser__reset(browser);
2688 return 0;
2689}
2690
2691static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002692add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002693 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002694{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002695 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002696 return 0;
2697
2698 if (asprintf(optstr, "Zoom %s %s DSO",
2699 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002700 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002701 return 0;
2702
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002703 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002704 act->fn = do_zoom_dso;
2705 return 1;
2706}
2707
2708static int
2709do_browse_map(struct hist_browser *browser __maybe_unused,
2710 struct popup_action *act)
2711{
2712 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002713 return 0;
2714}
2715
2716static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002717add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002718 struct popup_action *act, char **optstr, struct map *map)
2719{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002720 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002721 return 0;
2722
2723 if (asprintf(optstr, "Browse map details") < 0)
2724 return 0;
2725
2726 act->ms.map = map;
2727 act->fn = do_browse_map;
2728 return 1;
2729}
2730
2731static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002732do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002733 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002734{
2735 char script_opt[64];
2736 memset(script_opt, 0, sizeof(script_opt));
2737
Namhyung Kimea7cd592015-04-22 16:18:19 +09002738 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002739 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002740 thread__comm_str(act->thread));
2741 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002742 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002743 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002744 }
2745
2746 script_browse(script_opt);
2747 return 0;
2748}
2749
2750static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002751add_script_opt(struct hist_browser *browser __maybe_unused,
2752 struct popup_action *act, char **optstr,
2753 struct thread *thread, struct symbol *sym)
2754{
2755 if (thread) {
2756 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2757 thread__comm_str(thread)) < 0)
2758 return 0;
2759 } else if (sym) {
2760 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2761 sym->name) < 0)
2762 return 0;
2763 } else {
2764 if (asprintf(optstr, "Run scripts for all samples") < 0)
2765 return 0;
2766 }
2767
2768 act->thread = thread;
2769 act->ms.sym = sym;
2770 act->fn = do_run_script;
2771 return 1;
2772}
2773
2774static int
2775do_switch_data(struct hist_browser *browser __maybe_unused,
2776 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002777{
2778 if (switch_data_file()) {
2779 ui__warning("Won't switch the data files due to\n"
2780 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002781 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002782 }
2783
2784 return K_SWITCH_INPUT_DATA;
2785}
2786
Namhyung Kimea7cd592015-04-22 16:18:19 +09002787static int
2788add_switch_opt(struct hist_browser *browser,
2789 struct popup_action *act, char **optstr)
2790{
2791 if (!is_report_browser(browser->hbt))
2792 return 0;
2793
2794 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2795 return 0;
2796
2797 act->fn = do_switch_data;
2798 return 1;
2799}
2800
2801static int
2802do_exit_browser(struct hist_browser *browser __maybe_unused,
2803 struct popup_action *act __maybe_unused)
2804{
2805 return 0;
2806}
2807
2808static int
2809add_exit_opt(struct hist_browser *browser __maybe_unused,
2810 struct popup_action *act, char **optstr)
2811{
2812 if (asprintf(optstr, "Exit") < 0)
2813 return 0;
2814
2815 act->fn = do_exit_browser;
2816 return 1;
2817}
2818
Kan Liang84734b02015-09-04 10:45:45 -04002819static int
2820do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2821{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002822 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002823 return 0;
2824
Kan Liang84734b02015-09-04 10:45:45 -04002825 if (browser->hists->socket_filter > -1) {
2826 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2827 browser->hists->socket_filter = -1;
2828 perf_hpp__set_elide(HISTC_SOCKET, false);
2829 } else {
2830 browser->hists->socket_filter = act->socket;
2831 perf_hpp__set_elide(HISTC_SOCKET, true);
2832 pstack__push(browser->pstack, &browser->hists->socket_filter);
2833 }
2834
2835 hists__filter_by_socket(browser->hists);
2836 hist_browser__reset(browser);
2837 return 0;
2838}
2839
2840static int
2841add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2842 char **optstr, int socket_id)
2843{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002844 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002845 return 0;
2846
2847 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2848 (browser->hists->socket_filter > -1) ? "out of" : "into",
2849 socket_id) < 0)
2850 return 0;
2851
2852 act->socket = socket_id;
2853 act->fn = do_zoom_socket;
2854 return 1;
2855}
2856
Namhyung Kim112f7612014-04-22 14:05:35 +09002857static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002858{
2859 u64 nr_entries = 0;
2860 struct rb_node *nd = rb_first(&hb->hists->entries);
2861
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002862 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002863 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2864 return;
2865 }
2866
Namhyung Kim14135662013-10-31 10:17:39 +09002867 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002868 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002869 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002870 }
2871
Namhyung Kim112f7612014-04-22 14:05:35 +09002872 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002873 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002874}
Feng Tang341487ab2013-02-03 14:38:20 +08002875
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002876static void hist_browser__update_percent_limit(struct hist_browser *hb,
2877 double percent)
2878{
2879 struct hist_entry *he;
2880 struct rb_node *nd = rb_first(&hb->hists->entries);
2881 u64 total = hists__total_period(hb->hists);
2882 u64 min_callchain_hits = total * (percent / 100);
2883
2884 hb->min_pcnt = callchain_param.min_percent = percent;
2885
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002886 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2887 he = rb_entry(nd, struct hist_entry, rb_node);
2888
Namhyung Kim79dded82016-02-26 21:13:19 +09002889 if (he->has_no_entry) {
2890 he->has_no_entry = false;
2891 he->nr_rows = 0;
2892 }
2893
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002894 if (!he->leaf || !symbol_conf.use_callchain)
2895 goto next;
2896
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002897 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2898 total = he->stat.period;
2899
2900 if (symbol_conf.cumulate_callchain)
2901 total = he->stat_acc->period;
2902
2903 min_callchain_hits = total * (percent / 100);
2904 }
2905
2906 callchain_param.sort(&he->sorted_chain, he->callchain,
2907 min_callchain_hits, &callchain_param);
2908
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002909next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002910 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002911
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002912 /* force to re-evaluate folding state of callchains */
2913 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002914 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002915 }
2916}
2917
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002918static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002919 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002920 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002921 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002922 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002923 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002924{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002925 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002926 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002927 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002928#define MAX_OPTIONS 16
2929 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002930 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002931 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002932 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002933 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002934 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002935
Namhyung Kime8e684a2013-12-26 14:37:58 +09002936#define HIST_BROWSER_HELP_COMMON \
2937 "h/?/F1 Show this window\n" \
2938 "UP/DOWN/PGUP\n" \
2939 "PGDN/SPACE Navigate\n" \
2940 "q/ESC/CTRL+C Exit browser\n\n" \
2941 "For multiple event sessions:\n\n" \
2942 "TAB/UNTAB Switch events\n\n" \
2943 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002944 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2945 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002946 "a Annotate current symbol\n" \
2947 "C Collapse all callchains\n" \
2948 "d Zoom into current DSO\n" \
2949 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002950 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002951 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002952 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002953 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002954 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002955
2956 /* help messages are sorted by lexical order of the hotkey */
2957 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002958 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002959 "P Print histograms to perf.hist.N\n"
2960 "r Run available scripts\n"
2961 "s Switch to another data file in PWD\n"
2962 "t Zoom into current Thread\n"
2963 "V Verbose (DSO names in callchains, etc)\n"
2964 "/ Filter symbol by name";
2965 const char top_help[] = HIST_BROWSER_HELP_COMMON
2966 "P Print histograms to perf.hist.N\n"
2967 "t Zoom into current Thread\n"
2968 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002969 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002970 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002971 "/ Filter symbol by name";
2972
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002973 if (browser == NULL)
2974 return -1;
2975
Namhyung Kimed426912015-05-29 21:53:44 +09002976 /* reset abort key so that it can get Ctrl-C as a key */
2977 SLang_reset_tty();
2978 SLang_init_tty(0, 0, 0);
2979
Namhyung Kim03905042015-11-28 02:32:39 +09002980 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002981 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002982 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002983
Kan Liang84734b02015-09-04 10:45:45 -04002984 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002985 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002986 goto out;
2987
2988 ui_helpline__push(helpline);
2989
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002990 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002991 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002992
Namhyung Kim5b591662014-07-31 14:47:38 +09002993 if (symbol_conf.col_width_list_str)
2994 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2995
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002996 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002997 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002998 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002999 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04003000 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003001
Stephane Eranian24bff2d2012-03-12 16:13:30 +01003002 nr_options = 0;
3003
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03003004 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003005
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003006 if (browser->he_selection != NULL) {
3007 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003008 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04003009 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003010 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003011 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003012 case K_TAB:
3013 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06003014 if (nr_events == 1)
3015 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003016 /*
3017 * Exit the browser, let hists__browser_tree
3018 * go to the next or previous
3019 */
3020 goto out_free_stack;
3021 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003022 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003023 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003024 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003025 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003026 continue;
3027 }
3028
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003029 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08003030 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003031 browser->selection->map->dso->annotate_warned)
3032 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003033
Namhyung Kimea7cd592015-04-22 16:18:19 +09003034 actions->ms.map = browser->selection->map;
3035 actions->ms.sym = browser->selection->sym;
3036 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003037 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03003038 case 'P':
3039 hist_browser__dump(browser);
3040 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003041 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03003042 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003043 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003044 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003045 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02003046 verbose = (verbose + 1) % 4;
3047 browser->show_dso = verbose > 0;
3048 ui_helpline__fpush("Verbosity level set to %d\n",
3049 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003050 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003051 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003052 actions->thread = thread;
3053 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003054 continue;
Kan Liang84734b02015-09-04 10:45:45 -04003055 case 'S':
3056 actions->socket = socked_id;
3057 do_zoom_socket(browser, actions);
3058 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03003059 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09003060 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03003061 "Please enter the name of symbol you want to see.\n"
3062 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09003063 buf, "ENTER: OK, ESC: Cancel",
3064 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03003065 hists->symbol_filter_str = *buf ? buf : NULL;
3066 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09003067 hist_browser__reset(browser);
3068 }
3069 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08003070 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003071 if (is_report_browser(hbt)) {
3072 actions->thread = NULL;
3073 actions->ms.sym = NULL;
3074 do_run_script(browser, actions);
3075 }
Feng Tangc77d8d72012-11-01 00:00:55 +08003076 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08003077 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003078 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003079 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003080 if (key == K_SWITCH_INPUT_DATA)
3081 goto out_free_stack;
3082 }
Feng Tang341487ab2013-02-03 14:38:20 +08003083 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09003084 case 'i':
3085 /* env->arch is NULL for live-mode (i.e. perf top) */
3086 if (env->arch)
3087 tui__header_window(env);
3088 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09003089 case 'F':
3090 symbol_conf.filter_relative ^= 1;
3091 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09003092 case 'z':
3093 if (!is_report_browser(hbt)) {
3094 struct perf_top *top = hbt->arg;
3095
3096 top->zero = !top->zero;
3097 }
3098 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003099 case 'L':
3100 if (ui_browser__input_window("Percent Limit",
3101 "Please enter the value you want to hide entries under that percent.",
3102 buf, "ENTER: OK, ESC: Cancel",
3103 delay_secs * 2) == K_ENTER) {
3104 char *end;
3105 double new_percent = strtod(buf, &end);
3106
3107 if (new_percent < 0 || new_percent > 100) {
3108 ui_browser__warning(&browser->b, delay_secs * 2,
3109 "Invalid percent: %.2f", new_percent);
3110 continue;
3111 }
3112
3113 hist_browser__update_percent_limit(browser, new_percent);
3114 hist_browser__reset(browser);
3115 }
3116 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003117 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003118 case 'h':
3119 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003120 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003121 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003122 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003123 case K_ENTER:
3124 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003125 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003126 /* menu */
3127 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003128 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003129 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003130 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003131
Namhyung Kim01f00a12015-04-22 16:18:16 +09003132 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003133 /*
3134 * Go back to the perf_evsel_menu__run or other user
3135 */
3136 if (left_exits)
3137 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003138
3139 if (key == K_ESC &&
3140 ui_browser__dialog_yesno(&browser->b,
3141 "Do you really want to exit?"))
3142 goto out_free_stack;
3143
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003144 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003145 }
Namhyung Kim64221842015-04-24 10:15:33 +09003146 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003147 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003148 /*
3149 * No need to set actions->dso here since
3150 * it's just to remove the current filter.
3151 * Ditto for thread below.
3152 */
3153 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003154 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003155 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003156 } else if (top == &browser->hists->socket_filter) {
3157 do_zoom_socket(browser, actions);
3158 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003159 continue;
3160 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003161 case 'q':
3162 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003163 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003164 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003165 if (!is_report_browser(hbt)) {
3166 struct perf_top *top = hbt->arg;
3167
3168 perf_evlist__toggle_enable(top->evlist);
3169 /*
3170 * No need to refresh, resort/decay histogram
3171 * entries if we are not collecting samples:
3172 */
3173 if (top->evlist->enabled) {
3174 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3175 hbt->refresh = delay_secs;
3176 } else {
3177 helpline = "Press 'f' again to re-enable the events";
3178 hbt->refresh = 0;
3179 }
3180 continue;
3181 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003182 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003183 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003184 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003185 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003186 }
3187
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003188 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003189 goto skip_annotation;
3190
Namhyung Kim55369fc2013-04-01 20:35:20 +09003191 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003192 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003193
3194 if (bi == NULL)
3195 goto skip_annotation;
3196
Namhyung Kimea7cd592015-04-22 16:18:19 +09003197 nr_options += add_annotate_opt(browser,
3198 &actions[nr_options],
3199 &options[nr_options],
3200 bi->from.map,
3201 bi->from.sym);
3202 if (bi->to.sym != bi->from.sym)
3203 nr_options += add_annotate_opt(browser,
3204 &actions[nr_options],
3205 &options[nr_options],
3206 bi->to.map,
3207 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003208 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003209 nr_options += add_annotate_opt(browser,
3210 &actions[nr_options],
3211 &options[nr_options],
3212 browser->selection->map,
3213 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003214 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003215skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003216 nr_options += add_thread_opt(browser, &actions[nr_options],
3217 &options[nr_options], thread);
3218 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003219 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003220 nr_options += add_map_opt(browser, &actions[nr_options],
3221 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003222 browser->selection ?
3223 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003224 nr_options += add_socket_opt(browser, &actions[nr_options],
3225 &options[nr_options],
3226 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003227 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003228 if (!is_report_browser(hbt))
3229 goto skip_scripting;
3230
Feng Tangcdbab7c2012-10-30 11:56:06 +08003231 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003232 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003233 nr_options += add_script_opt(browser,
3234 &actions[nr_options],
3235 &options[nr_options],
3236 thread, NULL);
3237 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003238 /*
3239 * Note that browser->selection != NULL
3240 * when browser->he_selection is not NULL,
3241 * so we don't need to check browser->selection
3242 * before fetching browser->selection->sym like what
3243 * we do before fetching browser->selection->map.
3244 *
3245 * See hist_browser__show_entry.
3246 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003247 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003248 nr_options += add_script_opt(browser,
3249 &actions[nr_options],
3250 &options[nr_options],
3251 NULL, browser->selection->sym);
3252 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003253 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003254 nr_options += add_script_opt(browser, &actions[nr_options],
3255 &options[nr_options], NULL, NULL);
3256 nr_options += add_switch_opt(browser, &actions[nr_options],
3257 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003258skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003259 nr_options += add_exit_opt(browser, &actions[nr_options],
3260 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003261
Namhyung Kimea7cd592015-04-22 16:18:19 +09003262 do {
3263 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003264
Namhyung Kimea7cd592015-04-22 16:18:19 +09003265 choice = ui__popup_menu(nr_options, options);
3266 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003267 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003268
3269 act = &actions[choice];
3270 key = act->fn(browser, act);
3271 } while (key == 1);
3272
3273 if (key == K_SWITCH_INPUT_DATA)
3274 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003275 }
3276out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003277 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003278out:
3279 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003280 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003281 return key;
3282}
3283
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003284struct perf_evsel_menu {
3285 struct ui_browser b;
3286 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003287 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003288 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003289 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003290};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003291
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003292static void perf_evsel_menu__write(struct ui_browser *browser,
3293 void *entry, int row)
3294{
3295 struct perf_evsel_menu *menu = container_of(browser,
3296 struct perf_evsel_menu, b);
3297 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003298 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003299 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003300 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003301 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003302 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003303 const char *warn = " ";
3304 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003305
3306 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3307 HE_COLORSET_NORMAL);
3308
Namhyung Kim759ff492013-03-05 14:53:26 +09003309 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003310 struct perf_evsel *pos;
3311
3312 ev_name = perf_evsel__group_name(evsel);
3313
3314 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003315 struct hists *pos_hists = evsel__hists(pos);
3316 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003317 }
3318 }
3319
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003320 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003321 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003322 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003323 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003324
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003325 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003326 if (nr_events != 0) {
3327 menu->lost_events = true;
3328 if (!current_entry)
3329 ui_browser__set_color(browser, HE_COLORSET_TOP);
3330 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003331 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3332 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003333 warn = bf;
3334 }
3335
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003336 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003337
3338 if (current_entry)
3339 menu->selection = evsel;
3340}
3341
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003342static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3343 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003344 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003345{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003346 struct perf_evlist *evlist = menu->b.priv;
3347 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003348 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003349 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003350 int key;
3351
3352 if (ui_browser__show(&menu->b, title,
3353 "ESC: exit, ENTER|->: Browse histograms") < 0)
3354 return -1;
3355
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003356 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003357 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003358
3359 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003360 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003361 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003362
3363 if (!menu->lost_events_warned && menu->lost_events) {
3364 ui_browser__warn_lost_events(&menu->b);
3365 menu->lost_events_warned = true;
3366 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003367 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003368 case K_RIGHT:
3369 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003370 if (!menu->selection)
3371 continue;
3372 pos = menu->selection;
3373browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003374 perf_evlist__set_selected(evlist, pos);
3375 /*
3376 * Give the calling tool a chance to populate the non
3377 * default evsel resorted hists tree.
3378 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003379 if (hbt)
3380 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003381 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003382 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003383 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003384 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003385 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003386 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003387 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003388 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003389 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003390 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003391 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003392 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003393 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003394 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003395 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003396 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003397 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003398 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003399 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003400 case 'q':
3401 case CTRL('c'):
3402 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003403 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003404 default:
3405 continue;
3406 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003407 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003408 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003409 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003410 if (!ui_browser__dialog_yesno(&menu->b,
3411 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003412 continue;
3413 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003414 case 'q':
3415 case CTRL('c'):
3416 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003417 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003418 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003419 }
3420 }
3421
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003422out:
3423 ui_browser__hide(&menu->b);
3424 return key;
3425}
3426
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003427static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003428 void *entry)
3429{
3430 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3431
3432 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3433 return true;
3434
3435 return false;
3436}
3437
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003438static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003439 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003440 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003441 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003442 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003443{
3444 struct perf_evsel *pos;
3445 struct perf_evsel_menu menu = {
3446 .b = {
3447 .entries = &evlist->entries,
3448 .refresh = ui_browser__list_head_refresh,
3449 .seek = ui_browser__list_head_seek,
3450 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003451 .filter = filter_group_entries,
3452 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003453 .priv = evlist,
3454 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003455 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003456 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003457 };
3458
3459 ui_helpline__push("Press ESC to exit");
3460
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003461 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003462 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003463 size_t line_len = strlen(ev_name) + 7;
3464
3465 if (menu.b.width < line_len)
3466 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003467 }
3468
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003469 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003470}
3471
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003472int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003473 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003474 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003475 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003476{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003477 int nr_entries = evlist->nr_entries;
3478
3479single_entry:
3480 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003481 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003482
3483 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003484 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003485 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003486 }
3487
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003488 if (symbol_conf.event_group) {
3489 struct perf_evsel *pos;
3490
3491 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003492 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003493 if (perf_evsel__is_group_leader(pos))
3494 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003495 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003496
3497 if (nr_entries == 1)
3498 goto single_entry;
3499 }
3500
3501 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003502 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003503}