blob: 68146f4620a5730028c24c364001ce5e21766aad [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Arnaldo Carvalho de Melo76b31a22017-04-18 12:26:44 -03002#include <dirent.h>
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03003#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03004#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03006#include <stdlib.h>
7#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03008#include <linux/rbtree.h>
Arnaldo Carvalho de Melob0742e92017-04-18 11:08:10 -03009#include <sys/ttydefaults.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030010
Namhyung Kimaca7a942012-04-04 00:14:26 -070011#include "../../util/evsel.h"
12#include "../../util/evlist.h"
13#include "../../util/hist.h"
14#include "../../util/pstack.h"
15#include "../../util/sort.h"
16#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090017#include "../../util/top.h"
Arnaldo Carvalho de Meloe7ff8922017-04-19 21:34:35 -030018#include "../../util/thread.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090019#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030020
Jiri Olsaf7589902016-06-20 23:58:13 +020021#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030022#include "../helpline.h"
23#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020024#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030025#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020026#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030027#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030028#include "string2.h"
Arnaldo Carvalho de Melo58db1d62017-04-19 16:05:56 -030029#include "units.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030030
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030031#include "sane_ctype.h"
32
Namhyung Kimf5951d52012-09-03 11:53:09 +090033extern void hist_browser__init_hpp(void);
34
Jiri Olsa5b91a862016-06-20 23:58:15 +020035static int perf_evsel_browser_title(struct hist_browser *browser,
36 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090037static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030038
Namhyung Kimc3b78952014-04-22 15:56:17 +090039static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090040 float min_pcnt);
41
Namhyung Kim268397c2014-04-22 14:49:31 +090042static bool hist_browser__has_filter(struct hist_browser *hb)
43{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010044 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090045}
46
He Kuang4fabf3d2015-03-12 15:21:49 +080047static int hist_browser__get_folding(struct hist_browser *browser)
48{
49 struct rb_node *nd;
50 struct hists *hists = browser->hists;
51 int unfolded_rows = 0;
52
53 for (nd = rb_first(&hists->entries);
54 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090055 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080056 struct hist_entry *he =
57 rb_entry(nd, struct hist_entry, rb_node);
58
Namhyung Kimf5b763f2016-02-25 00:13:43 +090059 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080060 unfolded_rows += he->nr_rows;
61 }
62 return unfolded_rows;
63}
64
Namhyung Kimc3b78952014-04-22 15:56:17 +090065static u32 hist_browser__nr_entries(struct hist_browser *hb)
66{
67 u32 nr_entries;
68
Namhyung Kimf5b763f2016-02-25 00:13:43 +090069 if (symbol_conf.report_hierarchy)
70 nr_entries = hb->nr_hierarchy_entries;
71 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090072 nr_entries = hb->nr_non_filtered_entries;
73 else
74 nr_entries = hb->hists->nr_entries;
75
He Kuang4fabf3d2015-03-12 15:21:49 +080076 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090077 return nr_entries + hb->nr_callchain_rows;
78}
79
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020080static void hist_browser__update_rows(struct hist_browser *hb)
81{
82 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020083 struct hists *hists = hb->hists;
84 struct perf_hpp_list *hpp_list = hists->hpp_list;
85 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020086
Jiri Olsaf8e67102016-08-07 17:28:26 +020087 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020088 browser->rows = browser->height - header_offset;
89 /*
90 * Verify if we were at the last line and that line isn't
91 * visibe because we now show the header line(s).
92 */
93 index_row = browser->index - browser->top_idx;
94 if (index_row >= browser->rows)
95 browser->index -= index_row - browser->rows + 1;
96}
97
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030098static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030099{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300100 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
101
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300102 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300103 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
104 /*
105 * FIXME: Just keeping existing behaviour, but this really should be
106 * before updating browser->width, as it will invalidate the
107 * calculation above. Fix this and the fallout in another
108 * changeset.
109 */
110 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200111 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300112}
113
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300114static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
115{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200116 struct hists *hists = browser->hists;
117 struct perf_hpp_list *hpp_list = hists->hpp_list;
118 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200119
Jiri Olsaf8e67102016-08-07 17:28:26 +0200120 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200121 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300122}
123
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300124static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300125{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900126 /*
127 * The hists__remove_entry_filter() already folds non-filtered
128 * entries so we can assume it has 0 callchain rows.
129 */
130 browser->nr_callchain_rows = 0;
131
Namhyung Kim268397c2014-04-22 14:49:31 +0900132 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900133 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300134 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300135 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300136}
137
138static char tree__folded_sign(bool unfolded)
139{
140 return unfolded ? '-' : '+';
141}
142
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300143static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900145 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300146}
147
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300148static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300149{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900150 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300151}
152
Namhyung Kim3698dab2015-05-05 23:55:46 +0900153static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300154{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900155 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300156}
157
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300158static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300159{
Milian Wolff2a704fc2017-10-09 22:32:55 +0200160 int n = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300161 struct rb_node *nd;
162
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300163 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300164 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
165 struct callchain_list *chain;
166 char folded_sign = ' '; /* No children */
167
168 list_for_each_entry(chain, &child->val, list) {
169 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800170
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300171 /* We need this because we may not have children */
172 folded_sign = callchain_list__folded(chain);
173 if (folded_sign == '+')
174 break;
175 }
176
177 if (folded_sign == '-') /* Have children and they're unfolded */
178 n += callchain_node__count_rows_rb_tree(child);
179 }
180
181 return n;
182}
183
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900184static int callchain_node__count_flat_rows(struct callchain_node *node)
185{
186 struct callchain_list *chain;
187 char folded_sign = 0;
188 int n = 0;
189
190 list_for_each_entry(chain, &node->parent_val, list) {
191 if (!folded_sign) {
192 /* only check first chain list entry */
193 folded_sign = callchain_list__folded(chain);
194 if (folded_sign == '+')
195 return 1;
196 }
197 n++;
198 }
199
200 list_for_each_entry(chain, &node->val, list) {
201 if (!folded_sign) {
202 /* node->parent_val list might be empty */
203 folded_sign = callchain_list__folded(chain);
204 if (folded_sign == '+')
205 return 1;
206 }
207 n++;
208 }
209
210 return n;
211}
212
Namhyung Kim8c430a32015-11-09 14:45:44 +0900213static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
214{
215 return 1;
216}
217
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300218static int callchain_node__count_rows(struct callchain_node *node)
219{
220 struct callchain_list *chain;
221 bool unfolded = false;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200222 int n = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300223
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900224 if (callchain_param.mode == CHAIN_FLAT)
225 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900226 else if (callchain_param.mode == CHAIN_FOLDED)
227 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900228
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300229 list_for_each_entry(chain, &node->val, list) {
230 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800231
Namhyung Kim3698dab2015-05-05 23:55:46 +0900232 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300233 }
234
235 if (unfolded)
236 n += callchain_node__count_rows_rb_tree(node);
237
238 return n;
239}
240
241static int callchain__count_rows(struct rb_root *chain)
242{
243 struct rb_node *nd;
244 int n = 0;
245
246 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
247 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
248 n += callchain_node__count_rows(node);
249 }
250
251 return n;
252}
253
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900254static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
255 bool include_children)
256{
257 int count = 0;
258 struct rb_node *node;
259 struct hist_entry *child;
260
261 if (he->leaf)
262 return callchain__count_rows(&he->sorted_chain);
263
Namhyung Kim79dded82016-02-26 21:13:19 +0900264 if (he->has_no_entry)
265 return 1;
266
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900267 node = rb_first(&he->hroot_out);
268 while (node) {
269 float percent;
270
271 child = rb_entry(node, struct hist_entry, rb_node);
272 percent = hist_entry__get_percent_limit(child);
273
274 if (!child->filtered && percent >= hb->min_pcnt) {
275 count++;
276
277 if (include_children && child->unfolded)
278 count += hierarchy_count_rows(hb, child, true);
279 }
280
281 node = rb_next(node);
282 }
283 return count;
284}
285
Namhyung Kim3698dab2015-05-05 23:55:46 +0900286static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300287{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900288 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200289 return false;
290
Namhyung Kim3698dab2015-05-05 23:55:46 +0900291 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300292 return false;
293
Namhyung Kim3698dab2015-05-05 23:55:46 +0900294 he->unfolded = !he->unfolded;
295 return true;
296}
297
298static bool callchain_list__toggle_fold(struct callchain_list *cl)
299{
300 if (!cl)
301 return false;
302
303 if (!cl->has_children)
304 return false;
305
306 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300307 return true;
308}
309
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300310static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300311{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300312 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300313
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300314 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300315 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
316 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300317 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300318
319 list_for_each_entry(chain, &child->val, list) {
320 if (first) {
321 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900322 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300323 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300324 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900325 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300326 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300327 }
328
329 callchain_node__init_have_children_rb_tree(child);
330 }
331}
332
Namhyung Kima7444af2014-11-24 17:13:27 +0900333static void callchain_node__init_have_children(struct callchain_node *node,
334 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300335{
336 struct callchain_list *chain;
337
Namhyung Kima7444af2014-11-24 17:13:27 +0900338 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900339 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900340
Andres Freund90989032016-03-30 21:02:45 +0200341 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900342 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900343 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900344 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300345
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300346 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300347}
348
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300349static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300350{
Namhyung Kima7444af2014-11-24 17:13:27 +0900351 struct rb_node *nd = rb_first(root);
352 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300353
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300354 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300355 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900356 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900357 if (callchain_param.mode == CHAIN_FLAT ||
358 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900359 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300360 }
361}
362
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300363static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300364{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900365 if (he->init_have_children)
366 return;
367
368 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900369 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300370 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900371 } else {
372 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300373 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900374
375 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300376}
377
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300378static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300379{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900380 struct hist_entry *he = browser->he_selection;
381 struct map_symbol *ms = browser->selection;
382 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
383 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300384
Wang Nan4938cf02015-12-07 02:35:44 +0000385 if (!he || !ms)
386 return false;
387
Namhyung Kim3698dab2015-05-05 23:55:46 +0900388 if (ms == &he->ms)
389 has_children = hist_entry__toggle_fold(he);
390 else
391 has_children = callchain_list__toggle_fold(cl);
392
393 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900394 int child_rows = 0;
395
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300396 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900397 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300398
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900399 if (he->leaf)
400 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300401 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900402 browser->nr_hierarchy_entries -= he->nr_rows;
403
404 if (symbol_conf.report_hierarchy)
405 child_rows = hierarchy_count_rows(browser, he, true);
406
407 if (he->unfolded) {
408 if (he->leaf)
Milian Wolff2a704fc2017-10-09 22:32:55 +0200409 he->nr_rows = callchain__count_rows(
410 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900411 else
412 he->nr_rows = hierarchy_count_rows(browser, he, false);
413
414 /* account grand children */
415 if (symbol_conf.report_hierarchy)
416 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900417
418 if (!he->leaf && he->nr_rows == 0) {
419 he->has_no_entry = true;
420 he->nr_rows = 1;
421 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900422 } else {
423 if (symbol_conf.report_hierarchy)
424 browser->b.nr_entries -= child_rows - he->nr_rows;
425
Namhyung Kim79dded82016-02-26 21:13:19 +0900426 if (he->has_no_entry)
427 he->has_no_entry = false;
428
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300429 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900430 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900431
432 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900433
434 if (he->leaf)
435 browser->nr_callchain_rows += he->nr_rows;
436 else
437 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300438
439 return true;
440 }
441
442 /* If it doesn't have children, no toggling performed */
443 return false;
444}
445
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300446static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300447{
448 int n = 0;
449 struct rb_node *nd;
450
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300451 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300452 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
453 struct callchain_list *chain;
454 bool has_children = false;
455
456 list_for_each_entry(chain, &child->val, list) {
457 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900458 callchain_list__set_folding(chain, unfold);
459 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300460 }
461
462 if (has_children)
463 n += callchain_node__set_folding_rb_tree(child, unfold);
464 }
465
466 return n;
467}
468
469static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
470{
471 struct callchain_list *chain;
472 bool has_children = false;
473 int n = 0;
474
475 list_for_each_entry(chain, &node->val, list) {
476 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900477 callchain_list__set_folding(chain, unfold);
478 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300479 }
480
481 if (has_children)
482 n += callchain_node__set_folding_rb_tree(node, unfold);
483
484 return n;
485}
486
487static int callchain__set_folding(struct rb_root *chain, bool unfold)
488{
489 struct rb_node *nd;
490 int n = 0;
491
492 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
493 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
494 n += callchain_node__set_folding(node, unfold);
495 }
496
497 return n;
498}
499
Namhyung Kim492b1012016-02-25 00:13:44 +0900500static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
501 bool unfold __maybe_unused)
502{
503 float percent;
504 struct rb_node *nd;
505 struct hist_entry *child;
506 int n = 0;
507
508 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
509 child = rb_entry(nd, struct hist_entry, rb_node);
510 percent = hist_entry__get_percent_limit(child);
511 if (!child->filtered && percent >= hb->min_pcnt)
512 n++;
513 }
514
515 return n;
516}
517
Jiri Olsab33f9222017-01-20 10:20:29 +0100518static void __hist_entry__set_folding(struct hist_entry *he,
519 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300520{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300521 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900522 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300523
Namhyung Kim3698dab2015-05-05 23:55:46 +0900524 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900525 int n;
526
527 if (he->leaf)
528 n = callchain__set_folding(&he->sorted_chain, unfold);
529 else
530 n = hierarchy_set_folding(hb, he, unfold);
531
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300532 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300533 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300534 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300535}
536
Jiri Olsab33f9222017-01-20 10:20:29 +0100537static void hist_entry__set_folding(struct hist_entry *he,
538 struct hist_browser *browser, bool unfold)
539{
540 double percent;
541
542 percent = hist_entry__get_percent_limit(he);
543 if (he->filtered || percent < browser->min_pcnt)
544 return;
545
546 __hist_entry__set_folding(he, browser, unfold);
547
548 if (!he->depth || unfold)
549 browser->nr_hierarchy_entries++;
550 if (he->leaf)
551 browser->nr_callchain_rows += he->nr_rows;
552 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
553 browser->nr_hierarchy_entries++;
554 he->has_no_entry = true;
555 he->nr_rows = 1;
556 } else
557 he->has_no_entry = false;
558}
559
Namhyung Kimc3b78952014-04-22 15:56:17 +0900560static void
561__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300562{
563 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900564 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300565
Namhyung Kim492b1012016-02-25 00:13:44 +0900566 nd = rb_first(&browser->hists->entries);
567 while (nd) {
568 he = rb_entry(nd, struct hist_entry, rb_node);
569
570 /* set folding state even if it's currently folded */
571 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
572
573 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300574 }
575}
576
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300577static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300578{
Namhyung Kim492b1012016-02-25 00:13:44 +0900579 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900580 browser->nr_callchain_rows = 0;
581 __hist_browser__set_folding(browser, unfold);
582
583 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300584 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300585 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300586}
587
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100588static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
589{
590 if (!browser->he_selection)
591 return;
592
593 hist_entry__set_folding(browser->he_selection, browser, unfold);
594 browser->b.nr_entries = hist_browser__nr_entries(browser);
595}
596
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200597static void ui_browser__warn_lost_events(struct ui_browser *browser)
598{
599 ui_browser__warning(browser, 4,
600 "Events are being lost, check IO/CPU overload!\n\n"
601 "You may want to run 'perf' using a RT scheduler policy:\n\n"
602 " perf top -r 80\n\n"
603 "Or reduce the sampling frequency.");
604}
605
Jiri Olsa5b91a862016-06-20 23:58:15 +0200606static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
607{
608 return browser->title ? browser->title(browser, bf, size) : 0;
609}
610
Jiri Olsadabd2012016-06-20 23:58:14 +0200611int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300612{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300613 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300614 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900615 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900616 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300617
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300618 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900619 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300620
Jiri Olsa5b91a862016-06-20 23:58:15 +0200621 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300622
Namhyung Kim090cff32016-01-11 19:53:14 +0900623 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300624 return -1;
625
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300626 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300627 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300628
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300629 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900630 case K_TIMER: {
631 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900632 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900633
Namhyung Kimc6111522016-10-07 14:04:12 +0900634 if (hist_browser__has_filter(browser) ||
635 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900636 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900637
Namhyung Kimc3b78952014-04-22 15:56:17 +0900638 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900639 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200640
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300641 if (browser->hists->stats.nr_lost_warned !=
642 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
643 browser->hists->stats.nr_lost_warned =
644 browser->hists->stats.nr_events[PERF_RECORD_LOST];
645 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200646 }
647
Jiri Olsa5b91a862016-06-20 23:58:15 +0200648 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300649 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300650 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900651 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300652 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300653 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300654 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300655 struct hist_entry, rb_node);
656 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300657 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 -0300658 seq++, browser->b.nr_entries,
659 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300660 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300661 browser->b.index,
662 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300663 h->row_offset, h->nr_rows);
664 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300665 break;
666 case 'C':
667 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300668 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300669 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100670 case 'c':
671 /* Collapse the selected entry. */
672 hist_browser__set_folding_selected(browser, false);
673 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300674 case 'E':
675 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300676 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300677 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100678 case 'e':
679 /* Expand the selected entry. */
680 hist_browser__set_folding_selected(browser, true);
681 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200682 case 'H':
683 browser->show_headers = !browser->show_headers;
684 hist_browser__update_rows(browser);
685 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200686 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300687 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300688 break;
689 /* fall thru */
690 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300691 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300692 }
693 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300694out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300695 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300696 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300697}
698
Namhyung Kim39ee5332014-08-22 09:13:21 +0900699struct callchain_print_arg {
700 /* for hists browser */
701 off_t row_offset;
702 bool is_current_entry;
703
704 /* for file dump */
705 FILE *fp;
706 int printed;
707};
708
709typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
710 struct callchain_list *chain,
711 const char *str, int offset,
712 unsigned short row,
713 struct callchain_print_arg *arg);
714
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900715static void hist_browser__show_callchain_entry(struct hist_browser *browser,
716 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900717 const char *str, int offset,
718 unsigned short row,
719 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900720{
721 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900722 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300723 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900724
725 color = HE_COLORSET_NORMAL;
726 width = browser->b.width - (offset + 2);
727 if (ui_browser__is_current_entry(&browser->b, row)) {
728 browser->selection = &chain->ms;
729 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900730 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900731 }
732
733 ui_browser__set_color(&browser->b, color);
734 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300735 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300736 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300737 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300738 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900739}
740
Namhyung Kim39ee5332014-08-22 09:13:21 +0900741static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
742 struct callchain_list *chain,
743 const char *str, int offset,
744 unsigned short row __maybe_unused,
745 struct callchain_print_arg *arg)
746{
747 char folded_sign = callchain_list__folded(chain);
748
749 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
750 folded_sign, str);
751}
752
753typedef bool (*check_output_full_fn)(struct hist_browser *browser,
754 unsigned short row);
755
756static bool hist_browser__check_output_full(struct hist_browser *browser,
757 unsigned short row)
758{
759 return browser->b.rows == row;
760}
761
762static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
763 unsigned short row __maybe_unused)
764{
765 return false;
766}
767
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300768#define LEVEL_OFFSET_STEP 3
769
Namhyung Kim18bb8382015-11-09 14:45:42 +0900770static int hist_browser__show_callchain_list(struct hist_browser *browser,
771 struct callchain_node *node,
772 struct callchain_list *chain,
773 unsigned short row, u64 total,
774 bool need_percent, int offset,
775 print_callchain_entry_fn print,
776 struct callchain_print_arg *arg)
777{
778 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800779 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900780 const char *str;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200781 int ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900782
783 if (arg->row_offset != 0) {
784 arg->row_offset--;
785 return 0;
786 }
787
788 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800789 alloc_str2 = NULL;
790
Namhyung Kim18bb8382015-11-09 14:45:42 +0900791 str = callchain_list__sym_name(chain, bf, sizeof(bf),
792 browser->show_dso);
793
Jin Yaofef51ec2016-10-31 09:19:53 +0800794 if (symbol_conf.show_branchflag_count) {
Jin Yaoc4ee0622017-08-07 21:05:15 +0800795 callchain_list_counts__printf_value(chain, NULL,
796 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900797
Jin Yaofef51ec2016-10-31 09:19:53 +0800798 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
799 str = "Not enough memory!";
800 else
801 str = alloc_str2;
802 }
803
804 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900805 callchain_node__scnprintf_value(node, buf, sizeof(buf),
806 total);
807
808 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
809 str = "Not enough memory!";
810 else
811 str = alloc_str;
812 }
813
814 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900815 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800816 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800817
Milian Wolff2a704fc2017-10-09 22:32:55 +0200818 return ret;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900819}
820
Namhyung Kim59c624e2016-01-28 00:40:56 +0900821static bool check_percent_display(struct rb_node *node, u64 parent_total)
822{
823 struct callchain_node *child;
824
825 if (node == NULL)
826 return false;
827
828 if (rb_next(node))
829 return true;
830
831 child = rb_entry(node, struct callchain_node, rb_node);
832 return callchain_cumul_hits(child) != parent_total;
833}
834
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900835static int hist_browser__show_callchain_flat(struct hist_browser *browser,
836 struct rb_root *root,
837 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900838 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900839 print_callchain_entry_fn print,
840 struct callchain_print_arg *arg,
841 check_output_full_fn is_output_full)
842{
843 struct rb_node *node;
844 int first_row = row, offset = LEVEL_OFFSET_STEP;
845 bool need_percent;
846
847 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900848 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900849
850 while (node) {
851 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
852 struct rb_node *next = rb_next(node);
853 struct callchain_list *chain;
854 char folded_sign = ' ';
855 int first = true;
856 int extra_offset = 0;
857
858 list_for_each_entry(chain, &child->parent_val, list) {
859 bool was_first = first;
860
861 if (first)
862 first = false;
863 else if (need_percent)
864 extra_offset = LEVEL_OFFSET_STEP;
865
866 folded_sign = callchain_list__folded(chain);
867
868 row += hist_browser__show_callchain_list(browser, child,
869 chain, row, total,
870 was_first && need_percent,
871 offset + extra_offset,
872 print, arg);
873
874 if (is_output_full(browser, row))
875 goto out;
876
877 if (folded_sign == '+')
878 goto next;
879 }
880
881 list_for_each_entry(chain, &child->val, list) {
882 bool was_first = first;
883
884 if (first)
885 first = false;
886 else if (need_percent)
887 extra_offset = LEVEL_OFFSET_STEP;
888
889 folded_sign = callchain_list__folded(chain);
890
891 row += hist_browser__show_callchain_list(browser, child,
892 chain, row, total,
893 was_first && need_percent,
894 offset + extra_offset,
895 print, arg);
896
897 if (is_output_full(browser, row))
898 goto out;
899
900 if (folded_sign == '+')
901 break;
902 }
903
904next:
905 if (is_output_full(browser, row))
906 break;
907 node = next;
908 }
909out:
910 return row - first_row;
911}
912
Namhyung Kim8c430a32015-11-09 14:45:44 +0900913static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
914 struct callchain_list *chain,
915 char *value_str, char *old_str)
916{
917 char bf[1024];
918 const char *str;
919 char *new;
920
921 str = callchain_list__sym_name(chain, bf, sizeof(bf),
922 browser->show_dso);
923 if (old_str) {
924 if (asprintf(&new, "%s%s%s", old_str,
925 symbol_conf.field_sep ?: ";", str) < 0)
926 new = NULL;
927 } else {
928 if (value_str) {
929 if (asprintf(&new, "%s %s", value_str, str) < 0)
930 new = NULL;
931 } else {
932 if (asprintf(&new, "%s", str) < 0)
933 new = NULL;
934 }
935 }
936 return new;
937}
938
939static int hist_browser__show_callchain_folded(struct hist_browser *browser,
940 struct rb_root *root,
941 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900942 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900943 print_callchain_entry_fn print,
944 struct callchain_print_arg *arg,
945 check_output_full_fn is_output_full)
946{
947 struct rb_node *node;
948 int first_row = row, offset = LEVEL_OFFSET_STEP;
949 bool need_percent;
950
951 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900952 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900953
954 while (node) {
955 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
956 struct rb_node *next = rb_next(node);
957 struct callchain_list *chain, *first_chain = NULL;
958 int first = true;
959 char *value_str = NULL, *value_str_alloc = NULL;
960 char *chain_str = NULL, *chain_str_alloc = NULL;
961
962 if (arg->row_offset != 0) {
963 arg->row_offset--;
964 goto next;
965 }
966
967 if (need_percent) {
968 char buf[64];
969
970 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
971 if (asprintf(&value_str, "%s", buf) < 0) {
972 value_str = (char *)"<...>";
973 goto do_print;
974 }
975 value_str_alloc = value_str;
976 }
977
978 list_for_each_entry(chain, &child->parent_val, list) {
979 chain_str = hist_browser__folded_callchain_str(browser,
980 chain, value_str, chain_str);
981 if (first) {
982 first = false;
983 first_chain = chain;
984 }
985
986 if (chain_str == NULL) {
987 chain_str = (char *)"Not enough memory!";
988 goto do_print;
989 }
990
991 chain_str_alloc = chain_str;
992 }
993
994 list_for_each_entry(chain, &child->val, list) {
995 chain_str = hist_browser__folded_callchain_str(browser,
996 chain, value_str, chain_str);
997 if (first) {
998 first = false;
999 first_chain = chain;
1000 }
1001
1002 if (chain_str == NULL) {
1003 chain_str = (char *)"Not enough memory!";
1004 goto do_print;
1005 }
1006
1007 chain_str_alloc = chain_str;
1008 }
1009
1010do_print:
1011 print(browser, first_chain, chain_str, offset, row++, arg);
1012 free(value_str_alloc);
1013 free(chain_str_alloc);
1014
1015next:
1016 if (is_output_full(browser, row))
1017 break;
1018 node = next;
1019 }
1020
1021 return row - first_row;
1022}
1023
Namhyung Kim0c841c62016-01-28 00:40:54 +09001024static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001025 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001026 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001027 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001028 print_callchain_entry_fn print,
1029 struct callchain_print_arg *arg,
1030 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001031{
1032 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001033 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001034 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001035 u64 percent_total = total;
1036
1037 if (callchain_param.mode == CHAIN_GRAPH_REL)
1038 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001039
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001040 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001041 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001042
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001043 while (node) {
1044 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1045 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001046 struct callchain_list *chain;
1047 char folded_sign = ' ';
1048 int first = true;
1049 int extra_offset = 0;
1050
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001051 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001052 bool was_first = first;
1053
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001054 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001055 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001056 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001057 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001058
1059 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001060
Namhyung Kim18bb8382015-11-09 14:45:42 +09001061 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001062 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001063 was_first && need_percent,
1064 offset + extra_offset,
1065 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001066
Namhyung Kim18bb8382015-11-09 14:45:42 +09001067 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001068 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001069
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001070 if (folded_sign == '+')
1071 break;
1072 }
1073
1074 if (folded_sign == '-') {
1075 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001076
Namhyung Kim0c841c62016-01-28 00:40:54 +09001077 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001078 new_level, row, total,
1079 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001080 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001081 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001082 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001083 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001084 node = next;
1085 }
1086out:
1087 return row - first_row;
1088}
1089
Namhyung Kim0c841c62016-01-28 00:40:54 +09001090static int hist_browser__show_callchain(struct hist_browser *browser,
1091 struct hist_entry *entry, int level,
1092 unsigned short row,
1093 print_callchain_entry_fn print,
1094 struct callchain_print_arg *arg,
1095 check_output_full_fn is_output_full)
1096{
1097 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001098 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001099 int printed;
1100
Namhyung Kim5eca1042016-01-28 00:40:55 +09001101 if (symbol_conf.cumulate_callchain)
1102 parent_total = entry->stat_acc->period;
1103 else
1104 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001105
1106 if (callchain_param.mode == CHAIN_FLAT) {
1107 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001108 &entry->sorted_chain, row,
1109 total, parent_total, print, arg,
1110 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001111 } else if (callchain_param.mode == CHAIN_FOLDED) {
1112 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001113 &entry->sorted_chain, row,
1114 total, parent_total, print, arg,
1115 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001116 } else {
1117 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001118 &entry->sorted_chain, level, row,
1119 total, parent_total, print, arg,
1120 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001121 }
1122
1123 if (arg->is_current_entry)
1124 browser->he_selection = entry;
1125
1126 return printed;
1127}
1128
Namhyung Kim89701462013-01-22 18:09:38 +09001129struct hpp_arg {
1130 struct ui_browser *b;
1131 char folded_sign;
1132 bool current_entry;
1133};
1134
Jiri Olsa98ba1602016-09-22 17:36:35 +02001135int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001136{
1137 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd675107c2014-07-31 14:47:36 +09001138 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001139 va_list args;
1140 double percent;
1141
1142 va_start(args, fmt);
Namhyung Kimd675107c2014-07-31 14:47:36 +09001143 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001144 percent = va_arg(args, double);
1145 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001146
Namhyung Kim89701462013-01-22 18:09:38 +09001147 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001148
Namhyung Kimd675107c2014-07-31 14:47:36 +09001149 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001150 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001151
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001152 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001153}
1154
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001155#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001156static u64 __hpp_get_##_field(struct hist_entry *he) \
1157{ \
1158 return he->stat._field; \
1159} \
1160 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001161static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001162hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001163 struct perf_hpp *hpp, \
1164 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001165{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001166 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1167 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001168}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001169
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001170#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1171static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1172{ \
1173 return he->stat_acc->_field; \
1174} \
1175 \
1176static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001177hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001178 struct perf_hpp *hpp, \
1179 struct hist_entry *he) \
1180{ \
1181 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001182 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001183 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd675107c2014-07-31 14:47:36 +09001184 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001185 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001186 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001187 \
1188 return ret; \
1189 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001190 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1191 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001192}
1193
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001194__HPP_COLOR_PERCENT_FN(overhead, period)
1195__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1196__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1197__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1198__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001199__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001200
1201#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001202#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001203
1204void hist_browser__init_hpp(void)
1205{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001206 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1207 hist_browser__hpp_color_overhead;
1208 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1209 hist_browser__hpp_color_overhead_sys;
1210 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1211 hist_browser__hpp_color_overhead_us;
1212 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1213 hist_browser__hpp_color_overhead_guest_sys;
1214 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1215 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001216 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1217 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001218}
1219
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001220static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001221 struct hist_entry *entry,
1222 unsigned short row)
1223{
Jiri Olsa12400052012-10-13 00:06:16 +02001224 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001225 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001226 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001227 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001228 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001229 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001230 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001231
1232 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001233 browser->he_selection = entry;
1234 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001235 }
1236
1237 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001238 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001239 folded_sign = hist_entry__folded(entry);
1240 }
1241
1242 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001243 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001244 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001245 .folded_sign = folded_sign,
1246 .current_entry = current_entry,
1247 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001248 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001249
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001250 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001251
Jiri Olsaf0786af2016-01-18 10:24:23 +01001252 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001253 char s[2048];
1254 struct perf_hpp hpp = {
1255 .buf = s,
1256 .size = sizeof(s),
1257 .ptr = &arg,
1258 };
1259
Namhyung Kim361459f2015-12-23 02:07:08 +09001260 if (perf_hpp__should_skip(fmt, entry->hists) ||
1261 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001262 continue;
1263
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001264 if (current_entry && browser->b.navkeypressed) {
1265 ui_browser__set_color(&browser->b,
1266 HE_COLORSET_SELECTED);
1267 } else {
1268 ui_browser__set_color(&browser->b,
1269 HE_COLORSET_NORMAL);
1270 }
1271
1272 if (first) {
Milian Wolff2a704fc2017-10-09 22:32:55 +02001273 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001274 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001275 width -= 2;
1276 }
1277 first = false;
1278 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001279 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001280 width -= 2;
1281 }
1282
Jiri Olsa12400052012-10-13 00:06:16 +02001283 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001284 int ret = fmt->color(fmt, &hpp, entry);
1285 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1286 /*
1287 * fmt->color() already used ui_browser to
1288 * print the non alignment bits, skip it (+ret):
1289 */
1290 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001291 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001292 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001293 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001294 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001295 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001296 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001297
1298 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001299 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001300 width += 1;
1301
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001302 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001303
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001304 ++row;
1305 ++printed;
1306 } else
1307 --row_offset;
1308
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001309 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001310 struct callchain_print_arg arg = {
1311 .row_offset = row_offset,
1312 .is_current_entry = current_entry,
1313 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001314
Milian Wolff2a704fc2017-10-09 22:32:55 +02001315 printed += hist_browser__show_callchain(browser,
1316 entry, 1, row,
1317 hist_browser__show_callchain_entry,
1318 &arg,
1319 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001320 }
1321
1322 return printed;
1323}
1324
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001325static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1326 struct hist_entry *entry,
1327 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001328 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001329{
1330 int printed = 0;
1331 int width = browser->b.width;
1332 char folded_sign = ' ';
1333 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1334 off_t row_offset = entry->row_offset;
1335 bool first = true;
1336 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001337 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001338 struct hpp_arg arg = {
1339 .b = &browser->b,
1340 .current_entry = current_entry,
1341 };
1342 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001343 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001344
1345 if (current_entry) {
1346 browser->he_selection = entry;
1347 browser->selection = &entry->ms;
1348 }
1349
1350 hist_entry__init_have_children(entry);
1351 folded_sign = hist_entry__folded(entry);
1352 arg.folded_sign = folded_sign;
1353
1354 if (entry->leaf && row_offset) {
1355 row_offset--;
1356 goto show_callchain;
1357 }
1358
1359 hist_browser__gotorc(browser, row, 0);
1360
1361 if (current_entry && browser->b.navkeypressed)
1362 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1363 else
1364 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1365
1366 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1367 width -= level * HIERARCHY_INDENT;
1368
Namhyung Kima61a22f2016-03-07 16:44:50 -03001369 /* the first hpp_list_node is for overhead columns */
1370 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1371 struct perf_hpp_list_node, list);
1372 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001373 char s[2048];
1374 struct perf_hpp hpp = {
1375 .buf = s,
1376 .size = sizeof(s),
1377 .ptr = &arg,
1378 };
1379
1380 if (perf_hpp__should_skip(fmt, entry->hists) ||
1381 column++ < browser->b.horiz_scroll)
1382 continue;
1383
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001384 if (current_entry && browser->b.navkeypressed) {
1385 ui_browser__set_color(&browser->b,
1386 HE_COLORSET_SELECTED);
1387 } else {
1388 ui_browser__set_color(&browser->b,
1389 HE_COLORSET_NORMAL);
1390 }
1391
1392 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001393 ui_browser__printf(&browser->b, "%c ", folded_sign);
1394 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001395 first = false;
1396 } else {
1397 ui_browser__printf(&browser->b, " ");
1398 width -= 2;
1399 }
1400
1401 if (fmt->color) {
1402 int ret = fmt->color(fmt, &hpp, entry);
1403 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1404 /*
1405 * fmt->color() already used ui_browser to
1406 * print the non alignment bits, skip it (+ret):
1407 */
1408 ui_browser__printf(&browser->b, "%s", s + ret);
1409 } else {
1410 int ret = fmt->entry(fmt, &hpp, entry);
1411 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1412 ui_browser__printf(&browser->b, "%s", s);
1413 }
1414 width -= hpp.buf - s;
1415 }
1416
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001417 if (!first) {
1418 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1419 width -= hierarchy_indent;
1420 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001421
1422 if (column >= browser->b.horiz_scroll) {
1423 char s[2048];
1424 struct perf_hpp hpp = {
1425 .buf = s,
1426 .size = sizeof(s),
1427 .ptr = &arg,
1428 };
1429
1430 if (current_entry && browser->b.navkeypressed) {
1431 ui_browser__set_color(&browser->b,
1432 HE_COLORSET_SELECTED);
1433 } else {
1434 ui_browser__set_color(&browser->b,
1435 HE_COLORSET_NORMAL);
1436 }
1437
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001438 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001439 if (first) {
1440 ui_browser__printf(&browser->b, "%c ", folded_sign);
1441 first = false;
1442 } else {
1443 ui_browser__write_nstring(&browser->b, "", 2);
1444 }
1445
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001446 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001447
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001448 /*
1449 * No need to call hist_entry__snprintf_alignment()
1450 * since this fmt is always the last column in the
1451 * hierarchy mode.
1452 */
1453 if (fmt->color) {
1454 width -= fmt->color(fmt, &hpp, entry);
1455 } else {
1456 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001457
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001458 width -= fmt->entry(fmt, &hpp, entry);
1459 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001460
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001461 while (isspace(s[i++]))
1462 width++;
1463 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001464 }
1465 }
1466
1467 /* The scroll bar isn't being used */
1468 if (!browser->b.navkeypressed)
1469 width += 1;
1470
1471 ui_browser__write_nstring(&browser->b, "", width);
1472
1473 ++row;
1474 ++printed;
1475
1476show_callchain:
1477 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1478 struct callchain_print_arg carg = {
1479 .row_offset = row_offset,
1480 };
1481
1482 printed += hist_browser__show_callchain(browser, entry,
1483 level + 1, row,
1484 hist_browser__show_callchain_entry, &carg,
1485 hist_browser__check_output_full);
1486 }
1487
1488 return printed;
1489}
1490
Namhyung Kim79dded82016-02-26 21:13:19 +09001491static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001492 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001493{
1494 int width = browser->b.width;
1495 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1496 bool first = true;
1497 int column = 0;
1498 int ret;
1499 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001500 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001501 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001502
1503 if (current_entry) {
1504 browser->he_selection = NULL;
1505 browser->selection = NULL;
1506 }
1507
1508 hist_browser__gotorc(browser, row, 0);
1509
1510 if (current_entry && browser->b.navkeypressed)
1511 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1512 else
1513 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1514
1515 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1516 width -= level * HIERARCHY_INDENT;
1517
Namhyung Kima61a22f2016-03-07 16:44:50 -03001518 /* the first hpp_list_node is for overhead columns */
1519 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1520 struct perf_hpp_list_node, list);
1521 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001522 if (perf_hpp__should_skip(fmt, browser->hists) ||
1523 column++ < browser->b.horiz_scroll)
1524 continue;
1525
Jiri Olsada1b0402016-06-14 20:19:20 +02001526 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001527
1528 if (first) {
1529 /* for folded sign */
1530 first = false;
1531 ret++;
1532 } else {
1533 /* space between columns */
1534 ret += 2;
1535 }
1536
1537 ui_browser__write_nstring(&browser->b, "", ret);
1538 width -= ret;
1539 }
1540
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001541 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1542 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001543
1544 if (column >= browser->b.horiz_scroll) {
1545 char buf[32];
1546
1547 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1548 ui_browser__printf(&browser->b, " %s", buf);
1549 width -= ret + 2;
1550 }
1551
1552 /* The scroll bar isn't being used */
1553 if (!browser->b.navkeypressed)
1554 width += 1;
1555
1556 ui_browser__write_nstring(&browser->b, "", width);
1557 return 1;
1558}
1559
Jiri Olsa81a888f2014-06-14 15:44:52 +02001560static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1561{
1562 advance_hpp(hpp, inc);
1563 return hpp->size <= 0;
1564}
1565
Jiri Olsa69705b32016-08-07 17:28:28 +02001566static int
1567hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1568 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001569{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001570 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001571 struct perf_hpp dummy_hpp = {
1572 .buf = buf,
1573 .size = size,
1574 };
1575 struct perf_hpp_fmt *fmt;
1576 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001577 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001578 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001579
1580 if (symbol_conf.use_callchain) {
1581 ret = scnprintf(buf, size, " ");
1582 if (advance_hpp_check(&dummy_hpp, ret))
1583 return ret;
1584 }
1585
Jiri Olsaf0786af2016-01-18 10:24:23 +01001586 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001587 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001588 continue;
1589
Jiri Olsa29659ab2016-08-07 17:28:30 +02001590 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001591 if (advance_hpp_check(&dummy_hpp, ret))
1592 break;
1593
Jiri Olsa29659ab2016-08-07 17:28:30 +02001594 if (span)
1595 continue;
1596
Jiri Olsa81a888f2014-06-14 15:44:52 +02001597 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1598 if (advance_hpp_check(&dummy_hpp, ret))
1599 break;
1600 }
1601
1602 return ret;
1603}
1604
Namhyung Kimd8b92402016-02-25 00:13:46 +09001605static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1606{
1607 struct hists *hists = browser->hists;
1608 struct perf_hpp dummy_hpp = {
1609 .buf = buf,
1610 .size = size,
1611 };
1612 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001613 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001614 size_t ret = 0;
1615 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001616 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001617 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001618
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001619 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001620 if (advance_hpp_check(&dummy_hpp, ret))
1621 return ret;
1622
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001623 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001624 /* the first hpp_list_node is for overhead columns */
1625 fmt_node = list_first_entry(&hists->hpp_formats,
1626 struct perf_hpp_list_node, list);
1627 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001628 if (column++ < browser->b.horiz_scroll)
1629 continue;
1630
Jiri Olsa29659ab2016-08-07 17:28:30 +02001631 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001632 if (advance_hpp_check(&dummy_hpp, ret))
1633 break;
1634
1635 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1636 if (advance_hpp_check(&dummy_hpp, ret))
1637 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001638
1639 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001640 }
1641
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001642 if (!first_node) {
1643 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1644 indent * HIERARCHY_INDENT, "");
1645 if (advance_hpp_check(&dummy_hpp, ret))
1646 return ret;
1647 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001648
Namhyung Kima61a22f2016-03-07 16:44:50 -03001649 first_node = true;
1650 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1651 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001652 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1653 if (advance_hpp_check(&dummy_hpp, ret))
1654 break;
1655 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001656 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001657
Namhyung Kima61a22f2016-03-07 16:44:50 -03001658 first_col = true;
1659 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1660 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001661
Namhyung Kima61a22f2016-03-07 16:44:50 -03001662 if (perf_hpp__should_skip(fmt, hists))
1663 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001664
Namhyung Kima61a22f2016-03-07 16:44:50 -03001665 if (!first_col) {
1666 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1667 if (advance_hpp_check(&dummy_hpp, ret))
1668 break;
1669 }
1670 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001671
Jiri Olsa29659ab2016-08-07 17:28:30 +02001672 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001673 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001674
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001675 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001676 ret = strlen(start);
1677
1678 if (start != dummy_hpp.buf)
1679 memmove(dummy_hpp.buf, start, ret + 1);
1680
1681 if (advance_hpp_check(&dummy_hpp, ret))
1682 break;
1683 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001684 }
1685
1686 return ret;
1687}
1688
Jiri Olsa01b47702016-06-14 20:19:13 +02001689static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001690{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001691 char headers[1024];
1692
Jiri Olsa01b47702016-06-14 20:19:13 +02001693 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1694 sizeof(headers));
1695
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001696 ui_browser__gotorc(&browser->b, 0, 0);
1697 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001698 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001699}
1700
Jiri Olsa01b47702016-06-14 20:19:13 +02001701static void hists_browser__headers(struct hist_browser *browser)
1702{
Jiri Olsa69705b32016-08-07 17:28:28 +02001703 struct hists *hists = browser->hists;
1704 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001705
Jiri Olsa69705b32016-08-07 17:28:28 +02001706 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001707
Jiri Olsa69705b32016-08-07 17:28:28 +02001708 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1709 char headers[1024];
1710
1711 hists_browser__scnprintf_headers(browser, headers,
1712 sizeof(headers), line);
1713
1714 ui_browser__gotorc(&browser->b, line, 0);
1715 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1716 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1717 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001718}
1719
1720static void hist_browser__show_headers(struct hist_browser *browser)
1721{
1722 if (symbol_conf.report_hierarchy)
1723 hists_browser__hierarchy_headers(browser);
1724 else
1725 hists_browser__headers(browser);
1726}
1727
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001728static void ui_browser__hists_init_top(struct ui_browser *browser)
1729{
1730 if (browser->top == NULL) {
1731 struct hist_browser *hb;
1732
1733 hb = container_of(browser, struct hist_browser, b);
1734 browser->top = rb_first(&hb->hists->entries);
1735 }
1736}
1737
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001738static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001739{
1740 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001741 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001742 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001743 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001744 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001745
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001746 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001747 struct perf_hpp_list *hpp_list = hists->hpp_list;
1748
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001749 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001750 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001751 }
1752
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001753 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001754 hb->he_selection = NULL;
1755 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001756
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001757 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001759 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001760
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001761 if (h->filtered) {
1762 /* let it move to sibling */
1763 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001764 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001765 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766
Namhyung Kim14135662013-10-31 10:17:39 +09001767 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001768 if (percent < hb->min_pcnt)
1769 continue;
1770
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001771 if (symbol_conf.report_hierarchy) {
1772 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001773 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001774 if (row == browser->rows)
1775 break;
1776
1777 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001778 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001779 row++;
1780 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001781 } else {
1782 row += hist_browser__show_entry(hb, h, row);
1783 }
1784
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001785 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001786 break;
1787 }
1788
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001789 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001790}
1791
Namhyung Kim064f1982013-05-14 11:09:04 +09001792static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001793 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001794{
1795 while (nd != NULL) {
1796 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001797 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001798
Namhyung Kimc0f15272014-04-16 11:16:33 +09001799 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001800 return nd;
1801
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001802 /*
1803 * If it's filtered, its all children also were filtered.
1804 * So move to sibling node.
1805 */
1806 if (rb_next(nd))
1807 nd = rb_next(nd);
1808 else
1809 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001810 }
1811
1812 return NULL;
1813}
1814
Namhyung Kim064f1982013-05-14 11:09:04 +09001815static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001816 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001817{
1818 while (nd != NULL) {
1819 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001820 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001821
1822 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001823 return nd;
1824
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001825 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001826 }
1827
1828 return NULL;
1829}
1830
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001831static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001832 off_t offset, int whence)
1833{
1834 struct hist_entry *h;
1835 struct rb_node *nd;
1836 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001837 struct hist_browser *hb;
1838
1839 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001840
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001841 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001842 return;
1843
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001844 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001845
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001846 switch (whence) {
1847 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001848 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001849 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001850 break;
1851 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001852 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001853 goto do_offset;
1854 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001855 nd = rb_hierarchy_last(rb_last(browser->entries));
1856 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001857 first = false;
1858 break;
1859 default:
1860 return;
1861 }
1862
1863 /*
1864 * Moves not relative to the first visible entry invalidates its
1865 * row_offset:
1866 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001867 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001868 h->row_offset = 0;
1869
1870 /*
1871 * Here we have to check if nd is expanded (+), if it is we can't go
1872 * the next top level hist_entry, instead we must compute an offset of
1873 * what _not_ to show and not change the first visible entry.
1874 *
1875 * This offset increments when we are going from top to bottom and
1876 * decreases when we're going from bottom to top.
1877 *
1878 * As we don't have backpointers to the top level in the callchains
1879 * structure, we need to always print the whole hist_entry callchain,
1880 * skipping the first ones that are before the first visible entry
1881 * and stop when we printed enough lines to fill the screen.
1882 */
1883do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001884 if (!nd)
1885 return;
1886
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001887 if (offset > 0) {
1888 do {
1889 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001890 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001891 u16 remaining = h->nr_rows - h->row_offset;
1892 if (offset > remaining) {
1893 offset -= remaining;
1894 h->row_offset = 0;
1895 } else {
1896 h->row_offset += offset;
1897 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001898 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001899 break;
1900 }
1901 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001902 nd = hists__filter_entries(rb_hierarchy_next(nd),
1903 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001904 if (nd == NULL)
1905 break;
1906 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001907 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001908 } while (offset != 0);
1909 } else if (offset < 0) {
1910 while (1) {
1911 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001912 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001913 if (first) {
1914 if (-offset > h->row_offset) {
1915 offset += h->row_offset;
1916 h->row_offset = 0;
1917 } else {
1918 h->row_offset += offset;
1919 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001920 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001921 break;
1922 }
1923 } else {
1924 if (-offset > h->nr_rows) {
1925 offset += h->nr_rows;
1926 h->row_offset = 0;
1927 } else {
1928 h->row_offset = h->nr_rows + offset;
1929 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001930 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001931 break;
1932 }
1933 }
1934 }
1935
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001936 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001937 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001938 if (nd == NULL)
1939 break;
1940 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001941 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001942 if (offset == 0) {
1943 /*
1944 * Last unfiltered hist_entry, check if it is
1945 * unfolded, if it is then we should have
1946 * row_offset at its last entry.
1947 */
1948 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001949 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001950 h->row_offset = h->nr_rows;
1951 break;
1952 }
1953 first = false;
1954 }
1955 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001956 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001957 h = rb_entry(nd, struct hist_entry, rb_node);
1958 h->row_offset = 0;
1959 }
1960}
1961
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001962static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001963 struct hist_entry *he, FILE *fp,
1964 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001965{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001966 struct callchain_print_arg arg = {
1967 .fp = fp,
1968 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001969
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001970 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001971 hist_browser__fprintf_callchain_entry, &arg,
1972 hist_browser__check_dump_full);
1973 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001974}
1975
1976static int hist_browser__fprintf_entry(struct hist_browser *browser,
1977 struct hist_entry *he, FILE *fp)
1978{
1979 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001980 int printed = 0;
1981 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001982 struct perf_hpp hpp = {
1983 .buf = s,
1984 .size = sizeof(s),
1985 };
1986 struct perf_hpp_fmt *fmt;
1987 bool first = true;
1988 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001989
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001990 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001991 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001992 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001993 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001994
Jiri Olsaf0786af2016-01-18 10:24:23 +01001995 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001996 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001997 continue;
1998
Namhyung Kim26d8b332014-03-03 16:16:20 +09001999 if (!first) {
2000 ret = scnprintf(hpp.buf, hpp.size, " ");
2001 advance_hpp(&hpp, ret);
2002 } else
2003 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002004
Namhyung Kim26d8b332014-03-03 16:16:20 +09002005 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002006 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002007 advance_hpp(&hpp, ret);
2008 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002009 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002010
2011 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002012 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2013
2014 return printed;
2015}
2016
2017
2018static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2019 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002020 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002021{
2022 char s[8192];
2023 int printed = 0;
2024 char folded_sign = ' ';
2025 struct perf_hpp hpp = {
2026 .buf = s,
2027 .size = sizeof(s),
2028 };
2029 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002030 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002031 bool first = true;
2032 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002033 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002034
2035 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2036
2037 folded_sign = hist_entry__folded(he);
2038 printed += fprintf(fp, "%c", folded_sign);
2039
Namhyung Kim325a6282016-03-09 22:47:00 +09002040 /* the first hpp_list_node is for overhead columns */
2041 fmt_node = list_first_entry(&he->hists->hpp_formats,
2042 struct perf_hpp_list_node, list);
2043 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002044 if (!first) {
2045 ret = scnprintf(hpp.buf, hpp.size, " ");
2046 advance_hpp(&hpp, ret);
2047 } else
2048 first = false;
2049
2050 ret = fmt->entry(fmt, &hpp, he);
2051 advance_hpp(&hpp, ret);
2052 }
2053
2054 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2055 advance_hpp(&hpp, ret);
2056
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002057 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2058 ret = scnprintf(hpp.buf, hpp.size, " ");
2059 advance_hpp(&hpp, ret);
2060
2061 ret = fmt->entry(fmt, &hpp, he);
2062 advance_hpp(&hpp, ret);
2063 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002064
2065 printed += fprintf(fp, "%s\n", rtrim(s));
2066
2067 if (he->leaf && folded_sign == '-') {
2068 printed += hist_browser__fprintf_callchain(browser, he, fp,
2069 he->depth + 1);
2070 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002071
2072 return printed;
2073}
2074
2075static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2076{
Namhyung Kim064f1982013-05-14 11:09:04 +09002077 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002078 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002079 int printed = 0;
2080
2081 while (nd) {
2082 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2083
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002084 if (symbol_conf.report_hierarchy) {
2085 printed += hist_browser__fprintf_hierarchy_entry(browser,
2086 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002087 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002088 } else {
2089 printed += hist_browser__fprintf_entry(browser, h, fp);
2090 }
2091
2092 nd = hists__filter_entries(rb_hierarchy_next(nd),
2093 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002094 }
2095
2096 return printed;
2097}
2098
2099static int hist_browser__dump(struct hist_browser *browser)
2100{
2101 char filename[64];
2102 FILE *fp;
2103
2104 while (1) {
2105 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2106 if (access(filename, F_OK))
2107 break;
2108 /*
2109 * XXX: Just an arbitrary lazy upper limit
2110 */
2111 if (++browser->print_seq == 8192) {
2112 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2113 return -1;
2114 }
2115 }
2116
2117 fp = fopen(filename, "w");
2118 if (fp == NULL) {
2119 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002120 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002121 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002122 return -1;
2123 }
2124
2125 ++browser->print_seq;
2126 hist_browser__fprintf(browser, fp);
2127 fclose(fp);
2128 ui_helpline__fpush("%s written!", filename);
2129
2130 return 0;
2131}
2132
Jiri Olsafcd86422016-06-20 23:58:18 +02002133void hist_browser__init(struct hist_browser *browser,
2134 struct hists *hists)
2135{
2136 struct perf_hpp_fmt *fmt;
2137
2138 browser->hists = hists;
2139 browser->b.refresh = hist_browser__refresh;
2140 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2141 browser->b.seek = ui_browser__hists_seek;
2142 browser->b.use_navkeypressed = true;
2143 browser->show_headers = symbol_conf.show_hist_headers;
2144
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002145 if (symbol_conf.report_hierarchy) {
2146 struct perf_hpp_list_node *fmt_node;
2147
2148 /* count overhead columns (in the first node) */
2149 fmt_node = list_first_entry(&hists->hpp_formats,
2150 struct perf_hpp_list_node, list);
2151 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2152 ++browser->b.columns;
2153
2154 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002155 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002156 } else {
2157 hists__for_each_format(hists, fmt)
2158 ++browser->b.columns;
2159 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002160
2161 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002162}
2163
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002164struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002165{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002166 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002167
Jiri Olsafcd86422016-06-20 23:58:18 +02002168 if (browser)
2169 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002170
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002171 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002172}
2173
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002174static struct hist_browser *
2175perf_evsel_browser__new(struct perf_evsel *evsel,
2176 struct hist_browser_timer *hbt,
2177 struct perf_env *env)
2178{
2179 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2180
2181 if (browser) {
2182 browser->hbt = hbt;
2183 browser->env = env;
2184 browser->title = perf_evsel_browser_title;
2185 }
2186 return browser;
2187}
2188
Jiri Olsadabd2012016-06-20 23:58:14 +02002189void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002190{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002191 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002192}
2193
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002194static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002195{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002196 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002197}
2198
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002199static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002200{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002201 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002202}
2203
Taeung Song1e378eb2014-10-07 16:13:15 +09002204/* Check whether the browser is for 'top' or 'report' */
2205static inline bool is_report_browser(void *timer)
2206{
2207 return timer == NULL;
2208}
2209
Jiri Olsa5b91a862016-06-20 23:58:15 +02002210static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002211 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002212{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002213 struct hist_browser_timer *hbt = browser->hbt;
2214 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002215 char unit;
2216 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002217 const struct dso *dso = hists->dso_filter;
2218 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002219 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002220 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2221 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002222 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002223 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002224 char buf[512];
2225 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002226 char ref[30] = " show reference callgraph, ";
2227 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002228
Namhyung Kimf2148332014-01-14 11:52:48 +09002229 if (symbol_conf.filter_relative) {
2230 nr_samples = hists->stats.nr_non_filtered_samples;
2231 nr_events = hists->stats.total_non_filtered_period;
2232 }
2233
Namhyung Kim759ff492013-03-05 14:53:26 +09002234 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002235 struct perf_evsel *pos;
2236
2237 perf_evsel__group_desc(evsel, buf, buflen);
2238 ev_name = buf;
2239
2240 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002241 struct hists *pos_hists = evsel__hists(pos);
2242
Namhyung Kimf2148332014-01-14 11:52:48 +09002243 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002244 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2245 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002246 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002247 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2248 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002249 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002250 }
2251 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002252
Kan Liang9e207dd2015-08-11 06:30:49 -04002253 if (symbol_conf.show_ref_callgraph &&
2254 strstr(ev_name, "call-graph=no"))
2255 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002256 nr_samples = convert_unit(nr_samples, &unit);
2257 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002258 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2259 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002260
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002261
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002262 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002263 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002264 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002265 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002266 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002267 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002268 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002269 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002270 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002271 } else {
2272 printed += scnprintf(bf + printed, size - printed,
2273 ", Thread: %s",
2274 (thread->comm_set ? thread__comm_str(thread) : ""));
2275 }
2276 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002277 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002278 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002279 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002280 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002281 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002282 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002283 if (!is_report_browser(hbt)) {
2284 struct perf_top *top = hbt->arg;
2285
2286 if (top->zero)
2287 printed += scnprintf(bf + printed, size - printed, " [z]");
2288 }
2289
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002290 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002291}
2292
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002293static inline void free_popup_options(char **options, int n)
2294{
2295 int i;
2296
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002297 for (i = 0; i < n; ++i)
2298 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002299}
2300
Feng Tang341487ab2013-02-03 14:38:20 +08002301/*
2302 * Only runtime switching of perf data file will make "input_name" point
2303 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2304 * whether we need to call free() for current "input_name" during the switch.
2305 */
2306static bool is_input_name_malloced = false;
2307
2308static int switch_data_file(void)
2309{
2310 char *pwd, *options[32], *abs_path[32], *tmp;
2311 DIR *pwd_dir;
2312 int nr_options = 0, choice = -1, ret = -1;
2313 struct dirent *dent;
2314
2315 pwd = getenv("PWD");
2316 if (!pwd)
2317 return ret;
2318
2319 pwd_dir = opendir(pwd);
2320 if (!pwd_dir)
2321 return ret;
2322
2323 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002324 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002325
2326 while ((dent = readdir(pwd_dir))) {
2327 char path[PATH_MAX];
2328 u64 magic;
2329 char *name = dent->d_name;
2330 FILE *file;
2331
2332 if (!(dent->d_type == DT_REG))
2333 continue;
2334
2335 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2336
2337 file = fopen(path, "r");
2338 if (!file)
2339 continue;
2340
2341 if (fread(&magic, 1, 8, file) < 8)
2342 goto close_file_and_continue;
2343
2344 if (is_perf_magic(magic)) {
2345 options[nr_options] = strdup(name);
2346 if (!options[nr_options])
2347 goto close_file_and_continue;
2348
2349 abs_path[nr_options] = strdup(path);
2350 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002351 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002352 ui__warning("Can't search all data files due to memory shortage.\n");
2353 fclose(file);
2354 break;
2355 }
2356
2357 nr_options++;
2358 }
2359
2360close_file_and_continue:
2361 fclose(file);
2362 if (nr_options >= 32) {
2363 ui__warning("Too many perf data files in PWD!\n"
2364 "Only the first 32 files will be listed.\n");
2365 break;
2366 }
2367 }
2368 closedir(pwd_dir);
2369
2370 if (nr_options) {
2371 choice = ui__popup_menu(nr_options, options);
2372 if (choice < nr_options && choice >= 0) {
2373 tmp = strdup(abs_path[choice]);
2374 if (tmp) {
2375 if (is_input_name_malloced)
2376 free((void *)input_name);
2377 input_name = tmp;
2378 is_input_name_malloced = true;
2379 ret = 0;
2380 } else
2381 ui__warning("Data switch failed due to memory shortage!\n");
2382 }
2383 }
2384
2385 free_popup_options(options, nr_options);
2386 free_popup_options(abs_path, nr_options);
2387 return ret;
2388}
2389
Namhyung Kimea7cd592015-04-22 16:18:19 +09002390struct popup_action {
2391 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002392 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002393 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002394
2395 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2396};
2397
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002398static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002399do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002400{
2401 struct perf_evsel *evsel;
2402 struct annotation *notes;
2403 struct hist_entry *he;
2404 int err;
2405
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002406 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002407 return 0;
2408
Namhyung Kimea7cd592015-04-22 16:18:19 +09002409 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002410 if (!notes->src)
2411 return 0;
2412
2413 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002414 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002415 he = hist_browser__selected_entry(browser);
2416 /*
2417 * offer option to annotate the other branch source or target
2418 * (if they exists) when returning from annotate
2419 */
2420 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2421 return 1;
2422
2423 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2424 if (err)
2425 ui_browser__handle_resize(&browser->b);
2426 return 0;
2427}
2428
2429static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002430add_annotate_opt(struct hist_browser *browser __maybe_unused,
2431 struct popup_action *act, char **optstr,
2432 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002433{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002434 if (sym == NULL || map->dso->annotate_warned)
2435 return 0;
2436
2437 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2438 return 0;
2439
2440 act->ms.map = map;
2441 act->ms.sym = sym;
2442 act->fn = do_annotate;
2443 return 1;
2444}
2445
2446static int
2447do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2448{
2449 struct thread *thread = act->thread;
2450
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002451 if ((!hists__has(browser->hists, thread) &&
2452 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002453 return 0;
2454
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002455 if (browser->hists->thread_filter) {
2456 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2457 perf_hpp__set_elide(HISTC_THREAD, false);
2458 thread__zput(browser->hists->thread_filter);
2459 ui_helpline__pop();
2460 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002461 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002462 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2463 thread->comm_set ? thread__comm_str(thread) : "",
2464 thread->tid);
2465 } else {
2466 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2467 thread->comm_set ? thread__comm_str(thread) : "");
2468 }
2469
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002470 browser->hists->thread_filter = thread__get(thread);
2471 perf_hpp__set_elide(HISTC_THREAD, false);
2472 pstack__push(browser->pstack, &browser->hists->thread_filter);
2473 }
2474
2475 hists__filter_by_thread(browser->hists);
2476 hist_browser__reset(browser);
2477 return 0;
2478}
2479
2480static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002481add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2482 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002483{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002484 int ret;
2485
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002486 if ((!hists__has(browser->hists, thread) &&
2487 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002488 return 0;
2489
Jiri Olsafa829112016-05-03 13:54:47 +02002490 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002491 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2492 browser->hists->thread_filter ? "out of" : "into",
2493 thread->comm_set ? thread__comm_str(thread) : "",
2494 thread->tid);
2495 } else {
2496 ret = asprintf(optstr, "Zoom %s %s thread",
2497 browser->hists->thread_filter ? "out of" : "into",
2498 thread->comm_set ? thread__comm_str(thread) : "");
2499 }
2500 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002501 return 0;
2502
2503 act->thread = thread;
2504 act->fn = do_zoom_thread;
2505 return 1;
2506}
2507
2508static int
2509do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2510{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002511 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002512
Jiri Olsa69849fc2016-05-03 13:54:45 +02002513 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002514 return 0;
2515
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002516 if (browser->hists->dso_filter) {
2517 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2518 perf_hpp__set_elide(HISTC_DSO, false);
2519 browser->hists->dso_filter = NULL;
2520 ui_helpline__pop();
2521 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002522 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002523 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2524 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002525 perf_hpp__set_elide(HISTC_DSO, true);
2526 pstack__push(browser->pstack, &browser->hists->dso_filter);
2527 }
2528
2529 hists__filter_by_dso(browser->hists);
2530 hist_browser__reset(browser);
2531 return 0;
2532}
2533
2534static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002535add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002536 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002537{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002538 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002539 return 0;
2540
2541 if (asprintf(optstr, "Zoom %s %s DSO",
2542 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002543 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002544 return 0;
2545
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002546 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002547 act->fn = do_zoom_dso;
2548 return 1;
2549}
2550
2551static int
2552do_browse_map(struct hist_browser *browser __maybe_unused,
2553 struct popup_action *act)
2554{
2555 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002556 return 0;
2557}
2558
2559static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002560add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002561 struct popup_action *act, char **optstr, struct map *map)
2562{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002563 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002564 return 0;
2565
2566 if (asprintf(optstr, "Browse map details") < 0)
2567 return 0;
2568
2569 act->ms.map = map;
2570 act->fn = do_browse_map;
2571 return 1;
2572}
2573
2574static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002575do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002576 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002577{
2578 char script_opt[64];
2579 memset(script_opt, 0, sizeof(script_opt));
2580
Namhyung Kimea7cd592015-04-22 16:18:19 +09002581 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002582 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002583 thread__comm_str(act->thread));
2584 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002585 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002586 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002587 }
2588
2589 script_browse(script_opt);
2590 return 0;
2591}
2592
2593static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002594add_script_opt(struct hist_browser *browser __maybe_unused,
2595 struct popup_action *act, char **optstr,
2596 struct thread *thread, struct symbol *sym)
2597{
2598 if (thread) {
2599 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2600 thread__comm_str(thread)) < 0)
2601 return 0;
2602 } else if (sym) {
2603 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2604 sym->name) < 0)
2605 return 0;
2606 } else {
2607 if (asprintf(optstr, "Run scripts for all samples") < 0)
2608 return 0;
2609 }
2610
2611 act->thread = thread;
2612 act->ms.sym = sym;
2613 act->fn = do_run_script;
2614 return 1;
2615}
2616
2617static int
2618do_switch_data(struct hist_browser *browser __maybe_unused,
2619 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002620{
2621 if (switch_data_file()) {
2622 ui__warning("Won't switch the data files due to\n"
2623 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002624 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002625 }
2626
2627 return K_SWITCH_INPUT_DATA;
2628}
2629
Namhyung Kimea7cd592015-04-22 16:18:19 +09002630static int
2631add_switch_opt(struct hist_browser *browser,
2632 struct popup_action *act, char **optstr)
2633{
2634 if (!is_report_browser(browser->hbt))
2635 return 0;
2636
2637 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2638 return 0;
2639
2640 act->fn = do_switch_data;
2641 return 1;
2642}
2643
2644static int
2645do_exit_browser(struct hist_browser *browser __maybe_unused,
2646 struct popup_action *act __maybe_unused)
2647{
2648 return 0;
2649}
2650
2651static int
2652add_exit_opt(struct hist_browser *browser __maybe_unused,
2653 struct popup_action *act, char **optstr)
2654{
2655 if (asprintf(optstr, "Exit") < 0)
2656 return 0;
2657
2658 act->fn = do_exit_browser;
2659 return 1;
2660}
2661
Kan Liang84734b02015-09-04 10:45:45 -04002662static int
2663do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2664{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002665 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002666 return 0;
2667
Kan Liang84734b02015-09-04 10:45:45 -04002668 if (browser->hists->socket_filter > -1) {
2669 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2670 browser->hists->socket_filter = -1;
2671 perf_hpp__set_elide(HISTC_SOCKET, false);
2672 } else {
2673 browser->hists->socket_filter = act->socket;
2674 perf_hpp__set_elide(HISTC_SOCKET, true);
2675 pstack__push(browser->pstack, &browser->hists->socket_filter);
2676 }
2677
2678 hists__filter_by_socket(browser->hists);
2679 hist_browser__reset(browser);
2680 return 0;
2681}
2682
2683static int
2684add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2685 char **optstr, int socket_id)
2686{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002687 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002688 return 0;
2689
2690 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2691 (browser->hists->socket_filter > -1) ? "out of" : "into",
2692 socket_id) < 0)
2693 return 0;
2694
2695 act->socket = socket_id;
2696 act->fn = do_zoom_socket;
2697 return 1;
2698}
2699
Namhyung Kim112f7612014-04-22 14:05:35 +09002700static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002701{
2702 u64 nr_entries = 0;
2703 struct rb_node *nd = rb_first(&hb->hists->entries);
2704
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002705 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002706 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2707 return;
2708 }
2709
Namhyung Kim14135662013-10-31 10:17:39 +09002710 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002711 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002712 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002713 }
2714
Namhyung Kim112f7612014-04-22 14:05:35 +09002715 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002716 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002717}
Feng Tang341487ab2013-02-03 14:38:20 +08002718
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002719static void hist_browser__update_percent_limit(struct hist_browser *hb,
2720 double percent)
2721{
2722 struct hist_entry *he;
2723 struct rb_node *nd = rb_first(&hb->hists->entries);
2724 u64 total = hists__total_period(hb->hists);
2725 u64 min_callchain_hits = total * (percent / 100);
2726
2727 hb->min_pcnt = callchain_param.min_percent = percent;
2728
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002729 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2730 he = rb_entry(nd, struct hist_entry, rb_node);
2731
Namhyung Kim79dded82016-02-26 21:13:19 +09002732 if (he->has_no_entry) {
2733 he->has_no_entry = false;
2734 he->nr_rows = 0;
2735 }
2736
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002737 if (!he->leaf || !symbol_conf.use_callchain)
2738 goto next;
2739
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002740 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2741 total = he->stat.period;
2742
2743 if (symbol_conf.cumulate_callchain)
2744 total = he->stat_acc->period;
2745
2746 min_callchain_hits = total * (percent / 100);
2747 }
2748
2749 callchain_param.sort(&he->sorted_chain, he->callchain,
2750 min_callchain_hits, &callchain_param);
2751
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002752next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002753 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002754
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002755 /* force to re-evaluate folding state of callchains */
2756 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002757 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002758 }
2759}
2760
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002761static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002762 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002763 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002764 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002765 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002766 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002767{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002768 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002769 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002770 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002771#define MAX_OPTIONS 16
2772 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002773 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002774 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002775 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002776 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002777 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002778
Namhyung Kime8e684a2013-12-26 14:37:58 +09002779#define HIST_BROWSER_HELP_COMMON \
2780 "h/?/F1 Show this window\n" \
2781 "UP/DOWN/PGUP\n" \
2782 "PGDN/SPACE Navigate\n" \
2783 "q/ESC/CTRL+C Exit browser\n\n" \
2784 "For multiple event sessions:\n\n" \
2785 "TAB/UNTAB Switch events\n\n" \
2786 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002787 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2788 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002789 "a Annotate current symbol\n" \
2790 "C Collapse all callchains\n" \
2791 "d Zoom into current DSO\n" \
2792 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002793 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002794 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002795 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002796 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002797 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002798
2799 /* help messages are sorted by lexical order of the hotkey */
2800 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002801 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002802 "P Print histograms to perf.hist.N\n"
2803 "r Run available scripts\n"
2804 "s Switch to another data file in PWD\n"
2805 "t Zoom into current Thread\n"
2806 "V Verbose (DSO names in callchains, etc)\n"
2807 "/ Filter symbol by name";
2808 const char top_help[] = HIST_BROWSER_HELP_COMMON
2809 "P Print histograms to perf.hist.N\n"
2810 "t Zoom into current Thread\n"
2811 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002812 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002813 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002814 "/ Filter symbol by name";
2815
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002816 if (browser == NULL)
2817 return -1;
2818
Namhyung Kimed426912015-05-29 21:53:44 +09002819 /* reset abort key so that it can get Ctrl-C as a key */
2820 SLang_reset_tty();
2821 SLang_init_tty(0, 0, 0);
2822
Namhyung Kim03905042015-11-28 02:32:39 +09002823 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002824 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002825 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002826
Kan Liang84734b02015-09-04 10:45:45 -04002827 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002828 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002829 goto out;
2830
2831 ui_helpline__push(helpline);
2832
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002833 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002834 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002835
Namhyung Kim5b591662014-07-31 14:47:38 +09002836 if (symbol_conf.col_width_list_str)
2837 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2838
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002839 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002840 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002841 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002842 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002843 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002844
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002845 nr_options = 0;
2846
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002847 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002848
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002849 if (browser->he_selection != NULL) {
2850 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002851 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002852 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002853 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002854 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002855 case K_TAB:
2856 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002857 if (nr_events == 1)
2858 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002859 /*
2860 * Exit the browser, let hists__browser_tree
2861 * go to the next or previous
2862 */
2863 goto out_free_stack;
2864 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002865 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002866 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002867 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002868 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002869 continue;
2870 }
2871
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002872 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002873 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002874 browser->selection->map->dso->annotate_warned)
2875 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002876
Namhyung Kimea7cd592015-04-22 16:18:19 +09002877 actions->ms.map = browser->selection->map;
2878 actions->ms.sym = browser->selection->sym;
2879 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002880 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002881 case 'P':
2882 hist_browser__dump(browser);
2883 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002884 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002885 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002886 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002887 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002888 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02002889 verbose = (verbose + 1) % 4;
2890 browser->show_dso = verbose > 0;
2891 ui_helpline__fpush("Verbosity level set to %d\n",
2892 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002893 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002894 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002895 actions->thread = thread;
2896 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002897 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002898 case 'S':
2899 actions->socket = socked_id;
2900 do_zoom_socket(browser, actions);
2901 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002902 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002903 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002904 "Please enter the name of symbol you want to see.\n"
2905 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002906 buf, "ENTER: OK, ESC: Cancel",
2907 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002908 hists->symbol_filter_str = *buf ? buf : NULL;
2909 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002910 hist_browser__reset(browser);
2911 }
2912 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002913 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002914 if (is_report_browser(hbt)) {
2915 actions->thread = NULL;
2916 actions->ms.sym = NULL;
2917 do_run_script(browser, actions);
2918 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002919 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002920 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002921 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002922 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002923 if (key == K_SWITCH_INPUT_DATA)
2924 goto out_free_stack;
2925 }
Feng Tang341487ab2013-02-03 14:38:20 +08002926 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002927 case 'i':
2928 /* env->arch is NULL for live-mode (i.e. perf top) */
2929 if (env->arch)
2930 tui__header_window(env);
2931 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002932 case 'F':
2933 symbol_conf.filter_relative ^= 1;
2934 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002935 case 'z':
2936 if (!is_report_browser(hbt)) {
2937 struct perf_top *top = hbt->arg;
2938
2939 top->zero = !top->zero;
2940 }
2941 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002942 case 'L':
2943 if (ui_browser__input_window("Percent Limit",
2944 "Please enter the value you want to hide entries under that percent.",
2945 buf, "ENTER: OK, ESC: Cancel",
2946 delay_secs * 2) == K_ENTER) {
2947 char *end;
2948 double new_percent = strtod(buf, &end);
2949
2950 if (new_percent < 0 || new_percent > 100) {
2951 ui_browser__warning(&browser->b, delay_secs * 2,
2952 "Invalid percent: %.2f", new_percent);
2953 continue;
2954 }
2955
2956 hist_browser__update_percent_limit(browser, new_percent);
2957 hist_browser__reset(browser);
2958 }
2959 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002960 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002961 case 'h':
2962 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002963 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002964 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002965 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002966 case K_ENTER:
2967 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002968 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002969 /* menu */
2970 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002971 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002972 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002973 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002974
Namhyung Kim01f00a12015-04-22 16:18:16 +09002975 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002976 /*
2977 * Go back to the perf_evsel_menu__run or other user
2978 */
2979 if (left_exits)
2980 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002981
2982 if (key == K_ESC &&
2983 ui_browser__dialog_yesno(&browser->b,
2984 "Do you really want to exit?"))
2985 goto out_free_stack;
2986
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002987 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002988 }
Namhyung Kim64221842015-04-24 10:15:33 +09002989 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002990 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002991 /*
2992 * No need to set actions->dso here since
2993 * it's just to remove the current filter.
2994 * Ditto for thread below.
2995 */
2996 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002997 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002998 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002999 } else if (top == &browser->hists->socket_filter) {
3000 do_zoom_socket(browser, actions);
3001 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003002 continue;
3003 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003004 case 'q':
3005 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003006 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003007 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003008 if (!is_report_browser(hbt)) {
3009 struct perf_top *top = hbt->arg;
3010
3011 perf_evlist__toggle_enable(top->evlist);
3012 /*
3013 * No need to refresh, resort/decay histogram
3014 * entries if we are not collecting samples:
3015 */
3016 if (top->evlist->enabled) {
3017 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3018 hbt->refresh = delay_secs;
3019 } else {
3020 helpline = "Press 'f' again to re-enable the events";
3021 hbt->refresh = 0;
3022 }
3023 continue;
3024 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003025 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003026 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003027 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003028 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003029 }
3030
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003031 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003032 goto skip_annotation;
3033
Namhyung Kim55369fc2013-04-01 20:35:20 +09003034 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003035 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003036
3037 if (bi == NULL)
3038 goto skip_annotation;
3039
Namhyung Kimea7cd592015-04-22 16:18:19 +09003040 nr_options += add_annotate_opt(browser,
3041 &actions[nr_options],
3042 &options[nr_options],
3043 bi->from.map,
3044 bi->from.sym);
3045 if (bi->to.sym != bi->from.sym)
3046 nr_options += add_annotate_opt(browser,
3047 &actions[nr_options],
3048 &options[nr_options],
3049 bi->to.map,
3050 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003051 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003052 nr_options += add_annotate_opt(browser,
3053 &actions[nr_options],
3054 &options[nr_options],
3055 browser->selection->map,
3056 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003057 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003058skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003059 nr_options += add_thread_opt(browser, &actions[nr_options],
3060 &options[nr_options], thread);
3061 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003062 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003063 nr_options += add_map_opt(browser, &actions[nr_options],
3064 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003065 browser->selection ?
3066 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003067 nr_options += add_socket_opt(browser, &actions[nr_options],
3068 &options[nr_options],
3069 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003070 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003071 if (!is_report_browser(hbt))
3072 goto skip_scripting;
3073
Feng Tangcdbab7c2012-10-30 11:56:06 +08003074 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003075 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003076 nr_options += add_script_opt(browser,
3077 &actions[nr_options],
3078 &options[nr_options],
3079 thread, NULL);
3080 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003081 /*
3082 * Note that browser->selection != NULL
3083 * when browser->he_selection is not NULL,
3084 * so we don't need to check browser->selection
3085 * before fetching browser->selection->sym like what
3086 * we do before fetching browser->selection->map.
3087 *
3088 * See hist_browser__show_entry.
3089 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003090 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003091 nr_options += add_script_opt(browser,
3092 &actions[nr_options],
3093 &options[nr_options],
3094 NULL, browser->selection->sym);
3095 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003096 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003097 nr_options += add_script_opt(browser, &actions[nr_options],
3098 &options[nr_options], NULL, NULL);
3099 nr_options += add_switch_opt(browser, &actions[nr_options],
3100 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003101skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003102 nr_options += add_exit_opt(browser, &actions[nr_options],
3103 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003104
Namhyung Kimea7cd592015-04-22 16:18:19 +09003105 do {
3106 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003107
Namhyung Kimea7cd592015-04-22 16:18:19 +09003108 choice = ui__popup_menu(nr_options, options);
3109 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003110 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003111
3112 act = &actions[choice];
3113 key = act->fn(browser, act);
3114 } while (key == 1);
3115
3116 if (key == K_SWITCH_INPUT_DATA)
3117 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003118 }
3119out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003120 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003121out:
3122 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003123 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003124 return key;
3125}
3126
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003127struct perf_evsel_menu {
3128 struct ui_browser b;
3129 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003130 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003131 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003132 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003133};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003134
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003135static void perf_evsel_menu__write(struct ui_browser *browser,
3136 void *entry, int row)
3137{
3138 struct perf_evsel_menu *menu = container_of(browser,
3139 struct perf_evsel_menu, b);
3140 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003141 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003142 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003143 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003144 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003145 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003146 const char *warn = " ";
3147 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003148
3149 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3150 HE_COLORSET_NORMAL);
3151
Namhyung Kim759ff492013-03-05 14:53:26 +09003152 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003153 struct perf_evsel *pos;
3154
3155 ev_name = perf_evsel__group_name(evsel);
3156
3157 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003158 struct hists *pos_hists = evsel__hists(pos);
3159 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003160 }
3161 }
3162
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003163 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003164 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003165 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003166 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003167
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003168 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003169 if (nr_events != 0) {
3170 menu->lost_events = true;
3171 if (!current_entry)
3172 ui_browser__set_color(browser, HE_COLORSET_TOP);
3173 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003174 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3175 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003176 warn = bf;
3177 }
3178
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003179 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003180
3181 if (current_entry)
3182 menu->selection = evsel;
3183}
3184
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003185static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3186 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003187 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003188{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003189 struct perf_evlist *evlist = menu->b.priv;
3190 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003191 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003192 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003193 int key;
3194
3195 if (ui_browser__show(&menu->b, title,
3196 "ESC: exit, ENTER|->: Browse histograms") < 0)
3197 return -1;
3198
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003199 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003200 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003201
3202 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003203 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003204 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003205
3206 if (!menu->lost_events_warned && menu->lost_events) {
3207 ui_browser__warn_lost_events(&menu->b);
3208 menu->lost_events_warned = true;
3209 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003210 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003211 case K_RIGHT:
3212 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003213 if (!menu->selection)
3214 continue;
3215 pos = menu->selection;
3216browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003217 perf_evlist__set_selected(evlist, pos);
3218 /*
3219 * Give the calling tool a chance to populate the non
3220 * default evsel resorted hists tree.
3221 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003222 if (hbt)
3223 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003224 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003225 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003226 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003227 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003228 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003229 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003230 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003231 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003232 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003233 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003234 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003235 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003236 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003237 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003238 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003239 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003240 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003241 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003242 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003243 case 'q':
3244 case CTRL('c'):
3245 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003246 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003247 default:
3248 continue;
3249 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003250 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003251 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003252 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003253 if (!ui_browser__dialog_yesno(&menu->b,
3254 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003255 continue;
3256 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003257 case 'q':
3258 case CTRL('c'):
3259 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003260 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003261 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003262 }
3263 }
3264
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003265out:
3266 ui_browser__hide(&menu->b);
3267 return key;
3268}
3269
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003270static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003271 void *entry)
3272{
3273 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3274
3275 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3276 return true;
3277
3278 return false;
3279}
3280
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003281static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003282 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003283 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003284 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003285 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003286{
3287 struct perf_evsel *pos;
3288 struct perf_evsel_menu menu = {
3289 .b = {
3290 .entries = &evlist->entries,
3291 .refresh = ui_browser__list_head_refresh,
3292 .seek = ui_browser__list_head_seek,
3293 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003294 .filter = filter_group_entries,
3295 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003296 .priv = evlist,
3297 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003298 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003299 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003300 };
3301
3302 ui_helpline__push("Press ESC to exit");
3303
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003304 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003305 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003306 size_t line_len = strlen(ev_name) + 7;
3307
3308 if (menu.b.width < line_len)
3309 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003310 }
3311
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003312 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003313}
3314
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003315int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003316 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003317 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003318 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003319{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003320 int nr_entries = evlist->nr_entries;
3321
3322single_entry:
3323 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003324 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003325
3326 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003327 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003328 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003329 }
3330
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003331 if (symbol_conf.event_group) {
3332 struct perf_evsel *pos;
3333
3334 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003335 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003336 if (perf_evsel__is_group_leader(pos))
3337 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003338 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003339
3340 if (nr_entries == 1)
3341 goto single_entry;
3342 }
3343
3344 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003345 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003346}