blob: 13dfb0a0bdeb440776b506fd413be307e716e0bf [file] [log] [blame]
Arnaldo Carvalho de Melo76b31a22017-04-18 12:26:44 -03001#include <dirent.h>
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03002#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03003#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <stdlib.h>
6#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03007#include <linux/rbtree.h>
Arnaldo Carvalho de Melob0742e92017-04-18 11:08:10 -03008#include <sys/ttydefaults.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03009
Namhyung Kimaca7a942012-04-04 00:14:26 -070010#include "../../util/evsel.h"
11#include "../../util/evlist.h"
12#include "../../util/hist.h"
13#include "../../util/pstack.h"
14#include "../../util/sort.h"
15#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090016#include "../../util/top.h"
Arnaldo Carvalho de Meloe7ff8922017-04-19 21:34:35 -030017#include "../../util/thread.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090018#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019
Jiri Olsaf7589902016-06-20 23:58:13 +020020#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021#include "../helpline.h"
22#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020023#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030024#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020025#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030026#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030027#include "string2.h"
Arnaldo Carvalho de Melo58db1d62017-04-19 16:05:56 -030028#include "units.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030029
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030030#include "sane_ctype.h"
31
Namhyung Kimf5951d52012-09-03 11:53:09 +090032extern void hist_browser__init_hpp(void);
33
Jiri Olsa5b91a862016-06-20 23:58:15 +020034static int perf_evsel_browser_title(struct hist_browser *browser,
35 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090036static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030037
Namhyung Kimc3b78952014-04-22 15:56:17 +090038static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090039 float min_pcnt);
40
Namhyung Kim268397c2014-04-22 14:49:31 +090041static bool hist_browser__has_filter(struct hist_browser *hb)
42{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010043 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090044}
45
He Kuang4fabf3d2015-03-12 15:21:49 +080046static int hist_browser__get_folding(struct hist_browser *browser)
47{
48 struct rb_node *nd;
49 struct hists *hists = browser->hists;
50 int unfolded_rows = 0;
51
52 for (nd = rb_first(&hists->entries);
53 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090054 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080055 struct hist_entry *he =
56 rb_entry(nd, struct hist_entry, rb_node);
57
Namhyung Kimf5b763f2016-02-25 00:13:43 +090058 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080059 unfolded_rows += he->nr_rows;
60 }
61 return unfolded_rows;
62}
63
Namhyung Kimc3b78952014-04-22 15:56:17 +090064static u32 hist_browser__nr_entries(struct hist_browser *hb)
65{
66 u32 nr_entries;
67
Namhyung Kimf5b763f2016-02-25 00:13:43 +090068 if (symbol_conf.report_hierarchy)
69 nr_entries = hb->nr_hierarchy_entries;
70 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090071 nr_entries = hb->nr_non_filtered_entries;
72 else
73 nr_entries = hb->hists->nr_entries;
74
He Kuang4fabf3d2015-03-12 15:21:49 +080075 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090076 return nr_entries + hb->nr_callchain_rows;
77}
78
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020079static void hist_browser__update_rows(struct hist_browser *hb)
80{
81 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020082 struct hists *hists = hb->hists;
83 struct perf_hpp_list *hpp_list = hists->hpp_list;
84 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020085
Jiri Olsaf8e67102016-08-07 17:28:26 +020086 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020087 browser->rows = browser->height - header_offset;
88 /*
89 * Verify if we were at the last line and that line isn't
90 * visibe because we now show the header line(s).
91 */
92 index_row = browser->index - browser->top_idx;
93 if (index_row >= browser->rows)
94 browser->index -= index_row - browser->rows + 1;
95}
96
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030097static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030098{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030099 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
100
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300102 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
103 /*
104 * FIXME: Just keeping existing behaviour, but this really should be
105 * before updating browser->width, as it will invalidate the
106 * calculation above. Fix this and the fallout in another
107 * changeset.
108 */
109 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200110 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300111}
112
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300113static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
114{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200115 struct hists *hists = browser->hists;
116 struct perf_hpp_list *hpp_list = hists->hpp_list;
117 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200118
Jiri Olsaf8e67102016-08-07 17:28:26 +0200119 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200120 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300121}
122
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300123static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300124{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900125 /*
126 * The hists__remove_entry_filter() already folds non-filtered
127 * entries so we can assume it has 0 callchain rows.
128 */
129 browser->nr_callchain_rows = 0;
130
Namhyung Kim268397c2014-04-22 14:49:31 +0900131 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900132 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300133 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300134 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300135}
136
137static char tree__folded_sign(bool unfolded)
138{
139 return unfolded ? '-' : '+';
140}
141
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300142static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900144 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145}
146
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900149 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300150}
151
Namhyung Kim3698dab2015-05-05 23:55:46 +0900152static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300153{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900154 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300155}
156
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800157static struct inline_node *inline_node__create(struct map *map, u64 ip)
158{
159 struct dso *dso;
160 struct inline_node *node;
161
162 if (map == NULL)
163 return NULL;
164
165 dso = map->dso;
166 if (dso == NULL)
167 return NULL;
168
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800169 node = dso__parse_addr_inlines(dso,
170 map__rip_2objdump(map, ip));
171
172 return node;
173}
174
175static int inline__count_rows(struct inline_node *node)
176{
177 struct inline_list *ilist;
178 int i = 0;
179
180 if (node == NULL)
181 return 0;
182
183 list_for_each_entry(ilist, &node->val, list) {
184 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
185 i++;
186 }
187
188 return i;
189}
190
191static int callchain_list__inline_rows(struct callchain_list *chain)
192{
193 struct inline_node *node;
194 int rows;
195
196 node = inline_node__create(chain->ms.map, chain->ip);
197 if (node == NULL)
198 return 0;
199
200 rows = inline__count_rows(node);
201 inline_node__delete(node);
202 return rows;
203}
204
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300205static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300206{
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800207 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300208 struct rb_node *nd;
209
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300210 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300211 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
212 struct callchain_list *chain;
213 char folded_sign = ' '; /* No children */
214
215 list_for_each_entry(chain, &child->val, list) {
216 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800217
218 if (symbol_conf.inline_name) {
219 inline_rows =
220 callchain_list__inline_rows(chain);
221 n += inline_rows;
222 }
223
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300224 /* We need this because we may not have children */
225 folded_sign = callchain_list__folded(chain);
226 if (folded_sign == '+')
227 break;
228 }
229
230 if (folded_sign == '-') /* Have children and they're unfolded */
231 n += callchain_node__count_rows_rb_tree(child);
232 }
233
234 return n;
235}
236
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900237static int callchain_node__count_flat_rows(struct callchain_node *node)
238{
239 struct callchain_list *chain;
240 char folded_sign = 0;
241 int n = 0;
242
243 list_for_each_entry(chain, &node->parent_val, list) {
244 if (!folded_sign) {
245 /* only check first chain list entry */
246 folded_sign = callchain_list__folded(chain);
247 if (folded_sign == '+')
248 return 1;
249 }
250 n++;
251 }
252
253 list_for_each_entry(chain, &node->val, list) {
254 if (!folded_sign) {
255 /* node->parent_val list might be empty */
256 folded_sign = callchain_list__folded(chain);
257 if (folded_sign == '+')
258 return 1;
259 }
260 n++;
261 }
262
263 return n;
264}
265
Namhyung Kim8c430a32015-11-09 14:45:44 +0900266static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
267{
268 return 1;
269}
270
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300271static int callchain_node__count_rows(struct callchain_node *node)
272{
273 struct callchain_list *chain;
274 bool unfolded = false;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800275 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300276
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900277 if (callchain_param.mode == CHAIN_FLAT)
278 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900279 else if (callchain_param.mode == CHAIN_FOLDED)
280 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900281
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300282 list_for_each_entry(chain, &node->val, list) {
283 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800284 if (symbol_conf.inline_name) {
285 inline_rows = callchain_list__inline_rows(chain);
286 n += inline_rows;
287 }
288
Namhyung Kim3698dab2015-05-05 23:55:46 +0900289 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300290 }
291
292 if (unfolded)
293 n += callchain_node__count_rows_rb_tree(node);
294
295 return n;
296}
297
298static int callchain__count_rows(struct rb_root *chain)
299{
300 struct rb_node *nd;
301 int n = 0;
302
303 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
304 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
305 n += callchain_node__count_rows(node);
306 }
307
308 return n;
309}
310
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900311static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
312 bool include_children)
313{
314 int count = 0;
315 struct rb_node *node;
316 struct hist_entry *child;
317
318 if (he->leaf)
319 return callchain__count_rows(&he->sorted_chain);
320
Namhyung Kim79dded82016-02-26 21:13:19 +0900321 if (he->has_no_entry)
322 return 1;
323
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900324 node = rb_first(&he->hroot_out);
325 while (node) {
326 float percent;
327
328 child = rb_entry(node, struct hist_entry, rb_node);
329 percent = hist_entry__get_percent_limit(child);
330
331 if (!child->filtered && percent >= hb->min_pcnt) {
332 count++;
333
334 if (include_children && child->unfolded)
335 count += hierarchy_count_rows(hb, child, true);
336 }
337
338 node = rb_next(node);
339 }
340 return count;
341}
342
Namhyung Kim3698dab2015-05-05 23:55:46 +0900343static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300344{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900345 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200346 return false;
347
Namhyung Kim3698dab2015-05-05 23:55:46 +0900348 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300349 return false;
350
Namhyung Kim3698dab2015-05-05 23:55:46 +0900351 he->unfolded = !he->unfolded;
352 return true;
353}
354
355static bool callchain_list__toggle_fold(struct callchain_list *cl)
356{
357 if (!cl)
358 return false;
359
360 if (!cl->has_children)
361 return false;
362
363 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300364 return true;
365}
366
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300367static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300368{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300369 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300370
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
373 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300374 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300375
376 list_for_each_entry(chain, &child->val, list) {
377 if (first) {
378 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900379 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300380 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300381 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900382 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300383 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300384 }
385
386 callchain_node__init_have_children_rb_tree(child);
387 }
388}
389
Namhyung Kima7444af2014-11-24 17:13:27 +0900390static void callchain_node__init_have_children(struct callchain_node *node,
391 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392{
393 struct callchain_list *chain;
394
Namhyung Kima7444af2014-11-24 17:13:27 +0900395 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900396 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900397
Andres Freund90989032016-03-30 21:02:45 +0200398 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900399 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900400 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900401 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300402
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300403 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300404}
405
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300406static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300407{
Namhyung Kima7444af2014-11-24 17:13:27 +0900408 struct rb_node *nd = rb_first(root);
409 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300410
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300411 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300412 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900413 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900414 if (callchain_param.mode == CHAIN_FLAT ||
415 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900416 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300417 }
418}
419
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300420static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300421{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900422 if (he->init_have_children)
423 return;
424
425 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900426 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300427 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900428 } else {
429 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300430 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900431
432 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300433}
434
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800435static void hist_entry_init_inline_node(struct hist_entry *he)
436{
437 if (he->inline_node)
438 return;
439
440 he->inline_node = inline_node__create(he->ms.map, he->ip);
441
442 if (he->inline_node == NULL)
443 return;
444
445 he->has_children = true;
446}
447
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300448static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300449{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900450 struct hist_entry *he = browser->he_selection;
451 struct map_symbol *ms = browser->selection;
452 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
453 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300454
Wang Nan4938cf02015-12-07 02:35:44 +0000455 if (!he || !ms)
456 return false;
457
Namhyung Kim3698dab2015-05-05 23:55:46 +0900458 if (ms == &he->ms)
459 has_children = hist_entry__toggle_fold(he);
460 else
461 has_children = callchain_list__toggle_fold(cl);
462
463 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900464 int child_rows = 0;
465
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300466 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900467 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300468
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900469 if (he->leaf)
470 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300471 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900472 browser->nr_hierarchy_entries -= he->nr_rows;
473
474 if (symbol_conf.report_hierarchy)
475 child_rows = hierarchy_count_rows(browser, he, true);
476
477 if (he->unfolded) {
478 if (he->leaf)
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800479 if (he->inline_node)
480 he->nr_rows = inline__count_rows(
481 he->inline_node);
482 else
483 he->nr_rows = callchain__count_rows(
484 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900485 else
486 he->nr_rows = hierarchy_count_rows(browser, he, false);
487
488 /* account grand children */
489 if (symbol_conf.report_hierarchy)
490 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900491
492 if (!he->leaf && he->nr_rows == 0) {
493 he->has_no_entry = true;
494 he->nr_rows = 1;
495 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900496 } else {
497 if (symbol_conf.report_hierarchy)
498 browser->b.nr_entries -= child_rows - he->nr_rows;
499
Namhyung Kim79dded82016-02-26 21:13:19 +0900500 if (he->has_no_entry)
501 he->has_no_entry = false;
502
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300503 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900504 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900505
506 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900507
508 if (he->leaf)
509 browser->nr_callchain_rows += he->nr_rows;
510 else
511 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300512
513 return true;
514 }
515
516 /* If it doesn't have children, no toggling performed */
517 return false;
518}
519
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300520static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300521{
522 int n = 0;
523 struct rb_node *nd;
524
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300525 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300526 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
527 struct callchain_list *chain;
528 bool has_children = false;
529
530 list_for_each_entry(chain, &child->val, list) {
531 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900532 callchain_list__set_folding(chain, unfold);
533 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300534 }
535
536 if (has_children)
537 n += callchain_node__set_folding_rb_tree(child, unfold);
538 }
539
540 return n;
541}
542
543static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
544{
545 struct callchain_list *chain;
546 bool has_children = false;
547 int n = 0;
548
549 list_for_each_entry(chain, &node->val, list) {
550 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900551 callchain_list__set_folding(chain, unfold);
552 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300553 }
554
555 if (has_children)
556 n += callchain_node__set_folding_rb_tree(node, unfold);
557
558 return n;
559}
560
561static int callchain__set_folding(struct rb_root *chain, bool unfold)
562{
563 struct rb_node *nd;
564 int n = 0;
565
566 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
567 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
568 n += callchain_node__set_folding(node, unfold);
569 }
570
571 return n;
572}
573
Namhyung Kim492b1012016-02-25 00:13:44 +0900574static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
575 bool unfold __maybe_unused)
576{
577 float percent;
578 struct rb_node *nd;
579 struct hist_entry *child;
580 int n = 0;
581
582 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
583 child = rb_entry(nd, struct hist_entry, rb_node);
584 percent = hist_entry__get_percent_limit(child);
585 if (!child->filtered && percent >= hb->min_pcnt)
586 n++;
587 }
588
589 return n;
590}
591
Jiri Olsab33f9222017-01-20 10:20:29 +0100592static void __hist_entry__set_folding(struct hist_entry *he,
593 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300594{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300595 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900596 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300597
Namhyung Kim3698dab2015-05-05 23:55:46 +0900598 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900599 int n;
600
601 if (he->leaf)
602 n = callchain__set_folding(&he->sorted_chain, unfold);
603 else
604 n = hierarchy_set_folding(hb, he, unfold);
605
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300606 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300607 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300608 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300609}
610
Jiri Olsab33f9222017-01-20 10:20:29 +0100611static void hist_entry__set_folding(struct hist_entry *he,
612 struct hist_browser *browser, bool unfold)
613{
614 double percent;
615
616 percent = hist_entry__get_percent_limit(he);
617 if (he->filtered || percent < browser->min_pcnt)
618 return;
619
620 __hist_entry__set_folding(he, browser, unfold);
621
622 if (!he->depth || unfold)
623 browser->nr_hierarchy_entries++;
624 if (he->leaf)
625 browser->nr_callchain_rows += he->nr_rows;
626 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
627 browser->nr_hierarchy_entries++;
628 he->has_no_entry = true;
629 he->nr_rows = 1;
630 } else
631 he->has_no_entry = false;
632}
633
Namhyung Kimc3b78952014-04-22 15:56:17 +0900634static void
635__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300636{
637 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900638 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300639
Namhyung Kim492b1012016-02-25 00:13:44 +0900640 nd = rb_first(&browser->hists->entries);
641 while (nd) {
642 he = rb_entry(nd, struct hist_entry, rb_node);
643
644 /* set folding state even if it's currently folded */
645 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
646
647 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300648 }
649}
650
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300651static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300652{
Namhyung Kim492b1012016-02-25 00:13:44 +0900653 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900654 browser->nr_callchain_rows = 0;
655 __hist_browser__set_folding(browser, unfold);
656
657 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300658 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300659 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300660}
661
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100662static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
663{
664 if (!browser->he_selection)
665 return;
666
667 hist_entry__set_folding(browser->he_selection, browser, unfold);
668 browser->b.nr_entries = hist_browser__nr_entries(browser);
669}
670
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200671static void ui_browser__warn_lost_events(struct ui_browser *browser)
672{
673 ui_browser__warning(browser, 4,
674 "Events are being lost, check IO/CPU overload!\n\n"
675 "You may want to run 'perf' using a RT scheduler policy:\n\n"
676 " perf top -r 80\n\n"
677 "Or reduce the sampling frequency.");
678}
679
Jiri Olsa5b91a862016-06-20 23:58:15 +0200680static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
681{
682 return browser->title ? browser->title(browser, bf, size) : 0;
683}
684
Jiri Olsadabd2012016-06-20 23:58:14 +0200685int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300686{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300687 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300688 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900689 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900690 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300691
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300692 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900693 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300694
Jiri Olsa5b91a862016-06-20 23:58:15 +0200695 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300696
Namhyung Kim090cff32016-01-11 19:53:14 +0900697 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300698 return -1;
699
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300700 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300701 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300702
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300703 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900704 case K_TIMER: {
705 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900706 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900707
Namhyung Kimc6111522016-10-07 14:04:12 +0900708 if (hist_browser__has_filter(browser) ||
709 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900710 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900711
Namhyung Kimc3b78952014-04-22 15:56:17 +0900712 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900713 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200714
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300715 if (browser->hists->stats.nr_lost_warned !=
716 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
717 browser->hists->stats.nr_lost_warned =
718 browser->hists->stats.nr_events[PERF_RECORD_LOST];
719 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200720 }
721
Jiri Olsa5b91a862016-06-20 23:58:15 +0200722 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300723 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300724 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900725 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300726 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300727 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300728 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300729 struct hist_entry, rb_node);
730 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300731 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 -0300732 seq++, browser->b.nr_entries,
733 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300734 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300735 browser->b.index,
736 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300737 h->row_offset, h->nr_rows);
738 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300739 break;
740 case 'C':
741 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300742 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300743 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100744 case 'c':
745 /* Collapse the selected entry. */
746 hist_browser__set_folding_selected(browser, false);
747 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300748 case 'E':
749 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300750 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300751 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100752 case 'e':
753 /* Expand the selected entry. */
754 hist_browser__set_folding_selected(browser, true);
755 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200756 case 'H':
757 browser->show_headers = !browser->show_headers;
758 hist_browser__update_rows(browser);
759 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200760 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300761 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300762 break;
763 /* fall thru */
764 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300765 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300766 }
767 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300768out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300769 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300770 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300771}
772
Namhyung Kim39ee5332014-08-22 09:13:21 +0900773struct callchain_print_arg {
774 /* for hists browser */
775 off_t row_offset;
776 bool is_current_entry;
777
778 /* for file dump */
779 FILE *fp;
780 int printed;
781};
782
783typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
784 struct callchain_list *chain,
785 const char *str, int offset,
786 unsigned short row,
787 struct callchain_print_arg *arg);
788
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900789static void hist_browser__show_callchain_entry(struct hist_browser *browser,
790 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900791 const char *str, int offset,
792 unsigned short row,
793 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900794{
795 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900796 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300797 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900798
799 color = HE_COLORSET_NORMAL;
800 width = browser->b.width - (offset + 2);
801 if (ui_browser__is_current_entry(&browser->b, row)) {
802 browser->selection = &chain->ms;
803 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900804 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900805 }
806
807 ui_browser__set_color(&browser->b, color);
808 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300809 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300810 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300811 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300812 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900813}
814
Namhyung Kim39ee5332014-08-22 09:13:21 +0900815static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
816 struct callchain_list *chain,
817 const char *str, int offset,
818 unsigned short row __maybe_unused,
819 struct callchain_print_arg *arg)
820{
821 char folded_sign = callchain_list__folded(chain);
822
823 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
824 folded_sign, str);
825}
826
827typedef bool (*check_output_full_fn)(struct hist_browser *browser,
828 unsigned short row);
829
830static bool hist_browser__check_output_full(struct hist_browser *browser,
831 unsigned short row)
832{
833 return browser->b.rows == row;
834}
835
836static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
837 unsigned short row __maybe_unused)
838{
839 return false;
840}
841
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300842#define LEVEL_OFFSET_STEP 3
843
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800844static int hist_browser__show_inline(struct hist_browser *browser,
845 struct inline_node *node,
846 unsigned short row,
847 int offset)
848{
849 struct inline_list *ilist;
850 char buf[1024];
851 int color, width, first_row;
852
853 first_row = row;
854 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
855 list_for_each_entry(ilist, &node->val, list) {
856 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
857 color = HE_COLORSET_NORMAL;
858 if (ui_browser__is_current_entry(&browser->b, row))
859 color = HE_COLORSET_SELECTED;
860
Milian Wolff5dfa2102017-03-18 22:49:28 +0100861 if (callchain_param.key == CCKEY_ADDRESS ||
862 callchain_param.key == CCKEY_SRCLINE) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800863 if (ilist->filename != NULL)
864 scnprintf(buf, sizeof(buf),
865 "%s:%d (inline)",
866 ilist->filename,
867 ilist->line_nr);
868 else
869 scnprintf(buf, sizeof(buf), "??");
870 } else if (ilist->funcname != NULL)
871 scnprintf(buf, sizeof(buf), "%s (inline)",
872 ilist->funcname);
873 else if (ilist->filename != NULL)
874 scnprintf(buf, sizeof(buf),
875 "%s:%d (inline)",
876 ilist->filename,
877 ilist->line_nr);
878 else
879 scnprintf(buf, sizeof(buf), "??");
880
881 ui_browser__set_color(&browser->b, color);
882 hist_browser__gotorc(browser, row, 0);
883 ui_browser__write_nstring(&browser->b, " ",
884 LEVEL_OFFSET_STEP + offset);
885 ui_browser__write_nstring(&browser->b, buf, width);
886 row++;
887 }
888 }
889
890 return row - first_row;
891}
892
893static size_t show_inline_list(struct hist_browser *browser, struct map *map,
894 u64 ip, int row, int offset)
895{
896 struct inline_node *node;
897 int ret;
898
899 node = inline_node__create(map, ip);
900 if (node == NULL)
901 return 0;
902
903 ret = hist_browser__show_inline(browser, node, row, offset);
904
905 inline_node__delete(node);
906 return ret;
907}
908
Namhyung Kim18bb8382015-11-09 14:45:42 +0900909static int hist_browser__show_callchain_list(struct hist_browser *browser,
910 struct callchain_node *node,
911 struct callchain_list *chain,
912 unsigned short row, u64 total,
913 bool need_percent, int offset,
914 print_callchain_entry_fn print,
915 struct callchain_print_arg *arg)
916{
917 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800918 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900919 const char *str;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800920 int inline_rows = 0, ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900921
922 if (arg->row_offset != 0) {
923 arg->row_offset--;
924 return 0;
925 }
926
927 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800928 alloc_str2 = NULL;
929
Namhyung Kim18bb8382015-11-09 14:45:42 +0900930 str = callchain_list__sym_name(chain, bf, sizeof(bf),
931 browser->show_dso);
932
Jin Yaofef51ec2016-10-31 09:19:53 +0800933 if (symbol_conf.show_branchflag_count) {
Jin Yaoc4ee0622017-08-07 21:05:15 +0800934 callchain_list_counts__printf_value(chain, NULL,
935 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900936
Jin Yaofef51ec2016-10-31 09:19:53 +0800937 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
938 str = "Not enough memory!";
939 else
940 str = alloc_str2;
941 }
942
943 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900944 callchain_node__scnprintf_value(node, buf, sizeof(buf),
945 total);
946
947 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
948 str = "Not enough memory!";
949 else
950 str = alloc_str;
951 }
952
953 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900954 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800955 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800956
957 if (symbol_conf.inline_name) {
958 inline_rows = show_inline_list(browser, chain->ms.map,
959 chain->ip, row + 1, offset);
960 }
961
962 return ret + inline_rows;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900963}
964
Namhyung Kim59c624e2016-01-28 00:40:56 +0900965static bool check_percent_display(struct rb_node *node, u64 parent_total)
966{
967 struct callchain_node *child;
968
969 if (node == NULL)
970 return false;
971
972 if (rb_next(node))
973 return true;
974
975 child = rb_entry(node, struct callchain_node, rb_node);
976 return callchain_cumul_hits(child) != parent_total;
977}
978
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900979static int hist_browser__show_callchain_flat(struct hist_browser *browser,
980 struct rb_root *root,
981 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900982 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900983 print_callchain_entry_fn print,
984 struct callchain_print_arg *arg,
985 check_output_full_fn is_output_full)
986{
987 struct rb_node *node;
988 int first_row = row, offset = LEVEL_OFFSET_STEP;
989 bool need_percent;
990
991 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900992 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900993
994 while (node) {
995 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
996 struct rb_node *next = rb_next(node);
997 struct callchain_list *chain;
998 char folded_sign = ' ';
999 int first = true;
1000 int extra_offset = 0;
1001
1002 list_for_each_entry(chain, &child->parent_val, list) {
1003 bool was_first = first;
1004
1005 if (first)
1006 first = false;
1007 else if (need_percent)
1008 extra_offset = LEVEL_OFFSET_STEP;
1009
1010 folded_sign = callchain_list__folded(chain);
1011
1012 row += hist_browser__show_callchain_list(browser, child,
1013 chain, row, total,
1014 was_first && need_percent,
1015 offset + extra_offset,
1016 print, arg);
1017
1018 if (is_output_full(browser, row))
1019 goto out;
1020
1021 if (folded_sign == '+')
1022 goto next;
1023 }
1024
1025 list_for_each_entry(chain, &child->val, list) {
1026 bool was_first = first;
1027
1028 if (first)
1029 first = false;
1030 else if (need_percent)
1031 extra_offset = LEVEL_OFFSET_STEP;
1032
1033 folded_sign = callchain_list__folded(chain);
1034
1035 row += hist_browser__show_callchain_list(browser, child,
1036 chain, row, total,
1037 was_first && need_percent,
1038 offset + extra_offset,
1039 print, arg);
1040
1041 if (is_output_full(browser, row))
1042 goto out;
1043
1044 if (folded_sign == '+')
1045 break;
1046 }
1047
1048next:
1049 if (is_output_full(browser, row))
1050 break;
1051 node = next;
1052 }
1053out:
1054 return row - first_row;
1055}
1056
Namhyung Kim8c430a32015-11-09 14:45:44 +09001057static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
1058 struct callchain_list *chain,
1059 char *value_str, char *old_str)
1060{
1061 char bf[1024];
1062 const char *str;
1063 char *new;
1064
1065 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1066 browser->show_dso);
1067 if (old_str) {
1068 if (asprintf(&new, "%s%s%s", old_str,
1069 symbol_conf.field_sep ?: ";", str) < 0)
1070 new = NULL;
1071 } else {
1072 if (value_str) {
1073 if (asprintf(&new, "%s %s", value_str, str) < 0)
1074 new = NULL;
1075 } else {
1076 if (asprintf(&new, "%s", str) < 0)
1077 new = NULL;
1078 }
1079 }
1080 return new;
1081}
1082
1083static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1084 struct rb_root *root,
1085 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +09001086 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +09001087 print_callchain_entry_fn print,
1088 struct callchain_print_arg *arg,
1089 check_output_full_fn is_output_full)
1090{
1091 struct rb_node *node;
1092 int first_row = row, offset = LEVEL_OFFSET_STEP;
1093 bool need_percent;
1094
1095 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001096 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001097
1098 while (node) {
1099 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1100 struct rb_node *next = rb_next(node);
1101 struct callchain_list *chain, *first_chain = NULL;
1102 int first = true;
1103 char *value_str = NULL, *value_str_alloc = NULL;
1104 char *chain_str = NULL, *chain_str_alloc = NULL;
1105
1106 if (arg->row_offset != 0) {
1107 arg->row_offset--;
1108 goto next;
1109 }
1110
1111 if (need_percent) {
1112 char buf[64];
1113
1114 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1115 if (asprintf(&value_str, "%s", buf) < 0) {
1116 value_str = (char *)"<...>";
1117 goto do_print;
1118 }
1119 value_str_alloc = value_str;
1120 }
1121
1122 list_for_each_entry(chain, &child->parent_val, list) {
1123 chain_str = hist_browser__folded_callchain_str(browser,
1124 chain, value_str, chain_str);
1125 if (first) {
1126 first = false;
1127 first_chain = chain;
1128 }
1129
1130 if (chain_str == NULL) {
1131 chain_str = (char *)"Not enough memory!";
1132 goto do_print;
1133 }
1134
1135 chain_str_alloc = chain_str;
1136 }
1137
1138 list_for_each_entry(chain, &child->val, list) {
1139 chain_str = hist_browser__folded_callchain_str(browser,
1140 chain, value_str, chain_str);
1141 if (first) {
1142 first = false;
1143 first_chain = chain;
1144 }
1145
1146 if (chain_str == NULL) {
1147 chain_str = (char *)"Not enough memory!";
1148 goto do_print;
1149 }
1150
1151 chain_str_alloc = chain_str;
1152 }
1153
1154do_print:
1155 print(browser, first_chain, chain_str, offset, row++, arg);
1156 free(value_str_alloc);
1157 free(chain_str_alloc);
1158
1159next:
1160 if (is_output_full(browser, row))
1161 break;
1162 node = next;
1163 }
1164
1165 return row - first_row;
1166}
1167
Namhyung Kim0c841c62016-01-28 00:40:54 +09001168static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001169 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001170 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001171 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001172 print_callchain_entry_fn print,
1173 struct callchain_print_arg *arg,
1174 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001175{
1176 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001177 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001178 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001179 u64 percent_total = total;
1180
1181 if (callchain_param.mode == CHAIN_GRAPH_REL)
1182 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001183
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001184 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001185 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001186
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001187 while (node) {
1188 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1189 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001190 struct callchain_list *chain;
1191 char folded_sign = ' ';
1192 int first = true;
1193 int extra_offset = 0;
1194
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001195 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001196 bool was_first = first;
1197
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001198 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001199 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001200 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001202
1203 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204
Namhyung Kim18bb8382015-11-09 14:45:42 +09001205 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001206 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001207 was_first && need_percent,
1208 offset + extra_offset,
1209 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001210
Namhyung Kim18bb8382015-11-09 14:45:42 +09001211 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001212 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001213
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001214 if (folded_sign == '+')
1215 break;
1216 }
1217
1218 if (folded_sign == '-') {
1219 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001220
Namhyung Kim0c841c62016-01-28 00:40:54 +09001221 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001222 new_level, row, total,
1223 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001224 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001225 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001226 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001227 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001228 node = next;
1229 }
1230out:
1231 return row - first_row;
1232}
1233
Namhyung Kim0c841c62016-01-28 00:40:54 +09001234static int hist_browser__show_callchain(struct hist_browser *browser,
1235 struct hist_entry *entry, int level,
1236 unsigned short row,
1237 print_callchain_entry_fn print,
1238 struct callchain_print_arg *arg,
1239 check_output_full_fn is_output_full)
1240{
1241 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001242 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001243 int printed;
1244
Namhyung Kim5eca1042016-01-28 00:40:55 +09001245 if (symbol_conf.cumulate_callchain)
1246 parent_total = entry->stat_acc->period;
1247 else
1248 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001249
1250 if (callchain_param.mode == CHAIN_FLAT) {
1251 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001252 &entry->sorted_chain, row,
1253 total, parent_total, print, arg,
1254 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001255 } else if (callchain_param.mode == CHAIN_FOLDED) {
1256 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001257 &entry->sorted_chain, row,
1258 total, parent_total, print, arg,
1259 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001260 } else {
1261 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001262 &entry->sorted_chain, level, row,
1263 total, parent_total, print, arg,
1264 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001265 }
1266
1267 if (arg->is_current_entry)
1268 browser->he_selection = entry;
1269
1270 return printed;
1271}
1272
Namhyung Kim89701462013-01-22 18:09:38 +09001273struct hpp_arg {
1274 struct ui_browser *b;
1275 char folded_sign;
1276 bool current_entry;
1277};
1278
Jiri Olsa98ba1602016-09-22 17:36:35 +02001279int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001280{
1281 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001282 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001283 va_list args;
1284 double percent;
1285
1286 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001287 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001288 percent = va_arg(args, double);
1289 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001290
Namhyung Kim89701462013-01-22 18:09:38 +09001291 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001292
Namhyung Kimd6751072014-07-31 14:47:36 +09001293 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001294 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001295
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001296 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001297}
1298
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001299#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001300static u64 __hpp_get_##_field(struct hist_entry *he) \
1301{ \
1302 return he->stat._field; \
1303} \
1304 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001305static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001306hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001307 struct perf_hpp *hpp, \
1308 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001309{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001310 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1311 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001312}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001313
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001314#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1315static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1316{ \
1317 return he->stat_acc->_field; \
1318} \
1319 \
1320static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001321hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001322 struct perf_hpp *hpp, \
1323 struct hist_entry *he) \
1324{ \
1325 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001326 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001327 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001328 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001329 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001330 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001331 \
1332 return ret; \
1333 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001334 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1335 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001336}
1337
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001338__HPP_COLOR_PERCENT_FN(overhead, period)
1339__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1340__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1341__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1342__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001343__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001344
1345#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001346#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001347
1348void hist_browser__init_hpp(void)
1349{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001350 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1351 hist_browser__hpp_color_overhead;
1352 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1353 hist_browser__hpp_color_overhead_sys;
1354 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1355 hist_browser__hpp_color_overhead_us;
1356 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1357 hist_browser__hpp_color_overhead_guest_sys;
1358 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1359 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001360 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1361 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001362}
1363
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001364static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001365 struct hist_entry *entry,
1366 unsigned short row)
1367{
Jiri Olsa12400052012-10-13 00:06:16 +02001368 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001369 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001370 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001371 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001372 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001373 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001374 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001375
1376 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001377 browser->he_selection = entry;
1378 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001379 }
1380
1381 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001382 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001383 folded_sign = hist_entry__folded(entry);
1384 }
1385
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001386 if (symbol_conf.inline_name &&
1387 (!entry->has_children)) {
1388 hist_entry_init_inline_node(entry);
1389 folded_sign = hist_entry__folded(entry);
1390 }
1391
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001392 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001393 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001394 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001395 .folded_sign = folded_sign,
1396 .current_entry = current_entry,
1397 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001398 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001399
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001400 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001401
Jiri Olsaf0786af2016-01-18 10:24:23 +01001402 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001403 char s[2048];
1404 struct perf_hpp hpp = {
1405 .buf = s,
1406 .size = sizeof(s),
1407 .ptr = &arg,
1408 };
1409
Namhyung Kim361459f2015-12-23 02:07:08 +09001410 if (perf_hpp__should_skip(fmt, entry->hists) ||
1411 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001412 continue;
1413
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001414 if (current_entry && browser->b.navkeypressed) {
1415 ui_browser__set_color(&browser->b,
1416 HE_COLORSET_SELECTED);
1417 } else {
1418 ui_browser__set_color(&browser->b,
1419 HE_COLORSET_NORMAL);
1420 }
1421
1422 if (first) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001423 if (symbol_conf.use_callchain ||
1424 symbol_conf.inline_name) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001425 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001426 width -= 2;
1427 }
1428 first = false;
1429 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001430 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001431 width -= 2;
1432 }
1433
Jiri Olsa12400052012-10-13 00:06:16 +02001434 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001435 int ret = fmt->color(fmt, &hpp, entry);
1436 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1437 /*
1438 * fmt->color() already used ui_browser to
1439 * print the non alignment bits, skip it (+ret):
1440 */
1441 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001442 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001443 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001444 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001445 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001446 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001447 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001448
1449 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001450 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001451 width += 1;
1452
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001453 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001454
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001455 ++row;
1456 ++printed;
1457 } else
1458 --row_offset;
1459
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001460 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001461 struct callchain_print_arg arg = {
1462 .row_offset = row_offset,
1463 .is_current_entry = current_entry,
1464 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001465
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001466 if (entry->inline_node)
1467 printed += hist_browser__show_inline(browser,
1468 entry->inline_node, row, 0);
1469 else
1470 printed += hist_browser__show_callchain(browser,
1471 entry, 1, row,
1472 hist_browser__show_callchain_entry,
1473 &arg,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001474 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001475 }
1476
1477 return printed;
1478}
1479
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001480static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1481 struct hist_entry *entry,
1482 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001483 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001484{
1485 int printed = 0;
1486 int width = browser->b.width;
1487 char folded_sign = ' ';
1488 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1489 off_t row_offset = entry->row_offset;
1490 bool first = true;
1491 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001492 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001493 struct hpp_arg arg = {
1494 .b = &browser->b,
1495 .current_entry = current_entry,
1496 };
1497 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001498 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001499
1500 if (current_entry) {
1501 browser->he_selection = entry;
1502 browser->selection = &entry->ms;
1503 }
1504
1505 hist_entry__init_have_children(entry);
1506 folded_sign = hist_entry__folded(entry);
1507 arg.folded_sign = folded_sign;
1508
1509 if (entry->leaf && row_offset) {
1510 row_offset--;
1511 goto show_callchain;
1512 }
1513
1514 hist_browser__gotorc(browser, row, 0);
1515
1516 if (current_entry && browser->b.navkeypressed)
1517 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1518 else
1519 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1520
1521 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1522 width -= level * HIERARCHY_INDENT;
1523
Namhyung Kima61a22f2016-03-07 16:44:50 -03001524 /* the first hpp_list_node is for overhead columns */
1525 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1526 struct perf_hpp_list_node, list);
1527 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001528 char s[2048];
1529 struct perf_hpp hpp = {
1530 .buf = s,
1531 .size = sizeof(s),
1532 .ptr = &arg,
1533 };
1534
1535 if (perf_hpp__should_skip(fmt, entry->hists) ||
1536 column++ < browser->b.horiz_scroll)
1537 continue;
1538
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001539 if (current_entry && browser->b.navkeypressed) {
1540 ui_browser__set_color(&browser->b,
1541 HE_COLORSET_SELECTED);
1542 } else {
1543 ui_browser__set_color(&browser->b,
1544 HE_COLORSET_NORMAL);
1545 }
1546
1547 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001548 ui_browser__printf(&browser->b, "%c ", folded_sign);
1549 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001550 first = false;
1551 } else {
1552 ui_browser__printf(&browser->b, " ");
1553 width -= 2;
1554 }
1555
1556 if (fmt->color) {
1557 int ret = fmt->color(fmt, &hpp, entry);
1558 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1559 /*
1560 * fmt->color() already used ui_browser to
1561 * print the non alignment bits, skip it (+ret):
1562 */
1563 ui_browser__printf(&browser->b, "%s", s + ret);
1564 } else {
1565 int ret = fmt->entry(fmt, &hpp, entry);
1566 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1567 ui_browser__printf(&browser->b, "%s", s);
1568 }
1569 width -= hpp.buf - s;
1570 }
1571
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001572 if (!first) {
1573 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1574 width -= hierarchy_indent;
1575 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001576
1577 if (column >= browser->b.horiz_scroll) {
1578 char s[2048];
1579 struct perf_hpp hpp = {
1580 .buf = s,
1581 .size = sizeof(s),
1582 .ptr = &arg,
1583 };
1584
1585 if (current_entry && browser->b.navkeypressed) {
1586 ui_browser__set_color(&browser->b,
1587 HE_COLORSET_SELECTED);
1588 } else {
1589 ui_browser__set_color(&browser->b,
1590 HE_COLORSET_NORMAL);
1591 }
1592
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001593 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001594 if (first) {
1595 ui_browser__printf(&browser->b, "%c ", folded_sign);
1596 first = false;
1597 } else {
1598 ui_browser__write_nstring(&browser->b, "", 2);
1599 }
1600
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001601 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001602
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001603 /*
1604 * No need to call hist_entry__snprintf_alignment()
1605 * since this fmt is always the last column in the
1606 * hierarchy mode.
1607 */
1608 if (fmt->color) {
1609 width -= fmt->color(fmt, &hpp, entry);
1610 } else {
1611 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001612
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001613 width -= fmt->entry(fmt, &hpp, entry);
1614 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001615
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001616 while (isspace(s[i++]))
1617 width++;
1618 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001619 }
1620 }
1621
1622 /* The scroll bar isn't being used */
1623 if (!browser->b.navkeypressed)
1624 width += 1;
1625
1626 ui_browser__write_nstring(&browser->b, "", width);
1627
1628 ++row;
1629 ++printed;
1630
1631show_callchain:
1632 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1633 struct callchain_print_arg carg = {
1634 .row_offset = row_offset,
1635 };
1636
1637 printed += hist_browser__show_callchain(browser, entry,
1638 level + 1, row,
1639 hist_browser__show_callchain_entry, &carg,
1640 hist_browser__check_output_full);
1641 }
1642
1643 return printed;
1644}
1645
Namhyung Kim79dded82016-02-26 21:13:19 +09001646static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001647 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001648{
1649 int width = browser->b.width;
1650 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1651 bool first = true;
1652 int column = 0;
1653 int ret;
1654 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001655 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001656 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001657
1658 if (current_entry) {
1659 browser->he_selection = NULL;
1660 browser->selection = NULL;
1661 }
1662
1663 hist_browser__gotorc(browser, row, 0);
1664
1665 if (current_entry && browser->b.navkeypressed)
1666 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1667 else
1668 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1669
1670 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1671 width -= level * HIERARCHY_INDENT;
1672
Namhyung Kima61a22f2016-03-07 16:44:50 -03001673 /* the first hpp_list_node is for overhead columns */
1674 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1675 struct perf_hpp_list_node, list);
1676 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001677 if (perf_hpp__should_skip(fmt, browser->hists) ||
1678 column++ < browser->b.horiz_scroll)
1679 continue;
1680
Jiri Olsada1b0402016-06-14 20:19:20 +02001681 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001682
1683 if (first) {
1684 /* for folded sign */
1685 first = false;
1686 ret++;
1687 } else {
1688 /* space between columns */
1689 ret += 2;
1690 }
1691
1692 ui_browser__write_nstring(&browser->b, "", ret);
1693 width -= ret;
1694 }
1695
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001696 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1697 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001698
1699 if (column >= browser->b.horiz_scroll) {
1700 char buf[32];
1701
1702 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1703 ui_browser__printf(&browser->b, " %s", buf);
1704 width -= ret + 2;
1705 }
1706
1707 /* The scroll bar isn't being used */
1708 if (!browser->b.navkeypressed)
1709 width += 1;
1710
1711 ui_browser__write_nstring(&browser->b, "", width);
1712 return 1;
1713}
1714
Jiri Olsa81a888f2014-06-14 15:44:52 +02001715static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1716{
1717 advance_hpp(hpp, inc);
1718 return hpp->size <= 0;
1719}
1720
Jiri Olsa69705b32016-08-07 17:28:28 +02001721static int
1722hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1723 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001724{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001725 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001726 struct perf_hpp dummy_hpp = {
1727 .buf = buf,
1728 .size = size,
1729 };
1730 struct perf_hpp_fmt *fmt;
1731 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001732 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001733 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001734
1735 if (symbol_conf.use_callchain) {
1736 ret = scnprintf(buf, size, " ");
1737 if (advance_hpp_check(&dummy_hpp, ret))
1738 return ret;
1739 }
1740
Jiri Olsaf0786af2016-01-18 10:24:23 +01001741 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001742 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001743 continue;
1744
Jiri Olsa29659ab2016-08-07 17:28:30 +02001745 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001746 if (advance_hpp_check(&dummy_hpp, ret))
1747 break;
1748
Jiri Olsa29659ab2016-08-07 17:28:30 +02001749 if (span)
1750 continue;
1751
Jiri Olsa81a888f2014-06-14 15:44:52 +02001752 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1753 if (advance_hpp_check(&dummy_hpp, ret))
1754 break;
1755 }
1756
1757 return ret;
1758}
1759
Namhyung Kimd8b92402016-02-25 00:13:46 +09001760static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1761{
1762 struct hists *hists = browser->hists;
1763 struct perf_hpp dummy_hpp = {
1764 .buf = buf,
1765 .size = size,
1766 };
1767 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001768 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001769 size_t ret = 0;
1770 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001771 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001772 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001773
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001774 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001775 if (advance_hpp_check(&dummy_hpp, ret))
1776 return ret;
1777
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001778 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001779 /* the first hpp_list_node is for overhead columns */
1780 fmt_node = list_first_entry(&hists->hpp_formats,
1781 struct perf_hpp_list_node, list);
1782 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001783 if (column++ < browser->b.horiz_scroll)
1784 continue;
1785
Jiri Olsa29659ab2016-08-07 17:28:30 +02001786 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001787 if (advance_hpp_check(&dummy_hpp, ret))
1788 break;
1789
1790 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1791 if (advance_hpp_check(&dummy_hpp, ret))
1792 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001793
1794 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001795 }
1796
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001797 if (!first_node) {
1798 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1799 indent * HIERARCHY_INDENT, "");
1800 if (advance_hpp_check(&dummy_hpp, ret))
1801 return ret;
1802 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001803
Namhyung Kima61a22f2016-03-07 16:44:50 -03001804 first_node = true;
1805 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1806 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001807 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1808 if (advance_hpp_check(&dummy_hpp, ret))
1809 break;
1810 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001811 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001812
Namhyung Kima61a22f2016-03-07 16:44:50 -03001813 first_col = true;
1814 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1815 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001816
Namhyung Kima61a22f2016-03-07 16:44:50 -03001817 if (perf_hpp__should_skip(fmt, hists))
1818 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001819
Namhyung Kima61a22f2016-03-07 16:44:50 -03001820 if (!first_col) {
1821 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1822 if (advance_hpp_check(&dummy_hpp, ret))
1823 break;
1824 }
1825 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001826
Jiri Olsa29659ab2016-08-07 17:28:30 +02001827 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001828 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001829
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001830 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001831 ret = strlen(start);
1832
1833 if (start != dummy_hpp.buf)
1834 memmove(dummy_hpp.buf, start, ret + 1);
1835
1836 if (advance_hpp_check(&dummy_hpp, ret))
1837 break;
1838 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001839 }
1840
1841 return ret;
1842}
1843
Jiri Olsa01b47702016-06-14 20:19:13 +02001844static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001845{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001846 char headers[1024];
1847
Jiri Olsa01b47702016-06-14 20:19:13 +02001848 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1849 sizeof(headers));
1850
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001851 ui_browser__gotorc(&browser->b, 0, 0);
1852 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001853 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001854}
1855
Jiri Olsa01b47702016-06-14 20:19:13 +02001856static void hists_browser__headers(struct hist_browser *browser)
1857{
Jiri Olsa69705b32016-08-07 17:28:28 +02001858 struct hists *hists = browser->hists;
1859 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001860
Jiri Olsa69705b32016-08-07 17:28:28 +02001861 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001862
Jiri Olsa69705b32016-08-07 17:28:28 +02001863 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1864 char headers[1024];
1865
1866 hists_browser__scnprintf_headers(browser, headers,
1867 sizeof(headers), line);
1868
1869 ui_browser__gotorc(&browser->b, line, 0);
1870 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1871 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1872 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001873}
1874
1875static void hist_browser__show_headers(struct hist_browser *browser)
1876{
1877 if (symbol_conf.report_hierarchy)
1878 hists_browser__hierarchy_headers(browser);
1879 else
1880 hists_browser__headers(browser);
1881}
1882
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001883static void ui_browser__hists_init_top(struct ui_browser *browser)
1884{
1885 if (browser->top == NULL) {
1886 struct hist_browser *hb;
1887
1888 hb = container_of(browser, struct hist_browser, b);
1889 browser->top = rb_first(&hb->hists->entries);
1890 }
1891}
1892
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001893static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001894{
1895 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001896 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001897 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001898 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001899 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001900
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001901 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001902 struct perf_hpp_list *hpp_list = hists->hpp_list;
1903
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001904 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001905 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001906 }
1907
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001908 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001909 hb->he_selection = NULL;
1910 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001911
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001912 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001913 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001914 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001915
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001916 if (h->filtered) {
1917 /* let it move to sibling */
1918 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001919 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001920 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001921
Namhyung Kim14135662013-10-31 10:17:39 +09001922 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001923 if (percent < hb->min_pcnt)
1924 continue;
1925
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001926 if (symbol_conf.report_hierarchy) {
1927 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001928 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001929 if (row == browser->rows)
1930 break;
1931
1932 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001933 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001934 row++;
1935 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001936 } else {
1937 row += hist_browser__show_entry(hb, h, row);
1938 }
1939
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001940 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001941 break;
1942 }
1943
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001944 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001945}
1946
Namhyung Kim064f1982013-05-14 11:09:04 +09001947static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001948 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001949{
1950 while (nd != NULL) {
1951 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001952 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001953
Namhyung Kimc0f15272014-04-16 11:16:33 +09001954 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001955 return nd;
1956
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001957 /*
1958 * If it's filtered, its all children also were filtered.
1959 * So move to sibling node.
1960 */
1961 if (rb_next(nd))
1962 nd = rb_next(nd);
1963 else
1964 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001965 }
1966
1967 return NULL;
1968}
1969
Namhyung Kim064f1982013-05-14 11:09:04 +09001970static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001971 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001972{
1973 while (nd != NULL) {
1974 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001975 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001976
1977 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001978 return nd;
1979
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001980 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001981 }
1982
1983 return NULL;
1984}
1985
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001986static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001987 off_t offset, int whence)
1988{
1989 struct hist_entry *h;
1990 struct rb_node *nd;
1991 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001992 struct hist_browser *hb;
1993
1994 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001995
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001996 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001997 return;
1998
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001999 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03002000
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002001 switch (whence) {
2002 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09002003 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09002004 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002005 break;
2006 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002007 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002008 goto do_offset;
2009 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002010 nd = rb_hierarchy_last(rb_last(browser->entries));
2011 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002012 first = false;
2013 break;
2014 default:
2015 return;
2016 }
2017
2018 /*
2019 * Moves not relative to the first visible entry invalidates its
2020 * row_offset:
2021 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002022 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002023 h->row_offset = 0;
2024
2025 /*
2026 * Here we have to check if nd is expanded (+), if it is we can't go
2027 * the next top level hist_entry, instead we must compute an offset of
2028 * what _not_ to show and not change the first visible entry.
2029 *
2030 * This offset increments when we are going from top to bottom and
2031 * decreases when we're going from bottom to top.
2032 *
2033 * As we don't have backpointers to the top level in the callchains
2034 * structure, we need to always print the whole hist_entry callchain,
2035 * skipping the first ones that are before the first visible entry
2036 * and stop when we printed enough lines to fill the screen.
2037 */
2038do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00002039 if (!nd)
2040 return;
2041
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002042 if (offset > 0) {
2043 do {
2044 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002045 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002046 u16 remaining = h->nr_rows - h->row_offset;
2047 if (offset > remaining) {
2048 offset -= remaining;
2049 h->row_offset = 0;
2050 } else {
2051 h->row_offset += offset;
2052 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002053 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002054 break;
2055 }
2056 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002057 nd = hists__filter_entries(rb_hierarchy_next(nd),
2058 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002059 if (nd == NULL)
2060 break;
2061 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002062 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002063 } while (offset != 0);
2064 } else if (offset < 0) {
2065 while (1) {
2066 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002067 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002068 if (first) {
2069 if (-offset > h->row_offset) {
2070 offset += h->row_offset;
2071 h->row_offset = 0;
2072 } else {
2073 h->row_offset += offset;
2074 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002075 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002076 break;
2077 }
2078 } else {
2079 if (-offset > h->nr_rows) {
2080 offset += h->nr_rows;
2081 h->row_offset = 0;
2082 } else {
2083 h->row_offset = h->nr_rows + offset;
2084 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002085 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002086 break;
2087 }
2088 }
2089 }
2090
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002091 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09002092 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002093 if (nd == NULL)
2094 break;
2095 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002096 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002097 if (offset == 0) {
2098 /*
2099 * Last unfiltered hist_entry, check if it is
2100 * unfolded, if it is then we should have
2101 * row_offset at its last entry.
2102 */
2103 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002104 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002105 h->row_offset = h->nr_rows;
2106 break;
2107 }
2108 first = false;
2109 }
2110 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002111 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002112 h = rb_entry(nd, struct hist_entry, rb_node);
2113 h->row_offset = 0;
2114 }
2115}
2116
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002117static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002118 struct hist_entry *he, FILE *fp,
2119 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002120{
Namhyung Kim39ee5332014-08-22 09:13:21 +09002121 struct callchain_print_arg arg = {
2122 .fp = fp,
2123 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002124
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002125 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09002126 hist_browser__fprintf_callchain_entry, &arg,
2127 hist_browser__check_dump_full);
2128 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002129}
2130
2131static int hist_browser__fprintf_entry(struct hist_browser *browser,
2132 struct hist_entry *he, FILE *fp)
2133{
2134 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002135 int printed = 0;
2136 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09002137 struct perf_hpp hpp = {
2138 .buf = s,
2139 .size = sizeof(s),
2140 };
2141 struct perf_hpp_fmt *fmt;
2142 bool first = true;
2143 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002144
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002145 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002146 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002147 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002148 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002149
Jiri Olsaf0786af2016-01-18 10:24:23 +01002150 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002151 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002152 continue;
2153
Namhyung Kim26d8b332014-03-03 16:16:20 +09002154 if (!first) {
2155 ret = scnprintf(hpp.buf, hpp.size, " ");
2156 advance_hpp(&hpp, ret);
2157 } else
2158 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002159
Namhyung Kim26d8b332014-03-03 16:16:20 +09002160 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002161 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002162 advance_hpp(&hpp, ret);
2163 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002164 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002165
2166 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002167 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2168
2169 return printed;
2170}
2171
2172
2173static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2174 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002175 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002176{
2177 char s[8192];
2178 int printed = 0;
2179 char folded_sign = ' ';
2180 struct perf_hpp hpp = {
2181 .buf = s,
2182 .size = sizeof(s),
2183 };
2184 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002185 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002186 bool first = true;
2187 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002188 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002189
2190 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2191
2192 folded_sign = hist_entry__folded(he);
2193 printed += fprintf(fp, "%c", folded_sign);
2194
Namhyung Kim325a6282016-03-09 22:47:00 +09002195 /* the first hpp_list_node is for overhead columns */
2196 fmt_node = list_first_entry(&he->hists->hpp_formats,
2197 struct perf_hpp_list_node, list);
2198 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002199 if (!first) {
2200 ret = scnprintf(hpp.buf, hpp.size, " ");
2201 advance_hpp(&hpp, ret);
2202 } else
2203 first = false;
2204
2205 ret = fmt->entry(fmt, &hpp, he);
2206 advance_hpp(&hpp, ret);
2207 }
2208
2209 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2210 advance_hpp(&hpp, ret);
2211
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002212 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2213 ret = scnprintf(hpp.buf, hpp.size, " ");
2214 advance_hpp(&hpp, ret);
2215
2216 ret = fmt->entry(fmt, &hpp, he);
2217 advance_hpp(&hpp, ret);
2218 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002219
2220 printed += fprintf(fp, "%s\n", rtrim(s));
2221
2222 if (he->leaf && folded_sign == '-') {
2223 printed += hist_browser__fprintf_callchain(browser, he, fp,
2224 he->depth + 1);
2225 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002226
2227 return printed;
2228}
2229
2230static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2231{
Namhyung Kim064f1982013-05-14 11:09:04 +09002232 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002233 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002234 int printed = 0;
2235
2236 while (nd) {
2237 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2238
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002239 if (symbol_conf.report_hierarchy) {
2240 printed += hist_browser__fprintf_hierarchy_entry(browser,
2241 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002242 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002243 } else {
2244 printed += hist_browser__fprintf_entry(browser, h, fp);
2245 }
2246
2247 nd = hists__filter_entries(rb_hierarchy_next(nd),
2248 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002249 }
2250
2251 return printed;
2252}
2253
2254static int hist_browser__dump(struct hist_browser *browser)
2255{
2256 char filename[64];
2257 FILE *fp;
2258
2259 while (1) {
2260 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2261 if (access(filename, F_OK))
2262 break;
2263 /*
2264 * XXX: Just an arbitrary lazy upper limit
2265 */
2266 if (++browser->print_seq == 8192) {
2267 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2268 return -1;
2269 }
2270 }
2271
2272 fp = fopen(filename, "w");
2273 if (fp == NULL) {
2274 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002275 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002276 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002277 return -1;
2278 }
2279
2280 ++browser->print_seq;
2281 hist_browser__fprintf(browser, fp);
2282 fclose(fp);
2283 ui_helpline__fpush("%s written!", filename);
2284
2285 return 0;
2286}
2287
Jiri Olsafcd86422016-06-20 23:58:18 +02002288void hist_browser__init(struct hist_browser *browser,
2289 struct hists *hists)
2290{
2291 struct perf_hpp_fmt *fmt;
2292
2293 browser->hists = hists;
2294 browser->b.refresh = hist_browser__refresh;
2295 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2296 browser->b.seek = ui_browser__hists_seek;
2297 browser->b.use_navkeypressed = true;
2298 browser->show_headers = symbol_conf.show_hist_headers;
2299
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002300 if (symbol_conf.report_hierarchy) {
2301 struct perf_hpp_list_node *fmt_node;
2302
2303 /* count overhead columns (in the first node) */
2304 fmt_node = list_first_entry(&hists->hpp_formats,
2305 struct perf_hpp_list_node, list);
2306 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2307 ++browser->b.columns;
2308
2309 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002310 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002311 } else {
2312 hists__for_each_format(hists, fmt)
2313 ++browser->b.columns;
2314 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002315
2316 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002317}
2318
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002319struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002320{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002321 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002322
Jiri Olsafcd86422016-06-20 23:58:18 +02002323 if (browser)
2324 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002325
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002326 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002327}
2328
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002329static struct hist_browser *
2330perf_evsel_browser__new(struct perf_evsel *evsel,
2331 struct hist_browser_timer *hbt,
2332 struct perf_env *env)
2333{
2334 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2335
2336 if (browser) {
2337 browser->hbt = hbt;
2338 browser->env = env;
2339 browser->title = perf_evsel_browser_title;
2340 }
2341 return browser;
2342}
2343
Jiri Olsadabd2012016-06-20 23:58:14 +02002344void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002345{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002346 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002347}
2348
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002349static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002350{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002351 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002352}
2353
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002354static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002355{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002356 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002357}
2358
Taeung Song1e378eb2014-10-07 16:13:15 +09002359/* Check whether the browser is for 'top' or 'report' */
2360static inline bool is_report_browser(void *timer)
2361{
2362 return timer == NULL;
2363}
2364
Jiri Olsa5b91a862016-06-20 23:58:15 +02002365static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002366 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002367{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002368 struct hist_browser_timer *hbt = browser->hbt;
2369 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002370 char unit;
2371 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002372 const struct dso *dso = hists->dso_filter;
2373 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002374 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002375 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2376 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002377 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002378 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002379 char buf[512];
2380 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002381 char ref[30] = " show reference callgraph, ";
2382 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002383
Namhyung Kimf2148332014-01-14 11:52:48 +09002384 if (symbol_conf.filter_relative) {
2385 nr_samples = hists->stats.nr_non_filtered_samples;
2386 nr_events = hists->stats.total_non_filtered_period;
2387 }
2388
Namhyung Kim759ff492013-03-05 14:53:26 +09002389 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002390 struct perf_evsel *pos;
2391
2392 perf_evsel__group_desc(evsel, buf, buflen);
2393 ev_name = buf;
2394
2395 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002396 struct hists *pos_hists = evsel__hists(pos);
2397
Namhyung Kimf2148332014-01-14 11:52:48 +09002398 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002399 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2400 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002401 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002402 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2403 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002404 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002405 }
2406 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002407
Kan Liang9e207dd2015-08-11 06:30:49 -04002408 if (symbol_conf.show_ref_callgraph &&
2409 strstr(ev_name, "call-graph=no"))
2410 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002411 nr_samples = convert_unit(nr_samples, &unit);
2412 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002413 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2414 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002415
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002416
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002417 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002418 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002419 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002420 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002421 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002422 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002423 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002424 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002425 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002426 } else {
2427 printed += scnprintf(bf + printed, size - printed,
2428 ", Thread: %s",
2429 (thread->comm_set ? thread__comm_str(thread) : ""));
2430 }
2431 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002432 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002433 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002434 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002435 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002436 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002437 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002438 if (!is_report_browser(hbt)) {
2439 struct perf_top *top = hbt->arg;
2440
2441 if (top->zero)
2442 printed += scnprintf(bf + printed, size - printed, " [z]");
2443 }
2444
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002445 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002446}
2447
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002448static inline void free_popup_options(char **options, int n)
2449{
2450 int i;
2451
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002452 for (i = 0; i < n; ++i)
2453 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002454}
2455
Feng Tang341487ab2013-02-03 14:38:20 +08002456/*
2457 * Only runtime switching of perf data file will make "input_name" point
2458 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2459 * whether we need to call free() for current "input_name" during the switch.
2460 */
2461static bool is_input_name_malloced = false;
2462
2463static int switch_data_file(void)
2464{
2465 char *pwd, *options[32], *abs_path[32], *tmp;
2466 DIR *pwd_dir;
2467 int nr_options = 0, choice = -1, ret = -1;
2468 struct dirent *dent;
2469
2470 pwd = getenv("PWD");
2471 if (!pwd)
2472 return ret;
2473
2474 pwd_dir = opendir(pwd);
2475 if (!pwd_dir)
2476 return ret;
2477
2478 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002479 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002480
2481 while ((dent = readdir(pwd_dir))) {
2482 char path[PATH_MAX];
2483 u64 magic;
2484 char *name = dent->d_name;
2485 FILE *file;
2486
2487 if (!(dent->d_type == DT_REG))
2488 continue;
2489
2490 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2491
2492 file = fopen(path, "r");
2493 if (!file)
2494 continue;
2495
2496 if (fread(&magic, 1, 8, file) < 8)
2497 goto close_file_and_continue;
2498
2499 if (is_perf_magic(magic)) {
2500 options[nr_options] = strdup(name);
2501 if (!options[nr_options])
2502 goto close_file_and_continue;
2503
2504 abs_path[nr_options] = strdup(path);
2505 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002506 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002507 ui__warning("Can't search all data files due to memory shortage.\n");
2508 fclose(file);
2509 break;
2510 }
2511
2512 nr_options++;
2513 }
2514
2515close_file_and_continue:
2516 fclose(file);
2517 if (nr_options >= 32) {
2518 ui__warning("Too many perf data files in PWD!\n"
2519 "Only the first 32 files will be listed.\n");
2520 break;
2521 }
2522 }
2523 closedir(pwd_dir);
2524
2525 if (nr_options) {
2526 choice = ui__popup_menu(nr_options, options);
2527 if (choice < nr_options && choice >= 0) {
2528 tmp = strdup(abs_path[choice]);
2529 if (tmp) {
2530 if (is_input_name_malloced)
2531 free((void *)input_name);
2532 input_name = tmp;
2533 is_input_name_malloced = true;
2534 ret = 0;
2535 } else
2536 ui__warning("Data switch failed due to memory shortage!\n");
2537 }
2538 }
2539
2540 free_popup_options(options, nr_options);
2541 free_popup_options(abs_path, nr_options);
2542 return ret;
2543}
2544
Namhyung Kimea7cd592015-04-22 16:18:19 +09002545struct popup_action {
2546 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002547 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002548 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002549
2550 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2551};
2552
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002553static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002554do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002555{
2556 struct perf_evsel *evsel;
2557 struct annotation *notes;
2558 struct hist_entry *he;
2559 int err;
2560
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002561 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002562 return 0;
2563
Namhyung Kimea7cd592015-04-22 16:18:19 +09002564 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002565 if (!notes->src)
2566 return 0;
2567
2568 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002569 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002570 he = hist_browser__selected_entry(browser);
2571 /*
2572 * offer option to annotate the other branch source or target
2573 * (if they exists) when returning from annotate
2574 */
2575 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2576 return 1;
2577
2578 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2579 if (err)
2580 ui_browser__handle_resize(&browser->b);
2581 return 0;
2582}
2583
2584static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002585add_annotate_opt(struct hist_browser *browser __maybe_unused,
2586 struct popup_action *act, char **optstr,
2587 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002588{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002589 if (sym == NULL || map->dso->annotate_warned)
2590 return 0;
2591
2592 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2593 return 0;
2594
2595 act->ms.map = map;
2596 act->ms.sym = sym;
2597 act->fn = do_annotate;
2598 return 1;
2599}
2600
2601static int
2602do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2603{
2604 struct thread *thread = act->thread;
2605
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002606 if ((!hists__has(browser->hists, thread) &&
2607 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002608 return 0;
2609
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002610 if (browser->hists->thread_filter) {
2611 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2612 perf_hpp__set_elide(HISTC_THREAD, false);
2613 thread__zput(browser->hists->thread_filter);
2614 ui_helpline__pop();
2615 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002616 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002617 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2618 thread->comm_set ? thread__comm_str(thread) : "",
2619 thread->tid);
2620 } else {
2621 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2622 thread->comm_set ? thread__comm_str(thread) : "");
2623 }
2624
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002625 browser->hists->thread_filter = thread__get(thread);
2626 perf_hpp__set_elide(HISTC_THREAD, false);
2627 pstack__push(browser->pstack, &browser->hists->thread_filter);
2628 }
2629
2630 hists__filter_by_thread(browser->hists);
2631 hist_browser__reset(browser);
2632 return 0;
2633}
2634
2635static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002636add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2637 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002638{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002639 int ret;
2640
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002641 if ((!hists__has(browser->hists, thread) &&
2642 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002643 return 0;
2644
Jiri Olsafa829112016-05-03 13:54:47 +02002645 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002646 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2647 browser->hists->thread_filter ? "out of" : "into",
2648 thread->comm_set ? thread__comm_str(thread) : "",
2649 thread->tid);
2650 } else {
2651 ret = asprintf(optstr, "Zoom %s %s thread",
2652 browser->hists->thread_filter ? "out of" : "into",
2653 thread->comm_set ? thread__comm_str(thread) : "");
2654 }
2655 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002656 return 0;
2657
2658 act->thread = thread;
2659 act->fn = do_zoom_thread;
2660 return 1;
2661}
2662
2663static int
2664do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2665{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002666 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002667
Jiri Olsa69849fc2016-05-03 13:54:45 +02002668 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002669 return 0;
2670
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002671 if (browser->hists->dso_filter) {
2672 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2673 perf_hpp__set_elide(HISTC_DSO, false);
2674 browser->hists->dso_filter = NULL;
2675 ui_helpline__pop();
2676 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002677 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002678 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2679 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002680 perf_hpp__set_elide(HISTC_DSO, true);
2681 pstack__push(browser->pstack, &browser->hists->dso_filter);
2682 }
2683
2684 hists__filter_by_dso(browser->hists);
2685 hist_browser__reset(browser);
2686 return 0;
2687}
2688
2689static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002690add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002691 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002692{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002693 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002694 return 0;
2695
2696 if (asprintf(optstr, "Zoom %s %s DSO",
2697 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002698 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002699 return 0;
2700
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002701 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002702 act->fn = do_zoom_dso;
2703 return 1;
2704}
2705
2706static int
2707do_browse_map(struct hist_browser *browser __maybe_unused,
2708 struct popup_action *act)
2709{
2710 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002711 return 0;
2712}
2713
2714static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002715add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002716 struct popup_action *act, char **optstr, struct map *map)
2717{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002718 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002719 return 0;
2720
2721 if (asprintf(optstr, "Browse map details") < 0)
2722 return 0;
2723
2724 act->ms.map = map;
2725 act->fn = do_browse_map;
2726 return 1;
2727}
2728
2729static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002730do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002731 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002732{
2733 char script_opt[64];
2734 memset(script_opt, 0, sizeof(script_opt));
2735
Namhyung Kimea7cd592015-04-22 16:18:19 +09002736 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002737 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002738 thread__comm_str(act->thread));
2739 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002740 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002741 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002742 }
2743
2744 script_browse(script_opt);
2745 return 0;
2746}
2747
2748static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002749add_script_opt(struct hist_browser *browser __maybe_unused,
2750 struct popup_action *act, char **optstr,
2751 struct thread *thread, struct symbol *sym)
2752{
2753 if (thread) {
2754 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2755 thread__comm_str(thread)) < 0)
2756 return 0;
2757 } else if (sym) {
2758 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2759 sym->name) < 0)
2760 return 0;
2761 } else {
2762 if (asprintf(optstr, "Run scripts for all samples") < 0)
2763 return 0;
2764 }
2765
2766 act->thread = thread;
2767 act->ms.sym = sym;
2768 act->fn = do_run_script;
2769 return 1;
2770}
2771
2772static int
2773do_switch_data(struct hist_browser *browser __maybe_unused,
2774 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002775{
2776 if (switch_data_file()) {
2777 ui__warning("Won't switch the data files due to\n"
2778 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002779 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002780 }
2781
2782 return K_SWITCH_INPUT_DATA;
2783}
2784
Namhyung Kimea7cd592015-04-22 16:18:19 +09002785static int
2786add_switch_opt(struct hist_browser *browser,
2787 struct popup_action *act, char **optstr)
2788{
2789 if (!is_report_browser(browser->hbt))
2790 return 0;
2791
2792 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2793 return 0;
2794
2795 act->fn = do_switch_data;
2796 return 1;
2797}
2798
2799static int
2800do_exit_browser(struct hist_browser *browser __maybe_unused,
2801 struct popup_action *act __maybe_unused)
2802{
2803 return 0;
2804}
2805
2806static int
2807add_exit_opt(struct hist_browser *browser __maybe_unused,
2808 struct popup_action *act, char **optstr)
2809{
2810 if (asprintf(optstr, "Exit") < 0)
2811 return 0;
2812
2813 act->fn = do_exit_browser;
2814 return 1;
2815}
2816
Kan Liang84734b02015-09-04 10:45:45 -04002817static int
2818do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2819{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002820 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002821 return 0;
2822
Kan Liang84734b02015-09-04 10:45:45 -04002823 if (browser->hists->socket_filter > -1) {
2824 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2825 browser->hists->socket_filter = -1;
2826 perf_hpp__set_elide(HISTC_SOCKET, false);
2827 } else {
2828 browser->hists->socket_filter = act->socket;
2829 perf_hpp__set_elide(HISTC_SOCKET, true);
2830 pstack__push(browser->pstack, &browser->hists->socket_filter);
2831 }
2832
2833 hists__filter_by_socket(browser->hists);
2834 hist_browser__reset(browser);
2835 return 0;
2836}
2837
2838static int
2839add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2840 char **optstr, int socket_id)
2841{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002842 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002843 return 0;
2844
2845 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2846 (browser->hists->socket_filter > -1) ? "out of" : "into",
2847 socket_id) < 0)
2848 return 0;
2849
2850 act->socket = socket_id;
2851 act->fn = do_zoom_socket;
2852 return 1;
2853}
2854
Namhyung Kim112f7612014-04-22 14:05:35 +09002855static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002856{
2857 u64 nr_entries = 0;
2858 struct rb_node *nd = rb_first(&hb->hists->entries);
2859
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002860 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002861 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2862 return;
2863 }
2864
Namhyung Kim14135662013-10-31 10:17:39 +09002865 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002866 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002867 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002868 }
2869
Namhyung Kim112f7612014-04-22 14:05:35 +09002870 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002871 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002872}
Feng Tang341487ab2013-02-03 14:38:20 +08002873
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002874static void hist_browser__update_percent_limit(struct hist_browser *hb,
2875 double percent)
2876{
2877 struct hist_entry *he;
2878 struct rb_node *nd = rb_first(&hb->hists->entries);
2879 u64 total = hists__total_period(hb->hists);
2880 u64 min_callchain_hits = total * (percent / 100);
2881
2882 hb->min_pcnt = callchain_param.min_percent = percent;
2883
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002884 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2885 he = rb_entry(nd, struct hist_entry, rb_node);
2886
Namhyung Kim79dded82016-02-26 21:13:19 +09002887 if (he->has_no_entry) {
2888 he->has_no_entry = false;
2889 he->nr_rows = 0;
2890 }
2891
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002892 if (!he->leaf || !symbol_conf.use_callchain)
2893 goto next;
2894
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002895 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2896 total = he->stat.period;
2897
2898 if (symbol_conf.cumulate_callchain)
2899 total = he->stat_acc->period;
2900
2901 min_callchain_hits = total * (percent / 100);
2902 }
2903
2904 callchain_param.sort(&he->sorted_chain, he->callchain,
2905 min_callchain_hits, &callchain_param);
2906
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002907next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002908 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002909
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002910 /* force to re-evaluate folding state of callchains */
2911 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002912 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002913 }
2914}
2915
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002916static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002917 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002918 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002919 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002920 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002921 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002922{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002923 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002924 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002925 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002926#define MAX_OPTIONS 16
2927 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002928 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002929 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002930 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002931 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002932 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002933
Namhyung Kime8e684a2013-12-26 14:37:58 +09002934#define HIST_BROWSER_HELP_COMMON \
2935 "h/?/F1 Show this window\n" \
2936 "UP/DOWN/PGUP\n" \
2937 "PGDN/SPACE Navigate\n" \
2938 "q/ESC/CTRL+C Exit browser\n\n" \
2939 "For multiple event sessions:\n\n" \
2940 "TAB/UNTAB Switch events\n\n" \
2941 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002942 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2943 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002944 "a Annotate current symbol\n" \
2945 "C Collapse all callchains\n" \
2946 "d Zoom into current DSO\n" \
2947 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002948 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002949 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002950 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002951 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002952 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002953
2954 /* help messages are sorted by lexical order of the hotkey */
2955 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002956 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002957 "P Print histograms to perf.hist.N\n"
2958 "r Run available scripts\n"
2959 "s Switch to another data file in PWD\n"
2960 "t Zoom into current Thread\n"
2961 "V Verbose (DSO names in callchains, etc)\n"
2962 "/ Filter symbol by name";
2963 const char top_help[] = HIST_BROWSER_HELP_COMMON
2964 "P Print histograms to perf.hist.N\n"
2965 "t Zoom into current Thread\n"
2966 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002967 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002968 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002969 "/ Filter symbol by name";
2970
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002971 if (browser == NULL)
2972 return -1;
2973
Namhyung Kimed426912015-05-29 21:53:44 +09002974 /* reset abort key so that it can get Ctrl-C as a key */
2975 SLang_reset_tty();
2976 SLang_init_tty(0, 0, 0);
2977
Namhyung Kim03905042015-11-28 02:32:39 +09002978 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002979 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002980 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002981
Kan Liang84734b02015-09-04 10:45:45 -04002982 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002983 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002984 goto out;
2985
2986 ui_helpline__push(helpline);
2987
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002988 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002989 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002990
Namhyung Kim5b591662014-07-31 14:47:38 +09002991 if (symbol_conf.col_width_list_str)
2992 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2993
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002994 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002995 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002996 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002997 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002998 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002999
Stephane Eranian24bff2d2012-03-12 16:13:30 +01003000 nr_options = 0;
3001
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03003002 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003003
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003004 if (browser->he_selection != NULL) {
3005 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003006 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04003007 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003008 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003009 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003010 case K_TAB:
3011 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06003012 if (nr_events == 1)
3013 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003014 /*
3015 * Exit the browser, let hists__browser_tree
3016 * go to the next or previous
3017 */
3018 goto out_free_stack;
3019 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003020 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003021 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003022 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003023 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003024 continue;
3025 }
3026
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003027 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08003028 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003029 browser->selection->map->dso->annotate_warned)
3030 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003031
Namhyung Kimea7cd592015-04-22 16:18:19 +09003032 actions->ms.map = browser->selection->map;
3033 actions->ms.sym = browser->selection->sym;
3034 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003035 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03003036 case 'P':
3037 hist_browser__dump(browser);
3038 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003039 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03003040 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003041 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003042 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003043 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02003044 verbose = (verbose + 1) % 4;
3045 browser->show_dso = verbose > 0;
3046 ui_helpline__fpush("Verbosity level set to %d\n",
3047 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003048 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003049 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003050 actions->thread = thread;
3051 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003052 continue;
Kan Liang84734b02015-09-04 10:45:45 -04003053 case 'S':
3054 actions->socket = socked_id;
3055 do_zoom_socket(browser, actions);
3056 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03003057 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09003058 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03003059 "Please enter the name of symbol you want to see.\n"
3060 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09003061 buf, "ENTER: OK, ESC: Cancel",
3062 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03003063 hists->symbol_filter_str = *buf ? buf : NULL;
3064 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09003065 hist_browser__reset(browser);
3066 }
3067 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08003068 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003069 if (is_report_browser(hbt)) {
3070 actions->thread = NULL;
3071 actions->ms.sym = NULL;
3072 do_run_script(browser, actions);
3073 }
Feng Tangc77d8d72012-11-01 00:00:55 +08003074 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08003075 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003076 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003077 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003078 if (key == K_SWITCH_INPUT_DATA)
3079 goto out_free_stack;
3080 }
Feng Tang341487ab2013-02-03 14:38:20 +08003081 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09003082 case 'i':
3083 /* env->arch is NULL for live-mode (i.e. perf top) */
3084 if (env->arch)
3085 tui__header_window(env);
3086 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09003087 case 'F':
3088 symbol_conf.filter_relative ^= 1;
3089 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09003090 case 'z':
3091 if (!is_report_browser(hbt)) {
3092 struct perf_top *top = hbt->arg;
3093
3094 top->zero = !top->zero;
3095 }
3096 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003097 case 'L':
3098 if (ui_browser__input_window("Percent Limit",
3099 "Please enter the value you want to hide entries under that percent.",
3100 buf, "ENTER: OK, ESC: Cancel",
3101 delay_secs * 2) == K_ENTER) {
3102 char *end;
3103 double new_percent = strtod(buf, &end);
3104
3105 if (new_percent < 0 || new_percent > 100) {
3106 ui_browser__warning(&browser->b, delay_secs * 2,
3107 "Invalid percent: %.2f", new_percent);
3108 continue;
3109 }
3110
3111 hist_browser__update_percent_limit(browser, new_percent);
3112 hist_browser__reset(browser);
3113 }
3114 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003115 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003116 case 'h':
3117 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003118 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003119 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003120 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003121 case K_ENTER:
3122 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003123 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003124 /* menu */
3125 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003126 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003127 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003128 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003129
Namhyung Kim01f00a12015-04-22 16:18:16 +09003130 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003131 /*
3132 * Go back to the perf_evsel_menu__run or other user
3133 */
3134 if (left_exits)
3135 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003136
3137 if (key == K_ESC &&
3138 ui_browser__dialog_yesno(&browser->b,
3139 "Do you really want to exit?"))
3140 goto out_free_stack;
3141
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003142 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003143 }
Namhyung Kim64221842015-04-24 10:15:33 +09003144 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003145 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003146 /*
3147 * No need to set actions->dso here since
3148 * it's just to remove the current filter.
3149 * Ditto for thread below.
3150 */
3151 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003152 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003153 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003154 } else if (top == &browser->hists->socket_filter) {
3155 do_zoom_socket(browser, actions);
3156 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003157 continue;
3158 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003159 case 'q':
3160 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003161 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003162 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003163 if (!is_report_browser(hbt)) {
3164 struct perf_top *top = hbt->arg;
3165
3166 perf_evlist__toggle_enable(top->evlist);
3167 /*
3168 * No need to refresh, resort/decay histogram
3169 * entries if we are not collecting samples:
3170 */
3171 if (top->evlist->enabled) {
3172 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3173 hbt->refresh = delay_secs;
3174 } else {
3175 helpline = "Press 'f' again to re-enable the events";
3176 hbt->refresh = 0;
3177 }
3178 continue;
3179 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003180 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003181 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003182 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003183 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003184 }
3185
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003186 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003187 goto skip_annotation;
3188
Namhyung Kim55369fc2013-04-01 20:35:20 +09003189 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003190 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003191
3192 if (bi == NULL)
3193 goto skip_annotation;
3194
Namhyung Kimea7cd592015-04-22 16:18:19 +09003195 nr_options += add_annotate_opt(browser,
3196 &actions[nr_options],
3197 &options[nr_options],
3198 bi->from.map,
3199 bi->from.sym);
3200 if (bi->to.sym != bi->from.sym)
3201 nr_options += add_annotate_opt(browser,
3202 &actions[nr_options],
3203 &options[nr_options],
3204 bi->to.map,
3205 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003206 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003207 nr_options += add_annotate_opt(browser,
3208 &actions[nr_options],
3209 &options[nr_options],
3210 browser->selection->map,
3211 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003212 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003213skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003214 nr_options += add_thread_opt(browser, &actions[nr_options],
3215 &options[nr_options], thread);
3216 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003217 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003218 nr_options += add_map_opt(browser, &actions[nr_options],
3219 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003220 browser->selection ?
3221 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003222 nr_options += add_socket_opt(browser, &actions[nr_options],
3223 &options[nr_options],
3224 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003225 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003226 if (!is_report_browser(hbt))
3227 goto skip_scripting;
3228
Feng Tangcdbab7c2012-10-30 11:56:06 +08003229 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003230 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003231 nr_options += add_script_opt(browser,
3232 &actions[nr_options],
3233 &options[nr_options],
3234 thread, NULL);
3235 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003236 /*
3237 * Note that browser->selection != NULL
3238 * when browser->he_selection is not NULL,
3239 * so we don't need to check browser->selection
3240 * before fetching browser->selection->sym like what
3241 * we do before fetching browser->selection->map.
3242 *
3243 * See hist_browser__show_entry.
3244 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003245 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003246 nr_options += add_script_opt(browser,
3247 &actions[nr_options],
3248 &options[nr_options],
3249 NULL, browser->selection->sym);
3250 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003251 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003252 nr_options += add_script_opt(browser, &actions[nr_options],
3253 &options[nr_options], NULL, NULL);
3254 nr_options += add_switch_opt(browser, &actions[nr_options],
3255 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003256skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003257 nr_options += add_exit_opt(browser, &actions[nr_options],
3258 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003259
Namhyung Kimea7cd592015-04-22 16:18:19 +09003260 do {
3261 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003262
Namhyung Kimea7cd592015-04-22 16:18:19 +09003263 choice = ui__popup_menu(nr_options, options);
3264 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003265 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003266
3267 act = &actions[choice];
3268 key = act->fn(browser, act);
3269 } while (key == 1);
3270
3271 if (key == K_SWITCH_INPUT_DATA)
3272 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003273 }
3274out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003275 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003276out:
3277 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003278 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003279 return key;
3280}
3281
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003282struct perf_evsel_menu {
3283 struct ui_browser b;
3284 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003285 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003286 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003287 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003288};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003289
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003290static void perf_evsel_menu__write(struct ui_browser *browser,
3291 void *entry, int row)
3292{
3293 struct perf_evsel_menu *menu = container_of(browser,
3294 struct perf_evsel_menu, b);
3295 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003296 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003297 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003298 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003299 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003300 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003301 const char *warn = " ";
3302 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003303
3304 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3305 HE_COLORSET_NORMAL);
3306
Namhyung Kim759ff492013-03-05 14:53:26 +09003307 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003308 struct perf_evsel *pos;
3309
3310 ev_name = perf_evsel__group_name(evsel);
3311
3312 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003313 struct hists *pos_hists = evsel__hists(pos);
3314 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003315 }
3316 }
3317
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003318 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003319 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003320 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003321 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003322
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003323 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003324 if (nr_events != 0) {
3325 menu->lost_events = true;
3326 if (!current_entry)
3327 ui_browser__set_color(browser, HE_COLORSET_TOP);
3328 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003329 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3330 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003331 warn = bf;
3332 }
3333
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003334 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003335
3336 if (current_entry)
3337 menu->selection = evsel;
3338}
3339
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003340static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3341 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003342 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003343{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003344 struct perf_evlist *evlist = menu->b.priv;
3345 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003346 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003347 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003348 int key;
3349
3350 if (ui_browser__show(&menu->b, title,
3351 "ESC: exit, ENTER|->: Browse histograms") < 0)
3352 return -1;
3353
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003354 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003355 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003356
3357 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003358 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003359 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003360
3361 if (!menu->lost_events_warned && menu->lost_events) {
3362 ui_browser__warn_lost_events(&menu->b);
3363 menu->lost_events_warned = true;
3364 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003365 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003366 case K_RIGHT:
3367 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003368 if (!menu->selection)
3369 continue;
3370 pos = menu->selection;
3371browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003372 perf_evlist__set_selected(evlist, pos);
3373 /*
3374 * Give the calling tool a chance to populate the non
3375 * default evsel resorted hists tree.
3376 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003377 if (hbt)
3378 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003379 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003380 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003381 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003382 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003383 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003384 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003385 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003386 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003387 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003388 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003389 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003390 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003391 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003392 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003393 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003394 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003395 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003396 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003397 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003398 case 'q':
3399 case CTRL('c'):
3400 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003401 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003402 default:
3403 continue;
3404 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003405 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003406 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003407 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003408 if (!ui_browser__dialog_yesno(&menu->b,
3409 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003410 continue;
3411 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003412 case 'q':
3413 case CTRL('c'):
3414 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003415 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003416 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003417 }
3418 }
3419
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003420out:
3421 ui_browser__hide(&menu->b);
3422 return key;
3423}
3424
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003425static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003426 void *entry)
3427{
3428 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3429
3430 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3431 return true;
3432
3433 return false;
3434}
3435
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003436static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003437 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003438 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003439 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003440 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003441{
3442 struct perf_evsel *pos;
3443 struct perf_evsel_menu menu = {
3444 .b = {
3445 .entries = &evlist->entries,
3446 .refresh = ui_browser__list_head_refresh,
3447 .seek = ui_browser__list_head_seek,
3448 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003449 .filter = filter_group_entries,
3450 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003451 .priv = evlist,
3452 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003453 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003454 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003455 };
3456
3457 ui_helpline__push("Press ESC to exit");
3458
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003459 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003460 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003461 size_t line_len = strlen(ev_name) + 7;
3462
3463 if (menu.b.width < line_len)
3464 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003465 }
3466
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003467 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003468}
3469
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003470int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003471 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003472 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003473 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003474{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003475 int nr_entries = evlist->nr_entries;
3476
3477single_entry:
3478 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003479 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003480
3481 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003482 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003483 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003484 }
3485
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003486 if (symbol_conf.event_group) {
3487 struct perf_evsel *pos;
3488
3489 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003490 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003491 if (perf_evsel__is_group_leader(pos))
3492 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003493 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003494
3495 if (nr_entries == 1)
3496 goto single_entry;
3497 }
3498
3499 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003500 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003501}