blob: da24072bb76ec29ca481c1badfad9b9a6e1954ba [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include <stdlib.h>
3#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <linux/rbtree.h>
5
Namhyung Kimaca7a942012-04-04 00:14:26 -07006#include "../../util/evsel.h"
7#include "../../util/evlist.h"
8#include "../../util/hist.h"
9#include "../../util/pstack.h"
10#include "../../util/sort.h"
11#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090012#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
Jiri Olsaf7589902016-06-20 23:58:13 +020015#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030016#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020020#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021
Namhyung Kimf5951d52012-09-03 11:53:09 +090022extern void hist_browser__init_hpp(void);
23
Jiri Olsa5b91a862016-06-20 23:58:15 +020024static int perf_evsel_browser_title(struct hist_browser *browser,
25 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090026static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030027
Namhyung Kimc3b78952014-04-22 15:56:17 +090028static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090029 float min_pcnt);
30
Namhyung Kim268397c2014-04-22 14:49:31 +090031static bool hist_browser__has_filter(struct hist_browser *hb)
32{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010033 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090034}
35
He Kuang4fabf3d2015-03-12 15:21:49 +080036static int hist_browser__get_folding(struct hist_browser *browser)
37{
38 struct rb_node *nd;
39 struct hists *hists = browser->hists;
40 int unfolded_rows = 0;
41
42 for (nd = rb_first(&hists->entries);
43 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090044 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080045 struct hist_entry *he =
46 rb_entry(nd, struct hist_entry, rb_node);
47
Namhyung Kimf5b763f2016-02-25 00:13:43 +090048 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080049 unfolded_rows += he->nr_rows;
50 }
51 return unfolded_rows;
52}
53
Namhyung Kimc3b78952014-04-22 15:56:17 +090054static u32 hist_browser__nr_entries(struct hist_browser *hb)
55{
56 u32 nr_entries;
57
Namhyung Kimf5b763f2016-02-25 00:13:43 +090058 if (symbol_conf.report_hierarchy)
59 nr_entries = hb->nr_hierarchy_entries;
60 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090061 nr_entries = hb->nr_non_filtered_entries;
62 else
63 nr_entries = hb->hists->nr_entries;
64
He Kuang4fabf3d2015-03-12 15:21:49 +080065 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090066 return nr_entries + hb->nr_callchain_rows;
67}
68
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020069static void hist_browser__update_rows(struct hist_browser *hb)
70{
71 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020072 struct hists *hists = hb->hists;
73 struct perf_hpp_list *hpp_list = hists->hpp_list;
74 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020075
Jiri Olsaf8e67102016-08-07 17:28:26 +020076 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020077 browser->rows = browser->height - header_offset;
78 /*
79 * Verify if we were at the last line and that line isn't
80 * visibe because we now show the header line(s).
81 */
82 index_row = browser->index - browser->top_idx;
83 if (index_row >= browser->rows)
84 browser->index -= index_row - browser->rows + 1;
85}
86
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030087static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030088{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030089 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
90
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030091 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030092 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
93 /*
94 * FIXME: Just keeping existing behaviour, but this really should be
95 * before updating browser->width, as it will invalidate the
96 * calculation above. Fix this and the fallout in another
97 * changeset.
98 */
99 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200100 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101}
102
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300103static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
104{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200105 struct hists *hists = browser->hists;
106 struct perf_hpp_list *hpp_list = hists->hpp_list;
107 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200108
Jiri Olsaf8e67102016-08-07 17:28:26 +0200109 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200110 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300111}
112
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300113static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300114{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900115 /*
116 * The hists__remove_entry_filter() already folds non-filtered
117 * entries so we can assume it has 0 callchain rows.
118 */
119 browser->nr_callchain_rows = 0;
120
Namhyung Kim268397c2014-04-22 14:49:31 +0900121 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900122 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300123 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300124 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300125}
126
127static char tree__folded_sign(bool unfolded)
128{
129 return unfolded ? '-' : '+';
130}
131
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900134 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300135}
136
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300137static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300138{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900139 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300140}
141
Namhyung Kim3698dab2015-05-05 23:55:46 +0900142static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300143{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900144 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300145}
146
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800147static struct inline_node *inline_node__create(struct map *map, u64 ip)
148{
149 struct dso *dso;
150 struct inline_node *node;
151
152 if (map == NULL)
153 return NULL;
154
155 dso = map->dso;
156 if (dso == NULL)
157 return NULL;
158
159 if (dso->kernel != DSO_TYPE_USER)
160 return NULL;
161
162 node = dso__parse_addr_inlines(dso,
163 map__rip_2objdump(map, ip));
164
165 return node;
166}
167
168static int inline__count_rows(struct inline_node *node)
169{
170 struct inline_list *ilist;
171 int i = 0;
172
173 if (node == NULL)
174 return 0;
175
176 list_for_each_entry(ilist, &node->val, list) {
177 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
178 i++;
179 }
180
181 return i;
182}
183
184static int callchain_list__inline_rows(struct callchain_list *chain)
185{
186 struct inline_node *node;
187 int rows;
188
189 node = inline_node__create(chain->ms.map, chain->ip);
190 if (node == NULL)
191 return 0;
192
193 rows = inline__count_rows(node);
194 inline_node__delete(node);
195 return rows;
196}
197
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300198static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300199{
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800200 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300201 struct rb_node *nd;
202
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300203 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300204 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
205 struct callchain_list *chain;
206 char folded_sign = ' '; /* No children */
207
208 list_for_each_entry(chain, &child->val, list) {
209 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800210
211 if (symbol_conf.inline_name) {
212 inline_rows =
213 callchain_list__inline_rows(chain);
214 n += inline_rows;
215 }
216
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300217 /* We need this because we may not have children */
218 folded_sign = callchain_list__folded(chain);
219 if (folded_sign == '+')
220 break;
221 }
222
223 if (folded_sign == '-') /* Have children and they're unfolded */
224 n += callchain_node__count_rows_rb_tree(child);
225 }
226
227 return n;
228}
229
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900230static int callchain_node__count_flat_rows(struct callchain_node *node)
231{
232 struct callchain_list *chain;
233 char folded_sign = 0;
234 int n = 0;
235
236 list_for_each_entry(chain, &node->parent_val, list) {
237 if (!folded_sign) {
238 /* only check first chain list entry */
239 folded_sign = callchain_list__folded(chain);
240 if (folded_sign == '+')
241 return 1;
242 }
243 n++;
244 }
245
246 list_for_each_entry(chain, &node->val, list) {
247 if (!folded_sign) {
248 /* node->parent_val list might be empty */
249 folded_sign = callchain_list__folded(chain);
250 if (folded_sign == '+')
251 return 1;
252 }
253 n++;
254 }
255
256 return n;
257}
258
Namhyung Kim8c430a32015-11-09 14:45:44 +0900259static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
260{
261 return 1;
262}
263
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300264static int callchain_node__count_rows(struct callchain_node *node)
265{
266 struct callchain_list *chain;
267 bool unfolded = false;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800268 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300269
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900270 if (callchain_param.mode == CHAIN_FLAT)
271 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900272 else if (callchain_param.mode == CHAIN_FOLDED)
273 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900274
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300275 list_for_each_entry(chain, &node->val, list) {
276 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800277 if (symbol_conf.inline_name) {
278 inline_rows = callchain_list__inline_rows(chain);
279 n += inline_rows;
280 }
281
Namhyung Kim3698dab2015-05-05 23:55:46 +0900282 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300283 }
284
285 if (unfolded)
286 n += callchain_node__count_rows_rb_tree(node);
287
288 return n;
289}
290
291static int callchain__count_rows(struct rb_root *chain)
292{
293 struct rb_node *nd;
294 int n = 0;
295
296 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
297 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
298 n += callchain_node__count_rows(node);
299 }
300
301 return n;
302}
303
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900304static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
305 bool include_children)
306{
307 int count = 0;
308 struct rb_node *node;
309 struct hist_entry *child;
310
311 if (he->leaf)
312 return callchain__count_rows(&he->sorted_chain);
313
Namhyung Kim79dded82016-02-26 21:13:19 +0900314 if (he->has_no_entry)
315 return 1;
316
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900317 node = rb_first(&he->hroot_out);
318 while (node) {
319 float percent;
320
321 child = rb_entry(node, struct hist_entry, rb_node);
322 percent = hist_entry__get_percent_limit(child);
323
324 if (!child->filtered && percent >= hb->min_pcnt) {
325 count++;
326
327 if (include_children && child->unfolded)
328 count += hierarchy_count_rows(hb, child, true);
329 }
330
331 node = rb_next(node);
332 }
333 return count;
334}
335
Namhyung Kim3698dab2015-05-05 23:55:46 +0900336static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300337{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900338 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200339 return false;
340
Namhyung Kim3698dab2015-05-05 23:55:46 +0900341 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300342 return false;
343
Namhyung Kim3698dab2015-05-05 23:55:46 +0900344 he->unfolded = !he->unfolded;
345 return true;
346}
347
348static bool callchain_list__toggle_fold(struct callchain_list *cl)
349{
350 if (!cl)
351 return false;
352
353 if (!cl->has_children)
354 return false;
355
356 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300357 return true;
358}
359
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300360static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300361{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300362 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300364 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300365 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
366 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300367 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300368
369 list_for_each_entry(chain, &child->val, list) {
370 if (first) {
371 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900372 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300373 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300374 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900375 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300376 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300377 }
378
379 callchain_node__init_have_children_rb_tree(child);
380 }
381}
382
Namhyung Kima7444af2014-11-24 17:13:27 +0900383static void callchain_node__init_have_children(struct callchain_node *node,
384 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385{
386 struct callchain_list *chain;
387
Namhyung Kima7444af2014-11-24 17:13:27 +0900388 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900389 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900390
Andres Freund90989032016-03-30 21:02:45 +0200391 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900392 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900393 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900394 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300395
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300396 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300397}
398
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300399static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300400{
Namhyung Kima7444af2014-11-24 17:13:27 +0900401 struct rb_node *nd = rb_first(root);
402 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300403
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300404 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300405 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900406 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900407 if (callchain_param.mode == CHAIN_FLAT ||
408 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900409 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300410 }
411}
412
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300413static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300414{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900415 if (he->init_have_children)
416 return;
417
418 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900419 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300420 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900421 } else {
422 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300423 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900424
425 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300426}
427
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800428static void hist_entry_init_inline_node(struct hist_entry *he)
429{
430 if (he->inline_node)
431 return;
432
433 he->inline_node = inline_node__create(he->ms.map, he->ip);
434
435 if (he->inline_node == NULL)
436 return;
437
438 he->has_children = true;
439}
440
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300441static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300442{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900443 struct hist_entry *he = browser->he_selection;
444 struct map_symbol *ms = browser->selection;
445 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
446 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300447
Wang Nan4938cf02015-12-07 02:35:44 +0000448 if (!he || !ms)
449 return false;
450
Namhyung Kim3698dab2015-05-05 23:55:46 +0900451 if (ms == &he->ms)
452 has_children = hist_entry__toggle_fold(he);
453 else
454 has_children = callchain_list__toggle_fold(cl);
455
456 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900457 int child_rows = 0;
458
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300459 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900460 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300461
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900462 if (he->leaf)
463 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300464 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900465 browser->nr_hierarchy_entries -= he->nr_rows;
466
467 if (symbol_conf.report_hierarchy)
468 child_rows = hierarchy_count_rows(browser, he, true);
469
470 if (he->unfolded) {
471 if (he->leaf)
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800472 if (he->inline_node)
473 he->nr_rows = inline__count_rows(
474 he->inline_node);
475 else
476 he->nr_rows = callchain__count_rows(
477 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900478 else
479 he->nr_rows = hierarchy_count_rows(browser, he, false);
480
481 /* account grand children */
482 if (symbol_conf.report_hierarchy)
483 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900484
485 if (!he->leaf && he->nr_rows == 0) {
486 he->has_no_entry = true;
487 he->nr_rows = 1;
488 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900489 } else {
490 if (symbol_conf.report_hierarchy)
491 browser->b.nr_entries -= child_rows - he->nr_rows;
492
Namhyung Kim79dded82016-02-26 21:13:19 +0900493 if (he->has_no_entry)
494 he->has_no_entry = false;
495
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300496 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900497 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900498
499 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900500
501 if (he->leaf)
502 browser->nr_callchain_rows += he->nr_rows;
503 else
504 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300505
506 return true;
507 }
508
509 /* If it doesn't have children, no toggling performed */
510 return false;
511}
512
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300513static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300514{
515 int n = 0;
516 struct rb_node *nd;
517
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300518 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300519 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
520 struct callchain_list *chain;
521 bool has_children = false;
522
523 list_for_each_entry(chain, &child->val, list) {
524 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900525 callchain_list__set_folding(chain, unfold);
526 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300527 }
528
529 if (has_children)
530 n += callchain_node__set_folding_rb_tree(child, unfold);
531 }
532
533 return n;
534}
535
536static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
537{
538 struct callchain_list *chain;
539 bool has_children = false;
540 int n = 0;
541
542 list_for_each_entry(chain, &node->val, list) {
543 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900544 callchain_list__set_folding(chain, unfold);
545 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300546 }
547
548 if (has_children)
549 n += callchain_node__set_folding_rb_tree(node, unfold);
550
551 return n;
552}
553
554static int callchain__set_folding(struct rb_root *chain, bool unfold)
555{
556 struct rb_node *nd;
557 int n = 0;
558
559 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
560 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
561 n += callchain_node__set_folding(node, unfold);
562 }
563
564 return n;
565}
566
Namhyung Kim492b1012016-02-25 00:13:44 +0900567static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
568 bool unfold __maybe_unused)
569{
570 float percent;
571 struct rb_node *nd;
572 struct hist_entry *child;
573 int n = 0;
574
575 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
576 child = rb_entry(nd, struct hist_entry, rb_node);
577 percent = hist_entry__get_percent_limit(child);
578 if (!child->filtered && percent >= hb->min_pcnt)
579 n++;
580 }
581
582 return n;
583}
584
Jiri Olsab33f9222017-01-20 10:20:29 +0100585static void __hist_entry__set_folding(struct hist_entry *he,
586 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300587{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300588 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900589 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300590
Namhyung Kim3698dab2015-05-05 23:55:46 +0900591 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900592 int n;
593
594 if (he->leaf)
595 n = callchain__set_folding(&he->sorted_chain, unfold);
596 else
597 n = hierarchy_set_folding(hb, he, unfold);
598
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300599 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300600 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300601 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300602}
603
Jiri Olsab33f9222017-01-20 10:20:29 +0100604static void hist_entry__set_folding(struct hist_entry *he,
605 struct hist_browser *browser, bool unfold)
606{
607 double percent;
608
609 percent = hist_entry__get_percent_limit(he);
610 if (he->filtered || percent < browser->min_pcnt)
611 return;
612
613 __hist_entry__set_folding(he, browser, unfold);
614
615 if (!he->depth || unfold)
616 browser->nr_hierarchy_entries++;
617 if (he->leaf)
618 browser->nr_callchain_rows += he->nr_rows;
619 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
620 browser->nr_hierarchy_entries++;
621 he->has_no_entry = true;
622 he->nr_rows = 1;
623 } else
624 he->has_no_entry = false;
625}
626
Namhyung Kimc3b78952014-04-22 15:56:17 +0900627static void
628__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300629{
630 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900631 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300632
Namhyung Kim492b1012016-02-25 00:13:44 +0900633 nd = rb_first(&browser->hists->entries);
634 while (nd) {
635 he = rb_entry(nd, struct hist_entry, rb_node);
636
637 /* set folding state even if it's currently folded */
638 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
639
640 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300641 }
642}
643
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300644static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300645{
Namhyung Kim492b1012016-02-25 00:13:44 +0900646 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900647 browser->nr_callchain_rows = 0;
648 __hist_browser__set_folding(browser, unfold);
649
650 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300651 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300652 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300653}
654
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100655static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
656{
657 if (!browser->he_selection)
658 return;
659
660 hist_entry__set_folding(browser->he_selection, browser, unfold);
661 browser->b.nr_entries = hist_browser__nr_entries(browser);
662}
663
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200664static void ui_browser__warn_lost_events(struct ui_browser *browser)
665{
666 ui_browser__warning(browser, 4,
667 "Events are being lost, check IO/CPU overload!\n\n"
668 "You may want to run 'perf' using a RT scheduler policy:\n\n"
669 " perf top -r 80\n\n"
670 "Or reduce the sampling frequency.");
671}
672
Jiri Olsa5b91a862016-06-20 23:58:15 +0200673static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
674{
675 return browser->title ? browser->title(browser, bf, size) : 0;
676}
677
Jiri Olsadabd2012016-06-20 23:58:14 +0200678int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300679{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300680 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300681 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900682 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900683 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300684
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300685 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900686 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300687
Jiri Olsa5b91a862016-06-20 23:58:15 +0200688 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300689
Namhyung Kim090cff32016-01-11 19:53:14 +0900690 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300691 return -1;
692
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300693 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300694 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300695
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300696 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900697 case K_TIMER: {
698 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900699 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900700
Namhyung Kimc6111522016-10-07 14:04:12 +0900701 if (hist_browser__has_filter(browser) ||
702 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900703 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900704
Namhyung Kimc3b78952014-04-22 15:56:17 +0900705 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900706 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200707
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300708 if (browser->hists->stats.nr_lost_warned !=
709 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
710 browser->hists->stats.nr_lost_warned =
711 browser->hists->stats.nr_events[PERF_RECORD_LOST];
712 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200713 }
714
Jiri Olsa5b91a862016-06-20 23:58:15 +0200715 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300716 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300717 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900718 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300719 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300720 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300721 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300722 struct hist_entry, rb_node);
723 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300724 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 -0300725 seq++, browser->b.nr_entries,
726 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300727 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300728 browser->b.index,
729 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300730 h->row_offset, h->nr_rows);
731 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300732 break;
733 case 'C':
734 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300735 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300736 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100737 case 'c':
738 /* Collapse the selected entry. */
739 hist_browser__set_folding_selected(browser, false);
740 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300741 case 'E':
742 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300743 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300744 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100745 case 'e':
746 /* Expand the selected entry. */
747 hist_browser__set_folding_selected(browser, true);
748 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200749 case 'H':
750 browser->show_headers = !browser->show_headers;
751 hist_browser__update_rows(browser);
752 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200753 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300754 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300755 break;
756 /* fall thru */
757 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300758 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300759 }
760 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300761out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300762 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300763 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300764}
765
Namhyung Kim39ee5332014-08-22 09:13:21 +0900766struct callchain_print_arg {
767 /* for hists browser */
768 off_t row_offset;
769 bool is_current_entry;
770
771 /* for file dump */
772 FILE *fp;
773 int printed;
774};
775
776typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
777 struct callchain_list *chain,
778 const char *str, int offset,
779 unsigned short row,
780 struct callchain_print_arg *arg);
781
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900782static void hist_browser__show_callchain_entry(struct hist_browser *browser,
783 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900784 const char *str, int offset,
785 unsigned short row,
786 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900787{
788 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900789 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300790 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900791
792 color = HE_COLORSET_NORMAL;
793 width = browser->b.width - (offset + 2);
794 if (ui_browser__is_current_entry(&browser->b, row)) {
795 browser->selection = &chain->ms;
796 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900797 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900798 }
799
800 ui_browser__set_color(&browser->b, color);
801 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300802 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300803 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300804 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300805 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900806}
807
Namhyung Kim39ee5332014-08-22 09:13:21 +0900808static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
809 struct callchain_list *chain,
810 const char *str, int offset,
811 unsigned short row __maybe_unused,
812 struct callchain_print_arg *arg)
813{
814 char folded_sign = callchain_list__folded(chain);
815
816 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
817 folded_sign, str);
818}
819
820typedef bool (*check_output_full_fn)(struct hist_browser *browser,
821 unsigned short row);
822
823static bool hist_browser__check_output_full(struct hist_browser *browser,
824 unsigned short row)
825{
826 return browser->b.rows == row;
827}
828
829static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
830 unsigned short row __maybe_unused)
831{
832 return false;
833}
834
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300835#define LEVEL_OFFSET_STEP 3
836
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800837static int hist_browser__show_inline(struct hist_browser *browser,
838 struct inline_node *node,
839 unsigned short row,
840 int offset)
841{
842 struct inline_list *ilist;
843 char buf[1024];
844 int color, width, first_row;
845
846 first_row = row;
847 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
848 list_for_each_entry(ilist, &node->val, list) {
849 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
850 color = HE_COLORSET_NORMAL;
851 if (ui_browser__is_current_entry(&browser->b, row))
852 color = HE_COLORSET_SELECTED;
853
Milian Wolff5dfa2102017-03-18 22:49:28 +0100854 if (callchain_param.key == CCKEY_ADDRESS ||
855 callchain_param.key == CCKEY_SRCLINE) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800856 if (ilist->filename != NULL)
857 scnprintf(buf, sizeof(buf),
858 "%s:%d (inline)",
859 ilist->filename,
860 ilist->line_nr);
861 else
862 scnprintf(buf, sizeof(buf), "??");
863 } else if (ilist->funcname != NULL)
864 scnprintf(buf, sizeof(buf), "%s (inline)",
865 ilist->funcname);
866 else if (ilist->filename != NULL)
867 scnprintf(buf, sizeof(buf),
868 "%s:%d (inline)",
869 ilist->filename,
870 ilist->line_nr);
871 else
872 scnprintf(buf, sizeof(buf), "??");
873
874 ui_browser__set_color(&browser->b, color);
875 hist_browser__gotorc(browser, row, 0);
876 ui_browser__write_nstring(&browser->b, " ",
877 LEVEL_OFFSET_STEP + offset);
878 ui_browser__write_nstring(&browser->b, buf, width);
879 row++;
880 }
881 }
882
883 return row - first_row;
884}
885
886static size_t show_inline_list(struct hist_browser *browser, struct map *map,
887 u64 ip, int row, int offset)
888{
889 struct inline_node *node;
890 int ret;
891
892 node = inline_node__create(map, ip);
893 if (node == NULL)
894 return 0;
895
896 ret = hist_browser__show_inline(browser, node, row, offset);
897
898 inline_node__delete(node);
899 return ret;
900}
901
Namhyung Kim18bb8382015-11-09 14:45:42 +0900902static int hist_browser__show_callchain_list(struct hist_browser *browser,
903 struct callchain_node *node,
904 struct callchain_list *chain,
905 unsigned short row, u64 total,
906 bool need_percent, int offset,
907 print_callchain_entry_fn print,
908 struct callchain_print_arg *arg)
909{
910 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800911 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900912 const char *str;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800913 int inline_rows = 0, ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900914
915 if (arg->row_offset != 0) {
916 arg->row_offset--;
917 return 0;
918 }
919
920 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800921 alloc_str2 = NULL;
922
Namhyung Kim18bb8382015-11-09 14:45:42 +0900923 str = callchain_list__sym_name(chain, bf, sizeof(bf),
924 browser->show_dso);
925
Jin Yaofef51ec2016-10-31 09:19:53 +0800926 if (symbol_conf.show_branchflag_count) {
927 if (need_percent)
928 callchain_list_counts__printf_value(node, chain, NULL,
929 buf, sizeof(buf));
930 else
931 callchain_list_counts__printf_value(NULL, chain, NULL,
932 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900933
Jin Yaofef51ec2016-10-31 09:19:53 +0800934 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
935 str = "Not enough memory!";
936 else
937 str = alloc_str2;
938 }
939
940 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900941 callchain_node__scnprintf_value(node, buf, sizeof(buf),
942 total);
943
944 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
945 str = "Not enough memory!";
946 else
947 str = alloc_str;
948 }
949
950 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900951 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800952 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800953
954 if (symbol_conf.inline_name) {
955 inline_rows = show_inline_list(browser, chain->ms.map,
956 chain->ip, row + 1, offset);
957 }
958
959 return ret + inline_rows;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900960}
961
Namhyung Kim59c624e2016-01-28 00:40:56 +0900962static bool check_percent_display(struct rb_node *node, u64 parent_total)
963{
964 struct callchain_node *child;
965
966 if (node == NULL)
967 return false;
968
969 if (rb_next(node))
970 return true;
971
972 child = rb_entry(node, struct callchain_node, rb_node);
973 return callchain_cumul_hits(child) != parent_total;
974}
975
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900976static int hist_browser__show_callchain_flat(struct hist_browser *browser,
977 struct rb_root *root,
978 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900979 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900980 print_callchain_entry_fn print,
981 struct callchain_print_arg *arg,
982 check_output_full_fn is_output_full)
983{
984 struct rb_node *node;
985 int first_row = row, offset = LEVEL_OFFSET_STEP;
986 bool need_percent;
987
988 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900989 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900990
991 while (node) {
992 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
993 struct rb_node *next = rb_next(node);
994 struct callchain_list *chain;
995 char folded_sign = ' ';
996 int first = true;
997 int extra_offset = 0;
998
999 list_for_each_entry(chain, &child->parent_val, list) {
1000 bool was_first = first;
1001
1002 if (first)
1003 first = false;
1004 else if (need_percent)
1005 extra_offset = LEVEL_OFFSET_STEP;
1006
1007 folded_sign = callchain_list__folded(chain);
1008
1009 row += hist_browser__show_callchain_list(browser, child,
1010 chain, row, total,
1011 was_first && need_percent,
1012 offset + extra_offset,
1013 print, arg);
1014
1015 if (is_output_full(browser, row))
1016 goto out;
1017
1018 if (folded_sign == '+')
1019 goto next;
1020 }
1021
1022 list_for_each_entry(chain, &child->val, list) {
1023 bool was_first = first;
1024
1025 if (first)
1026 first = false;
1027 else if (need_percent)
1028 extra_offset = LEVEL_OFFSET_STEP;
1029
1030 folded_sign = callchain_list__folded(chain);
1031
1032 row += hist_browser__show_callchain_list(browser, child,
1033 chain, row, total,
1034 was_first && need_percent,
1035 offset + extra_offset,
1036 print, arg);
1037
1038 if (is_output_full(browser, row))
1039 goto out;
1040
1041 if (folded_sign == '+')
1042 break;
1043 }
1044
1045next:
1046 if (is_output_full(browser, row))
1047 break;
1048 node = next;
1049 }
1050out:
1051 return row - first_row;
1052}
1053
Namhyung Kim8c430a32015-11-09 14:45:44 +09001054static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
1055 struct callchain_list *chain,
1056 char *value_str, char *old_str)
1057{
1058 char bf[1024];
1059 const char *str;
1060 char *new;
1061
1062 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1063 browser->show_dso);
1064 if (old_str) {
1065 if (asprintf(&new, "%s%s%s", old_str,
1066 symbol_conf.field_sep ?: ";", str) < 0)
1067 new = NULL;
1068 } else {
1069 if (value_str) {
1070 if (asprintf(&new, "%s %s", value_str, str) < 0)
1071 new = NULL;
1072 } else {
1073 if (asprintf(&new, "%s", str) < 0)
1074 new = NULL;
1075 }
1076 }
1077 return new;
1078}
1079
1080static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1081 struct rb_root *root,
1082 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +09001083 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +09001084 print_callchain_entry_fn print,
1085 struct callchain_print_arg *arg,
1086 check_output_full_fn is_output_full)
1087{
1088 struct rb_node *node;
1089 int first_row = row, offset = LEVEL_OFFSET_STEP;
1090 bool need_percent;
1091
1092 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001093 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001094
1095 while (node) {
1096 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1097 struct rb_node *next = rb_next(node);
1098 struct callchain_list *chain, *first_chain = NULL;
1099 int first = true;
1100 char *value_str = NULL, *value_str_alloc = NULL;
1101 char *chain_str = NULL, *chain_str_alloc = NULL;
1102
1103 if (arg->row_offset != 0) {
1104 arg->row_offset--;
1105 goto next;
1106 }
1107
1108 if (need_percent) {
1109 char buf[64];
1110
1111 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1112 if (asprintf(&value_str, "%s", buf) < 0) {
1113 value_str = (char *)"<...>";
1114 goto do_print;
1115 }
1116 value_str_alloc = value_str;
1117 }
1118
1119 list_for_each_entry(chain, &child->parent_val, list) {
1120 chain_str = hist_browser__folded_callchain_str(browser,
1121 chain, value_str, chain_str);
1122 if (first) {
1123 first = false;
1124 first_chain = chain;
1125 }
1126
1127 if (chain_str == NULL) {
1128 chain_str = (char *)"Not enough memory!";
1129 goto do_print;
1130 }
1131
1132 chain_str_alloc = chain_str;
1133 }
1134
1135 list_for_each_entry(chain, &child->val, list) {
1136 chain_str = hist_browser__folded_callchain_str(browser,
1137 chain, value_str, chain_str);
1138 if (first) {
1139 first = false;
1140 first_chain = chain;
1141 }
1142
1143 if (chain_str == NULL) {
1144 chain_str = (char *)"Not enough memory!";
1145 goto do_print;
1146 }
1147
1148 chain_str_alloc = chain_str;
1149 }
1150
1151do_print:
1152 print(browser, first_chain, chain_str, offset, row++, arg);
1153 free(value_str_alloc);
1154 free(chain_str_alloc);
1155
1156next:
1157 if (is_output_full(browser, row))
1158 break;
1159 node = next;
1160 }
1161
1162 return row - first_row;
1163}
1164
Namhyung Kim0c841c62016-01-28 00:40:54 +09001165static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001166 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001167 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001168 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001169 print_callchain_entry_fn print,
1170 struct callchain_print_arg *arg,
1171 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001172{
1173 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001174 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001175 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001176 u64 percent_total = total;
1177
1178 if (callchain_param.mode == CHAIN_GRAPH_REL)
1179 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001181 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001182 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001183
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001184 while (node) {
1185 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1186 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001187 struct callchain_list *chain;
1188 char folded_sign = ' ';
1189 int first = true;
1190 int extra_offset = 0;
1191
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001192 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001193 bool was_first = first;
1194
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001195 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001197 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001198 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199
1200 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201
Namhyung Kim18bb8382015-11-09 14:45:42 +09001202 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001203 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001204 was_first && need_percent,
1205 offset + extra_offset,
1206 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001207
Namhyung Kim18bb8382015-11-09 14:45:42 +09001208 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001209 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001210
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001211 if (folded_sign == '+')
1212 break;
1213 }
1214
1215 if (folded_sign == '-') {
1216 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001217
Namhyung Kim0c841c62016-01-28 00:40:54 +09001218 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001219 new_level, row, total,
1220 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001221 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001222 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001223 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001224 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001225 node = next;
1226 }
1227out:
1228 return row - first_row;
1229}
1230
Namhyung Kim0c841c62016-01-28 00:40:54 +09001231static int hist_browser__show_callchain(struct hist_browser *browser,
1232 struct hist_entry *entry, int level,
1233 unsigned short row,
1234 print_callchain_entry_fn print,
1235 struct callchain_print_arg *arg,
1236 check_output_full_fn is_output_full)
1237{
1238 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001239 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001240 int printed;
1241
Namhyung Kim5eca1042016-01-28 00:40:55 +09001242 if (symbol_conf.cumulate_callchain)
1243 parent_total = entry->stat_acc->period;
1244 else
1245 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001246
1247 if (callchain_param.mode == CHAIN_FLAT) {
1248 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001249 &entry->sorted_chain, row,
1250 total, parent_total, print, arg,
1251 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001252 } else if (callchain_param.mode == CHAIN_FOLDED) {
1253 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001254 &entry->sorted_chain, row,
1255 total, parent_total, print, arg,
1256 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001257 } else {
1258 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001259 &entry->sorted_chain, level, row,
1260 total, parent_total, print, arg,
1261 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001262 }
1263
1264 if (arg->is_current_entry)
1265 browser->he_selection = entry;
1266
1267 return printed;
1268}
1269
Namhyung Kim89701462013-01-22 18:09:38 +09001270struct hpp_arg {
1271 struct ui_browser *b;
1272 char folded_sign;
1273 bool current_entry;
1274};
1275
Jiri Olsa98ba1602016-09-22 17:36:35 +02001276int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001277{
1278 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001279 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001280 va_list args;
1281 double percent;
1282
1283 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001284 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001285 percent = va_arg(args, double);
1286 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001287
Namhyung Kim89701462013-01-22 18:09:38 +09001288 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001289
Namhyung Kimd6751072014-07-31 14:47:36 +09001290 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001291 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001292
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001293 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001294}
1295
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001296#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001297static u64 __hpp_get_##_field(struct hist_entry *he) \
1298{ \
1299 return he->stat._field; \
1300} \
1301 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001302static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001303hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001304 struct perf_hpp *hpp, \
1305 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001306{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001307 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1308 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001309}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001310
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001311#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1312static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1313{ \
1314 return he->stat_acc->_field; \
1315} \
1316 \
1317static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001318hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001319 struct perf_hpp *hpp, \
1320 struct hist_entry *he) \
1321{ \
1322 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001323 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001324 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001325 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001326 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001327 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001328 \
1329 return ret; \
1330 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001331 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1332 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001333}
1334
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001335__HPP_COLOR_PERCENT_FN(overhead, period)
1336__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1337__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1338__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1339__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001340__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001341
1342#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001343#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001344
1345void hist_browser__init_hpp(void)
1346{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001347 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1348 hist_browser__hpp_color_overhead;
1349 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1350 hist_browser__hpp_color_overhead_sys;
1351 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1352 hist_browser__hpp_color_overhead_us;
1353 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1354 hist_browser__hpp_color_overhead_guest_sys;
1355 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1356 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001357 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1358 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001359}
1360
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001361static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001362 struct hist_entry *entry,
1363 unsigned short row)
1364{
Jiri Olsa12400052012-10-13 00:06:16 +02001365 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001366 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001367 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001368 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001369 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001370 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001371 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001372
1373 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001374 browser->he_selection = entry;
1375 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001376 }
1377
1378 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001379 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001380 folded_sign = hist_entry__folded(entry);
1381 }
1382
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001383 if (symbol_conf.inline_name &&
1384 (!entry->has_children)) {
1385 hist_entry_init_inline_node(entry);
1386 folded_sign = hist_entry__folded(entry);
1387 }
1388
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001389 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001390 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001391 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001392 .folded_sign = folded_sign,
1393 .current_entry = current_entry,
1394 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001395 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001396
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001397 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001398
Jiri Olsaf0786af2016-01-18 10:24:23 +01001399 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001400 char s[2048];
1401 struct perf_hpp hpp = {
1402 .buf = s,
1403 .size = sizeof(s),
1404 .ptr = &arg,
1405 };
1406
Namhyung Kim361459f2015-12-23 02:07:08 +09001407 if (perf_hpp__should_skip(fmt, entry->hists) ||
1408 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001409 continue;
1410
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001411 if (current_entry && browser->b.navkeypressed) {
1412 ui_browser__set_color(&browser->b,
1413 HE_COLORSET_SELECTED);
1414 } else {
1415 ui_browser__set_color(&browser->b,
1416 HE_COLORSET_NORMAL);
1417 }
1418
1419 if (first) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001420 if (symbol_conf.use_callchain ||
1421 symbol_conf.inline_name) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001422 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001423 width -= 2;
1424 }
1425 first = false;
1426 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001427 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001428 width -= 2;
1429 }
1430
Jiri Olsa12400052012-10-13 00:06:16 +02001431 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001432 int ret = fmt->color(fmt, &hpp, entry);
1433 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1434 /*
1435 * fmt->color() already used ui_browser to
1436 * print the non alignment bits, skip it (+ret):
1437 */
1438 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001439 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001440 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001441 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001442 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001443 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001444 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001445
1446 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001447 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001448 width += 1;
1449
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001450 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001451
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001452 ++row;
1453 ++printed;
1454 } else
1455 --row_offset;
1456
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001457 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001458 struct callchain_print_arg arg = {
1459 .row_offset = row_offset,
1460 .is_current_entry = current_entry,
1461 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001462
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001463 if (entry->inline_node)
1464 printed += hist_browser__show_inline(browser,
1465 entry->inline_node, row, 0);
1466 else
1467 printed += hist_browser__show_callchain(browser,
1468 entry, 1, row,
1469 hist_browser__show_callchain_entry,
1470 &arg,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001471 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001472 }
1473
1474 return printed;
1475}
1476
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001477static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1478 struct hist_entry *entry,
1479 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001480 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001481{
1482 int printed = 0;
1483 int width = browser->b.width;
1484 char folded_sign = ' ';
1485 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1486 off_t row_offset = entry->row_offset;
1487 bool first = true;
1488 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001489 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001490 struct hpp_arg arg = {
1491 .b = &browser->b,
1492 .current_entry = current_entry,
1493 };
1494 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001495 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001496
1497 if (current_entry) {
1498 browser->he_selection = entry;
1499 browser->selection = &entry->ms;
1500 }
1501
1502 hist_entry__init_have_children(entry);
1503 folded_sign = hist_entry__folded(entry);
1504 arg.folded_sign = folded_sign;
1505
1506 if (entry->leaf && row_offset) {
1507 row_offset--;
1508 goto show_callchain;
1509 }
1510
1511 hist_browser__gotorc(browser, row, 0);
1512
1513 if (current_entry && browser->b.navkeypressed)
1514 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1515 else
1516 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1517
1518 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1519 width -= level * HIERARCHY_INDENT;
1520
Namhyung Kima61a22f2016-03-07 16:44:50 -03001521 /* the first hpp_list_node is for overhead columns */
1522 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1523 struct perf_hpp_list_node, list);
1524 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001525 char s[2048];
1526 struct perf_hpp hpp = {
1527 .buf = s,
1528 .size = sizeof(s),
1529 .ptr = &arg,
1530 };
1531
1532 if (perf_hpp__should_skip(fmt, entry->hists) ||
1533 column++ < browser->b.horiz_scroll)
1534 continue;
1535
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001536 if (current_entry && browser->b.navkeypressed) {
1537 ui_browser__set_color(&browser->b,
1538 HE_COLORSET_SELECTED);
1539 } else {
1540 ui_browser__set_color(&browser->b,
1541 HE_COLORSET_NORMAL);
1542 }
1543
1544 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001545 ui_browser__printf(&browser->b, "%c ", folded_sign);
1546 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001547 first = false;
1548 } else {
1549 ui_browser__printf(&browser->b, " ");
1550 width -= 2;
1551 }
1552
1553 if (fmt->color) {
1554 int ret = fmt->color(fmt, &hpp, entry);
1555 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1556 /*
1557 * fmt->color() already used ui_browser to
1558 * print the non alignment bits, skip it (+ret):
1559 */
1560 ui_browser__printf(&browser->b, "%s", s + ret);
1561 } else {
1562 int ret = fmt->entry(fmt, &hpp, entry);
1563 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1564 ui_browser__printf(&browser->b, "%s", s);
1565 }
1566 width -= hpp.buf - s;
1567 }
1568
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001569 if (!first) {
1570 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1571 width -= hierarchy_indent;
1572 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001573
1574 if (column >= browser->b.horiz_scroll) {
1575 char s[2048];
1576 struct perf_hpp hpp = {
1577 .buf = s,
1578 .size = sizeof(s),
1579 .ptr = &arg,
1580 };
1581
1582 if (current_entry && browser->b.navkeypressed) {
1583 ui_browser__set_color(&browser->b,
1584 HE_COLORSET_SELECTED);
1585 } else {
1586 ui_browser__set_color(&browser->b,
1587 HE_COLORSET_NORMAL);
1588 }
1589
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001590 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001591 if (first) {
1592 ui_browser__printf(&browser->b, "%c ", folded_sign);
1593 first = false;
1594 } else {
1595 ui_browser__write_nstring(&browser->b, "", 2);
1596 }
1597
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001598 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001599
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001600 /*
1601 * No need to call hist_entry__snprintf_alignment()
1602 * since this fmt is always the last column in the
1603 * hierarchy mode.
1604 */
1605 if (fmt->color) {
1606 width -= fmt->color(fmt, &hpp, entry);
1607 } else {
1608 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001609
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001610 width -= fmt->entry(fmt, &hpp, entry);
1611 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001612
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001613 while (isspace(s[i++]))
1614 width++;
1615 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001616 }
1617 }
1618
1619 /* The scroll bar isn't being used */
1620 if (!browser->b.navkeypressed)
1621 width += 1;
1622
1623 ui_browser__write_nstring(&browser->b, "", width);
1624
1625 ++row;
1626 ++printed;
1627
1628show_callchain:
1629 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1630 struct callchain_print_arg carg = {
1631 .row_offset = row_offset,
1632 };
1633
1634 printed += hist_browser__show_callchain(browser, entry,
1635 level + 1, row,
1636 hist_browser__show_callchain_entry, &carg,
1637 hist_browser__check_output_full);
1638 }
1639
1640 return printed;
1641}
1642
Namhyung Kim79dded82016-02-26 21:13:19 +09001643static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001644 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001645{
1646 int width = browser->b.width;
1647 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1648 bool first = true;
1649 int column = 0;
1650 int ret;
1651 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001652 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001653 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001654
1655 if (current_entry) {
1656 browser->he_selection = NULL;
1657 browser->selection = NULL;
1658 }
1659
1660 hist_browser__gotorc(browser, row, 0);
1661
1662 if (current_entry && browser->b.navkeypressed)
1663 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1664 else
1665 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1666
1667 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1668 width -= level * HIERARCHY_INDENT;
1669
Namhyung Kima61a22f2016-03-07 16:44:50 -03001670 /* the first hpp_list_node is for overhead columns */
1671 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1672 struct perf_hpp_list_node, list);
1673 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001674 if (perf_hpp__should_skip(fmt, browser->hists) ||
1675 column++ < browser->b.horiz_scroll)
1676 continue;
1677
Jiri Olsada1b0402016-06-14 20:19:20 +02001678 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001679
1680 if (first) {
1681 /* for folded sign */
1682 first = false;
1683 ret++;
1684 } else {
1685 /* space between columns */
1686 ret += 2;
1687 }
1688
1689 ui_browser__write_nstring(&browser->b, "", ret);
1690 width -= ret;
1691 }
1692
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001693 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1694 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001695
1696 if (column >= browser->b.horiz_scroll) {
1697 char buf[32];
1698
1699 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1700 ui_browser__printf(&browser->b, " %s", buf);
1701 width -= ret + 2;
1702 }
1703
1704 /* The scroll bar isn't being used */
1705 if (!browser->b.navkeypressed)
1706 width += 1;
1707
1708 ui_browser__write_nstring(&browser->b, "", width);
1709 return 1;
1710}
1711
Jiri Olsa81a888f2014-06-14 15:44:52 +02001712static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1713{
1714 advance_hpp(hpp, inc);
1715 return hpp->size <= 0;
1716}
1717
Jiri Olsa69705b32016-08-07 17:28:28 +02001718static int
1719hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1720 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001721{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001722 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001723 struct perf_hpp dummy_hpp = {
1724 .buf = buf,
1725 .size = size,
1726 };
1727 struct perf_hpp_fmt *fmt;
1728 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001729 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001730 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001731
1732 if (symbol_conf.use_callchain) {
1733 ret = scnprintf(buf, size, " ");
1734 if (advance_hpp_check(&dummy_hpp, ret))
1735 return ret;
1736 }
1737
Jiri Olsaf0786af2016-01-18 10:24:23 +01001738 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001739 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001740 continue;
1741
Jiri Olsa29659ab2016-08-07 17:28:30 +02001742 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001743 if (advance_hpp_check(&dummy_hpp, ret))
1744 break;
1745
Jiri Olsa29659ab2016-08-07 17:28:30 +02001746 if (span)
1747 continue;
1748
Jiri Olsa81a888f2014-06-14 15:44:52 +02001749 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1750 if (advance_hpp_check(&dummy_hpp, ret))
1751 break;
1752 }
1753
1754 return ret;
1755}
1756
Namhyung Kimd8b92402016-02-25 00:13:46 +09001757static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1758{
1759 struct hists *hists = browser->hists;
1760 struct perf_hpp dummy_hpp = {
1761 .buf = buf,
1762 .size = size,
1763 };
1764 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001765 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001766 size_t ret = 0;
1767 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001768 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001769 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001770
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001771 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001772 if (advance_hpp_check(&dummy_hpp, ret))
1773 return ret;
1774
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001775 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001776 /* the first hpp_list_node is for overhead columns */
1777 fmt_node = list_first_entry(&hists->hpp_formats,
1778 struct perf_hpp_list_node, list);
1779 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001780 if (column++ < browser->b.horiz_scroll)
1781 continue;
1782
Jiri Olsa29659ab2016-08-07 17:28:30 +02001783 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001784 if (advance_hpp_check(&dummy_hpp, ret))
1785 break;
1786
1787 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1788 if (advance_hpp_check(&dummy_hpp, ret))
1789 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001790
1791 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001792 }
1793
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001794 if (!first_node) {
1795 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1796 indent * HIERARCHY_INDENT, "");
1797 if (advance_hpp_check(&dummy_hpp, ret))
1798 return ret;
1799 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001800
Namhyung Kima61a22f2016-03-07 16:44:50 -03001801 first_node = true;
1802 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1803 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001804 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1805 if (advance_hpp_check(&dummy_hpp, ret))
1806 break;
1807 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001808 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001809
Namhyung Kima61a22f2016-03-07 16:44:50 -03001810 first_col = true;
1811 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1812 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001813
Namhyung Kima61a22f2016-03-07 16:44:50 -03001814 if (perf_hpp__should_skip(fmt, hists))
1815 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001816
Namhyung Kima61a22f2016-03-07 16:44:50 -03001817 if (!first_col) {
1818 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1819 if (advance_hpp_check(&dummy_hpp, ret))
1820 break;
1821 }
1822 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001823
Jiri Olsa29659ab2016-08-07 17:28:30 +02001824 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001825 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001826
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001827 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001828 ret = strlen(start);
1829
1830 if (start != dummy_hpp.buf)
1831 memmove(dummy_hpp.buf, start, ret + 1);
1832
1833 if (advance_hpp_check(&dummy_hpp, ret))
1834 break;
1835 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001836 }
1837
1838 return ret;
1839}
1840
Jiri Olsa01b47702016-06-14 20:19:13 +02001841static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001842{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001843 char headers[1024];
1844
Jiri Olsa01b47702016-06-14 20:19:13 +02001845 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1846 sizeof(headers));
1847
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001848 ui_browser__gotorc(&browser->b, 0, 0);
1849 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001850 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001851}
1852
Jiri Olsa01b47702016-06-14 20:19:13 +02001853static void hists_browser__headers(struct hist_browser *browser)
1854{
Jiri Olsa69705b32016-08-07 17:28:28 +02001855 struct hists *hists = browser->hists;
1856 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001857
Jiri Olsa69705b32016-08-07 17:28:28 +02001858 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001859
Jiri Olsa69705b32016-08-07 17:28:28 +02001860 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1861 char headers[1024];
1862
1863 hists_browser__scnprintf_headers(browser, headers,
1864 sizeof(headers), line);
1865
1866 ui_browser__gotorc(&browser->b, line, 0);
1867 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1868 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1869 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001870}
1871
1872static void hist_browser__show_headers(struct hist_browser *browser)
1873{
1874 if (symbol_conf.report_hierarchy)
1875 hists_browser__hierarchy_headers(browser);
1876 else
1877 hists_browser__headers(browser);
1878}
1879
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001880static void ui_browser__hists_init_top(struct ui_browser *browser)
1881{
1882 if (browser->top == NULL) {
1883 struct hist_browser *hb;
1884
1885 hb = container_of(browser, struct hist_browser, b);
1886 browser->top = rb_first(&hb->hists->entries);
1887 }
1888}
1889
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001890static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001891{
1892 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001893 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001894 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001895 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001896 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001897
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001898 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001899 struct perf_hpp_list *hpp_list = hists->hpp_list;
1900
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001901 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001902 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001903 }
1904
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001905 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001906 hb->he_selection = NULL;
1907 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001908
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001909 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001910 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001911 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001912
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001913 if (h->filtered) {
1914 /* let it move to sibling */
1915 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001916 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001917 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001918
Namhyung Kim14135662013-10-31 10:17:39 +09001919 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001920 if (percent < hb->min_pcnt)
1921 continue;
1922
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001923 if (symbol_conf.report_hierarchy) {
1924 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001925 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001926 if (row == browser->rows)
1927 break;
1928
1929 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001930 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001931 row++;
1932 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001933 } else {
1934 row += hist_browser__show_entry(hb, h, row);
1935 }
1936
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001937 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001938 break;
1939 }
1940
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001941 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001942}
1943
Namhyung Kim064f1982013-05-14 11:09:04 +09001944static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001945 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001946{
1947 while (nd != NULL) {
1948 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001949 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001950
Namhyung Kimc0f15272014-04-16 11:16:33 +09001951 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001952 return nd;
1953
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001954 /*
1955 * If it's filtered, its all children also were filtered.
1956 * So move to sibling node.
1957 */
1958 if (rb_next(nd))
1959 nd = rb_next(nd);
1960 else
1961 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001962 }
1963
1964 return NULL;
1965}
1966
Namhyung Kim064f1982013-05-14 11:09:04 +09001967static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001968 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001969{
1970 while (nd != NULL) {
1971 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001972 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001973
1974 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001975 return nd;
1976
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001977 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001978 }
1979
1980 return NULL;
1981}
1982
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001983static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001984 off_t offset, int whence)
1985{
1986 struct hist_entry *h;
1987 struct rb_node *nd;
1988 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001989 struct hist_browser *hb;
1990
1991 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001992
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001993 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001994 return;
1995
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001996 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001997
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001998 switch (whence) {
1999 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09002000 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09002001 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002002 break;
2003 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002004 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002005 goto do_offset;
2006 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002007 nd = rb_hierarchy_last(rb_last(browser->entries));
2008 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002009 first = false;
2010 break;
2011 default:
2012 return;
2013 }
2014
2015 /*
2016 * Moves not relative to the first visible entry invalidates its
2017 * row_offset:
2018 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002019 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002020 h->row_offset = 0;
2021
2022 /*
2023 * Here we have to check if nd is expanded (+), if it is we can't go
2024 * the next top level hist_entry, instead we must compute an offset of
2025 * what _not_ to show and not change the first visible entry.
2026 *
2027 * This offset increments when we are going from top to bottom and
2028 * decreases when we're going from bottom to top.
2029 *
2030 * As we don't have backpointers to the top level in the callchains
2031 * structure, we need to always print the whole hist_entry callchain,
2032 * skipping the first ones that are before the first visible entry
2033 * and stop when we printed enough lines to fill the screen.
2034 */
2035do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00002036 if (!nd)
2037 return;
2038
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002039 if (offset > 0) {
2040 do {
2041 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002042 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002043 u16 remaining = h->nr_rows - h->row_offset;
2044 if (offset > remaining) {
2045 offset -= remaining;
2046 h->row_offset = 0;
2047 } else {
2048 h->row_offset += offset;
2049 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002050 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002051 break;
2052 }
2053 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002054 nd = hists__filter_entries(rb_hierarchy_next(nd),
2055 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002056 if (nd == NULL)
2057 break;
2058 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002059 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002060 } while (offset != 0);
2061 } else if (offset < 0) {
2062 while (1) {
2063 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002064 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002065 if (first) {
2066 if (-offset > h->row_offset) {
2067 offset += h->row_offset;
2068 h->row_offset = 0;
2069 } else {
2070 h->row_offset += offset;
2071 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002072 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002073 break;
2074 }
2075 } else {
2076 if (-offset > h->nr_rows) {
2077 offset += h->nr_rows;
2078 h->row_offset = 0;
2079 } else {
2080 h->row_offset = h->nr_rows + offset;
2081 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002082 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002083 break;
2084 }
2085 }
2086 }
2087
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002088 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09002089 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002090 if (nd == NULL)
2091 break;
2092 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002093 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002094 if (offset == 0) {
2095 /*
2096 * Last unfiltered hist_entry, check if it is
2097 * unfolded, if it is then we should have
2098 * row_offset at its last entry.
2099 */
2100 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002101 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002102 h->row_offset = h->nr_rows;
2103 break;
2104 }
2105 first = false;
2106 }
2107 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002108 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002109 h = rb_entry(nd, struct hist_entry, rb_node);
2110 h->row_offset = 0;
2111 }
2112}
2113
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002114static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002115 struct hist_entry *he, FILE *fp,
2116 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002117{
Namhyung Kim39ee5332014-08-22 09:13:21 +09002118 struct callchain_print_arg arg = {
2119 .fp = fp,
2120 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002121
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002122 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09002123 hist_browser__fprintf_callchain_entry, &arg,
2124 hist_browser__check_dump_full);
2125 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002126}
2127
2128static int hist_browser__fprintf_entry(struct hist_browser *browser,
2129 struct hist_entry *he, FILE *fp)
2130{
2131 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002132 int printed = 0;
2133 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09002134 struct perf_hpp hpp = {
2135 .buf = s,
2136 .size = sizeof(s),
2137 };
2138 struct perf_hpp_fmt *fmt;
2139 bool first = true;
2140 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002141
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002142 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002143 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002144 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002145 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002146
Jiri Olsaf0786af2016-01-18 10:24:23 +01002147 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002148 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002149 continue;
2150
Namhyung Kim26d8b332014-03-03 16:16:20 +09002151 if (!first) {
2152 ret = scnprintf(hpp.buf, hpp.size, " ");
2153 advance_hpp(&hpp, ret);
2154 } else
2155 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002156
Namhyung Kim26d8b332014-03-03 16:16:20 +09002157 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002158 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002159 advance_hpp(&hpp, ret);
2160 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002161 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002162
2163 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002164 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2165
2166 return printed;
2167}
2168
2169
2170static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2171 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002172 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002173{
2174 char s[8192];
2175 int printed = 0;
2176 char folded_sign = ' ';
2177 struct perf_hpp hpp = {
2178 .buf = s,
2179 .size = sizeof(s),
2180 };
2181 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002182 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002183 bool first = true;
2184 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002185 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002186
2187 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2188
2189 folded_sign = hist_entry__folded(he);
2190 printed += fprintf(fp, "%c", folded_sign);
2191
Namhyung Kim325a6282016-03-09 22:47:00 +09002192 /* the first hpp_list_node is for overhead columns */
2193 fmt_node = list_first_entry(&he->hists->hpp_formats,
2194 struct perf_hpp_list_node, list);
2195 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002196 if (!first) {
2197 ret = scnprintf(hpp.buf, hpp.size, " ");
2198 advance_hpp(&hpp, ret);
2199 } else
2200 first = false;
2201
2202 ret = fmt->entry(fmt, &hpp, he);
2203 advance_hpp(&hpp, ret);
2204 }
2205
2206 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2207 advance_hpp(&hpp, ret);
2208
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002209 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2210 ret = scnprintf(hpp.buf, hpp.size, " ");
2211 advance_hpp(&hpp, ret);
2212
2213 ret = fmt->entry(fmt, &hpp, he);
2214 advance_hpp(&hpp, ret);
2215 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002216
2217 printed += fprintf(fp, "%s\n", rtrim(s));
2218
2219 if (he->leaf && folded_sign == '-') {
2220 printed += hist_browser__fprintf_callchain(browser, he, fp,
2221 he->depth + 1);
2222 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002223
2224 return printed;
2225}
2226
2227static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2228{
Namhyung Kim064f1982013-05-14 11:09:04 +09002229 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002230 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002231 int printed = 0;
2232
2233 while (nd) {
2234 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2235
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002236 if (symbol_conf.report_hierarchy) {
2237 printed += hist_browser__fprintf_hierarchy_entry(browser,
2238 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002239 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002240 } else {
2241 printed += hist_browser__fprintf_entry(browser, h, fp);
2242 }
2243
2244 nd = hists__filter_entries(rb_hierarchy_next(nd),
2245 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002246 }
2247
2248 return printed;
2249}
2250
2251static int hist_browser__dump(struct hist_browser *browser)
2252{
2253 char filename[64];
2254 FILE *fp;
2255
2256 while (1) {
2257 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2258 if (access(filename, F_OK))
2259 break;
2260 /*
2261 * XXX: Just an arbitrary lazy upper limit
2262 */
2263 if (++browser->print_seq == 8192) {
2264 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2265 return -1;
2266 }
2267 }
2268
2269 fp = fopen(filename, "w");
2270 if (fp == NULL) {
2271 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002272 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002273 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002274 return -1;
2275 }
2276
2277 ++browser->print_seq;
2278 hist_browser__fprintf(browser, fp);
2279 fclose(fp);
2280 ui_helpline__fpush("%s written!", filename);
2281
2282 return 0;
2283}
2284
Jiri Olsafcd86422016-06-20 23:58:18 +02002285void hist_browser__init(struct hist_browser *browser,
2286 struct hists *hists)
2287{
2288 struct perf_hpp_fmt *fmt;
2289
2290 browser->hists = hists;
2291 browser->b.refresh = hist_browser__refresh;
2292 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2293 browser->b.seek = ui_browser__hists_seek;
2294 browser->b.use_navkeypressed = true;
2295 browser->show_headers = symbol_conf.show_hist_headers;
2296
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002297 if (symbol_conf.report_hierarchy) {
2298 struct perf_hpp_list_node *fmt_node;
2299
2300 /* count overhead columns (in the first node) */
2301 fmt_node = list_first_entry(&hists->hpp_formats,
2302 struct perf_hpp_list_node, list);
2303 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2304 ++browser->b.columns;
2305
2306 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002307 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002308 } else {
2309 hists__for_each_format(hists, fmt)
2310 ++browser->b.columns;
2311 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002312
2313 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002314}
2315
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002316struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002317{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002318 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002319
Jiri Olsafcd86422016-06-20 23:58:18 +02002320 if (browser)
2321 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002322
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002323 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002324}
2325
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002326static struct hist_browser *
2327perf_evsel_browser__new(struct perf_evsel *evsel,
2328 struct hist_browser_timer *hbt,
2329 struct perf_env *env)
2330{
2331 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2332
2333 if (browser) {
2334 browser->hbt = hbt;
2335 browser->env = env;
2336 browser->title = perf_evsel_browser_title;
2337 }
2338 return browser;
2339}
2340
Jiri Olsadabd2012016-06-20 23:58:14 +02002341void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002342{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002343 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002344}
2345
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002346static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002347{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002348 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002349}
2350
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002351static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002352{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002353 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002354}
2355
Taeung Song1e378eb2014-10-07 16:13:15 +09002356/* Check whether the browser is for 'top' or 'report' */
2357static inline bool is_report_browser(void *timer)
2358{
2359 return timer == NULL;
2360}
2361
Jiri Olsa5b91a862016-06-20 23:58:15 +02002362static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002363 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002364{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002365 struct hist_browser_timer *hbt = browser->hbt;
2366 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002367 char unit;
2368 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002369 const struct dso *dso = hists->dso_filter;
2370 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002371 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002372 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2373 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002374 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002375 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002376 char buf[512];
2377 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002378 char ref[30] = " show reference callgraph, ";
2379 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002380
Namhyung Kimf2148332014-01-14 11:52:48 +09002381 if (symbol_conf.filter_relative) {
2382 nr_samples = hists->stats.nr_non_filtered_samples;
2383 nr_events = hists->stats.total_non_filtered_period;
2384 }
2385
Namhyung Kim759ff492013-03-05 14:53:26 +09002386 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002387 struct perf_evsel *pos;
2388
2389 perf_evsel__group_desc(evsel, buf, buflen);
2390 ev_name = buf;
2391
2392 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002393 struct hists *pos_hists = evsel__hists(pos);
2394
Namhyung Kimf2148332014-01-14 11:52:48 +09002395 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002396 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2397 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002398 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002399 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2400 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002401 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002402 }
2403 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002404
Kan Liang9e207dd2015-08-11 06:30:49 -04002405 if (symbol_conf.show_ref_callgraph &&
2406 strstr(ev_name, "call-graph=no"))
2407 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002408 nr_samples = convert_unit(nr_samples, &unit);
2409 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002410 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2411 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002412
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002413
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002414 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002415 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002416 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002417 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002418 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002419 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002420 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002421 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002422 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002423 } else {
2424 printed += scnprintf(bf + printed, size - printed,
2425 ", Thread: %s",
2426 (thread->comm_set ? thread__comm_str(thread) : ""));
2427 }
2428 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002429 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002430 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002431 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002432 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002433 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002434 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002435 if (!is_report_browser(hbt)) {
2436 struct perf_top *top = hbt->arg;
2437
2438 if (top->zero)
2439 printed += scnprintf(bf + printed, size - printed, " [z]");
2440 }
2441
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002442 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002443}
2444
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002445static inline void free_popup_options(char **options, int n)
2446{
2447 int i;
2448
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002449 for (i = 0; i < n; ++i)
2450 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002451}
2452
Feng Tang341487ab2013-02-03 14:38:20 +08002453/*
2454 * Only runtime switching of perf data file will make "input_name" point
2455 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2456 * whether we need to call free() for current "input_name" during the switch.
2457 */
2458static bool is_input_name_malloced = false;
2459
2460static int switch_data_file(void)
2461{
2462 char *pwd, *options[32], *abs_path[32], *tmp;
2463 DIR *pwd_dir;
2464 int nr_options = 0, choice = -1, ret = -1;
2465 struct dirent *dent;
2466
2467 pwd = getenv("PWD");
2468 if (!pwd)
2469 return ret;
2470
2471 pwd_dir = opendir(pwd);
2472 if (!pwd_dir)
2473 return ret;
2474
2475 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002476 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002477
2478 while ((dent = readdir(pwd_dir))) {
2479 char path[PATH_MAX];
2480 u64 magic;
2481 char *name = dent->d_name;
2482 FILE *file;
2483
2484 if (!(dent->d_type == DT_REG))
2485 continue;
2486
2487 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2488
2489 file = fopen(path, "r");
2490 if (!file)
2491 continue;
2492
2493 if (fread(&magic, 1, 8, file) < 8)
2494 goto close_file_and_continue;
2495
2496 if (is_perf_magic(magic)) {
2497 options[nr_options] = strdup(name);
2498 if (!options[nr_options])
2499 goto close_file_and_continue;
2500
2501 abs_path[nr_options] = strdup(path);
2502 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002503 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002504 ui__warning("Can't search all data files due to memory shortage.\n");
2505 fclose(file);
2506 break;
2507 }
2508
2509 nr_options++;
2510 }
2511
2512close_file_and_continue:
2513 fclose(file);
2514 if (nr_options >= 32) {
2515 ui__warning("Too many perf data files in PWD!\n"
2516 "Only the first 32 files will be listed.\n");
2517 break;
2518 }
2519 }
2520 closedir(pwd_dir);
2521
2522 if (nr_options) {
2523 choice = ui__popup_menu(nr_options, options);
2524 if (choice < nr_options && choice >= 0) {
2525 tmp = strdup(abs_path[choice]);
2526 if (tmp) {
2527 if (is_input_name_malloced)
2528 free((void *)input_name);
2529 input_name = tmp;
2530 is_input_name_malloced = true;
2531 ret = 0;
2532 } else
2533 ui__warning("Data switch failed due to memory shortage!\n");
2534 }
2535 }
2536
2537 free_popup_options(options, nr_options);
2538 free_popup_options(abs_path, nr_options);
2539 return ret;
2540}
2541
Namhyung Kimea7cd592015-04-22 16:18:19 +09002542struct popup_action {
2543 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002544 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002545 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002546
2547 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2548};
2549
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002550static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002551do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002552{
2553 struct perf_evsel *evsel;
2554 struct annotation *notes;
2555 struct hist_entry *he;
2556 int err;
2557
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002558 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002559 return 0;
2560
Namhyung Kimea7cd592015-04-22 16:18:19 +09002561 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002562 if (!notes->src)
2563 return 0;
2564
2565 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002566 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002567 he = hist_browser__selected_entry(browser);
2568 /*
2569 * offer option to annotate the other branch source or target
2570 * (if they exists) when returning from annotate
2571 */
2572 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2573 return 1;
2574
2575 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2576 if (err)
2577 ui_browser__handle_resize(&browser->b);
2578 return 0;
2579}
2580
2581static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002582add_annotate_opt(struct hist_browser *browser __maybe_unused,
2583 struct popup_action *act, char **optstr,
2584 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002585{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002586 if (sym == NULL || map->dso->annotate_warned)
2587 return 0;
2588
2589 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2590 return 0;
2591
2592 act->ms.map = map;
2593 act->ms.sym = sym;
2594 act->fn = do_annotate;
2595 return 1;
2596}
2597
2598static int
2599do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2600{
2601 struct thread *thread = act->thread;
2602
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002603 if ((!hists__has(browser->hists, thread) &&
2604 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002605 return 0;
2606
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002607 if (browser->hists->thread_filter) {
2608 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2609 perf_hpp__set_elide(HISTC_THREAD, false);
2610 thread__zput(browser->hists->thread_filter);
2611 ui_helpline__pop();
2612 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002613 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002614 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2615 thread->comm_set ? thread__comm_str(thread) : "",
2616 thread->tid);
2617 } else {
2618 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2619 thread->comm_set ? thread__comm_str(thread) : "");
2620 }
2621
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002622 browser->hists->thread_filter = thread__get(thread);
2623 perf_hpp__set_elide(HISTC_THREAD, false);
2624 pstack__push(browser->pstack, &browser->hists->thread_filter);
2625 }
2626
2627 hists__filter_by_thread(browser->hists);
2628 hist_browser__reset(browser);
2629 return 0;
2630}
2631
2632static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002633add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2634 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002635{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002636 int ret;
2637
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002638 if ((!hists__has(browser->hists, thread) &&
2639 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002640 return 0;
2641
Jiri Olsafa829112016-05-03 13:54:47 +02002642 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002643 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2644 browser->hists->thread_filter ? "out of" : "into",
2645 thread->comm_set ? thread__comm_str(thread) : "",
2646 thread->tid);
2647 } else {
2648 ret = asprintf(optstr, "Zoom %s %s thread",
2649 browser->hists->thread_filter ? "out of" : "into",
2650 thread->comm_set ? thread__comm_str(thread) : "");
2651 }
2652 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002653 return 0;
2654
2655 act->thread = thread;
2656 act->fn = do_zoom_thread;
2657 return 1;
2658}
2659
2660static int
2661do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2662{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002663 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002664
Jiri Olsa69849fc2016-05-03 13:54:45 +02002665 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002666 return 0;
2667
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002668 if (browser->hists->dso_filter) {
2669 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2670 perf_hpp__set_elide(HISTC_DSO, false);
2671 browser->hists->dso_filter = NULL;
2672 ui_helpline__pop();
2673 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002674 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002675 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2676 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002677 perf_hpp__set_elide(HISTC_DSO, true);
2678 pstack__push(browser->pstack, &browser->hists->dso_filter);
2679 }
2680
2681 hists__filter_by_dso(browser->hists);
2682 hist_browser__reset(browser);
2683 return 0;
2684}
2685
2686static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002687add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002688 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002689{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002690 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002691 return 0;
2692
2693 if (asprintf(optstr, "Zoom %s %s DSO",
2694 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002695 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002696 return 0;
2697
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002698 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002699 act->fn = do_zoom_dso;
2700 return 1;
2701}
2702
2703static int
2704do_browse_map(struct hist_browser *browser __maybe_unused,
2705 struct popup_action *act)
2706{
2707 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002708 return 0;
2709}
2710
2711static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002712add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002713 struct popup_action *act, char **optstr, struct map *map)
2714{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002715 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002716 return 0;
2717
2718 if (asprintf(optstr, "Browse map details") < 0)
2719 return 0;
2720
2721 act->ms.map = map;
2722 act->fn = do_browse_map;
2723 return 1;
2724}
2725
2726static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002727do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002728 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002729{
2730 char script_opt[64];
2731 memset(script_opt, 0, sizeof(script_opt));
2732
Namhyung Kimea7cd592015-04-22 16:18:19 +09002733 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002734 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002735 thread__comm_str(act->thread));
2736 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002737 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002738 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002739 }
2740
2741 script_browse(script_opt);
2742 return 0;
2743}
2744
2745static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002746add_script_opt(struct hist_browser *browser __maybe_unused,
2747 struct popup_action *act, char **optstr,
2748 struct thread *thread, struct symbol *sym)
2749{
2750 if (thread) {
2751 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2752 thread__comm_str(thread)) < 0)
2753 return 0;
2754 } else if (sym) {
2755 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2756 sym->name) < 0)
2757 return 0;
2758 } else {
2759 if (asprintf(optstr, "Run scripts for all samples") < 0)
2760 return 0;
2761 }
2762
2763 act->thread = thread;
2764 act->ms.sym = sym;
2765 act->fn = do_run_script;
2766 return 1;
2767}
2768
2769static int
2770do_switch_data(struct hist_browser *browser __maybe_unused,
2771 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002772{
2773 if (switch_data_file()) {
2774 ui__warning("Won't switch the data files due to\n"
2775 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002776 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002777 }
2778
2779 return K_SWITCH_INPUT_DATA;
2780}
2781
Namhyung Kimea7cd592015-04-22 16:18:19 +09002782static int
2783add_switch_opt(struct hist_browser *browser,
2784 struct popup_action *act, char **optstr)
2785{
2786 if (!is_report_browser(browser->hbt))
2787 return 0;
2788
2789 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2790 return 0;
2791
2792 act->fn = do_switch_data;
2793 return 1;
2794}
2795
2796static int
2797do_exit_browser(struct hist_browser *browser __maybe_unused,
2798 struct popup_action *act __maybe_unused)
2799{
2800 return 0;
2801}
2802
2803static int
2804add_exit_opt(struct hist_browser *browser __maybe_unused,
2805 struct popup_action *act, char **optstr)
2806{
2807 if (asprintf(optstr, "Exit") < 0)
2808 return 0;
2809
2810 act->fn = do_exit_browser;
2811 return 1;
2812}
2813
Kan Liang84734b02015-09-04 10:45:45 -04002814static int
2815do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2816{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002817 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002818 return 0;
2819
Kan Liang84734b02015-09-04 10:45:45 -04002820 if (browser->hists->socket_filter > -1) {
2821 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2822 browser->hists->socket_filter = -1;
2823 perf_hpp__set_elide(HISTC_SOCKET, false);
2824 } else {
2825 browser->hists->socket_filter = act->socket;
2826 perf_hpp__set_elide(HISTC_SOCKET, true);
2827 pstack__push(browser->pstack, &browser->hists->socket_filter);
2828 }
2829
2830 hists__filter_by_socket(browser->hists);
2831 hist_browser__reset(browser);
2832 return 0;
2833}
2834
2835static int
2836add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2837 char **optstr, int socket_id)
2838{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002839 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002840 return 0;
2841
2842 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2843 (browser->hists->socket_filter > -1) ? "out of" : "into",
2844 socket_id) < 0)
2845 return 0;
2846
2847 act->socket = socket_id;
2848 act->fn = do_zoom_socket;
2849 return 1;
2850}
2851
Namhyung Kim112f7612014-04-22 14:05:35 +09002852static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002853{
2854 u64 nr_entries = 0;
2855 struct rb_node *nd = rb_first(&hb->hists->entries);
2856
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002857 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002858 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2859 return;
2860 }
2861
Namhyung Kim14135662013-10-31 10:17:39 +09002862 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002863 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002864 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002865 }
2866
Namhyung Kim112f7612014-04-22 14:05:35 +09002867 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002868 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002869}
Feng Tang341487ab2013-02-03 14:38:20 +08002870
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002871static void hist_browser__update_percent_limit(struct hist_browser *hb,
2872 double percent)
2873{
2874 struct hist_entry *he;
2875 struct rb_node *nd = rb_first(&hb->hists->entries);
2876 u64 total = hists__total_period(hb->hists);
2877 u64 min_callchain_hits = total * (percent / 100);
2878
2879 hb->min_pcnt = callchain_param.min_percent = percent;
2880
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002881 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2882 he = rb_entry(nd, struct hist_entry, rb_node);
2883
Namhyung Kim79dded82016-02-26 21:13:19 +09002884 if (he->has_no_entry) {
2885 he->has_no_entry = false;
2886 he->nr_rows = 0;
2887 }
2888
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002889 if (!he->leaf || !symbol_conf.use_callchain)
2890 goto next;
2891
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002892 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2893 total = he->stat.period;
2894
2895 if (symbol_conf.cumulate_callchain)
2896 total = he->stat_acc->period;
2897
2898 min_callchain_hits = total * (percent / 100);
2899 }
2900
2901 callchain_param.sort(&he->sorted_chain, he->callchain,
2902 min_callchain_hits, &callchain_param);
2903
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002904next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002905 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002906
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002907 /* force to re-evaluate folding state of callchains */
2908 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002909 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002910 }
2911}
2912
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002913static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002914 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002915 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002916 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002917 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002918 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002919{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002920 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002921 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002922 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002923#define MAX_OPTIONS 16
2924 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002925 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002926 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002927 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002928 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002929 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002930
Namhyung Kime8e684a2013-12-26 14:37:58 +09002931#define HIST_BROWSER_HELP_COMMON \
2932 "h/?/F1 Show this window\n" \
2933 "UP/DOWN/PGUP\n" \
2934 "PGDN/SPACE Navigate\n" \
2935 "q/ESC/CTRL+C Exit browser\n\n" \
2936 "For multiple event sessions:\n\n" \
2937 "TAB/UNTAB Switch events\n\n" \
2938 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002939 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2940 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002941 "a Annotate current symbol\n" \
2942 "C Collapse all callchains\n" \
2943 "d Zoom into current DSO\n" \
2944 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002945 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002946 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002947 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002948 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002949 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002950
2951 /* help messages are sorted by lexical order of the hotkey */
2952 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002953 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002954 "P Print histograms to perf.hist.N\n"
2955 "r Run available scripts\n"
2956 "s Switch to another data file in PWD\n"
2957 "t Zoom into current Thread\n"
2958 "V Verbose (DSO names in callchains, etc)\n"
2959 "/ Filter symbol by name";
2960 const char top_help[] = HIST_BROWSER_HELP_COMMON
2961 "P Print histograms to perf.hist.N\n"
2962 "t Zoom into current Thread\n"
2963 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002964 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002965 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002966 "/ Filter symbol by name";
2967
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002968 if (browser == NULL)
2969 return -1;
2970
Namhyung Kimed426912015-05-29 21:53:44 +09002971 /* reset abort key so that it can get Ctrl-C as a key */
2972 SLang_reset_tty();
2973 SLang_init_tty(0, 0, 0);
2974
Namhyung Kim03905042015-11-28 02:32:39 +09002975 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002976 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002977 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002978
Kan Liang84734b02015-09-04 10:45:45 -04002979 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002980 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002981 goto out;
2982
2983 ui_helpline__push(helpline);
2984
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002985 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002986 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002987
Namhyung Kim5b591662014-07-31 14:47:38 +09002988 if (symbol_conf.col_width_list_str)
2989 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2990
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002991 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002992 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002993 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002994 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002995 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002996
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002997 nr_options = 0;
2998
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002999 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003000
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003001 if (browser->he_selection != NULL) {
3002 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003003 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04003004 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003005 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003006 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003007 case K_TAB:
3008 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06003009 if (nr_events == 1)
3010 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003011 /*
3012 * Exit the browser, let hists__browser_tree
3013 * go to the next or previous
3014 */
3015 goto out_free_stack;
3016 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003017 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003018 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003019 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003020 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003021 continue;
3022 }
3023
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003024 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08003025 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003026 browser->selection->map->dso->annotate_warned)
3027 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003028
Namhyung Kimea7cd592015-04-22 16:18:19 +09003029 actions->ms.map = browser->selection->map;
3030 actions->ms.sym = browser->selection->sym;
3031 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003032 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03003033 case 'P':
3034 hist_browser__dump(browser);
3035 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003036 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03003037 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003038 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003039 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003040 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02003041 verbose = (verbose + 1) % 4;
3042 browser->show_dso = verbose > 0;
3043 ui_helpline__fpush("Verbosity level set to %d\n",
3044 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003045 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003046 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003047 actions->thread = thread;
3048 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003049 continue;
Kan Liang84734b02015-09-04 10:45:45 -04003050 case 'S':
3051 actions->socket = socked_id;
3052 do_zoom_socket(browser, actions);
3053 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03003054 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09003055 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03003056 "Please enter the name of symbol you want to see.\n"
3057 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09003058 buf, "ENTER: OK, ESC: Cancel",
3059 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03003060 hists->symbol_filter_str = *buf ? buf : NULL;
3061 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09003062 hist_browser__reset(browser);
3063 }
3064 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08003065 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003066 if (is_report_browser(hbt)) {
3067 actions->thread = NULL;
3068 actions->ms.sym = NULL;
3069 do_run_script(browser, actions);
3070 }
Feng Tangc77d8d72012-11-01 00:00:55 +08003071 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08003072 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003073 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003074 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003075 if (key == K_SWITCH_INPUT_DATA)
3076 goto out_free_stack;
3077 }
Feng Tang341487ab2013-02-03 14:38:20 +08003078 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09003079 case 'i':
3080 /* env->arch is NULL for live-mode (i.e. perf top) */
3081 if (env->arch)
3082 tui__header_window(env);
3083 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09003084 case 'F':
3085 symbol_conf.filter_relative ^= 1;
3086 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09003087 case 'z':
3088 if (!is_report_browser(hbt)) {
3089 struct perf_top *top = hbt->arg;
3090
3091 top->zero = !top->zero;
3092 }
3093 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003094 case 'L':
3095 if (ui_browser__input_window("Percent Limit",
3096 "Please enter the value you want to hide entries under that percent.",
3097 buf, "ENTER: OK, ESC: Cancel",
3098 delay_secs * 2) == K_ENTER) {
3099 char *end;
3100 double new_percent = strtod(buf, &end);
3101
3102 if (new_percent < 0 || new_percent > 100) {
3103 ui_browser__warning(&browser->b, delay_secs * 2,
3104 "Invalid percent: %.2f", new_percent);
3105 continue;
3106 }
3107
3108 hist_browser__update_percent_limit(browser, new_percent);
3109 hist_browser__reset(browser);
3110 }
3111 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003112 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003113 case 'h':
3114 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003115 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003116 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003117 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003118 case K_ENTER:
3119 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003120 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003121 /* menu */
3122 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003123 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003124 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003125 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003126
Namhyung Kim01f00a12015-04-22 16:18:16 +09003127 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003128 /*
3129 * Go back to the perf_evsel_menu__run or other user
3130 */
3131 if (left_exits)
3132 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003133
3134 if (key == K_ESC &&
3135 ui_browser__dialog_yesno(&browser->b,
3136 "Do you really want to exit?"))
3137 goto out_free_stack;
3138
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003139 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003140 }
Namhyung Kim64221842015-04-24 10:15:33 +09003141 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003142 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003143 /*
3144 * No need to set actions->dso here since
3145 * it's just to remove the current filter.
3146 * Ditto for thread below.
3147 */
3148 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003149 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003150 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003151 } else if (top == &browser->hists->socket_filter) {
3152 do_zoom_socket(browser, actions);
3153 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003154 continue;
3155 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003156 case 'q':
3157 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003158 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003159 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003160 if (!is_report_browser(hbt)) {
3161 struct perf_top *top = hbt->arg;
3162
3163 perf_evlist__toggle_enable(top->evlist);
3164 /*
3165 * No need to refresh, resort/decay histogram
3166 * entries if we are not collecting samples:
3167 */
3168 if (top->evlist->enabled) {
3169 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3170 hbt->refresh = delay_secs;
3171 } else {
3172 helpline = "Press 'f' again to re-enable the events";
3173 hbt->refresh = 0;
3174 }
3175 continue;
3176 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003177 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003178 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003179 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003180 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003181 }
3182
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003183 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003184 goto skip_annotation;
3185
Namhyung Kim55369fc2013-04-01 20:35:20 +09003186 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003187 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003188
3189 if (bi == NULL)
3190 goto skip_annotation;
3191
Namhyung Kimea7cd592015-04-22 16:18:19 +09003192 nr_options += add_annotate_opt(browser,
3193 &actions[nr_options],
3194 &options[nr_options],
3195 bi->from.map,
3196 bi->from.sym);
3197 if (bi->to.sym != bi->from.sym)
3198 nr_options += add_annotate_opt(browser,
3199 &actions[nr_options],
3200 &options[nr_options],
3201 bi->to.map,
3202 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003203 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003204 nr_options += add_annotate_opt(browser,
3205 &actions[nr_options],
3206 &options[nr_options],
3207 browser->selection->map,
3208 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003209 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003210skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003211 nr_options += add_thread_opt(browser, &actions[nr_options],
3212 &options[nr_options], thread);
3213 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003214 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003215 nr_options += add_map_opt(browser, &actions[nr_options],
3216 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003217 browser->selection ?
3218 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003219 nr_options += add_socket_opt(browser, &actions[nr_options],
3220 &options[nr_options],
3221 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003222 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003223 if (!is_report_browser(hbt))
3224 goto skip_scripting;
3225
Feng Tangcdbab7c2012-10-30 11:56:06 +08003226 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003227 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003228 nr_options += add_script_opt(browser,
3229 &actions[nr_options],
3230 &options[nr_options],
3231 thread, NULL);
3232 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003233 /*
3234 * Note that browser->selection != NULL
3235 * when browser->he_selection is not NULL,
3236 * so we don't need to check browser->selection
3237 * before fetching browser->selection->sym like what
3238 * we do before fetching browser->selection->map.
3239 *
3240 * See hist_browser__show_entry.
3241 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003242 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003243 nr_options += add_script_opt(browser,
3244 &actions[nr_options],
3245 &options[nr_options],
3246 NULL, browser->selection->sym);
3247 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003248 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003249 nr_options += add_script_opt(browser, &actions[nr_options],
3250 &options[nr_options], NULL, NULL);
3251 nr_options += add_switch_opt(browser, &actions[nr_options],
3252 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003253skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003254 nr_options += add_exit_opt(browser, &actions[nr_options],
3255 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003256
Namhyung Kimea7cd592015-04-22 16:18:19 +09003257 do {
3258 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003259
Namhyung Kimea7cd592015-04-22 16:18:19 +09003260 choice = ui__popup_menu(nr_options, options);
3261 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003262 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003263
3264 act = &actions[choice];
3265 key = act->fn(browser, act);
3266 } while (key == 1);
3267
3268 if (key == K_SWITCH_INPUT_DATA)
3269 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003270 }
3271out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003272 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003273out:
3274 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003275 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003276 return key;
3277}
3278
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003279struct perf_evsel_menu {
3280 struct ui_browser b;
3281 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003282 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003283 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003284 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003285};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003286
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003287static void perf_evsel_menu__write(struct ui_browser *browser,
3288 void *entry, int row)
3289{
3290 struct perf_evsel_menu *menu = container_of(browser,
3291 struct perf_evsel_menu, b);
3292 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003293 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003294 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003295 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003296 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003297 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003298 const char *warn = " ";
3299 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003300
3301 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3302 HE_COLORSET_NORMAL);
3303
Namhyung Kim759ff492013-03-05 14:53:26 +09003304 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003305 struct perf_evsel *pos;
3306
3307 ev_name = perf_evsel__group_name(evsel);
3308
3309 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003310 struct hists *pos_hists = evsel__hists(pos);
3311 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003312 }
3313 }
3314
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003315 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003316 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003317 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003318 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003319
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003320 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003321 if (nr_events != 0) {
3322 menu->lost_events = true;
3323 if (!current_entry)
3324 ui_browser__set_color(browser, HE_COLORSET_TOP);
3325 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003326 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3327 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003328 warn = bf;
3329 }
3330
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003331 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003332
3333 if (current_entry)
3334 menu->selection = evsel;
3335}
3336
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003337static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3338 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003339 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003340{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003341 struct perf_evlist *evlist = menu->b.priv;
3342 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003343 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003344 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003345 int key;
3346
3347 if (ui_browser__show(&menu->b, title,
3348 "ESC: exit, ENTER|->: Browse histograms") < 0)
3349 return -1;
3350
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003351 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003352 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003353
3354 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003355 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003356 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003357
3358 if (!menu->lost_events_warned && menu->lost_events) {
3359 ui_browser__warn_lost_events(&menu->b);
3360 menu->lost_events_warned = true;
3361 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003362 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003363 case K_RIGHT:
3364 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003365 if (!menu->selection)
3366 continue;
3367 pos = menu->selection;
3368browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003369 perf_evlist__set_selected(evlist, pos);
3370 /*
3371 * Give the calling tool a chance to populate the non
3372 * default evsel resorted hists tree.
3373 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003374 if (hbt)
3375 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003376 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003377 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003378 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003379 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003380 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003381 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003382 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003383 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003384 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003385 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003386 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003387 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003388 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003389 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003390 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003391 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003392 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003393 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003394 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003395 case 'q':
3396 case CTRL('c'):
3397 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003398 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003399 default:
3400 continue;
3401 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003402 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003403 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003404 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003405 if (!ui_browser__dialog_yesno(&menu->b,
3406 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003407 continue;
3408 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003409 case 'q':
3410 case CTRL('c'):
3411 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003412 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003413 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003414 }
3415 }
3416
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003417out:
3418 ui_browser__hide(&menu->b);
3419 return key;
3420}
3421
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003422static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003423 void *entry)
3424{
3425 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3426
3427 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3428 return true;
3429
3430 return false;
3431}
3432
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003433static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003434 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003435 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003436 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003437 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003438{
3439 struct perf_evsel *pos;
3440 struct perf_evsel_menu menu = {
3441 .b = {
3442 .entries = &evlist->entries,
3443 .refresh = ui_browser__list_head_refresh,
3444 .seek = ui_browser__list_head_seek,
3445 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003446 .filter = filter_group_entries,
3447 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003448 .priv = evlist,
3449 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003450 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003451 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003452 };
3453
3454 ui_helpline__push("Press ESC to exit");
3455
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003456 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003457 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003458 size_t line_len = strlen(ev_name) + 7;
3459
3460 if (menu.b.width < line_len)
3461 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003462 }
3463
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003464 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003465}
3466
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003467int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003468 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003469 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003470 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003471{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003472 int nr_entries = evlist->nr_entries;
3473
3474single_entry:
3475 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003476 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003477
3478 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003479 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003480 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003481 }
3482
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003483 if (symbol_conf.event_group) {
3484 struct perf_evsel *pos;
3485
3486 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003487 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003488 if (perf_evsel__is_group_leader(pos))
3489 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003490 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003491
3492 if (nr_entries == 1)
3493 goto single_entry;
3494 }
3495
3496 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003497 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003498}