blob: 1b12a69740b31cc11d4877cd3006b2105460e819 [file] [log] [blame]
Arnaldo Carvalho de Melo76b31a22017-04-18 12:26:44 -03001#include <dirent.h>
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03002#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03003#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <stdlib.h>
6#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03007#include <linux/rbtree.h>
Arnaldo Carvalho de Melob0742e92017-04-18 11:08:10 -03008#include <sys/ttydefaults.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03009
Namhyung Kimaca7a942012-04-04 00:14:26 -070010#include "../../util/evsel.h"
11#include "../../util/evlist.h"
12#include "../../util/hist.h"
13#include "../../util/pstack.h"
14#include "../../util/sort.h"
15#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090016#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090017#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030018
Jiri Olsaf7589902016-06-20 23:58:13 +020019#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030020#include "../helpline.h"
21#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020022#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030023#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020024#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030025#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030026#include "string2.h"
Arnaldo Carvalho de Melo58db1d62017-04-19 16:05:56 -030027#include "units.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030028
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030029#include "sane_ctype.h"
30
Namhyung Kimf5951d52012-09-03 11:53:09 +090031extern void hist_browser__init_hpp(void);
32
Jiri Olsa5b91a862016-06-20 23:58:15 +020033static int perf_evsel_browser_title(struct hist_browser *browser,
34 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090035static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030036
Namhyung Kimc3b78952014-04-22 15:56:17 +090037static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090038 float min_pcnt);
39
Namhyung Kim268397c2014-04-22 14:49:31 +090040static bool hist_browser__has_filter(struct hist_browser *hb)
41{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010042 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090043}
44
He Kuang4fabf3d2015-03-12 15:21:49 +080045static int hist_browser__get_folding(struct hist_browser *browser)
46{
47 struct rb_node *nd;
48 struct hists *hists = browser->hists;
49 int unfolded_rows = 0;
50
51 for (nd = rb_first(&hists->entries);
52 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090053 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080054 struct hist_entry *he =
55 rb_entry(nd, struct hist_entry, rb_node);
56
Namhyung Kimf5b763f2016-02-25 00:13:43 +090057 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080058 unfolded_rows += he->nr_rows;
59 }
60 return unfolded_rows;
61}
62
Namhyung Kimc3b78952014-04-22 15:56:17 +090063static u32 hist_browser__nr_entries(struct hist_browser *hb)
64{
65 u32 nr_entries;
66
Namhyung Kimf5b763f2016-02-25 00:13:43 +090067 if (symbol_conf.report_hierarchy)
68 nr_entries = hb->nr_hierarchy_entries;
69 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090070 nr_entries = hb->nr_non_filtered_entries;
71 else
72 nr_entries = hb->hists->nr_entries;
73
He Kuang4fabf3d2015-03-12 15:21:49 +080074 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090075 return nr_entries + hb->nr_callchain_rows;
76}
77
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020078static void hist_browser__update_rows(struct hist_browser *hb)
79{
80 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020081 struct hists *hists = hb->hists;
82 struct perf_hpp_list *hpp_list = hists->hpp_list;
83 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020084
Jiri Olsaf8e67102016-08-07 17:28:26 +020085 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020086 browser->rows = browser->height - header_offset;
87 /*
88 * Verify if we were at the last line and that line isn't
89 * visibe because we now show the header line(s).
90 */
91 index_row = browser->index - browser->top_idx;
92 if (index_row >= browser->rows)
93 browser->index -= index_row - browser->rows + 1;
94}
95
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030096static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030097{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030098 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
99
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300100 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300101 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
102 /*
103 * FIXME: Just keeping existing behaviour, but this really should be
104 * before updating browser->width, as it will invalidate the
105 * calculation above. Fix this and the fallout in another
106 * changeset.
107 */
108 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200109 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300110}
111
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300112static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
113{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200114 struct hists *hists = browser->hists;
115 struct perf_hpp_list *hpp_list = hists->hpp_list;
116 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200117
Jiri Olsaf8e67102016-08-07 17:28:26 +0200118 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200119 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300120}
121
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300122static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300123{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900124 /*
125 * The hists__remove_entry_filter() already folds non-filtered
126 * entries so we can assume it has 0 callchain rows.
127 */
128 browser->nr_callchain_rows = 0;
129
Namhyung Kim268397c2014-04-22 14:49:31 +0900130 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900131 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300132 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300133 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300134}
135
136static char tree__folded_sign(bool unfolded)
137{
138 return unfolded ? '-' : '+';
139}
140
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300141static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300142{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900143 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144}
145
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300146static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300147{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900148 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300149}
150
Namhyung Kim3698dab2015-05-05 23:55:46 +0900151static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300152{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900153 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300154}
155
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800156static struct inline_node *inline_node__create(struct map *map, u64 ip)
157{
158 struct dso *dso;
159 struct inline_node *node;
160
161 if (map == NULL)
162 return NULL;
163
164 dso = map->dso;
165 if (dso == NULL)
166 return NULL;
167
168 if (dso->kernel != DSO_TYPE_USER)
169 return NULL;
170
171 node = dso__parse_addr_inlines(dso,
172 map__rip_2objdump(map, ip));
173
174 return node;
175}
176
177static int inline__count_rows(struct inline_node *node)
178{
179 struct inline_list *ilist;
180 int i = 0;
181
182 if (node == NULL)
183 return 0;
184
185 list_for_each_entry(ilist, &node->val, list) {
186 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
187 i++;
188 }
189
190 return i;
191}
192
193static int callchain_list__inline_rows(struct callchain_list *chain)
194{
195 struct inline_node *node;
196 int rows;
197
198 node = inline_node__create(chain->ms.map, chain->ip);
199 if (node == NULL)
200 return 0;
201
202 rows = inline__count_rows(node);
203 inline_node__delete(node);
204 return rows;
205}
206
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300207static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300208{
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800209 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300210 struct rb_node *nd;
211
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300212 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300213 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
214 struct callchain_list *chain;
215 char folded_sign = ' '; /* No children */
216
217 list_for_each_entry(chain, &child->val, list) {
218 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800219
220 if (symbol_conf.inline_name) {
221 inline_rows =
222 callchain_list__inline_rows(chain);
223 n += inline_rows;
224 }
225
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300226 /* We need this because we may not have children */
227 folded_sign = callchain_list__folded(chain);
228 if (folded_sign == '+')
229 break;
230 }
231
232 if (folded_sign == '-') /* Have children and they're unfolded */
233 n += callchain_node__count_rows_rb_tree(child);
234 }
235
236 return n;
237}
238
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900239static int callchain_node__count_flat_rows(struct callchain_node *node)
240{
241 struct callchain_list *chain;
242 char folded_sign = 0;
243 int n = 0;
244
245 list_for_each_entry(chain, &node->parent_val, list) {
246 if (!folded_sign) {
247 /* only check first chain list entry */
248 folded_sign = callchain_list__folded(chain);
249 if (folded_sign == '+')
250 return 1;
251 }
252 n++;
253 }
254
255 list_for_each_entry(chain, &node->val, list) {
256 if (!folded_sign) {
257 /* node->parent_val list might be empty */
258 folded_sign = callchain_list__folded(chain);
259 if (folded_sign == '+')
260 return 1;
261 }
262 n++;
263 }
264
265 return n;
266}
267
Namhyung Kim8c430a32015-11-09 14:45:44 +0900268static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
269{
270 return 1;
271}
272
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300273static int callchain_node__count_rows(struct callchain_node *node)
274{
275 struct callchain_list *chain;
276 bool unfolded = false;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800277 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300278
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900279 if (callchain_param.mode == CHAIN_FLAT)
280 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900281 else if (callchain_param.mode == CHAIN_FOLDED)
282 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900283
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300284 list_for_each_entry(chain, &node->val, list) {
285 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800286 if (symbol_conf.inline_name) {
287 inline_rows = callchain_list__inline_rows(chain);
288 n += inline_rows;
289 }
290
Namhyung Kim3698dab2015-05-05 23:55:46 +0900291 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300292 }
293
294 if (unfolded)
295 n += callchain_node__count_rows_rb_tree(node);
296
297 return n;
298}
299
300static int callchain__count_rows(struct rb_root *chain)
301{
302 struct rb_node *nd;
303 int n = 0;
304
305 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
306 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
307 n += callchain_node__count_rows(node);
308 }
309
310 return n;
311}
312
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900313static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
314 bool include_children)
315{
316 int count = 0;
317 struct rb_node *node;
318 struct hist_entry *child;
319
320 if (he->leaf)
321 return callchain__count_rows(&he->sorted_chain);
322
Namhyung Kim79dded82016-02-26 21:13:19 +0900323 if (he->has_no_entry)
324 return 1;
325
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900326 node = rb_first(&he->hroot_out);
327 while (node) {
328 float percent;
329
330 child = rb_entry(node, struct hist_entry, rb_node);
331 percent = hist_entry__get_percent_limit(child);
332
333 if (!child->filtered && percent >= hb->min_pcnt) {
334 count++;
335
336 if (include_children && child->unfolded)
337 count += hierarchy_count_rows(hb, child, true);
338 }
339
340 node = rb_next(node);
341 }
342 return count;
343}
344
Namhyung Kim3698dab2015-05-05 23:55:46 +0900345static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300346{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900347 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200348 return false;
349
Namhyung Kim3698dab2015-05-05 23:55:46 +0900350 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300351 return false;
352
Namhyung Kim3698dab2015-05-05 23:55:46 +0900353 he->unfolded = !he->unfolded;
354 return true;
355}
356
357static bool callchain_list__toggle_fold(struct callchain_list *cl)
358{
359 if (!cl)
360 return false;
361
362 if (!cl->has_children)
363 return false;
364
365 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300366 return true;
367}
368
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300369static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300370{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300373 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300374 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
375 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300376 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300377
378 list_for_each_entry(chain, &child->val, list) {
379 if (first) {
380 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900381 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300382 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300383 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900384 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300385 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300386 }
387
388 callchain_node__init_have_children_rb_tree(child);
389 }
390}
391
Namhyung Kima7444af2014-11-24 17:13:27 +0900392static void callchain_node__init_have_children(struct callchain_node *node,
393 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300394{
395 struct callchain_list *chain;
396
Namhyung Kima7444af2014-11-24 17:13:27 +0900397 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900398 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900399
Andres Freund90989032016-03-30 21:02:45 +0200400 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900401 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900402 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900403 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300404
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300405 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300406}
407
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300408static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300409{
Namhyung Kima7444af2014-11-24 17:13:27 +0900410 struct rb_node *nd = rb_first(root);
411 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300412
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300413 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300414 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900415 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900416 if (callchain_param.mode == CHAIN_FLAT ||
417 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900418 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300419 }
420}
421
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300422static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300423{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900424 if (he->init_have_children)
425 return;
426
427 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900428 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300429 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900430 } else {
431 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300432 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900433
434 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300435}
436
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800437static void hist_entry_init_inline_node(struct hist_entry *he)
438{
439 if (he->inline_node)
440 return;
441
442 he->inline_node = inline_node__create(he->ms.map, he->ip);
443
444 if (he->inline_node == NULL)
445 return;
446
447 he->has_children = true;
448}
449
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300450static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300451{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900452 struct hist_entry *he = browser->he_selection;
453 struct map_symbol *ms = browser->selection;
454 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
455 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300456
Wang Nan4938cf02015-12-07 02:35:44 +0000457 if (!he || !ms)
458 return false;
459
Namhyung Kim3698dab2015-05-05 23:55:46 +0900460 if (ms == &he->ms)
461 has_children = hist_entry__toggle_fold(he);
462 else
463 has_children = callchain_list__toggle_fold(cl);
464
465 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900466 int child_rows = 0;
467
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300468 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900469 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300470
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900471 if (he->leaf)
472 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300473 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900474 browser->nr_hierarchy_entries -= he->nr_rows;
475
476 if (symbol_conf.report_hierarchy)
477 child_rows = hierarchy_count_rows(browser, he, true);
478
479 if (he->unfolded) {
480 if (he->leaf)
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800481 if (he->inline_node)
482 he->nr_rows = inline__count_rows(
483 he->inline_node);
484 else
485 he->nr_rows = callchain__count_rows(
486 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900487 else
488 he->nr_rows = hierarchy_count_rows(browser, he, false);
489
490 /* account grand children */
491 if (symbol_conf.report_hierarchy)
492 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900493
494 if (!he->leaf && he->nr_rows == 0) {
495 he->has_no_entry = true;
496 he->nr_rows = 1;
497 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900498 } else {
499 if (symbol_conf.report_hierarchy)
500 browser->b.nr_entries -= child_rows - he->nr_rows;
501
Namhyung Kim79dded82016-02-26 21:13:19 +0900502 if (he->has_no_entry)
503 he->has_no_entry = false;
504
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300505 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900506 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900507
508 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900509
510 if (he->leaf)
511 browser->nr_callchain_rows += he->nr_rows;
512 else
513 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300514
515 return true;
516 }
517
518 /* If it doesn't have children, no toggling performed */
519 return false;
520}
521
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300522static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300523{
524 int n = 0;
525 struct rb_node *nd;
526
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300527 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300528 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
529 struct callchain_list *chain;
530 bool has_children = false;
531
532 list_for_each_entry(chain, &child->val, list) {
533 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900534 callchain_list__set_folding(chain, unfold);
535 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300536 }
537
538 if (has_children)
539 n += callchain_node__set_folding_rb_tree(child, unfold);
540 }
541
542 return n;
543}
544
545static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
546{
547 struct callchain_list *chain;
548 bool has_children = false;
549 int n = 0;
550
551 list_for_each_entry(chain, &node->val, list) {
552 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900553 callchain_list__set_folding(chain, unfold);
554 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300555 }
556
557 if (has_children)
558 n += callchain_node__set_folding_rb_tree(node, unfold);
559
560 return n;
561}
562
563static int callchain__set_folding(struct rb_root *chain, bool unfold)
564{
565 struct rb_node *nd;
566 int n = 0;
567
568 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
569 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
570 n += callchain_node__set_folding(node, unfold);
571 }
572
573 return n;
574}
575
Namhyung Kim492b1012016-02-25 00:13:44 +0900576static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
577 bool unfold __maybe_unused)
578{
579 float percent;
580 struct rb_node *nd;
581 struct hist_entry *child;
582 int n = 0;
583
584 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
585 child = rb_entry(nd, struct hist_entry, rb_node);
586 percent = hist_entry__get_percent_limit(child);
587 if (!child->filtered && percent >= hb->min_pcnt)
588 n++;
589 }
590
591 return n;
592}
593
Jiri Olsab33f9222017-01-20 10:20:29 +0100594static void __hist_entry__set_folding(struct hist_entry *he,
595 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300596{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300597 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900598 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300599
Namhyung Kim3698dab2015-05-05 23:55:46 +0900600 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900601 int n;
602
603 if (he->leaf)
604 n = callchain__set_folding(&he->sorted_chain, unfold);
605 else
606 n = hierarchy_set_folding(hb, he, unfold);
607
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300608 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300609 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300610 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300611}
612
Jiri Olsab33f9222017-01-20 10:20:29 +0100613static void hist_entry__set_folding(struct hist_entry *he,
614 struct hist_browser *browser, bool unfold)
615{
616 double percent;
617
618 percent = hist_entry__get_percent_limit(he);
619 if (he->filtered || percent < browser->min_pcnt)
620 return;
621
622 __hist_entry__set_folding(he, browser, unfold);
623
624 if (!he->depth || unfold)
625 browser->nr_hierarchy_entries++;
626 if (he->leaf)
627 browser->nr_callchain_rows += he->nr_rows;
628 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
629 browser->nr_hierarchy_entries++;
630 he->has_no_entry = true;
631 he->nr_rows = 1;
632 } else
633 he->has_no_entry = false;
634}
635
Namhyung Kimc3b78952014-04-22 15:56:17 +0900636static void
637__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300638{
639 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900640 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300641
Namhyung Kim492b1012016-02-25 00:13:44 +0900642 nd = rb_first(&browser->hists->entries);
643 while (nd) {
644 he = rb_entry(nd, struct hist_entry, rb_node);
645
646 /* set folding state even if it's currently folded */
647 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
648
649 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300650 }
651}
652
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300653static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300654{
Namhyung Kim492b1012016-02-25 00:13:44 +0900655 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900656 browser->nr_callchain_rows = 0;
657 __hist_browser__set_folding(browser, unfold);
658
659 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300660 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300661 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300662}
663
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100664static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
665{
666 if (!browser->he_selection)
667 return;
668
669 hist_entry__set_folding(browser->he_selection, browser, unfold);
670 browser->b.nr_entries = hist_browser__nr_entries(browser);
671}
672
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200673static void ui_browser__warn_lost_events(struct ui_browser *browser)
674{
675 ui_browser__warning(browser, 4,
676 "Events are being lost, check IO/CPU overload!\n\n"
677 "You may want to run 'perf' using a RT scheduler policy:\n\n"
678 " perf top -r 80\n\n"
679 "Or reduce the sampling frequency.");
680}
681
Jiri Olsa5b91a862016-06-20 23:58:15 +0200682static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
683{
684 return browser->title ? browser->title(browser, bf, size) : 0;
685}
686
Jiri Olsadabd2012016-06-20 23:58:14 +0200687int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300688{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300689 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300690 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900691 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900692 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300693
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300694 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900695 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300696
Jiri Olsa5b91a862016-06-20 23:58:15 +0200697 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300698
Namhyung Kim090cff32016-01-11 19:53:14 +0900699 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300700 return -1;
701
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300702 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300703 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300704
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300705 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900706 case K_TIMER: {
707 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900708 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900709
Namhyung Kimc6111522016-10-07 14:04:12 +0900710 if (hist_browser__has_filter(browser) ||
711 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900712 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900713
Namhyung Kimc3b78952014-04-22 15:56:17 +0900714 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900715 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200716
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300717 if (browser->hists->stats.nr_lost_warned !=
718 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
719 browser->hists->stats.nr_lost_warned =
720 browser->hists->stats.nr_events[PERF_RECORD_LOST];
721 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200722 }
723
Jiri Olsa5b91a862016-06-20 23:58:15 +0200724 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300725 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300726 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900727 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300728 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300729 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300730 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300731 struct hist_entry, rb_node);
732 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300733 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 -0300734 seq++, browser->b.nr_entries,
735 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300736 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300737 browser->b.index,
738 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300739 h->row_offset, h->nr_rows);
740 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300741 break;
742 case 'C':
743 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300744 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300745 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100746 case 'c':
747 /* Collapse the selected entry. */
748 hist_browser__set_folding_selected(browser, false);
749 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300750 case 'E':
751 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300752 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300753 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100754 case 'e':
755 /* Expand the selected entry. */
756 hist_browser__set_folding_selected(browser, true);
757 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200758 case 'H':
759 browser->show_headers = !browser->show_headers;
760 hist_browser__update_rows(browser);
761 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200762 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300763 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300764 break;
765 /* fall thru */
766 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300767 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300768 }
769 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300770out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300771 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300772 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300773}
774
Namhyung Kim39ee5332014-08-22 09:13:21 +0900775struct callchain_print_arg {
776 /* for hists browser */
777 off_t row_offset;
778 bool is_current_entry;
779
780 /* for file dump */
781 FILE *fp;
782 int printed;
783};
784
785typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
786 struct callchain_list *chain,
787 const char *str, int offset,
788 unsigned short row,
789 struct callchain_print_arg *arg);
790
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900791static void hist_browser__show_callchain_entry(struct hist_browser *browser,
792 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900793 const char *str, int offset,
794 unsigned short row,
795 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900796{
797 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900798 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300799 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900800
801 color = HE_COLORSET_NORMAL;
802 width = browser->b.width - (offset + 2);
803 if (ui_browser__is_current_entry(&browser->b, row)) {
804 browser->selection = &chain->ms;
805 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900806 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900807 }
808
809 ui_browser__set_color(&browser->b, color);
810 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300811 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300812 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300813 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300814 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900815}
816
Namhyung Kim39ee5332014-08-22 09:13:21 +0900817static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
818 struct callchain_list *chain,
819 const char *str, int offset,
820 unsigned short row __maybe_unused,
821 struct callchain_print_arg *arg)
822{
823 char folded_sign = callchain_list__folded(chain);
824
825 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
826 folded_sign, str);
827}
828
829typedef bool (*check_output_full_fn)(struct hist_browser *browser,
830 unsigned short row);
831
832static bool hist_browser__check_output_full(struct hist_browser *browser,
833 unsigned short row)
834{
835 return browser->b.rows == row;
836}
837
838static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
839 unsigned short row __maybe_unused)
840{
841 return false;
842}
843
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300844#define LEVEL_OFFSET_STEP 3
845
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800846static int hist_browser__show_inline(struct hist_browser *browser,
847 struct inline_node *node,
848 unsigned short row,
849 int offset)
850{
851 struct inline_list *ilist;
852 char buf[1024];
853 int color, width, first_row;
854
855 first_row = row;
856 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
857 list_for_each_entry(ilist, &node->val, list) {
858 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
859 color = HE_COLORSET_NORMAL;
860 if (ui_browser__is_current_entry(&browser->b, row))
861 color = HE_COLORSET_SELECTED;
862
Milian Wolff5dfa2102017-03-18 22:49:28 +0100863 if (callchain_param.key == CCKEY_ADDRESS ||
864 callchain_param.key == CCKEY_SRCLINE) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800865 if (ilist->filename != NULL)
866 scnprintf(buf, sizeof(buf),
867 "%s:%d (inline)",
868 ilist->filename,
869 ilist->line_nr);
870 else
871 scnprintf(buf, sizeof(buf), "??");
872 } else if (ilist->funcname != NULL)
873 scnprintf(buf, sizeof(buf), "%s (inline)",
874 ilist->funcname);
875 else if (ilist->filename != NULL)
876 scnprintf(buf, sizeof(buf),
877 "%s:%d (inline)",
878 ilist->filename,
879 ilist->line_nr);
880 else
881 scnprintf(buf, sizeof(buf), "??");
882
883 ui_browser__set_color(&browser->b, color);
884 hist_browser__gotorc(browser, row, 0);
885 ui_browser__write_nstring(&browser->b, " ",
886 LEVEL_OFFSET_STEP + offset);
887 ui_browser__write_nstring(&browser->b, buf, width);
888 row++;
889 }
890 }
891
892 return row - first_row;
893}
894
895static size_t show_inline_list(struct hist_browser *browser, struct map *map,
896 u64 ip, int row, int offset)
897{
898 struct inline_node *node;
899 int ret;
900
901 node = inline_node__create(map, ip);
902 if (node == NULL)
903 return 0;
904
905 ret = hist_browser__show_inline(browser, node, row, offset);
906
907 inline_node__delete(node);
908 return ret;
909}
910
Namhyung Kim18bb8382015-11-09 14:45:42 +0900911static int hist_browser__show_callchain_list(struct hist_browser *browser,
912 struct callchain_node *node,
913 struct callchain_list *chain,
914 unsigned short row, u64 total,
915 bool need_percent, int offset,
916 print_callchain_entry_fn print,
917 struct callchain_print_arg *arg)
918{
919 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800920 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900921 const char *str;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800922 int inline_rows = 0, ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900923
924 if (arg->row_offset != 0) {
925 arg->row_offset--;
926 return 0;
927 }
928
929 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800930 alloc_str2 = NULL;
931
Namhyung Kim18bb8382015-11-09 14:45:42 +0900932 str = callchain_list__sym_name(chain, bf, sizeof(bf),
933 browser->show_dso);
934
Jin Yaofef51ec2016-10-31 09:19:53 +0800935 if (symbol_conf.show_branchflag_count) {
936 if (need_percent)
937 callchain_list_counts__printf_value(node, chain, NULL,
938 buf, sizeof(buf));
939 else
940 callchain_list_counts__printf_value(NULL, chain, NULL,
941 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900942
Jin Yaofef51ec2016-10-31 09:19:53 +0800943 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
944 str = "Not enough memory!";
945 else
946 str = alloc_str2;
947 }
948
949 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900950 callchain_node__scnprintf_value(node, buf, sizeof(buf),
951 total);
952
953 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
954 str = "Not enough memory!";
955 else
956 str = alloc_str;
957 }
958
959 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900960 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800961 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800962
963 if (symbol_conf.inline_name) {
964 inline_rows = show_inline_list(browser, chain->ms.map,
965 chain->ip, row + 1, offset);
966 }
967
968 return ret + inline_rows;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900969}
970
Namhyung Kim59c624e2016-01-28 00:40:56 +0900971static bool check_percent_display(struct rb_node *node, u64 parent_total)
972{
973 struct callchain_node *child;
974
975 if (node == NULL)
976 return false;
977
978 if (rb_next(node))
979 return true;
980
981 child = rb_entry(node, struct callchain_node, rb_node);
982 return callchain_cumul_hits(child) != parent_total;
983}
984
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900985static int hist_browser__show_callchain_flat(struct hist_browser *browser,
986 struct rb_root *root,
987 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900988 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900989 print_callchain_entry_fn print,
990 struct callchain_print_arg *arg,
991 check_output_full_fn is_output_full)
992{
993 struct rb_node *node;
994 int first_row = row, offset = LEVEL_OFFSET_STEP;
995 bool need_percent;
996
997 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900998 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900999
1000 while (node) {
1001 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1002 struct rb_node *next = rb_next(node);
1003 struct callchain_list *chain;
1004 char folded_sign = ' ';
1005 int first = true;
1006 int extra_offset = 0;
1007
1008 list_for_each_entry(chain, &child->parent_val, list) {
1009 bool was_first = first;
1010
1011 if (first)
1012 first = false;
1013 else if (need_percent)
1014 extra_offset = LEVEL_OFFSET_STEP;
1015
1016 folded_sign = callchain_list__folded(chain);
1017
1018 row += hist_browser__show_callchain_list(browser, child,
1019 chain, row, total,
1020 was_first && need_percent,
1021 offset + extra_offset,
1022 print, arg);
1023
1024 if (is_output_full(browser, row))
1025 goto out;
1026
1027 if (folded_sign == '+')
1028 goto next;
1029 }
1030
1031 list_for_each_entry(chain, &child->val, list) {
1032 bool was_first = first;
1033
1034 if (first)
1035 first = false;
1036 else if (need_percent)
1037 extra_offset = LEVEL_OFFSET_STEP;
1038
1039 folded_sign = callchain_list__folded(chain);
1040
1041 row += hist_browser__show_callchain_list(browser, child,
1042 chain, row, total,
1043 was_first && need_percent,
1044 offset + extra_offset,
1045 print, arg);
1046
1047 if (is_output_full(browser, row))
1048 goto out;
1049
1050 if (folded_sign == '+')
1051 break;
1052 }
1053
1054next:
1055 if (is_output_full(browser, row))
1056 break;
1057 node = next;
1058 }
1059out:
1060 return row - first_row;
1061}
1062
Namhyung Kim8c430a32015-11-09 14:45:44 +09001063static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
1064 struct callchain_list *chain,
1065 char *value_str, char *old_str)
1066{
1067 char bf[1024];
1068 const char *str;
1069 char *new;
1070
1071 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1072 browser->show_dso);
1073 if (old_str) {
1074 if (asprintf(&new, "%s%s%s", old_str,
1075 symbol_conf.field_sep ?: ";", str) < 0)
1076 new = NULL;
1077 } else {
1078 if (value_str) {
1079 if (asprintf(&new, "%s %s", value_str, str) < 0)
1080 new = NULL;
1081 } else {
1082 if (asprintf(&new, "%s", str) < 0)
1083 new = NULL;
1084 }
1085 }
1086 return new;
1087}
1088
1089static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1090 struct rb_root *root,
1091 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +09001092 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +09001093 print_callchain_entry_fn print,
1094 struct callchain_print_arg *arg,
1095 check_output_full_fn is_output_full)
1096{
1097 struct rb_node *node;
1098 int first_row = row, offset = LEVEL_OFFSET_STEP;
1099 bool need_percent;
1100
1101 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001102 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001103
1104 while (node) {
1105 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1106 struct rb_node *next = rb_next(node);
1107 struct callchain_list *chain, *first_chain = NULL;
1108 int first = true;
1109 char *value_str = NULL, *value_str_alloc = NULL;
1110 char *chain_str = NULL, *chain_str_alloc = NULL;
1111
1112 if (arg->row_offset != 0) {
1113 arg->row_offset--;
1114 goto next;
1115 }
1116
1117 if (need_percent) {
1118 char buf[64];
1119
1120 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1121 if (asprintf(&value_str, "%s", buf) < 0) {
1122 value_str = (char *)"<...>";
1123 goto do_print;
1124 }
1125 value_str_alloc = value_str;
1126 }
1127
1128 list_for_each_entry(chain, &child->parent_val, list) {
1129 chain_str = hist_browser__folded_callchain_str(browser,
1130 chain, value_str, chain_str);
1131 if (first) {
1132 first = false;
1133 first_chain = chain;
1134 }
1135
1136 if (chain_str == NULL) {
1137 chain_str = (char *)"Not enough memory!";
1138 goto do_print;
1139 }
1140
1141 chain_str_alloc = chain_str;
1142 }
1143
1144 list_for_each_entry(chain, &child->val, list) {
1145 chain_str = hist_browser__folded_callchain_str(browser,
1146 chain, value_str, chain_str);
1147 if (first) {
1148 first = false;
1149 first_chain = chain;
1150 }
1151
1152 if (chain_str == NULL) {
1153 chain_str = (char *)"Not enough memory!";
1154 goto do_print;
1155 }
1156
1157 chain_str_alloc = chain_str;
1158 }
1159
1160do_print:
1161 print(browser, first_chain, chain_str, offset, row++, arg);
1162 free(value_str_alloc);
1163 free(chain_str_alloc);
1164
1165next:
1166 if (is_output_full(browser, row))
1167 break;
1168 node = next;
1169 }
1170
1171 return row - first_row;
1172}
1173
Namhyung Kim0c841c62016-01-28 00:40:54 +09001174static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001175 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001176 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001177 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001178 print_callchain_entry_fn print,
1179 struct callchain_print_arg *arg,
1180 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001181{
1182 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001183 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001184 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001185 u64 percent_total = total;
1186
1187 if (callchain_param.mode == CHAIN_GRAPH_REL)
1188 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001189
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001190 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001191 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001192
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001193 while (node) {
1194 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1195 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196 struct callchain_list *chain;
1197 char folded_sign = ' ';
1198 int first = true;
1199 int extra_offset = 0;
1200
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202 bool was_first = first;
1203
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001204 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001205 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001206 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001208
1209 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001210
Namhyung Kim18bb8382015-11-09 14:45:42 +09001211 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001212 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001213 was_first && need_percent,
1214 offset + extra_offset,
1215 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001216
Namhyung Kim18bb8382015-11-09 14:45:42 +09001217 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001218 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001219
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220 if (folded_sign == '+')
1221 break;
1222 }
1223
1224 if (folded_sign == '-') {
1225 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001226
Namhyung Kim0c841c62016-01-28 00:40:54 +09001227 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001228 new_level, row, total,
1229 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001230 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001231 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001232 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001233 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001234 node = next;
1235 }
1236out:
1237 return row - first_row;
1238}
1239
Namhyung Kim0c841c62016-01-28 00:40:54 +09001240static int hist_browser__show_callchain(struct hist_browser *browser,
1241 struct hist_entry *entry, int level,
1242 unsigned short row,
1243 print_callchain_entry_fn print,
1244 struct callchain_print_arg *arg,
1245 check_output_full_fn is_output_full)
1246{
1247 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001248 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001249 int printed;
1250
Namhyung Kim5eca1042016-01-28 00:40:55 +09001251 if (symbol_conf.cumulate_callchain)
1252 parent_total = entry->stat_acc->period;
1253 else
1254 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001255
1256 if (callchain_param.mode == CHAIN_FLAT) {
1257 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001258 &entry->sorted_chain, row,
1259 total, parent_total, print, arg,
1260 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001261 } else if (callchain_param.mode == CHAIN_FOLDED) {
1262 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001263 &entry->sorted_chain, row,
1264 total, parent_total, print, arg,
1265 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001266 } else {
1267 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001268 &entry->sorted_chain, level, row,
1269 total, parent_total, print, arg,
1270 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001271 }
1272
1273 if (arg->is_current_entry)
1274 browser->he_selection = entry;
1275
1276 return printed;
1277}
1278
Namhyung Kim89701462013-01-22 18:09:38 +09001279struct hpp_arg {
1280 struct ui_browser *b;
1281 char folded_sign;
1282 bool current_entry;
1283};
1284
Jiri Olsa98ba1602016-09-22 17:36:35 +02001285int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001286{
1287 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001288 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001289 va_list args;
1290 double percent;
1291
1292 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001293 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001294 percent = va_arg(args, double);
1295 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001296
Namhyung Kim89701462013-01-22 18:09:38 +09001297 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001298
Namhyung Kimd6751072014-07-31 14:47:36 +09001299 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001300 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001301
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001302 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001303}
1304
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001305#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001306static u64 __hpp_get_##_field(struct hist_entry *he) \
1307{ \
1308 return he->stat._field; \
1309} \
1310 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001311static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001312hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001313 struct perf_hpp *hpp, \
1314 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001315{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001316 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1317 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001318}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001319
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001320#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1321static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1322{ \
1323 return he->stat_acc->_field; \
1324} \
1325 \
1326static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001327hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001328 struct perf_hpp *hpp, \
1329 struct hist_entry *he) \
1330{ \
1331 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001332 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001333 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001334 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001335 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001336 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001337 \
1338 return ret; \
1339 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001340 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1341 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001342}
1343
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001344__HPP_COLOR_PERCENT_FN(overhead, period)
1345__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1346__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1347__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1348__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001349__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001350
1351#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001352#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001353
1354void hist_browser__init_hpp(void)
1355{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001356 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1357 hist_browser__hpp_color_overhead;
1358 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1359 hist_browser__hpp_color_overhead_sys;
1360 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1361 hist_browser__hpp_color_overhead_us;
1362 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1363 hist_browser__hpp_color_overhead_guest_sys;
1364 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1365 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001366 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1367 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001368}
1369
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001370static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001371 struct hist_entry *entry,
1372 unsigned short row)
1373{
Jiri Olsa12400052012-10-13 00:06:16 +02001374 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001375 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001376 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001377 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001378 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001379 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001380 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001381
1382 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001383 browser->he_selection = entry;
1384 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001385 }
1386
1387 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001388 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001389 folded_sign = hist_entry__folded(entry);
1390 }
1391
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001392 if (symbol_conf.inline_name &&
1393 (!entry->has_children)) {
1394 hist_entry_init_inline_node(entry);
1395 folded_sign = hist_entry__folded(entry);
1396 }
1397
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001398 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001399 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001400 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001401 .folded_sign = folded_sign,
1402 .current_entry = current_entry,
1403 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001404 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001405
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001406 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001407
Jiri Olsaf0786af2016-01-18 10:24:23 +01001408 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001409 char s[2048];
1410 struct perf_hpp hpp = {
1411 .buf = s,
1412 .size = sizeof(s),
1413 .ptr = &arg,
1414 };
1415
Namhyung Kim361459f2015-12-23 02:07:08 +09001416 if (perf_hpp__should_skip(fmt, entry->hists) ||
1417 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001418 continue;
1419
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001420 if (current_entry && browser->b.navkeypressed) {
1421 ui_browser__set_color(&browser->b,
1422 HE_COLORSET_SELECTED);
1423 } else {
1424 ui_browser__set_color(&browser->b,
1425 HE_COLORSET_NORMAL);
1426 }
1427
1428 if (first) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001429 if (symbol_conf.use_callchain ||
1430 symbol_conf.inline_name) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001431 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001432 width -= 2;
1433 }
1434 first = false;
1435 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001436 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001437 width -= 2;
1438 }
1439
Jiri Olsa12400052012-10-13 00:06:16 +02001440 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001441 int ret = fmt->color(fmt, &hpp, entry);
1442 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1443 /*
1444 * fmt->color() already used ui_browser to
1445 * print the non alignment bits, skip it (+ret):
1446 */
1447 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001448 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001449 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001450 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001451 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001452 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001453 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001454
1455 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001456 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001457 width += 1;
1458
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001459 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001460
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001461 ++row;
1462 ++printed;
1463 } else
1464 --row_offset;
1465
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001466 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001467 struct callchain_print_arg arg = {
1468 .row_offset = row_offset,
1469 .is_current_entry = current_entry,
1470 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001471
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001472 if (entry->inline_node)
1473 printed += hist_browser__show_inline(browser,
1474 entry->inline_node, row, 0);
1475 else
1476 printed += hist_browser__show_callchain(browser,
1477 entry, 1, row,
1478 hist_browser__show_callchain_entry,
1479 &arg,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001480 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001481 }
1482
1483 return printed;
1484}
1485
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001486static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1487 struct hist_entry *entry,
1488 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001489 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001490{
1491 int printed = 0;
1492 int width = browser->b.width;
1493 char folded_sign = ' ';
1494 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1495 off_t row_offset = entry->row_offset;
1496 bool first = true;
1497 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001498 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001499 struct hpp_arg arg = {
1500 .b = &browser->b,
1501 .current_entry = current_entry,
1502 };
1503 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001504 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001505
1506 if (current_entry) {
1507 browser->he_selection = entry;
1508 browser->selection = &entry->ms;
1509 }
1510
1511 hist_entry__init_have_children(entry);
1512 folded_sign = hist_entry__folded(entry);
1513 arg.folded_sign = folded_sign;
1514
1515 if (entry->leaf && row_offset) {
1516 row_offset--;
1517 goto show_callchain;
1518 }
1519
1520 hist_browser__gotorc(browser, row, 0);
1521
1522 if (current_entry && browser->b.navkeypressed)
1523 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1524 else
1525 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1526
1527 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1528 width -= level * HIERARCHY_INDENT;
1529
Namhyung Kima61a22f2016-03-07 16:44:50 -03001530 /* the first hpp_list_node is for overhead columns */
1531 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1532 struct perf_hpp_list_node, list);
1533 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001534 char s[2048];
1535 struct perf_hpp hpp = {
1536 .buf = s,
1537 .size = sizeof(s),
1538 .ptr = &arg,
1539 };
1540
1541 if (perf_hpp__should_skip(fmt, entry->hists) ||
1542 column++ < browser->b.horiz_scroll)
1543 continue;
1544
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001545 if (current_entry && browser->b.navkeypressed) {
1546 ui_browser__set_color(&browser->b,
1547 HE_COLORSET_SELECTED);
1548 } else {
1549 ui_browser__set_color(&browser->b,
1550 HE_COLORSET_NORMAL);
1551 }
1552
1553 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001554 ui_browser__printf(&browser->b, "%c ", folded_sign);
1555 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001556 first = false;
1557 } else {
1558 ui_browser__printf(&browser->b, " ");
1559 width -= 2;
1560 }
1561
1562 if (fmt->color) {
1563 int ret = fmt->color(fmt, &hpp, entry);
1564 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1565 /*
1566 * fmt->color() already used ui_browser to
1567 * print the non alignment bits, skip it (+ret):
1568 */
1569 ui_browser__printf(&browser->b, "%s", s + ret);
1570 } else {
1571 int ret = fmt->entry(fmt, &hpp, entry);
1572 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1573 ui_browser__printf(&browser->b, "%s", s);
1574 }
1575 width -= hpp.buf - s;
1576 }
1577
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001578 if (!first) {
1579 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1580 width -= hierarchy_indent;
1581 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001582
1583 if (column >= browser->b.horiz_scroll) {
1584 char s[2048];
1585 struct perf_hpp hpp = {
1586 .buf = s,
1587 .size = sizeof(s),
1588 .ptr = &arg,
1589 };
1590
1591 if (current_entry && browser->b.navkeypressed) {
1592 ui_browser__set_color(&browser->b,
1593 HE_COLORSET_SELECTED);
1594 } else {
1595 ui_browser__set_color(&browser->b,
1596 HE_COLORSET_NORMAL);
1597 }
1598
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001599 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001600 if (first) {
1601 ui_browser__printf(&browser->b, "%c ", folded_sign);
1602 first = false;
1603 } else {
1604 ui_browser__write_nstring(&browser->b, "", 2);
1605 }
1606
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001607 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001608
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001609 /*
1610 * No need to call hist_entry__snprintf_alignment()
1611 * since this fmt is always the last column in the
1612 * hierarchy mode.
1613 */
1614 if (fmt->color) {
1615 width -= fmt->color(fmt, &hpp, entry);
1616 } else {
1617 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001618
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001619 width -= fmt->entry(fmt, &hpp, entry);
1620 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001621
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001622 while (isspace(s[i++]))
1623 width++;
1624 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001625 }
1626 }
1627
1628 /* The scroll bar isn't being used */
1629 if (!browser->b.navkeypressed)
1630 width += 1;
1631
1632 ui_browser__write_nstring(&browser->b, "", width);
1633
1634 ++row;
1635 ++printed;
1636
1637show_callchain:
1638 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1639 struct callchain_print_arg carg = {
1640 .row_offset = row_offset,
1641 };
1642
1643 printed += hist_browser__show_callchain(browser, entry,
1644 level + 1, row,
1645 hist_browser__show_callchain_entry, &carg,
1646 hist_browser__check_output_full);
1647 }
1648
1649 return printed;
1650}
1651
Namhyung Kim79dded82016-02-26 21:13:19 +09001652static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001653 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001654{
1655 int width = browser->b.width;
1656 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1657 bool first = true;
1658 int column = 0;
1659 int ret;
1660 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001661 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001662 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001663
1664 if (current_entry) {
1665 browser->he_selection = NULL;
1666 browser->selection = NULL;
1667 }
1668
1669 hist_browser__gotorc(browser, row, 0);
1670
1671 if (current_entry && browser->b.navkeypressed)
1672 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1673 else
1674 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1675
1676 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1677 width -= level * HIERARCHY_INDENT;
1678
Namhyung Kima61a22f2016-03-07 16:44:50 -03001679 /* the first hpp_list_node is for overhead columns */
1680 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1681 struct perf_hpp_list_node, list);
1682 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001683 if (perf_hpp__should_skip(fmt, browser->hists) ||
1684 column++ < browser->b.horiz_scroll)
1685 continue;
1686
Jiri Olsada1b0402016-06-14 20:19:20 +02001687 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001688
1689 if (first) {
1690 /* for folded sign */
1691 first = false;
1692 ret++;
1693 } else {
1694 /* space between columns */
1695 ret += 2;
1696 }
1697
1698 ui_browser__write_nstring(&browser->b, "", ret);
1699 width -= ret;
1700 }
1701
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001702 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1703 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001704
1705 if (column >= browser->b.horiz_scroll) {
1706 char buf[32];
1707
1708 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1709 ui_browser__printf(&browser->b, " %s", buf);
1710 width -= ret + 2;
1711 }
1712
1713 /* The scroll bar isn't being used */
1714 if (!browser->b.navkeypressed)
1715 width += 1;
1716
1717 ui_browser__write_nstring(&browser->b, "", width);
1718 return 1;
1719}
1720
Jiri Olsa81a888f2014-06-14 15:44:52 +02001721static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1722{
1723 advance_hpp(hpp, inc);
1724 return hpp->size <= 0;
1725}
1726
Jiri Olsa69705b32016-08-07 17:28:28 +02001727static int
1728hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1729 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001730{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001731 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001732 struct perf_hpp dummy_hpp = {
1733 .buf = buf,
1734 .size = size,
1735 };
1736 struct perf_hpp_fmt *fmt;
1737 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001738 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001739 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001740
1741 if (symbol_conf.use_callchain) {
1742 ret = scnprintf(buf, size, " ");
1743 if (advance_hpp_check(&dummy_hpp, ret))
1744 return ret;
1745 }
1746
Jiri Olsaf0786af2016-01-18 10:24:23 +01001747 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001748 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001749 continue;
1750
Jiri Olsa29659ab2016-08-07 17:28:30 +02001751 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001752 if (advance_hpp_check(&dummy_hpp, ret))
1753 break;
1754
Jiri Olsa29659ab2016-08-07 17:28:30 +02001755 if (span)
1756 continue;
1757
Jiri Olsa81a888f2014-06-14 15:44:52 +02001758 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1759 if (advance_hpp_check(&dummy_hpp, ret))
1760 break;
1761 }
1762
1763 return ret;
1764}
1765
Namhyung Kimd8b92402016-02-25 00:13:46 +09001766static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1767{
1768 struct hists *hists = browser->hists;
1769 struct perf_hpp dummy_hpp = {
1770 .buf = buf,
1771 .size = size,
1772 };
1773 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001774 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001775 size_t ret = 0;
1776 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001777 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001778 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001779
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001780 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001781 if (advance_hpp_check(&dummy_hpp, ret))
1782 return ret;
1783
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001784 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001785 /* the first hpp_list_node is for overhead columns */
1786 fmt_node = list_first_entry(&hists->hpp_formats,
1787 struct perf_hpp_list_node, list);
1788 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001789 if (column++ < browser->b.horiz_scroll)
1790 continue;
1791
Jiri Olsa29659ab2016-08-07 17:28:30 +02001792 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001793 if (advance_hpp_check(&dummy_hpp, ret))
1794 break;
1795
1796 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1797 if (advance_hpp_check(&dummy_hpp, ret))
1798 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001799
1800 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001801 }
1802
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001803 if (!first_node) {
1804 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1805 indent * HIERARCHY_INDENT, "");
1806 if (advance_hpp_check(&dummy_hpp, ret))
1807 return ret;
1808 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001809
Namhyung Kima61a22f2016-03-07 16:44:50 -03001810 first_node = true;
1811 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1812 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001813 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1814 if (advance_hpp_check(&dummy_hpp, ret))
1815 break;
1816 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001817 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001818
Namhyung Kima61a22f2016-03-07 16:44:50 -03001819 first_col = true;
1820 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1821 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001822
Namhyung Kima61a22f2016-03-07 16:44:50 -03001823 if (perf_hpp__should_skip(fmt, hists))
1824 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001825
Namhyung Kima61a22f2016-03-07 16:44:50 -03001826 if (!first_col) {
1827 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1828 if (advance_hpp_check(&dummy_hpp, ret))
1829 break;
1830 }
1831 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001832
Jiri Olsa29659ab2016-08-07 17:28:30 +02001833 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001834 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001835
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001836 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001837 ret = strlen(start);
1838
1839 if (start != dummy_hpp.buf)
1840 memmove(dummy_hpp.buf, start, ret + 1);
1841
1842 if (advance_hpp_check(&dummy_hpp, ret))
1843 break;
1844 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001845 }
1846
1847 return ret;
1848}
1849
Jiri Olsa01b47702016-06-14 20:19:13 +02001850static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001851{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001852 char headers[1024];
1853
Jiri Olsa01b47702016-06-14 20:19:13 +02001854 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1855 sizeof(headers));
1856
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001857 ui_browser__gotorc(&browser->b, 0, 0);
1858 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001859 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001860}
1861
Jiri Olsa01b47702016-06-14 20:19:13 +02001862static void hists_browser__headers(struct hist_browser *browser)
1863{
Jiri Olsa69705b32016-08-07 17:28:28 +02001864 struct hists *hists = browser->hists;
1865 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001866
Jiri Olsa69705b32016-08-07 17:28:28 +02001867 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001868
Jiri Olsa69705b32016-08-07 17:28:28 +02001869 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1870 char headers[1024];
1871
1872 hists_browser__scnprintf_headers(browser, headers,
1873 sizeof(headers), line);
1874
1875 ui_browser__gotorc(&browser->b, line, 0);
1876 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1877 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1878 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001879}
1880
1881static void hist_browser__show_headers(struct hist_browser *browser)
1882{
1883 if (symbol_conf.report_hierarchy)
1884 hists_browser__hierarchy_headers(browser);
1885 else
1886 hists_browser__headers(browser);
1887}
1888
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001889static void ui_browser__hists_init_top(struct ui_browser *browser)
1890{
1891 if (browser->top == NULL) {
1892 struct hist_browser *hb;
1893
1894 hb = container_of(browser, struct hist_browser, b);
1895 browser->top = rb_first(&hb->hists->entries);
1896 }
1897}
1898
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001899static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001900{
1901 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001902 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001903 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001904 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001905 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001906
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001907 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001908 struct perf_hpp_list *hpp_list = hists->hpp_list;
1909
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001910 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001911 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001912 }
1913
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001914 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001915 hb->he_selection = NULL;
1916 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001917
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001918 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001919 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001920 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001921
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001922 if (h->filtered) {
1923 /* let it move to sibling */
1924 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001925 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001926 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001927
Namhyung Kim14135662013-10-31 10:17:39 +09001928 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001929 if (percent < hb->min_pcnt)
1930 continue;
1931
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001932 if (symbol_conf.report_hierarchy) {
1933 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001934 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001935 if (row == browser->rows)
1936 break;
1937
1938 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001939 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001940 row++;
1941 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001942 } else {
1943 row += hist_browser__show_entry(hb, h, row);
1944 }
1945
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001946 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001947 break;
1948 }
1949
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001950 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001951}
1952
Namhyung Kim064f1982013-05-14 11:09:04 +09001953static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001954 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001955{
1956 while (nd != NULL) {
1957 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001958 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001959
Namhyung Kimc0f15272014-04-16 11:16:33 +09001960 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001961 return nd;
1962
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001963 /*
1964 * If it's filtered, its all children also were filtered.
1965 * So move to sibling node.
1966 */
1967 if (rb_next(nd))
1968 nd = rb_next(nd);
1969 else
1970 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001971 }
1972
1973 return NULL;
1974}
1975
Namhyung Kim064f1982013-05-14 11:09:04 +09001976static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001977 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001978{
1979 while (nd != NULL) {
1980 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001981 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001982
1983 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001984 return nd;
1985
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001986 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001987 }
1988
1989 return NULL;
1990}
1991
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001992static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001993 off_t offset, int whence)
1994{
1995 struct hist_entry *h;
1996 struct rb_node *nd;
1997 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001998 struct hist_browser *hb;
1999
2000 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002001
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002002 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002003 return;
2004
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002005 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03002006
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002007 switch (whence) {
2008 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09002009 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09002010 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002011 break;
2012 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002013 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002014 goto do_offset;
2015 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002016 nd = rb_hierarchy_last(rb_last(browser->entries));
2017 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002018 first = false;
2019 break;
2020 default:
2021 return;
2022 }
2023
2024 /*
2025 * Moves not relative to the first visible entry invalidates its
2026 * row_offset:
2027 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002028 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002029 h->row_offset = 0;
2030
2031 /*
2032 * Here we have to check if nd is expanded (+), if it is we can't go
2033 * the next top level hist_entry, instead we must compute an offset of
2034 * what _not_ to show and not change the first visible entry.
2035 *
2036 * This offset increments when we are going from top to bottom and
2037 * decreases when we're going from bottom to top.
2038 *
2039 * As we don't have backpointers to the top level in the callchains
2040 * structure, we need to always print the whole hist_entry callchain,
2041 * skipping the first ones that are before the first visible entry
2042 * and stop when we printed enough lines to fill the screen.
2043 */
2044do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00002045 if (!nd)
2046 return;
2047
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002048 if (offset > 0) {
2049 do {
2050 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002051 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002052 u16 remaining = h->nr_rows - h->row_offset;
2053 if (offset > remaining) {
2054 offset -= remaining;
2055 h->row_offset = 0;
2056 } else {
2057 h->row_offset += offset;
2058 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002059 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002060 break;
2061 }
2062 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002063 nd = hists__filter_entries(rb_hierarchy_next(nd),
2064 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002065 if (nd == NULL)
2066 break;
2067 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002068 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002069 } while (offset != 0);
2070 } else if (offset < 0) {
2071 while (1) {
2072 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002073 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002074 if (first) {
2075 if (-offset > h->row_offset) {
2076 offset += h->row_offset;
2077 h->row_offset = 0;
2078 } else {
2079 h->row_offset += offset;
2080 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002081 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002082 break;
2083 }
2084 } else {
2085 if (-offset > h->nr_rows) {
2086 offset += h->nr_rows;
2087 h->row_offset = 0;
2088 } else {
2089 h->row_offset = h->nr_rows + offset;
2090 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002091 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002092 break;
2093 }
2094 }
2095 }
2096
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002097 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09002098 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002099 if (nd == NULL)
2100 break;
2101 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002102 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002103 if (offset == 0) {
2104 /*
2105 * Last unfiltered hist_entry, check if it is
2106 * unfolded, if it is then we should have
2107 * row_offset at its last entry.
2108 */
2109 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002110 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002111 h->row_offset = h->nr_rows;
2112 break;
2113 }
2114 first = false;
2115 }
2116 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002117 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002118 h = rb_entry(nd, struct hist_entry, rb_node);
2119 h->row_offset = 0;
2120 }
2121}
2122
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002123static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002124 struct hist_entry *he, FILE *fp,
2125 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002126{
Namhyung Kim39ee5332014-08-22 09:13:21 +09002127 struct callchain_print_arg arg = {
2128 .fp = fp,
2129 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002130
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002131 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09002132 hist_browser__fprintf_callchain_entry, &arg,
2133 hist_browser__check_dump_full);
2134 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002135}
2136
2137static int hist_browser__fprintf_entry(struct hist_browser *browser,
2138 struct hist_entry *he, FILE *fp)
2139{
2140 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002141 int printed = 0;
2142 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09002143 struct perf_hpp hpp = {
2144 .buf = s,
2145 .size = sizeof(s),
2146 };
2147 struct perf_hpp_fmt *fmt;
2148 bool first = true;
2149 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002150
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002151 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002152 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002153 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002154 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002155
Jiri Olsaf0786af2016-01-18 10:24:23 +01002156 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002157 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002158 continue;
2159
Namhyung Kim26d8b332014-03-03 16:16:20 +09002160 if (!first) {
2161 ret = scnprintf(hpp.buf, hpp.size, " ");
2162 advance_hpp(&hpp, ret);
2163 } else
2164 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002165
Namhyung Kim26d8b332014-03-03 16:16:20 +09002166 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002167 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002168 advance_hpp(&hpp, ret);
2169 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002170 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002171
2172 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002173 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2174
2175 return printed;
2176}
2177
2178
2179static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2180 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002181 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002182{
2183 char s[8192];
2184 int printed = 0;
2185 char folded_sign = ' ';
2186 struct perf_hpp hpp = {
2187 .buf = s,
2188 .size = sizeof(s),
2189 };
2190 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002191 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002192 bool first = true;
2193 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002194 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002195
2196 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2197
2198 folded_sign = hist_entry__folded(he);
2199 printed += fprintf(fp, "%c", folded_sign);
2200
Namhyung Kim325a6282016-03-09 22:47:00 +09002201 /* the first hpp_list_node is for overhead columns */
2202 fmt_node = list_first_entry(&he->hists->hpp_formats,
2203 struct perf_hpp_list_node, list);
2204 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002205 if (!first) {
2206 ret = scnprintf(hpp.buf, hpp.size, " ");
2207 advance_hpp(&hpp, ret);
2208 } else
2209 first = false;
2210
2211 ret = fmt->entry(fmt, &hpp, he);
2212 advance_hpp(&hpp, ret);
2213 }
2214
2215 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2216 advance_hpp(&hpp, ret);
2217
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002218 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2219 ret = scnprintf(hpp.buf, hpp.size, " ");
2220 advance_hpp(&hpp, ret);
2221
2222 ret = fmt->entry(fmt, &hpp, he);
2223 advance_hpp(&hpp, ret);
2224 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002225
2226 printed += fprintf(fp, "%s\n", rtrim(s));
2227
2228 if (he->leaf && folded_sign == '-') {
2229 printed += hist_browser__fprintf_callchain(browser, he, fp,
2230 he->depth + 1);
2231 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002232
2233 return printed;
2234}
2235
2236static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2237{
Namhyung Kim064f1982013-05-14 11:09:04 +09002238 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002239 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002240 int printed = 0;
2241
2242 while (nd) {
2243 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2244
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002245 if (symbol_conf.report_hierarchy) {
2246 printed += hist_browser__fprintf_hierarchy_entry(browser,
2247 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002248 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002249 } else {
2250 printed += hist_browser__fprintf_entry(browser, h, fp);
2251 }
2252
2253 nd = hists__filter_entries(rb_hierarchy_next(nd),
2254 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002255 }
2256
2257 return printed;
2258}
2259
2260static int hist_browser__dump(struct hist_browser *browser)
2261{
2262 char filename[64];
2263 FILE *fp;
2264
2265 while (1) {
2266 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2267 if (access(filename, F_OK))
2268 break;
2269 /*
2270 * XXX: Just an arbitrary lazy upper limit
2271 */
2272 if (++browser->print_seq == 8192) {
2273 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2274 return -1;
2275 }
2276 }
2277
2278 fp = fopen(filename, "w");
2279 if (fp == NULL) {
2280 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002281 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002282 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002283 return -1;
2284 }
2285
2286 ++browser->print_seq;
2287 hist_browser__fprintf(browser, fp);
2288 fclose(fp);
2289 ui_helpline__fpush("%s written!", filename);
2290
2291 return 0;
2292}
2293
Jiri Olsafcd86422016-06-20 23:58:18 +02002294void hist_browser__init(struct hist_browser *browser,
2295 struct hists *hists)
2296{
2297 struct perf_hpp_fmt *fmt;
2298
2299 browser->hists = hists;
2300 browser->b.refresh = hist_browser__refresh;
2301 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2302 browser->b.seek = ui_browser__hists_seek;
2303 browser->b.use_navkeypressed = true;
2304 browser->show_headers = symbol_conf.show_hist_headers;
2305
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002306 if (symbol_conf.report_hierarchy) {
2307 struct perf_hpp_list_node *fmt_node;
2308
2309 /* count overhead columns (in the first node) */
2310 fmt_node = list_first_entry(&hists->hpp_formats,
2311 struct perf_hpp_list_node, list);
2312 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2313 ++browser->b.columns;
2314
2315 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002316 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002317 } else {
2318 hists__for_each_format(hists, fmt)
2319 ++browser->b.columns;
2320 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002321
2322 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002323}
2324
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002325struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002326{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002327 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002328
Jiri Olsafcd86422016-06-20 23:58:18 +02002329 if (browser)
2330 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002331
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002332 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002333}
2334
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002335static struct hist_browser *
2336perf_evsel_browser__new(struct perf_evsel *evsel,
2337 struct hist_browser_timer *hbt,
2338 struct perf_env *env)
2339{
2340 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2341
2342 if (browser) {
2343 browser->hbt = hbt;
2344 browser->env = env;
2345 browser->title = perf_evsel_browser_title;
2346 }
2347 return browser;
2348}
2349
Jiri Olsadabd2012016-06-20 23:58:14 +02002350void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002351{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002352 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002353}
2354
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002355static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002356{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002357 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002358}
2359
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002360static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002361{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002362 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002363}
2364
Taeung Song1e378eb2014-10-07 16:13:15 +09002365/* Check whether the browser is for 'top' or 'report' */
2366static inline bool is_report_browser(void *timer)
2367{
2368 return timer == NULL;
2369}
2370
Jiri Olsa5b91a862016-06-20 23:58:15 +02002371static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002372 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002373{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002374 struct hist_browser_timer *hbt = browser->hbt;
2375 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002376 char unit;
2377 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002378 const struct dso *dso = hists->dso_filter;
2379 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002380 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002381 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2382 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002383 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002384 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002385 char buf[512];
2386 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002387 char ref[30] = " show reference callgraph, ";
2388 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002389
Namhyung Kimf2148332014-01-14 11:52:48 +09002390 if (symbol_conf.filter_relative) {
2391 nr_samples = hists->stats.nr_non_filtered_samples;
2392 nr_events = hists->stats.total_non_filtered_period;
2393 }
2394
Namhyung Kim759ff492013-03-05 14:53:26 +09002395 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002396 struct perf_evsel *pos;
2397
2398 perf_evsel__group_desc(evsel, buf, buflen);
2399 ev_name = buf;
2400
2401 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002402 struct hists *pos_hists = evsel__hists(pos);
2403
Namhyung Kimf2148332014-01-14 11:52:48 +09002404 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002405 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2406 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002407 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002408 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2409 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002410 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002411 }
2412 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002413
Kan Liang9e207dd2015-08-11 06:30:49 -04002414 if (symbol_conf.show_ref_callgraph &&
2415 strstr(ev_name, "call-graph=no"))
2416 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002417 nr_samples = convert_unit(nr_samples, &unit);
2418 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002419 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2420 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002421
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002422
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002423 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002424 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002425 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002426 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002427 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002428 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002429 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002430 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002431 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002432 } else {
2433 printed += scnprintf(bf + printed, size - printed,
2434 ", Thread: %s",
2435 (thread->comm_set ? thread__comm_str(thread) : ""));
2436 }
2437 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002438 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002439 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002440 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002441 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002442 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002443 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002444 if (!is_report_browser(hbt)) {
2445 struct perf_top *top = hbt->arg;
2446
2447 if (top->zero)
2448 printed += scnprintf(bf + printed, size - printed, " [z]");
2449 }
2450
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002451 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002452}
2453
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002454static inline void free_popup_options(char **options, int n)
2455{
2456 int i;
2457
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002458 for (i = 0; i < n; ++i)
2459 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002460}
2461
Feng Tang341487ab2013-02-03 14:38:20 +08002462/*
2463 * Only runtime switching of perf data file will make "input_name" point
2464 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2465 * whether we need to call free() for current "input_name" during the switch.
2466 */
2467static bool is_input_name_malloced = false;
2468
2469static int switch_data_file(void)
2470{
2471 char *pwd, *options[32], *abs_path[32], *tmp;
2472 DIR *pwd_dir;
2473 int nr_options = 0, choice = -1, ret = -1;
2474 struct dirent *dent;
2475
2476 pwd = getenv("PWD");
2477 if (!pwd)
2478 return ret;
2479
2480 pwd_dir = opendir(pwd);
2481 if (!pwd_dir)
2482 return ret;
2483
2484 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002485 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002486
2487 while ((dent = readdir(pwd_dir))) {
2488 char path[PATH_MAX];
2489 u64 magic;
2490 char *name = dent->d_name;
2491 FILE *file;
2492
2493 if (!(dent->d_type == DT_REG))
2494 continue;
2495
2496 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2497
2498 file = fopen(path, "r");
2499 if (!file)
2500 continue;
2501
2502 if (fread(&magic, 1, 8, file) < 8)
2503 goto close_file_and_continue;
2504
2505 if (is_perf_magic(magic)) {
2506 options[nr_options] = strdup(name);
2507 if (!options[nr_options])
2508 goto close_file_and_continue;
2509
2510 abs_path[nr_options] = strdup(path);
2511 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002512 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002513 ui__warning("Can't search all data files due to memory shortage.\n");
2514 fclose(file);
2515 break;
2516 }
2517
2518 nr_options++;
2519 }
2520
2521close_file_and_continue:
2522 fclose(file);
2523 if (nr_options >= 32) {
2524 ui__warning("Too many perf data files in PWD!\n"
2525 "Only the first 32 files will be listed.\n");
2526 break;
2527 }
2528 }
2529 closedir(pwd_dir);
2530
2531 if (nr_options) {
2532 choice = ui__popup_menu(nr_options, options);
2533 if (choice < nr_options && choice >= 0) {
2534 tmp = strdup(abs_path[choice]);
2535 if (tmp) {
2536 if (is_input_name_malloced)
2537 free((void *)input_name);
2538 input_name = tmp;
2539 is_input_name_malloced = true;
2540 ret = 0;
2541 } else
2542 ui__warning("Data switch failed due to memory shortage!\n");
2543 }
2544 }
2545
2546 free_popup_options(options, nr_options);
2547 free_popup_options(abs_path, nr_options);
2548 return ret;
2549}
2550
Namhyung Kimea7cd592015-04-22 16:18:19 +09002551struct popup_action {
2552 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002553 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002554 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002555
2556 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2557};
2558
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002559static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002560do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002561{
2562 struct perf_evsel *evsel;
2563 struct annotation *notes;
2564 struct hist_entry *he;
2565 int err;
2566
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002567 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002568 return 0;
2569
Namhyung Kimea7cd592015-04-22 16:18:19 +09002570 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002571 if (!notes->src)
2572 return 0;
2573
2574 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002575 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002576 he = hist_browser__selected_entry(browser);
2577 /*
2578 * offer option to annotate the other branch source or target
2579 * (if they exists) when returning from annotate
2580 */
2581 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2582 return 1;
2583
2584 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2585 if (err)
2586 ui_browser__handle_resize(&browser->b);
2587 return 0;
2588}
2589
2590static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002591add_annotate_opt(struct hist_browser *browser __maybe_unused,
2592 struct popup_action *act, char **optstr,
2593 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002594{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002595 if (sym == NULL || map->dso->annotate_warned)
2596 return 0;
2597
2598 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2599 return 0;
2600
2601 act->ms.map = map;
2602 act->ms.sym = sym;
2603 act->fn = do_annotate;
2604 return 1;
2605}
2606
2607static int
2608do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2609{
2610 struct thread *thread = act->thread;
2611
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002612 if ((!hists__has(browser->hists, thread) &&
2613 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002614 return 0;
2615
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002616 if (browser->hists->thread_filter) {
2617 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2618 perf_hpp__set_elide(HISTC_THREAD, false);
2619 thread__zput(browser->hists->thread_filter);
2620 ui_helpline__pop();
2621 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002622 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002623 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2624 thread->comm_set ? thread__comm_str(thread) : "",
2625 thread->tid);
2626 } else {
2627 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2628 thread->comm_set ? thread__comm_str(thread) : "");
2629 }
2630
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002631 browser->hists->thread_filter = thread__get(thread);
2632 perf_hpp__set_elide(HISTC_THREAD, false);
2633 pstack__push(browser->pstack, &browser->hists->thread_filter);
2634 }
2635
2636 hists__filter_by_thread(browser->hists);
2637 hist_browser__reset(browser);
2638 return 0;
2639}
2640
2641static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002642add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2643 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002644{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002645 int ret;
2646
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002647 if ((!hists__has(browser->hists, thread) &&
2648 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002649 return 0;
2650
Jiri Olsafa829112016-05-03 13:54:47 +02002651 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002652 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2653 browser->hists->thread_filter ? "out of" : "into",
2654 thread->comm_set ? thread__comm_str(thread) : "",
2655 thread->tid);
2656 } else {
2657 ret = asprintf(optstr, "Zoom %s %s thread",
2658 browser->hists->thread_filter ? "out of" : "into",
2659 thread->comm_set ? thread__comm_str(thread) : "");
2660 }
2661 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002662 return 0;
2663
2664 act->thread = thread;
2665 act->fn = do_zoom_thread;
2666 return 1;
2667}
2668
2669static int
2670do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2671{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002672 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002673
Jiri Olsa69849fc2016-05-03 13:54:45 +02002674 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002675 return 0;
2676
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002677 if (browser->hists->dso_filter) {
2678 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2679 perf_hpp__set_elide(HISTC_DSO, false);
2680 browser->hists->dso_filter = NULL;
2681 ui_helpline__pop();
2682 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002683 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002684 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2685 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002686 perf_hpp__set_elide(HISTC_DSO, true);
2687 pstack__push(browser->pstack, &browser->hists->dso_filter);
2688 }
2689
2690 hists__filter_by_dso(browser->hists);
2691 hist_browser__reset(browser);
2692 return 0;
2693}
2694
2695static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002696add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002697 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002698{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002699 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002700 return 0;
2701
2702 if (asprintf(optstr, "Zoom %s %s DSO",
2703 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002704 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002705 return 0;
2706
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002707 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002708 act->fn = do_zoom_dso;
2709 return 1;
2710}
2711
2712static int
2713do_browse_map(struct hist_browser *browser __maybe_unused,
2714 struct popup_action *act)
2715{
2716 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002717 return 0;
2718}
2719
2720static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002721add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002722 struct popup_action *act, char **optstr, struct map *map)
2723{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002724 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002725 return 0;
2726
2727 if (asprintf(optstr, "Browse map details") < 0)
2728 return 0;
2729
2730 act->ms.map = map;
2731 act->fn = do_browse_map;
2732 return 1;
2733}
2734
2735static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002736do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002737 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002738{
2739 char script_opt[64];
2740 memset(script_opt, 0, sizeof(script_opt));
2741
Namhyung Kimea7cd592015-04-22 16:18:19 +09002742 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002743 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002744 thread__comm_str(act->thread));
2745 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002746 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002747 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002748 }
2749
2750 script_browse(script_opt);
2751 return 0;
2752}
2753
2754static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002755add_script_opt(struct hist_browser *browser __maybe_unused,
2756 struct popup_action *act, char **optstr,
2757 struct thread *thread, struct symbol *sym)
2758{
2759 if (thread) {
2760 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2761 thread__comm_str(thread)) < 0)
2762 return 0;
2763 } else if (sym) {
2764 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2765 sym->name) < 0)
2766 return 0;
2767 } else {
2768 if (asprintf(optstr, "Run scripts for all samples") < 0)
2769 return 0;
2770 }
2771
2772 act->thread = thread;
2773 act->ms.sym = sym;
2774 act->fn = do_run_script;
2775 return 1;
2776}
2777
2778static int
2779do_switch_data(struct hist_browser *browser __maybe_unused,
2780 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002781{
2782 if (switch_data_file()) {
2783 ui__warning("Won't switch the data files due to\n"
2784 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002785 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002786 }
2787
2788 return K_SWITCH_INPUT_DATA;
2789}
2790
Namhyung Kimea7cd592015-04-22 16:18:19 +09002791static int
2792add_switch_opt(struct hist_browser *browser,
2793 struct popup_action *act, char **optstr)
2794{
2795 if (!is_report_browser(browser->hbt))
2796 return 0;
2797
2798 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2799 return 0;
2800
2801 act->fn = do_switch_data;
2802 return 1;
2803}
2804
2805static int
2806do_exit_browser(struct hist_browser *browser __maybe_unused,
2807 struct popup_action *act __maybe_unused)
2808{
2809 return 0;
2810}
2811
2812static int
2813add_exit_opt(struct hist_browser *browser __maybe_unused,
2814 struct popup_action *act, char **optstr)
2815{
2816 if (asprintf(optstr, "Exit") < 0)
2817 return 0;
2818
2819 act->fn = do_exit_browser;
2820 return 1;
2821}
2822
Kan Liang84734b02015-09-04 10:45:45 -04002823static int
2824do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2825{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002826 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002827 return 0;
2828
Kan Liang84734b02015-09-04 10:45:45 -04002829 if (browser->hists->socket_filter > -1) {
2830 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2831 browser->hists->socket_filter = -1;
2832 perf_hpp__set_elide(HISTC_SOCKET, false);
2833 } else {
2834 browser->hists->socket_filter = act->socket;
2835 perf_hpp__set_elide(HISTC_SOCKET, true);
2836 pstack__push(browser->pstack, &browser->hists->socket_filter);
2837 }
2838
2839 hists__filter_by_socket(browser->hists);
2840 hist_browser__reset(browser);
2841 return 0;
2842}
2843
2844static int
2845add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2846 char **optstr, int socket_id)
2847{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002848 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002849 return 0;
2850
2851 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2852 (browser->hists->socket_filter > -1) ? "out of" : "into",
2853 socket_id) < 0)
2854 return 0;
2855
2856 act->socket = socket_id;
2857 act->fn = do_zoom_socket;
2858 return 1;
2859}
2860
Namhyung Kim112f7612014-04-22 14:05:35 +09002861static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002862{
2863 u64 nr_entries = 0;
2864 struct rb_node *nd = rb_first(&hb->hists->entries);
2865
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002866 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002867 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2868 return;
2869 }
2870
Namhyung Kim14135662013-10-31 10:17:39 +09002871 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002872 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002873 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002874 }
2875
Namhyung Kim112f7612014-04-22 14:05:35 +09002876 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002877 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002878}
Feng Tang341487ab2013-02-03 14:38:20 +08002879
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002880static void hist_browser__update_percent_limit(struct hist_browser *hb,
2881 double percent)
2882{
2883 struct hist_entry *he;
2884 struct rb_node *nd = rb_first(&hb->hists->entries);
2885 u64 total = hists__total_period(hb->hists);
2886 u64 min_callchain_hits = total * (percent / 100);
2887
2888 hb->min_pcnt = callchain_param.min_percent = percent;
2889
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002890 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2891 he = rb_entry(nd, struct hist_entry, rb_node);
2892
Namhyung Kim79dded82016-02-26 21:13:19 +09002893 if (he->has_no_entry) {
2894 he->has_no_entry = false;
2895 he->nr_rows = 0;
2896 }
2897
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002898 if (!he->leaf || !symbol_conf.use_callchain)
2899 goto next;
2900
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002901 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2902 total = he->stat.period;
2903
2904 if (symbol_conf.cumulate_callchain)
2905 total = he->stat_acc->period;
2906
2907 min_callchain_hits = total * (percent / 100);
2908 }
2909
2910 callchain_param.sort(&he->sorted_chain, he->callchain,
2911 min_callchain_hits, &callchain_param);
2912
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002913next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002914 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002915
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002916 /* force to re-evaluate folding state of callchains */
2917 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002918 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002919 }
2920}
2921
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002922static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002923 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002924 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002925 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002926 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002927 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002928{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002929 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002930 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002931 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002932#define MAX_OPTIONS 16
2933 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002934 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002935 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002936 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002937 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002938 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002939
Namhyung Kime8e684a2013-12-26 14:37:58 +09002940#define HIST_BROWSER_HELP_COMMON \
2941 "h/?/F1 Show this window\n" \
2942 "UP/DOWN/PGUP\n" \
2943 "PGDN/SPACE Navigate\n" \
2944 "q/ESC/CTRL+C Exit browser\n\n" \
2945 "For multiple event sessions:\n\n" \
2946 "TAB/UNTAB Switch events\n\n" \
2947 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002948 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2949 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002950 "a Annotate current symbol\n" \
2951 "C Collapse all callchains\n" \
2952 "d Zoom into current DSO\n" \
2953 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002954 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002955 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002956 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002957 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002958 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002959
2960 /* help messages are sorted by lexical order of the hotkey */
2961 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002962 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002963 "P Print histograms to perf.hist.N\n"
2964 "r Run available scripts\n"
2965 "s Switch to another data file in PWD\n"
2966 "t Zoom into current Thread\n"
2967 "V Verbose (DSO names in callchains, etc)\n"
2968 "/ Filter symbol by name";
2969 const char top_help[] = HIST_BROWSER_HELP_COMMON
2970 "P Print histograms to perf.hist.N\n"
2971 "t Zoom into current Thread\n"
2972 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002973 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002974 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002975 "/ Filter symbol by name";
2976
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002977 if (browser == NULL)
2978 return -1;
2979
Namhyung Kimed426912015-05-29 21:53:44 +09002980 /* reset abort key so that it can get Ctrl-C as a key */
2981 SLang_reset_tty();
2982 SLang_init_tty(0, 0, 0);
2983
Namhyung Kim03905042015-11-28 02:32:39 +09002984 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002985 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002986 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002987
Kan Liang84734b02015-09-04 10:45:45 -04002988 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002989 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002990 goto out;
2991
2992 ui_helpline__push(helpline);
2993
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002994 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002995 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002996
Namhyung Kim5b591662014-07-31 14:47:38 +09002997 if (symbol_conf.col_width_list_str)
2998 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2999
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003000 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03003001 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003002 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003003 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04003004 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003005
Stephane Eranian24bff2d2012-03-12 16:13:30 +01003006 nr_options = 0;
3007
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03003008 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003009
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003010 if (browser->he_selection != NULL) {
3011 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003012 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04003013 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003014 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003015 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003016 case K_TAB:
3017 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06003018 if (nr_events == 1)
3019 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003020 /*
3021 * Exit the browser, let hists__browser_tree
3022 * go to the next or previous
3023 */
3024 goto out_free_stack;
3025 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003026 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003027 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003028 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003029 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003030 continue;
3031 }
3032
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003033 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08003034 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003035 browser->selection->map->dso->annotate_warned)
3036 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003037
Namhyung Kimea7cd592015-04-22 16:18:19 +09003038 actions->ms.map = browser->selection->map;
3039 actions->ms.sym = browser->selection->sym;
3040 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003041 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03003042 case 'P':
3043 hist_browser__dump(browser);
3044 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003045 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03003046 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003047 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003048 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003049 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02003050 verbose = (verbose + 1) % 4;
3051 browser->show_dso = verbose > 0;
3052 ui_helpline__fpush("Verbosity level set to %d\n",
3053 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003054 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003055 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003056 actions->thread = thread;
3057 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003058 continue;
Kan Liang84734b02015-09-04 10:45:45 -04003059 case 'S':
3060 actions->socket = socked_id;
3061 do_zoom_socket(browser, actions);
3062 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03003063 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09003064 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03003065 "Please enter the name of symbol you want to see.\n"
3066 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09003067 buf, "ENTER: OK, ESC: Cancel",
3068 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03003069 hists->symbol_filter_str = *buf ? buf : NULL;
3070 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09003071 hist_browser__reset(browser);
3072 }
3073 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08003074 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003075 if (is_report_browser(hbt)) {
3076 actions->thread = NULL;
3077 actions->ms.sym = NULL;
3078 do_run_script(browser, actions);
3079 }
Feng Tangc77d8d72012-11-01 00:00:55 +08003080 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08003081 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003082 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003083 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003084 if (key == K_SWITCH_INPUT_DATA)
3085 goto out_free_stack;
3086 }
Feng Tang341487ab2013-02-03 14:38:20 +08003087 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09003088 case 'i':
3089 /* env->arch is NULL for live-mode (i.e. perf top) */
3090 if (env->arch)
3091 tui__header_window(env);
3092 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09003093 case 'F':
3094 symbol_conf.filter_relative ^= 1;
3095 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09003096 case 'z':
3097 if (!is_report_browser(hbt)) {
3098 struct perf_top *top = hbt->arg;
3099
3100 top->zero = !top->zero;
3101 }
3102 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003103 case 'L':
3104 if (ui_browser__input_window("Percent Limit",
3105 "Please enter the value you want to hide entries under that percent.",
3106 buf, "ENTER: OK, ESC: Cancel",
3107 delay_secs * 2) == K_ENTER) {
3108 char *end;
3109 double new_percent = strtod(buf, &end);
3110
3111 if (new_percent < 0 || new_percent > 100) {
3112 ui_browser__warning(&browser->b, delay_secs * 2,
3113 "Invalid percent: %.2f", new_percent);
3114 continue;
3115 }
3116
3117 hist_browser__update_percent_limit(browser, new_percent);
3118 hist_browser__reset(browser);
3119 }
3120 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003121 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003122 case 'h':
3123 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003124 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003125 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003126 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003127 case K_ENTER:
3128 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003129 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003130 /* menu */
3131 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003132 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003133 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003134 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003135
Namhyung Kim01f00a12015-04-22 16:18:16 +09003136 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003137 /*
3138 * Go back to the perf_evsel_menu__run or other user
3139 */
3140 if (left_exits)
3141 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003142
3143 if (key == K_ESC &&
3144 ui_browser__dialog_yesno(&browser->b,
3145 "Do you really want to exit?"))
3146 goto out_free_stack;
3147
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003148 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003149 }
Namhyung Kim64221842015-04-24 10:15:33 +09003150 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003151 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003152 /*
3153 * No need to set actions->dso here since
3154 * it's just to remove the current filter.
3155 * Ditto for thread below.
3156 */
3157 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003158 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003159 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003160 } else if (top == &browser->hists->socket_filter) {
3161 do_zoom_socket(browser, actions);
3162 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003163 continue;
3164 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003165 case 'q':
3166 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003167 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003168 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003169 if (!is_report_browser(hbt)) {
3170 struct perf_top *top = hbt->arg;
3171
3172 perf_evlist__toggle_enable(top->evlist);
3173 /*
3174 * No need to refresh, resort/decay histogram
3175 * entries if we are not collecting samples:
3176 */
3177 if (top->evlist->enabled) {
3178 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3179 hbt->refresh = delay_secs;
3180 } else {
3181 helpline = "Press 'f' again to re-enable the events";
3182 hbt->refresh = 0;
3183 }
3184 continue;
3185 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003186 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003187 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003188 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003189 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003190 }
3191
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003192 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003193 goto skip_annotation;
3194
Namhyung Kim55369fc2013-04-01 20:35:20 +09003195 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003196 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003197
3198 if (bi == NULL)
3199 goto skip_annotation;
3200
Namhyung Kimea7cd592015-04-22 16:18:19 +09003201 nr_options += add_annotate_opt(browser,
3202 &actions[nr_options],
3203 &options[nr_options],
3204 bi->from.map,
3205 bi->from.sym);
3206 if (bi->to.sym != bi->from.sym)
3207 nr_options += add_annotate_opt(browser,
3208 &actions[nr_options],
3209 &options[nr_options],
3210 bi->to.map,
3211 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003212 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003213 nr_options += add_annotate_opt(browser,
3214 &actions[nr_options],
3215 &options[nr_options],
3216 browser->selection->map,
3217 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003218 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003219skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003220 nr_options += add_thread_opt(browser, &actions[nr_options],
3221 &options[nr_options], thread);
3222 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003223 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003224 nr_options += add_map_opt(browser, &actions[nr_options],
3225 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003226 browser->selection ?
3227 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003228 nr_options += add_socket_opt(browser, &actions[nr_options],
3229 &options[nr_options],
3230 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003231 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003232 if (!is_report_browser(hbt))
3233 goto skip_scripting;
3234
Feng Tangcdbab7c2012-10-30 11:56:06 +08003235 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003236 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003237 nr_options += add_script_opt(browser,
3238 &actions[nr_options],
3239 &options[nr_options],
3240 thread, NULL);
3241 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003242 /*
3243 * Note that browser->selection != NULL
3244 * when browser->he_selection is not NULL,
3245 * so we don't need to check browser->selection
3246 * before fetching browser->selection->sym like what
3247 * we do before fetching browser->selection->map.
3248 *
3249 * See hist_browser__show_entry.
3250 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003251 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003252 nr_options += add_script_opt(browser,
3253 &actions[nr_options],
3254 &options[nr_options],
3255 NULL, browser->selection->sym);
3256 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003257 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003258 nr_options += add_script_opt(browser, &actions[nr_options],
3259 &options[nr_options], NULL, NULL);
3260 nr_options += add_switch_opt(browser, &actions[nr_options],
3261 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003262skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003263 nr_options += add_exit_opt(browser, &actions[nr_options],
3264 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003265
Namhyung Kimea7cd592015-04-22 16:18:19 +09003266 do {
3267 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003268
Namhyung Kimea7cd592015-04-22 16:18:19 +09003269 choice = ui__popup_menu(nr_options, options);
3270 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003271 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003272
3273 act = &actions[choice];
3274 key = act->fn(browser, act);
3275 } while (key == 1);
3276
3277 if (key == K_SWITCH_INPUT_DATA)
3278 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003279 }
3280out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003281 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003282out:
3283 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003284 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003285 return key;
3286}
3287
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003288struct perf_evsel_menu {
3289 struct ui_browser b;
3290 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003291 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003292 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003293 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003294};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003295
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003296static void perf_evsel_menu__write(struct ui_browser *browser,
3297 void *entry, int row)
3298{
3299 struct perf_evsel_menu *menu = container_of(browser,
3300 struct perf_evsel_menu, b);
3301 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003302 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003303 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003304 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003305 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003306 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003307 const char *warn = " ";
3308 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003309
3310 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3311 HE_COLORSET_NORMAL);
3312
Namhyung Kim759ff492013-03-05 14:53:26 +09003313 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003314 struct perf_evsel *pos;
3315
3316 ev_name = perf_evsel__group_name(evsel);
3317
3318 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003319 struct hists *pos_hists = evsel__hists(pos);
3320 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003321 }
3322 }
3323
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003324 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003325 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003326 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003327 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003328
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003329 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003330 if (nr_events != 0) {
3331 menu->lost_events = true;
3332 if (!current_entry)
3333 ui_browser__set_color(browser, HE_COLORSET_TOP);
3334 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003335 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3336 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003337 warn = bf;
3338 }
3339
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003340 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003341
3342 if (current_entry)
3343 menu->selection = evsel;
3344}
3345
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003346static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3347 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003348 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003349{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003350 struct perf_evlist *evlist = menu->b.priv;
3351 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003352 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003353 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003354 int key;
3355
3356 if (ui_browser__show(&menu->b, title,
3357 "ESC: exit, ENTER|->: Browse histograms") < 0)
3358 return -1;
3359
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003360 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003361 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003362
3363 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003364 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003365 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003366
3367 if (!menu->lost_events_warned && menu->lost_events) {
3368 ui_browser__warn_lost_events(&menu->b);
3369 menu->lost_events_warned = true;
3370 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003371 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003372 case K_RIGHT:
3373 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003374 if (!menu->selection)
3375 continue;
3376 pos = menu->selection;
3377browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003378 perf_evlist__set_selected(evlist, pos);
3379 /*
3380 * Give the calling tool a chance to populate the non
3381 * default evsel resorted hists tree.
3382 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003383 if (hbt)
3384 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003385 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003386 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003387 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003388 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003389 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003390 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003391 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003392 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003393 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003394 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003395 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003396 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003397 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003398 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003399 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003400 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003401 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003402 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003403 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003404 case 'q':
3405 case CTRL('c'):
3406 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003407 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003408 default:
3409 continue;
3410 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003411 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003412 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003413 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003414 if (!ui_browser__dialog_yesno(&menu->b,
3415 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003416 continue;
3417 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003418 case 'q':
3419 case CTRL('c'):
3420 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003421 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003422 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003423 }
3424 }
3425
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003426out:
3427 ui_browser__hide(&menu->b);
3428 return key;
3429}
3430
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003431static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003432 void *entry)
3433{
3434 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3435
3436 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3437 return true;
3438
3439 return false;
3440}
3441
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003442static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003443 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003444 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003445 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003446 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003447{
3448 struct perf_evsel *pos;
3449 struct perf_evsel_menu menu = {
3450 .b = {
3451 .entries = &evlist->entries,
3452 .refresh = ui_browser__list_head_refresh,
3453 .seek = ui_browser__list_head_seek,
3454 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003455 .filter = filter_group_entries,
3456 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003457 .priv = evlist,
3458 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003459 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003460 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003461 };
3462
3463 ui_helpline__push("Press ESC to exit");
3464
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003465 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003466 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003467 size_t line_len = strlen(ev_name) + 7;
3468
3469 if (menu.b.width < line_len)
3470 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003471 }
3472
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003473 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003474}
3475
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003476int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003477 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003478 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003479 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003480{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003481 int nr_entries = evlist->nr_entries;
3482
3483single_entry:
3484 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003485 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003486
3487 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003488 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003489 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003490 }
3491
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003492 if (symbol_conf.event_group) {
3493 struct perf_evsel *pos;
3494
3495 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003496 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003497 if (perf_evsel__is_group_leader(pos))
3498 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003499 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003500
3501 if (nr_entries == 1)
3502 goto single_entry;
3503 }
3504
3505 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003506 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003507}