blob: 8b4e82548f8e15e2a786dd64e4bc339631ccc01d [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
Kan Liang06cc1a42018-01-18 13:26:29 -0800611int hist_browser__run(struct hist_browser *browser, const char *help,
612 bool warn_lost_event)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300613{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300614 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300615 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900616 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900617 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300618
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300619 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900620 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300621
Jiri Olsa5b91a862016-06-20 23:58:15 +0200622 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300623
Namhyung Kim090cff32016-01-11 19:53:14 +0900624 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300625 return -1;
626
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300627 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300628 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300629
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300630 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900631 case K_TIMER: {
632 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900633 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900634
Namhyung Kimc6111522016-10-07 14:04:12 +0900635 if (hist_browser__has_filter(browser) ||
636 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900637 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900638
Namhyung Kimc3b78952014-04-22 15:56:17 +0900639 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900640 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200641
Kan Liang06cc1a42018-01-18 13:26:29 -0800642 if (warn_lost_event &&
643 (browser->hists->stats.nr_lost_warned !=
644 browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300645 browser->hists->stats.nr_lost_warned =
646 browser->hists->stats.nr_events[PERF_RECORD_LOST];
647 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200648 }
649
Jiri Olsa5b91a862016-06-20 23:58:15 +0200650 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300651 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300652 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900653 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300654 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300655 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300656 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300657 struct hist_entry, rb_node);
658 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300659 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 -0300660 seq++, browser->b.nr_entries,
661 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300662 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300663 browser->b.index,
664 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300665 h->row_offset, h->nr_rows);
666 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300667 break;
668 case 'C':
669 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300670 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300671 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100672 case 'c':
673 /* Collapse the selected entry. */
674 hist_browser__set_folding_selected(browser, false);
675 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300676 case 'E':
677 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300678 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300679 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100680 case 'e':
681 /* Expand the selected entry. */
682 hist_browser__set_folding_selected(browser, true);
683 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200684 case 'H':
685 browser->show_headers = !browser->show_headers;
686 hist_browser__update_rows(browser);
687 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200688 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300689 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300690 break;
691 /* fall thru */
692 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300693 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300694 }
695 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300696out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300697 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300698 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300699}
700
Namhyung Kim39ee5332014-08-22 09:13:21 +0900701struct callchain_print_arg {
702 /* for hists browser */
703 off_t row_offset;
704 bool is_current_entry;
705
706 /* for file dump */
707 FILE *fp;
708 int printed;
709};
710
711typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
712 struct callchain_list *chain,
713 const char *str, int offset,
714 unsigned short row,
715 struct callchain_print_arg *arg);
716
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900717static void hist_browser__show_callchain_entry(struct hist_browser *browser,
718 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900719 const char *str, int offset,
720 unsigned short row,
721 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900722{
723 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900724 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300725 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900726
727 color = HE_COLORSET_NORMAL;
728 width = browser->b.width - (offset + 2);
729 if (ui_browser__is_current_entry(&browser->b, row)) {
730 browser->selection = &chain->ms;
731 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900732 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900733 }
734
735 ui_browser__set_color(&browser->b, color);
736 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300737 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300738 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300739 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300740 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900741}
742
Namhyung Kim39ee5332014-08-22 09:13:21 +0900743static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
744 struct callchain_list *chain,
745 const char *str, int offset,
746 unsigned short row __maybe_unused,
747 struct callchain_print_arg *arg)
748{
749 char folded_sign = callchain_list__folded(chain);
750
751 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
752 folded_sign, str);
753}
754
755typedef bool (*check_output_full_fn)(struct hist_browser *browser,
756 unsigned short row);
757
758static bool hist_browser__check_output_full(struct hist_browser *browser,
759 unsigned short row)
760{
761 return browser->b.rows == row;
762}
763
764static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
765 unsigned short row __maybe_unused)
766{
767 return false;
768}
769
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300770#define LEVEL_OFFSET_STEP 3
771
Namhyung Kim18bb8382015-11-09 14:45:42 +0900772static int hist_browser__show_callchain_list(struct hist_browser *browser,
773 struct callchain_node *node,
774 struct callchain_list *chain,
775 unsigned short row, u64 total,
776 bool need_percent, int offset,
777 print_callchain_entry_fn print,
778 struct callchain_print_arg *arg)
779{
780 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800781 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900782 const char *str;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200783 int ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900784
785 if (arg->row_offset != 0) {
786 arg->row_offset--;
787 return 0;
788 }
789
790 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800791 alloc_str2 = NULL;
792
Namhyung Kim18bb8382015-11-09 14:45:42 +0900793 str = callchain_list__sym_name(chain, bf, sizeof(bf),
794 browser->show_dso);
795
Jin Yaofef51ec2016-10-31 09:19:53 +0800796 if (symbol_conf.show_branchflag_count) {
Jin Yaoc4ee0622017-08-07 21:05:15 +0800797 callchain_list_counts__printf_value(chain, NULL,
798 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900799
Jin Yaofef51ec2016-10-31 09:19:53 +0800800 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
801 str = "Not enough memory!";
802 else
803 str = alloc_str2;
804 }
805
806 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900807 callchain_node__scnprintf_value(node, buf, sizeof(buf),
808 total);
809
810 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
811 str = "Not enough memory!";
812 else
813 str = alloc_str;
814 }
815
816 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900817 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800818 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800819
Milian Wolff2a704fc2017-10-09 22:32:55 +0200820 return ret;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900821}
822
Namhyung Kim59c624e2016-01-28 00:40:56 +0900823static bool check_percent_display(struct rb_node *node, u64 parent_total)
824{
825 struct callchain_node *child;
826
827 if (node == NULL)
828 return false;
829
830 if (rb_next(node))
831 return true;
832
833 child = rb_entry(node, struct callchain_node, rb_node);
834 return callchain_cumul_hits(child) != parent_total;
835}
836
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900837static int hist_browser__show_callchain_flat(struct hist_browser *browser,
838 struct rb_root *root,
839 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900840 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900841 print_callchain_entry_fn print,
842 struct callchain_print_arg *arg,
843 check_output_full_fn is_output_full)
844{
845 struct rb_node *node;
846 int first_row = row, offset = LEVEL_OFFSET_STEP;
847 bool need_percent;
848
849 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900850 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900851
852 while (node) {
853 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
854 struct rb_node *next = rb_next(node);
855 struct callchain_list *chain;
856 char folded_sign = ' ';
857 int first = true;
858 int extra_offset = 0;
859
860 list_for_each_entry(chain, &child->parent_val, list) {
861 bool was_first = first;
862
863 if (first)
864 first = false;
865 else if (need_percent)
866 extra_offset = LEVEL_OFFSET_STEP;
867
868 folded_sign = callchain_list__folded(chain);
869
870 row += hist_browser__show_callchain_list(browser, child,
871 chain, row, total,
872 was_first && need_percent,
873 offset + extra_offset,
874 print, arg);
875
876 if (is_output_full(browser, row))
877 goto out;
878
879 if (folded_sign == '+')
880 goto next;
881 }
882
883 list_for_each_entry(chain, &child->val, list) {
884 bool was_first = first;
885
886 if (first)
887 first = false;
888 else if (need_percent)
889 extra_offset = LEVEL_OFFSET_STEP;
890
891 folded_sign = callchain_list__folded(chain);
892
893 row += hist_browser__show_callchain_list(browser, child,
894 chain, row, total,
895 was_first && need_percent,
896 offset + extra_offset,
897 print, arg);
898
899 if (is_output_full(browser, row))
900 goto out;
901
902 if (folded_sign == '+')
903 break;
904 }
905
906next:
907 if (is_output_full(browser, row))
908 break;
909 node = next;
910 }
911out:
912 return row - first_row;
913}
914
Namhyung Kim8c430a32015-11-09 14:45:44 +0900915static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
916 struct callchain_list *chain,
917 char *value_str, char *old_str)
918{
919 char bf[1024];
920 const char *str;
921 char *new;
922
923 str = callchain_list__sym_name(chain, bf, sizeof(bf),
924 browser->show_dso);
925 if (old_str) {
926 if (asprintf(&new, "%s%s%s", old_str,
927 symbol_conf.field_sep ?: ";", str) < 0)
928 new = NULL;
929 } else {
930 if (value_str) {
931 if (asprintf(&new, "%s %s", value_str, str) < 0)
932 new = NULL;
933 } else {
934 if (asprintf(&new, "%s", str) < 0)
935 new = NULL;
936 }
937 }
938 return new;
939}
940
941static int hist_browser__show_callchain_folded(struct hist_browser *browser,
942 struct rb_root *root,
943 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900944 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900945 print_callchain_entry_fn print,
946 struct callchain_print_arg *arg,
947 check_output_full_fn is_output_full)
948{
949 struct rb_node *node;
950 int first_row = row, offset = LEVEL_OFFSET_STEP;
951 bool need_percent;
952
953 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900954 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900955
956 while (node) {
957 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
958 struct rb_node *next = rb_next(node);
959 struct callchain_list *chain, *first_chain = NULL;
960 int first = true;
961 char *value_str = NULL, *value_str_alloc = NULL;
962 char *chain_str = NULL, *chain_str_alloc = NULL;
963
964 if (arg->row_offset != 0) {
965 arg->row_offset--;
966 goto next;
967 }
968
969 if (need_percent) {
970 char buf[64];
971
972 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
973 if (asprintf(&value_str, "%s", buf) < 0) {
974 value_str = (char *)"<...>";
975 goto do_print;
976 }
977 value_str_alloc = value_str;
978 }
979
980 list_for_each_entry(chain, &child->parent_val, list) {
981 chain_str = hist_browser__folded_callchain_str(browser,
982 chain, value_str, chain_str);
983 if (first) {
984 first = false;
985 first_chain = chain;
986 }
987
988 if (chain_str == NULL) {
989 chain_str = (char *)"Not enough memory!";
990 goto do_print;
991 }
992
993 chain_str_alloc = chain_str;
994 }
995
996 list_for_each_entry(chain, &child->val, list) {
997 chain_str = hist_browser__folded_callchain_str(browser,
998 chain, value_str, chain_str);
999 if (first) {
1000 first = false;
1001 first_chain = chain;
1002 }
1003
1004 if (chain_str == NULL) {
1005 chain_str = (char *)"Not enough memory!";
1006 goto do_print;
1007 }
1008
1009 chain_str_alloc = chain_str;
1010 }
1011
1012do_print:
1013 print(browser, first_chain, chain_str, offset, row++, arg);
1014 free(value_str_alloc);
1015 free(chain_str_alloc);
1016
1017next:
1018 if (is_output_full(browser, row))
1019 break;
1020 node = next;
1021 }
1022
1023 return row - first_row;
1024}
1025
Namhyung Kim0c841c62016-01-28 00:40:54 +09001026static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001027 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001028 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001029 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001030 print_callchain_entry_fn print,
1031 struct callchain_print_arg *arg,
1032 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001033{
1034 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001035 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001036 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001037 u64 percent_total = total;
1038
1039 if (callchain_param.mode == CHAIN_GRAPH_REL)
1040 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001041
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001042 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001043 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001044
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001045 while (node) {
1046 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1047 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001048 struct callchain_list *chain;
1049 char folded_sign = ' ';
1050 int first = true;
1051 int extra_offset = 0;
1052
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001053 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001054 bool was_first = first;
1055
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001056 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001057 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001058 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001059 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001060
1061 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001062
Namhyung Kim18bb8382015-11-09 14:45:42 +09001063 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001064 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001065 was_first && need_percent,
1066 offset + extra_offset,
1067 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001068
Namhyung Kim18bb8382015-11-09 14:45:42 +09001069 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001070 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001071
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001072 if (folded_sign == '+')
1073 break;
1074 }
1075
1076 if (folded_sign == '-') {
1077 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001078
Namhyung Kim0c841c62016-01-28 00:40:54 +09001079 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001080 new_level, row, total,
1081 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001082 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001083 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001084 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001085 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001086 node = next;
1087 }
1088out:
1089 return row - first_row;
1090}
1091
Namhyung Kim0c841c62016-01-28 00:40:54 +09001092static int hist_browser__show_callchain(struct hist_browser *browser,
1093 struct hist_entry *entry, int level,
1094 unsigned short row,
1095 print_callchain_entry_fn print,
1096 struct callchain_print_arg *arg,
1097 check_output_full_fn is_output_full)
1098{
1099 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001100 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001101 int printed;
1102
Namhyung Kim5eca1042016-01-28 00:40:55 +09001103 if (symbol_conf.cumulate_callchain)
1104 parent_total = entry->stat_acc->period;
1105 else
1106 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001107
1108 if (callchain_param.mode == CHAIN_FLAT) {
1109 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001110 &entry->sorted_chain, row,
1111 total, parent_total, print, arg,
1112 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001113 } else if (callchain_param.mode == CHAIN_FOLDED) {
1114 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001115 &entry->sorted_chain, row,
1116 total, parent_total, print, arg,
1117 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001118 } else {
1119 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001120 &entry->sorted_chain, level, row,
1121 total, parent_total, print, arg,
1122 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001123 }
1124
1125 if (arg->is_current_entry)
1126 browser->he_selection = entry;
1127
1128 return printed;
1129}
1130
Namhyung Kim89701462013-01-22 18:09:38 +09001131struct hpp_arg {
1132 struct ui_browser *b;
1133 char folded_sign;
1134 bool current_entry;
1135};
1136
Jiri Olsa98ba1602016-09-22 17:36:35 +02001137int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001138{
1139 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001140 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001141 va_list args;
1142 double percent;
1143
1144 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001145 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001146 percent = va_arg(args, double);
1147 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001148
Namhyung Kim89701462013-01-22 18:09:38 +09001149 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001150
Namhyung Kimd6751072014-07-31 14:47:36 +09001151 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001152 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001153
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001154 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001155}
1156
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001157#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001158static u64 __hpp_get_##_field(struct hist_entry *he) \
1159{ \
1160 return he->stat._field; \
1161} \
1162 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001163static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001164hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001165 struct perf_hpp *hpp, \
1166 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001167{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001168 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1169 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001170}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001171
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001172#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1173static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1174{ \
1175 return he->stat_acc->_field; \
1176} \
1177 \
1178static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001179hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001180 struct perf_hpp *hpp, \
1181 struct hist_entry *he) \
1182{ \
1183 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001184 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001185 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001186 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001187 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001188 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001189 \
1190 return ret; \
1191 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001192 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1193 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001194}
1195
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001196__HPP_COLOR_PERCENT_FN(overhead, period)
1197__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1198__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1199__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1200__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001201__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001202
1203#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001204#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001205
1206void hist_browser__init_hpp(void)
1207{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001208 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1209 hist_browser__hpp_color_overhead;
1210 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1211 hist_browser__hpp_color_overhead_sys;
1212 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1213 hist_browser__hpp_color_overhead_us;
1214 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1215 hist_browser__hpp_color_overhead_guest_sys;
1216 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1217 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001218 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1219 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001220}
1221
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001222static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001223 struct hist_entry *entry,
1224 unsigned short row)
1225{
Jiri Olsa12400052012-10-13 00:06:16 +02001226 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001227 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001228 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001229 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001230 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001231 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001232 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001233
1234 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001235 browser->he_selection = entry;
1236 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001237 }
1238
1239 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001240 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001241 folded_sign = hist_entry__folded(entry);
1242 }
1243
1244 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001245 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001246 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001247 .folded_sign = folded_sign,
1248 .current_entry = current_entry,
1249 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001250 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001251
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001252 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001253
Jiri Olsaf0786af2016-01-18 10:24:23 +01001254 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001255 char s[2048];
1256 struct perf_hpp hpp = {
1257 .buf = s,
1258 .size = sizeof(s),
1259 .ptr = &arg,
1260 };
1261
Namhyung Kim361459f2015-12-23 02:07:08 +09001262 if (perf_hpp__should_skip(fmt, entry->hists) ||
1263 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001264 continue;
1265
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001266 if (current_entry && browser->b.navkeypressed) {
1267 ui_browser__set_color(&browser->b,
1268 HE_COLORSET_SELECTED);
1269 } else {
1270 ui_browser__set_color(&browser->b,
1271 HE_COLORSET_NORMAL);
1272 }
1273
1274 if (first) {
Milian Wolff2a704fc2017-10-09 22:32:55 +02001275 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001276 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001277 width -= 2;
1278 }
1279 first = false;
1280 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001281 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001282 width -= 2;
1283 }
1284
Jiri Olsa12400052012-10-13 00:06:16 +02001285 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001286 int ret = fmt->color(fmt, &hpp, entry);
1287 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1288 /*
1289 * fmt->color() already used ui_browser to
1290 * print the non alignment bits, skip it (+ret):
1291 */
1292 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001293 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001294 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001295 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001296 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001297 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001298 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001299
1300 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001301 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001302 width += 1;
1303
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001304 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001305
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001306 ++row;
1307 ++printed;
1308 } else
1309 --row_offset;
1310
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001311 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001312 struct callchain_print_arg arg = {
1313 .row_offset = row_offset,
1314 .is_current_entry = current_entry,
1315 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001316
Milian Wolff2a704fc2017-10-09 22:32:55 +02001317 printed += hist_browser__show_callchain(browser,
1318 entry, 1, row,
1319 hist_browser__show_callchain_entry,
1320 &arg,
1321 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001322 }
1323
1324 return printed;
1325}
1326
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001327static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1328 struct hist_entry *entry,
1329 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001330 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001331{
1332 int printed = 0;
1333 int width = browser->b.width;
1334 char folded_sign = ' ';
1335 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1336 off_t row_offset = entry->row_offset;
1337 bool first = true;
1338 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001339 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001340 struct hpp_arg arg = {
1341 .b = &browser->b,
1342 .current_entry = current_entry,
1343 };
1344 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001345 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001346
1347 if (current_entry) {
1348 browser->he_selection = entry;
1349 browser->selection = &entry->ms;
1350 }
1351
1352 hist_entry__init_have_children(entry);
1353 folded_sign = hist_entry__folded(entry);
1354 arg.folded_sign = folded_sign;
1355
1356 if (entry->leaf && row_offset) {
1357 row_offset--;
1358 goto show_callchain;
1359 }
1360
1361 hist_browser__gotorc(browser, row, 0);
1362
1363 if (current_entry && browser->b.navkeypressed)
1364 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1365 else
1366 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1367
1368 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1369 width -= level * HIERARCHY_INDENT;
1370
Namhyung Kima61a22f2016-03-07 16:44:50 -03001371 /* the first hpp_list_node is for overhead columns */
1372 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1373 struct perf_hpp_list_node, list);
1374 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001375 char s[2048];
1376 struct perf_hpp hpp = {
1377 .buf = s,
1378 .size = sizeof(s),
1379 .ptr = &arg,
1380 };
1381
1382 if (perf_hpp__should_skip(fmt, entry->hists) ||
1383 column++ < browser->b.horiz_scroll)
1384 continue;
1385
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001386 if (current_entry && browser->b.navkeypressed) {
1387 ui_browser__set_color(&browser->b,
1388 HE_COLORSET_SELECTED);
1389 } else {
1390 ui_browser__set_color(&browser->b,
1391 HE_COLORSET_NORMAL);
1392 }
1393
1394 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001395 ui_browser__printf(&browser->b, "%c ", folded_sign);
1396 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001397 first = false;
1398 } else {
1399 ui_browser__printf(&browser->b, " ");
1400 width -= 2;
1401 }
1402
1403 if (fmt->color) {
1404 int ret = fmt->color(fmt, &hpp, entry);
1405 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1406 /*
1407 * fmt->color() already used ui_browser to
1408 * print the non alignment bits, skip it (+ret):
1409 */
1410 ui_browser__printf(&browser->b, "%s", s + ret);
1411 } else {
1412 int ret = fmt->entry(fmt, &hpp, entry);
1413 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1414 ui_browser__printf(&browser->b, "%s", s);
1415 }
1416 width -= hpp.buf - s;
1417 }
1418
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001419 if (!first) {
1420 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1421 width -= hierarchy_indent;
1422 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001423
1424 if (column >= browser->b.horiz_scroll) {
1425 char s[2048];
1426 struct perf_hpp hpp = {
1427 .buf = s,
1428 .size = sizeof(s),
1429 .ptr = &arg,
1430 };
1431
1432 if (current_entry && browser->b.navkeypressed) {
1433 ui_browser__set_color(&browser->b,
1434 HE_COLORSET_SELECTED);
1435 } else {
1436 ui_browser__set_color(&browser->b,
1437 HE_COLORSET_NORMAL);
1438 }
1439
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001440 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001441 if (first) {
1442 ui_browser__printf(&browser->b, "%c ", folded_sign);
1443 first = false;
1444 } else {
1445 ui_browser__write_nstring(&browser->b, "", 2);
1446 }
1447
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001448 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001449
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001450 /*
1451 * No need to call hist_entry__snprintf_alignment()
1452 * since this fmt is always the last column in the
1453 * hierarchy mode.
1454 */
1455 if (fmt->color) {
1456 width -= fmt->color(fmt, &hpp, entry);
1457 } else {
1458 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001459
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001460 width -= fmt->entry(fmt, &hpp, entry);
1461 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001462
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001463 while (isspace(s[i++]))
1464 width++;
1465 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001466 }
1467 }
1468
1469 /* The scroll bar isn't being used */
1470 if (!browser->b.navkeypressed)
1471 width += 1;
1472
1473 ui_browser__write_nstring(&browser->b, "", width);
1474
1475 ++row;
1476 ++printed;
1477
1478show_callchain:
1479 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1480 struct callchain_print_arg carg = {
1481 .row_offset = row_offset,
1482 };
1483
1484 printed += hist_browser__show_callchain(browser, entry,
1485 level + 1, row,
1486 hist_browser__show_callchain_entry, &carg,
1487 hist_browser__check_output_full);
1488 }
1489
1490 return printed;
1491}
1492
Namhyung Kim79dded82016-02-26 21:13:19 +09001493static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001494 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001495{
1496 int width = browser->b.width;
1497 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1498 bool first = true;
1499 int column = 0;
1500 int ret;
1501 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001502 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001503 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001504
1505 if (current_entry) {
1506 browser->he_selection = NULL;
1507 browser->selection = NULL;
1508 }
1509
1510 hist_browser__gotorc(browser, row, 0);
1511
1512 if (current_entry && browser->b.navkeypressed)
1513 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1514 else
1515 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1516
1517 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1518 width -= level * HIERARCHY_INDENT;
1519
Namhyung Kima61a22f2016-03-07 16:44:50 -03001520 /* the first hpp_list_node is for overhead columns */
1521 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1522 struct perf_hpp_list_node, list);
1523 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001524 if (perf_hpp__should_skip(fmt, browser->hists) ||
1525 column++ < browser->b.horiz_scroll)
1526 continue;
1527
Jiri Olsada1b0402016-06-14 20:19:20 +02001528 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001529
1530 if (first) {
1531 /* for folded sign */
1532 first = false;
1533 ret++;
1534 } else {
1535 /* space between columns */
1536 ret += 2;
1537 }
1538
1539 ui_browser__write_nstring(&browser->b, "", ret);
1540 width -= ret;
1541 }
1542
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001543 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1544 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001545
1546 if (column >= browser->b.horiz_scroll) {
1547 char buf[32];
1548
1549 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1550 ui_browser__printf(&browser->b, " %s", buf);
1551 width -= ret + 2;
1552 }
1553
1554 /* The scroll bar isn't being used */
1555 if (!browser->b.navkeypressed)
1556 width += 1;
1557
1558 ui_browser__write_nstring(&browser->b, "", width);
1559 return 1;
1560}
1561
Jiri Olsa81a888f2014-06-14 15:44:52 +02001562static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1563{
1564 advance_hpp(hpp, inc);
1565 return hpp->size <= 0;
1566}
1567
Jiri Olsa69705b32016-08-07 17:28:28 +02001568static int
1569hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1570 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001571{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001572 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001573 struct perf_hpp dummy_hpp = {
1574 .buf = buf,
1575 .size = size,
1576 };
1577 struct perf_hpp_fmt *fmt;
1578 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001579 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001580 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001581
1582 if (symbol_conf.use_callchain) {
1583 ret = scnprintf(buf, size, " ");
1584 if (advance_hpp_check(&dummy_hpp, ret))
1585 return ret;
1586 }
1587
Jiri Olsaf0786af2016-01-18 10:24:23 +01001588 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001589 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001590 continue;
1591
Jiri Olsa29659ab2016-08-07 17:28:30 +02001592 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001593 if (advance_hpp_check(&dummy_hpp, ret))
1594 break;
1595
Jiri Olsa29659ab2016-08-07 17:28:30 +02001596 if (span)
1597 continue;
1598
Jiri Olsa81a888f2014-06-14 15:44:52 +02001599 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1600 if (advance_hpp_check(&dummy_hpp, ret))
1601 break;
1602 }
1603
1604 return ret;
1605}
1606
Namhyung Kimd8b92402016-02-25 00:13:46 +09001607static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1608{
1609 struct hists *hists = browser->hists;
1610 struct perf_hpp dummy_hpp = {
1611 .buf = buf,
1612 .size = size,
1613 };
1614 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001615 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001616 size_t ret = 0;
1617 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001618 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001619 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001620
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001621 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001622 if (advance_hpp_check(&dummy_hpp, ret))
1623 return ret;
1624
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001625 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001626 /* the first hpp_list_node is for overhead columns */
1627 fmt_node = list_first_entry(&hists->hpp_formats,
1628 struct perf_hpp_list_node, list);
1629 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001630 if (column++ < browser->b.horiz_scroll)
1631 continue;
1632
Jiri Olsa29659ab2016-08-07 17:28:30 +02001633 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001634 if (advance_hpp_check(&dummy_hpp, ret))
1635 break;
1636
1637 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1638 if (advance_hpp_check(&dummy_hpp, ret))
1639 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001640
1641 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001642 }
1643
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001644 if (!first_node) {
1645 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1646 indent * HIERARCHY_INDENT, "");
1647 if (advance_hpp_check(&dummy_hpp, ret))
1648 return ret;
1649 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001650
Namhyung Kima61a22f2016-03-07 16:44:50 -03001651 first_node = true;
1652 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1653 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001654 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1655 if (advance_hpp_check(&dummy_hpp, ret))
1656 break;
1657 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001658 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001659
Namhyung Kima61a22f2016-03-07 16:44:50 -03001660 first_col = true;
1661 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1662 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001663
Namhyung Kima61a22f2016-03-07 16:44:50 -03001664 if (perf_hpp__should_skip(fmt, hists))
1665 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001666
Namhyung Kima61a22f2016-03-07 16:44:50 -03001667 if (!first_col) {
1668 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1669 if (advance_hpp_check(&dummy_hpp, ret))
1670 break;
1671 }
1672 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001673
Jiri Olsa29659ab2016-08-07 17:28:30 +02001674 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001675 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001676
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001677 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001678 ret = strlen(start);
1679
1680 if (start != dummy_hpp.buf)
1681 memmove(dummy_hpp.buf, start, ret + 1);
1682
1683 if (advance_hpp_check(&dummy_hpp, ret))
1684 break;
1685 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001686 }
1687
1688 return ret;
1689}
1690
Jiri Olsa01b47702016-06-14 20:19:13 +02001691static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001692{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001693 char headers[1024];
1694
Jiri Olsa01b47702016-06-14 20:19:13 +02001695 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1696 sizeof(headers));
1697
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001698 ui_browser__gotorc(&browser->b, 0, 0);
1699 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001700 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001701}
1702
Jiri Olsa01b47702016-06-14 20:19:13 +02001703static void hists_browser__headers(struct hist_browser *browser)
1704{
Jiri Olsa69705b32016-08-07 17:28:28 +02001705 struct hists *hists = browser->hists;
1706 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001707
Jiri Olsa69705b32016-08-07 17:28:28 +02001708 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001709
Jiri Olsa69705b32016-08-07 17:28:28 +02001710 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1711 char headers[1024];
1712
1713 hists_browser__scnprintf_headers(browser, headers,
1714 sizeof(headers), line);
1715
1716 ui_browser__gotorc(&browser->b, line, 0);
1717 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1718 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1719 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001720}
1721
1722static void hist_browser__show_headers(struct hist_browser *browser)
1723{
1724 if (symbol_conf.report_hierarchy)
1725 hists_browser__hierarchy_headers(browser);
1726 else
1727 hists_browser__headers(browser);
1728}
1729
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001730static void ui_browser__hists_init_top(struct ui_browser *browser)
1731{
1732 if (browser->top == NULL) {
1733 struct hist_browser *hb;
1734
1735 hb = container_of(browser, struct hist_browser, b);
1736 browser->top = rb_first(&hb->hists->entries);
1737 }
1738}
1739
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001740static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001741{
1742 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001743 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001744 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001745 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001746 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001747
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001748 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001749 struct perf_hpp_list *hpp_list = hists->hpp_list;
1750
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001751 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001752 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001753 }
1754
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001755 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001756 hb->he_selection = NULL;
1757 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001759 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001760 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001761 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001762
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001763 if (h->filtered) {
1764 /* let it move to sibling */
1765 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001767 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001768
Namhyung Kim14135662013-10-31 10:17:39 +09001769 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001770 if (percent < hb->min_pcnt)
1771 continue;
1772
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001773 if (symbol_conf.report_hierarchy) {
1774 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001775 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001776 if (row == browser->rows)
1777 break;
1778
1779 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001780 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001781 row++;
1782 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001783 } else {
1784 row += hist_browser__show_entry(hb, h, row);
1785 }
1786
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001787 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001788 break;
1789 }
1790
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001791 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001792}
1793
Namhyung Kim064f1982013-05-14 11:09:04 +09001794static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001795 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001796{
1797 while (nd != NULL) {
1798 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001799 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001800
Namhyung Kimc0f15272014-04-16 11:16:33 +09001801 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001802 return nd;
1803
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001804 /*
1805 * If it's filtered, its all children also were filtered.
1806 * So move to sibling node.
1807 */
1808 if (rb_next(nd))
1809 nd = rb_next(nd);
1810 else
1811 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001812 }
1813
1814 return NULL;
1815}
1816
Namhyung Kim064f1982013-05-14 11:09:04 +09001817static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001818 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001819{
1820 while (nd != NULL) {
1821 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001822 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001823
1824 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001825 return nd;
1826
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001827 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001828 }
1829
1830 return NULL;
1831}
1832
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001833static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001834 off_t offset, int whence)
1835{
1836 struct hist_entry *h;
1837 struct rb_node *nd;
1838 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001839 struct hist_browser *hb;
1840
1841 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001842
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001843 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001844 return;
1845
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001846 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001847
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001848 switch (whence) {
1849 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001850 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001851 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001852 break;
1853 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001854 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001855 goto do_offset;
1856 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001857 nd = rb_hierarchy_last(rb_last(browser->entries));
1858 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001859 first = false;
1860 break;
1861 default:
1862 return;
1863 }
1864
1865 /*
1866 * Moves not relative to the first visible entry invalidates its
1867 * row_offset:
1868 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001869 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001870 h->row_offset = 0;
1871
1872 /*
1873 * Here we have to check if nd is expanded (+), if it is we can't go
1874 * the next top level hist_entry, instead we must compute an offset of
1875 * what _not_ to show and not change the first visible entry.
1876 *
1877 * This offset increments when we are going from top to bottom and
1878 * decreases when we're going from bottom to top.
1879 *
1880 * As we don't have backpointers to the top level in the callchains
1881 * structure, we need to always print the whole hist_entry callchain,
1882 * skipping the first ones that are before the first visible entry
1883 * and stop when we printed enough lines to fill the screen.
1884 */
1885do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001886 if (!nd)
1887 return;
1888
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001889 if (offset > 0) {
1890 do {
1891 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001892 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001893 u16 remaining = h->nr_rows - h->row_offset;
1894 if (offset > remaining) {
1895 offset -= remaining;
1896 h->row_offset = 0;
1897 } else {
1898 h->row_offset += offset;
1899 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001900 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001901 break;
1902 }
1903 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001904 nd = hists__filter_entries(rb_hierarchy_next(nd),
1905 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001906 if (nd == NULL)
1907 break;
1908 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001909 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001910 } while (offset != 0);
1911 } else if (offset < 0) {
1912 while (1) {
1913 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001914 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001915 if (first) {
1916 if (-offset > h->row_offset) {
1917 offset += h->row_offset;
1918 h->row_offset = 0;
1919 } else {
1920 h->row_offset += offset;
1921 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001922 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001923 break;
1924 }
1925 } else {
1926 if (-offset > h->nr_rows) {
1927 offset += h->nr_rows;
1928 h->row_offset = 0;
1929 } else {
1930 h->row_offset = h->nr_rows + offset;
1931 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001932 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001933 break;
1934 }
1935 }
1936 }
1937
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001938 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001939 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001940 if (nd == NULL)
1941 break;
1942 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001943 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001944 if (offset == 0) {
1945 /*
1946 * Last unfiltered hist_entry, check if it is
1947 * unfolded, if it is then we should have
1948 * row_offset at its last entry.
1949 */
1950 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001951 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001952 h->row_offset = h->nr_rows;
1953 break;
1954 }
1955 first = false;
1956 }
1957 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001958 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001959 h = rb_entry(nd, struct hist_entry, rb_node);
1960 h->row_offset = 0;
1961 }
1962}
1963
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001964static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001965 struct hist_entry *he, FILE *fp,
1966 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001967{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001968 struct callchain_print_arg arg = {
1969 .fp = fp,
1970 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001971
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001972 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001973 hist_browser__fprintf_callchain_entry, &arg,
1974 hist_browser__check_dump_full);
1975 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001976}
1977
1978static int hist_browser__fprintf_entry(struct hist_browser *browser,
1979 struct hist_entry *he, FILE *fp)
1980{
1981 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001982 int printed = 0;
1983 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001984 struct perf_hpp hpp = {
1985 .buf = s,
1986 .size = sizeof(s),
1987 };
1988 struct perf_hpp_fmt *fmt;
1989 bool first = true;
1990 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001991
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001992 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001993 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001994 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001995 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001996
Jiri Olsaf0786af2016-01-18 10:24:23 +01001997 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001998 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001999 continue;
2000
Namhyung Kim26d8b332014-03-03 16:16:20 +09002001 if (!first) {
2002 ret = scnprintf(hpp.buf, hpp.size, " ");
2003 advance_hpp(&hpp, ret);
2004 } else
2005 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002006
Namhyung Kim26d8b332014-03-03 16:16:20 +09002007 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002008 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002009 advance_hpp(&hpp, ret);
2010 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002011 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002012
2013 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002014 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2015
2016 return printed;
2017}
2018
2019
2020static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2021 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002022 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002023{
2024 char s[8192];
2025 int printed = 0;
2026 char folded_sign = ' ';
2027 struct perf_hpp hpp = {
2028 .buf = s,
2029 .size = sizeof(s),
2030 };
2031 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002032 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002033 bool first = true;
2034 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002035 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002036
2037 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2038
2039 folded_sign = hist_entry__folded(he);
2040 printed += fprintf(fp, "%c", folded_sign);
2041
Namhyung Kim325a6282016-03-09 22:47:00 +09002042 /* the first hpp_list_node is for overhead columns */
2043 fmt_node = list_first_entry(&he->hists->hpp_formats,
2044 struct perf_hpp_list_node, list);
2045 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002046 if (!first) {
2047 ret = scnprintf(hpp.buf, hpp.size, " ");
2048 advance_hpp(&hpp, ret);
2049 } else
2050 first = false;
2051
2052 ret = fmt->entry(fmt, &hpp, he);
2053 advance_hpp(&hpp, ret);
2054 }
2055
2056 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2057 advance_hpp(&hpp, ret);
2058
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002059 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2060 ret = scnprintf(hpp.buf, hpp.size, " ");
2061 advance_hpp(&hpp, ret);
2062
2063 ret = fmt->entry(fmt, &hpp, he);
2064 advance_hpp(&hpp, ret);
2065 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002066
2067 printed += fprintf(fp, "%s\n", rtrim(s));
2068
2069 if (he->leaf && folded_sign == '-') {
2070 printed += hist_browser__fprintf_callchain(browser, he, fp,
2071 he->depth + 1);
2072 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002073
2074 return printed;
2075}
2076
2077static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2078{
Namhyung Kim064f1982013-05-14 11:09:04 +09002079 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002080 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002081 int printed = 0;
2082
2083 while (nd) {
2084 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2085
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002086 if (symbol_conf.report_hierarchy) {
2087 printed += hist_browser__fprintf_hierarchy_entry(browser,
2088 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002089 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002090 } else {
2091 printed += hist_browser__fprintf_entry(browser, h, fp);
2092 }
2093
2094 nd = hists__filter_entries(rb_hierarchy_next(nd),
2095 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002096 }
2097
2098 return printed;
2099}
2100
2101static int hist_browser__dump(struct hist_browser *browser)
2102{
2103 char filename[64];
2104 FILE *fp;
2105
2106 while (1) {
2107 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2108 if (access(filename, F_OK))
2109 break;
2110 /*
2111 * XXX: Just an arbitrary lazy upper limit
2112 */
2113 if (++browser->print_seq == 8192) {
2114 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2115 return -1;
2116 }
2117 }
2118
2119 fp = fopen(filename, "w");
2120 if (fp == NULL) {
2121 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002122 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002123 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002124 return -1;
2125 }
2126
2127 ++browser->print_seq;
2128 hist_browser__fprintf(browser, fp);
2129 fclose(fp);
2130 ui_helpline__fpush("%s written!", filename);
2131
2132 return 0;
2133}
2134
Jiri Olsafcd86422016-06-20 23:58:18 +02002135void hist_browser__init(struct hist_browser *browser,
2136 struct hists *hists)
2137{
2138 struct perf_hpp_fmt *fmt;
2139
2140 browser->hists = hists;
2141 browser->b.refresh = hist_browser__refresh;
2142 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2143 browser->b.seek = ui_browser__hists_seek;
2144 browser->b.use_navkeypressed = true;
2145 browser->show_headers = symbol_conf.show_hist_headers;
2146
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002147 if (symbol_conf.report_hierarchy) {
2148 struct perf_hpp_list_node *fmt_node;
2149
2150 /* count overhead columns (in the first node) */
2151 fmt_node = list_first_entry(&hists->hpp_formats,
2152 struct perf_hpp_list_node, list);
2153 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2154 ++browser->b.columns;
2155
2156 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002157 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002158 } else {
2159 hists__for_each_format(hists, fmt)
2160 ++browser->b.columns;
2161 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002162
2163 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002164}
2165
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002166struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002167{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002168 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002169
Jiri Olsafcd86422016-06-20 23:58:18 +02002170 if (browser)
2171 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002172
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002173 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002174}
2175
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002176static struct hist_browser *
2177perf_evsel_browser__new(struct perf_evsel *evsel,
2178 struct hist_browser_timer *hbt,
2179 struct perf_env *env)
2180{
2181 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2182
2183 if (browser) {
2184 browser->hbt = hbt;
2185 browser->env = env;
2186 browser->title = perf_evsel_browser_title;
2187 }
2188 return browser;
2189}
2190
Jiri Olsadabd2012016-06-20 23:58:14 +02002191void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002192{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002193 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002194}
2195
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002196static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002197{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002198 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002199}
2200
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002201static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002202{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002203 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002204}
2205
Taeung Song1e378eb2014-10-07 16:13:15 +09002206/* Check whether the browser is for 'top' or 'report' */
2207static inline bool is_report_browser(void *timer)
2208{
2209 return timer == NULL;
2210}
2211
Jiri Olsa5b91a862016-06-20 23:58:15 +02002212static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002213 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002214{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002215 struct hist_browser_timer *hbt = browser->hbt;
2216 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002217 char unit;
2218 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002219 const struct dso *dso = hists->dso_filter;
2220 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002221 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002222 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2223 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002224 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002225 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Meloa9980a62018-03-01 14:22:12 -03002226 char buf[512], sample_freq_str[64] = "";
Namhyung Kim717e2632013-01-22 18:09:44 +09002227 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002228 char ref[30] = " show reference callgraph, ";
2229 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002230
Namhyung Kimf2148332014-01-14 11:52:48 +09002231 if (symbol_conf.filter_relative) {
2232 nr_samples = hists->stats.nr_non_filtered_samples;
2233 nr_events = hists->stats.total_non_filtered_period;
2234 }
2235
Namhyung Kim759ff492013-03-05 14:53:26 +09002236 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002237 struct perf_evsel *pos;
2238
2239 perf_evsel__group_desc(evsel, buf, buflen);
2240 ev_name = buf;
2241
2242 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002243 struct hists *pos_hists = evsel__hists(pos);
2244
Namhyung Kimf2148332014-01-14 11:52:48 +09002245 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002246 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2247 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002248 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002249 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2250 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002251 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002252 }
2253 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002254
Kan Liang9e207dd2015-08-11 06:30:49 -04002255 if (symbol_conf.show_ref_callgraph &&
2256 strstr(ev_name, "call-graph=no"))
2257 enable_ref = true;
Arnaldo Carvalho de Meloa9980a62018-03-01 14:22:12 -03002258
2259 if (!is_report_browser(hbt))
2260 scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq);
2261
Ashay Ranecc6862802012-04-05 21:01:01 -05002262 nr_samples = convert_unit(nr_samples, &unit);
2263 printed = scnprintf(bf, size,
Jiri Olsa8ef278b2018-03-07 16:50:02 +01002264 "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
2265 nr_samples, unit, evsel->nr_members > 1 ? "s" : "",
2266 ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002267
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002268
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002269 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002270 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002271 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002272 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002273 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002274 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002275 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002276 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002277 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002278 } else {
2279 printed += scnprintf(bf + printed, size - printed,
2280 ", Thread: %s",
2281 (thread->comm_set ? thread__comm_str(thread) : ""));
2282 }
2283 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002284 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002285 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002286 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002287 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002288 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002289 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002290 if (!is_report_browser(hbt)) {
2291 struct perf_top *top = hbt->arg;
2292
2293 if (top->zero)
2294 printed += scnprintf(bf + printed, size - printed, " [z]");
2295 }
2296
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002297 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002298}
2299
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002300static inline void free_popup_options(char **options, int n)
2301{
2302 int i;
2303
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002304 for (i = 0; i < n; ++i)
2305 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002306}
2307
Feng Tang341487ab2013-02-03 14:38:20 +08002308/*
2309 * Only runtime switching of perf data file will make "input_name" point
2310 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2311 * whether we need to call free() for current "input_name" during the switch.
2312 */
2313static bool is_input_name_malloced = false;
2314
2315static int switch_data_file(void)
2316{
2317 char *pwd, *options[32], *abs_path[32], *tmp;
2318 DIR *pwd_dir;
2319 int nr_options = 0, choice = -1, ret = -1;
2320 struct dirent *dent;
2321
2322 pwd = getenv("PWD");
2323 if (!pwd)
2324 return ret;
2325
2326 pwd_dir = opendir(pwd);
2327 if (!pwd_dir)
2328 return ret;
2329
2330 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002331 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002332
2333 while ((dent = readdir(pwd_dir))) {
2334 char path[PATH_MAX];
2335 u64 magic;
2336 char *name = dent->d_name;
2337 FILE *file;
2338
2339 if (!(dent->d_type == DT_REG))
2340 continue;
2341
2342 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2343
2344 file = fopen(path, "r");
2345 if (!file)
2346 continue;
2347
2348 if (fread(&magic, 1, 8, file) < 8)
2349 goto close_file_and_continue;
2350
2351 if (is_perf_magic(magic)) {
2352 options[nr_options] = strdup(name);
2353 if (!options[nr_options])
2354 goto close_file_and_continue;
2355
2356 abs_path[nr_options] = strdup(path);
2357 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002358 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002359 ui__warning("Can't search all data files due to memory shortage.\n");
2360 fclose(file);
2361 break;
2362 }
2363
2364 nr_options++;
2365 }
2366
2367close_file_and_continue:
2368 fclose(file);
2369 if (nr_options >= 32) {
2370 ui__warning("Too many perf data files in PWD!\n"
2371 "Only the first 32 files will be listed.\n");
2372 break;
2373 }
2374 }
2375 closedir(pwd_dir);
2376
2377 if (nr_options) {
2378 choice = ui__popup_menu(nr_options, options);
2379 if (choice < nr_options && choice >= 0) {
2380 tmp = strdup(abs_path[choice]);
2381 if (tmp) {
2382 if (is_input_name_malloced)
2383 free((void *)input_name);
2384 input_name = tmp;
2385 is_input_name_malloced = true;
2386 ret = 0;
2387 } else
2388 ui__warning("Data switch failed due to memory shortage!\n");
2389 }
2390 }
2391
2392 free_popup_options(options, nr_options);
2393 free_popup_options(abs_path, nr_options);
2394 return ret;
2395}
2396
Namhyung Kimea7cd592015-04-22 16:18:19 +09002397struct popup_action {
2398 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002399 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002400 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002401
2402 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2403};
2404
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002405static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002406do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002407{
2408 struct perf_evsel *evsel;
2409 struct annotation *notes;
2410 struct hist_entry *he;
2411 int err;
2412
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002413 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002414 return 0;
2415
Namhyung Kimea7cd592015-04-22 16:18:19 +09002416 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002417 if (!notes->src)
2418 return 0;
2419
2420 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002421 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002422 he = hist_browser__selected_entry(browser);
2423 /*
2424 * offer option to annotate the other branch source or target
2425 * (if they exists) when returning from annotate
2426 */
2427 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2428 return 1;
2429
2430 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2431 if (err)
2432 ui_browser__handle_resize(&browser->b);
2433 return 0;
2434}
2435
2436static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002437add_annotate_opt(struct hist_browser *browser __maybe_unused,
2438 struct popup_action *act, char **optstr,
2439 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002440{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002441 if (sym == NULL || map->dso->annotate_warned)
2442 return 0;
2443
2444 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2445 return 0;
2446
2447 act->ms.map = map;
2448 act->ms.sym = sym;
2449 act->fn = do_annotate;
2450 return 1;
2451}
2452
2453static int
2454do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2455{
2456 struct thread *thread = act->thread;
2457
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002458 if ((!hists__has(browser->hists, thread) &&
2459 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002460 return 0;
2461
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002462 if (browser->hists->thread_filter) {
2463 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2464 perf_hpp__set_elide(HISTC_THREAD, false);
2465 thread__zput(browser->hists->thread_filter);
2466 ui_helpline__pop();
2467 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002468 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002469 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2470 thread->comm_set ? thread__comm_str(thread) : "",
2471 thread->tid);
2472 } else {
2473 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2474 thread->comm_set ? thread__comm_str(thread) : "");
2475 }
2476
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002477 browser->hists->thread_filter = thread__get(thread);
2478 perf_hpp__set_elide(HISTC_THREAD, false);
2479 pstack__push(browser->pstack, &browser->hists->thread_filter);
2480 }
2481
2482 hists__filter_by_thread(browser->hists);
2483 hist_browser__reset(browser);
2484 return 0;
2485}
2486
2487static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002488add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2489 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002490{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002491 int ret;
2492
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002493 if ((!hists__has(browser->hists, thread) &&
2494 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002495 return 0;
2496
Jiri Olsafa829112016-05-03 13:54:47 +02002497 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002498 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2499 browser->hists->thread_filter ? "out of" : "into",
2500 thread->comm_set ? thread__comm_str(thread) : "",
2501 thread->tid);
2502 } else {
2503 ret = asprintf(optstr, "Zoom %s %s thread",
2504 browser->hists->thread_filter ? "out of" : "into",
2505 thread->comm_set ? thread__comm_str(thread) : "");
2506 }
2507 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002508 return 0;
2509
2510 act->thread = thread;
2511 act->fn = do_zoom_thread;
2512 return 1;
2513}
2514
2515static int
2516do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2517{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002518 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002519
Jiri Olsa69849fc2016-05-03 13:54:45 +02002520 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002521 return 0;
2522
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002523 if (browser->hists->dso_filter) {
2524 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2525 perf_hpp__set_elide(HISTC_DSO, false);
2526 browser->hists->dso_filter = NULL;
2527 ui_helpline__pop();
2528 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002529 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002530 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2531 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002532 perf_hpp__set_elide(HISTC_DSO, true);
2533 pstack__push(browser->pstack, &browser->hists->dso_filter);
2534 }
2535
2536 hists__filter_by_dso(browser->hists);
2537 hist_browser__reset(browser);
2538 return 0;
2539}
2540
2541static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002542add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002543 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002544{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002545 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002546 return 0;
2547
2548 if (asprintf(optstr, "Zoom %s %s DSO",
2549 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002550 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002551 return 0;
2552
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002553 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002554 act->fn = do_zoom_dso;
2555 return 1;
2556}
2557
2558static int
2559do_browse_map(struct hist_browser *browser __maybe_unused,
2560 struct popup_action *act)
2561{
2562 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002563 return 0;
2564}
2565
2566static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002567add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002568 struct popup_action *act, char **optstr, struct map *map)
2569{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002570 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002571 return 0;
2572
2573 if (asprintf(optstr, "Browse map details") < 0)
2574 return 0;
2575
2576 act->ms.map = map;
2577 act->fn = do_browse_map;
2578 return 1;
2579}
2580
2581static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002582do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002583 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002584{
2585 char script_opt[64];
2586 memset(script_opt, 0, sizeof(script_opt));
2587
Namhyung Kimea7cd592015-04-22 16:18:19 +09002588 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002589 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002590 thread__comm_str(act->thread));
2591 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002592 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002593 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002594 }
2595
2596 script_browse(script_opt);
2597 return 0;
2598}
2599
2600static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002601add_script_opt(struct hist_browser *browser __maybe_unused,
2602 struct popup_action *act, char **optstr,
2603 struct thread *thread, struct symbol *sym)
2604{
2605 if (thread) {
2606 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2607 thread__comm_str(thread)) < 0)
2608 return 0;
2609 } else if (sym) {
2610 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2611 sym->name) < 0)
2612 return 0;
2613 } else {
2614 if (asprintf(optstr, "Run scripts for all samples") < 0)
2615 return 0;
2616 }
2617
2618 act->thread = thread;
2619 act->ms.sym = sym;
2620 act->fn = do_run_script;
2621 return 1;
2622}
2623
2624static int
2625do_switch_data(struct hist_browser *browser __maybe_unused,
2626 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002627{
2628 if (switch_data_file()) {
2629 ui__warning("Won't switch the data files due to\n"
2630 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002631 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002632 }
2633
2634 return K_SWITCH_INPUT_DATA;
2635}
2636
Namhyung Kimea7cd592015-04-22 16:18:19 +09002637static int
2638add_switch_opt(struct hist_browser *browser,
2639 struct popup_action *act, char **optstr)
2640{
2641 if (!is_report_browser(browser->hbt))
2642 return 0;
2643
2644 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2645 return 0;
2646
2647 act->fn = do_switch_data;
2648 return 1;
2649}
2650
2651static int
2652do_exit_browser(struct hist_browser *browser __maybe_unused,
2653 struct popup_action *act __maybe_unused)
2654{
2655 return 0;
2656}
2657
2658static int
2659add_exit_opt(struct hist_browser *browser __maybe_unused,
2660 struct popup_action *act, char **optstr)
2661{
2662 if (asprintf(optstr, "Exit") < 0)
2663 return 0;
2664
2665 act->fn = do_exit_browser;
2666 return 1;
2667}
2668
Kan Liang84734b02015-09-04 10:45:45 -04002669static int
2670do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2671{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002672 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002673 return 0;
2674
Kan Liang84734b02015-09-04 10:45:45 -04002675 if (browser->hists->socket_filter > -1) {
2676 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2677 browser->hists->socket_filter = -1;
2678 perf_hpp__set_elide(HISTC_SOCKET, false);
2679 } else {
2680 browser->hists->socket_filter = act->socket;
2681 perf_hpp__set_elide(HISTC_SOCKET, true);
2682 pstack__push(browser->pstack, &browser->hists->socket_filter);
2683 }
2684
2685 hists__filter_by_socket(browser->hists);
2686 hist_browser__reset(browser);
2687 return 0;
2688}
2689
2690static int
2691add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2692 char **optstr, int socket_id)
2693{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002694 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002695 return 0;
2696
2697 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2698 (browser->hists->socket_filter > -1) ? "out of" : "into",
2699 socket_id) < 0)
2700 return 0;
2701
2702 act->socket = socket_id;
2703 act->fn = do_zoom_socket;
2704 return 1;
2705}
2706
Namhyung Kim112f7612014-04-22 14:05:35 +09002707static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002708{
2709 u64 nr_entries = 0;
2710 struct rb_node *nd = rb_first(&hb->hists->entries);
2711
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002712 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002713 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2714 return;
2715 }
2716
Namhyung Kim14135662013-10-31 10:17:39 +09002717 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002718 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002719 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002720 }
2721
Namhyung Kim112f7612014-04-22 14:05:35 +09002722 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002723 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002724}
Feng Tang341487ab2013-02-03 14:38:20 +08002725
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002726static void hist_browser__update_percent_limit(struct hist_browser *hb,
2727 double percent)
2728{
2729 struct hist_entry *he;
2730 struct rb_node *nd = rb_first(&hb->hists->entries);
2731 u64 total = hists__total_period(hb->hists);
2732 u64 min_callchain_hits = total * (percent / 100);
2733
2734 hb->min_pcnt = callchain_param.min_percent = percent;
2735
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002736 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2737 he = rb_entry(nd, struct hist_entry, rb_node);
2738
Namhyung Kim79dded82016-02-26 21:13:19 +09002739 if (he->has_no_entry) {
2740 he->has_no_entry = false;
2741 he->nr_rows = 0;
2742 }
2743
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002744 if (!he->leaf || !symbol_conf.use_callchain)
2745 goto next;
2746
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002747 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2748 total = he->stat.period;
2749
2750 if (symbol_conf.cumulate_callchain)
2751 total = he->stat_acc->period;
2752
2753 min_callchain_hits = total * (percent / 100);
2754 }
2755
2756 callchain_param.sort(&he->sorted_chain, he->callchain,
2757 min_callchain_hits, &callchain_param);
2758
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002759next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002760 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002761
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002762 /* force to re-evaluate folding state of callchains */
2763 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002764 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002765 }
2766}
2767
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002768static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002769 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002770 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002771 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002772 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08002773 struct perf_env *env,
2774 bool warn_lost_event)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002775{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002776 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002777 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002778 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002779#define MAX_OPTIONS 16
2780 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002781 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002782 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002783 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002784 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002785 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002786
Namhyung Kime8e684a2013-12-26 14:37:58 +09002787#define HIST_BROWSER_HELP_COMMON \
2788 "h/?/F1 Show this window\n" \
2789 "UP/DOWN/PGUP\n" \
2790 "PGDN/SPACE Navigate\n" \
2791 "q/ESC/CTRL+C Exit browser\n\n" \
2792 "For multiple event sessions:\n\n" \
2793 "TAB/UNTAB Switch events\n\n" \
2794 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002795 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2796 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002797 "a Annotate current symbol\n" \
2798 "C Collapse all callchains\n" \
2799 "d Zoom into current DSO\n" \
2800 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002801 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002802 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002803 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002804 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002805 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002806
2807 /* help messages are sorted by lexical order of the hotkey */
2808 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002809 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002810 "P Print histograms to perf.hist.N\n"
2811 "r Run available scripts\n"
2812 "s Switch to another data file in PWD\n"
2813 "t Zoom into current Thread\n"
2814 "V Verbose (DSO names in callchains, etc)\n"
2815 "/ Filter symbol by name";
2816 const char top_help[] = HIST_BROWSER_HELP_COMMON
2817 "P Print histograms to perf.hist.N\n"
2818 "t Zoom into current Thread\n"
2819 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002820 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002821 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002822 "/ Filter symbol by name";
2823
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002824 if (browser == NULL)
2825 return -1;
2826
Namhyung Kimed426912015-05-29 21:53:44 +09002827 /* reset abort key so that it can get Ctrl-C as a key */
2828 SLang_reset_tty();
2829 SLang_init_tty(0, 0, 0);
2830
Namhyung Kim03905042015-11-28 02:32:39 +09002831 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002832 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002833 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002834
Kan Liang84734b02015-09-04 10:45:45 -04002835 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002836 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002837 goto out;
2838
2839 ui_helpline__push(helpline);
2840
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002841 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002842 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002843
Namhyung Kim5b591662014-07-31 14:47:38 +09002844 if (symbol_conf.col_width_list_str)
2845 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2846
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002847 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002848 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002849 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002850 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002851 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002852
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002853 nr_options = 0;
2854
Kan Liang06cc1a42018-01-18 13:26:29 -08002855 key = hist_browser__run(browser, helpline,
2856 warn_lost_event);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002857
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002858 if (browser->he_selection != NULL) {
2859 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002860 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002861 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002862 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002863 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002864 case K_TAB:
2865 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002866 if (nr_events == 1)
2867 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002868 /*
2869 * Exit the browser, let hists__browser_tree
2870 * go to the next or previous
2871 */
2872 goto out_free_stack;
2873 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002874 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002875 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002876 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002877 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002878 continue;
2879 }
2880
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002881 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002882 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002883 browser->selection->map->dso->annotate_warned)
2884 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002885
Namhyung Kimea7cd592015-04-22 16:18:19 +09002886 actions->ms.map = browser->selection->map;
2887 actions->ms.sym = browser->selection->sym;
2888 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002889 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002890 case 'P':
2891 hist_browser__dump(browser);
2892 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002893 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002894 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002895 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002896 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002897 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02002898 verbose = (verbose + 1) % 4;
2899 browser->show_dso = verbose > 0;
2900 ui_helpline__fpush("Verbosity level set to %d\n",
2901 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002902 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002903 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002904 actions->thread = thread;
2905 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002906 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002907 case 'S':
2908 actions->socket = socked_id;
2909 do_zoom_socket(browser, actions);
2910 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002911 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002912 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002913 "Please enter the name of symbol you want to see.\n"
2914 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002915 buf, "ENTER: OK, ESC: Cancel",
2916 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002917 hists->symbol_filter_str = *buf ? buf : NULL;
2918 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002919 hist_browser__reset(browser);
2920 }
2921 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002922 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002923 if (is_report_browser(hbt)) {
2924 actions->thread = NULL;
2925 actions->ms.sym = NULL;
2926 do_run_script(browser, actions);
2927 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002928 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002929 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002930 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002931 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002932 if (key == K_SWITCH_INPUT_DATA)
2933 goto out_free_stack;
2934 }
Feng Tang341487ab2013-02-03 14:38:20 +08002935 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002936 case 'i':
2937 /* env->arch is NULL for live-mode (i.e. perf top) */
2938 if (env->arch)
2939 tui__header_window(env);
2940 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002941 case 'F':
2942 symbol_conf.filter_relative ^= 1;
2943 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002944 case 'z':
2945 if (!is_report_browser(hbt)) {
2946 struct perf_top *top = hbt->arg;
2947
2948 top->zero = !top->zero;
2949 }
2950 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002951 case 'L':
2952 if (ui_browser__input_window("Percent Limit",
2953 "Please enter the value you want to hide entries under that percent.",
2954 buf, "ENTER: OK, ESC: Cancel",
2955 delay_secs * 2) == K_ENTER) {
2956 char *end;
2957 double new_percent = strtod(buf, &end);
2958
2959 if (new_percent < 0 || new_percent > 100) {
2960 ui_browser__warning(&browser->b, delay_secs * 2,
2961 "Invalid percent: %.2f", new_percent);
2962 continue;
2963 }
2964
2965 hist_browser__update_percent_limit(browser, new_percent);
2966 hist_browser__reset(browser);
2967 }
2968 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002969 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002970 case 'h':
2971 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002972 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002973 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002974 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002975 case K_ENTER:
2976 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002977 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002978 /* menu */
2979 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002980 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002981 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002982 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002983
Namhyung Kim01f00a12015-04-22 16:18:16 +09002984 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002985 /*
2986 * Go back to the perf_evsel_menu__run or other user
2987 */
2988 if (left_exits)
2989 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002990
2991 if (key == K_ESC &&
2992 ui_browser__dialog_yesno(&browser->b,
2993 "Do you really want to exit?"))
2994 goto out_free_stack;
2995
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002996 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002997 }
Namhyung Kim64221842015-04-24 10:15:33 +09002998 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002999 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003000 /*
3001 * No need to set actions->dso here since
3002 * it's just to remove the current filter.
3003 * Ditto for thread below.
3004 */
3005 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003006 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003007 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003008 } else if (top == &browser->hists->socket_filter) {
3009 do_zoom_socket(browser, actions);
3010 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003011 continue;
3012 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003013 case 'q':
3014 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003015 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003016 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003017 if (!is_report_browser(hbt)) {
3018 struct perf_top *top = hbt->arg;
3019
3020 perf_evlist__toggle_enable(top->evlist);
3021 /*
3022 * No need to refresh, resort/decay histogram
3023 * entries if we are not collecting samples:
3024 */
3025 if (top->evlist->enabled) {
3026 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3027 hbt->refresh = delay_secs;
3028 } else {
3029 helpline = "Press 'f' again to re-enable the events";
3030 hbt->refresh = 0;
3031 }
3032 continue;
3033 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003034 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003035 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003036 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003037 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003038 }
3039
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003040 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003041 goto skip_annotation;
3042
Namhyung Kim55369fc2013-04-01 20:35:20 +09003043 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003044 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003045
3046 if (bi == NULL)
3047 goto skip_annotation;
3048
Namhyung Kimea7cd592015-04-22 16:18:19 +09003049 nr_options += add_annotate_opt(browser,
3050 &actions[nr_options],
3051 &options[nr_options],
3052 bi->from.map,
3053 bi->from.sym);
3054 if (bi->to.sym != bi->from.sym)
3055 nr_options += add_annotate_opt(browser,
3056 &actions[nr_options],
3057 &options[nr_options],
3058 bi->to.map,
3059 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003060 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003061 nr_options += add_annotate_opt(browser,
3062 &actions[nr_options],
3063 &options[nr_options],
3064 browser->selection->map,
3065 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003066 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003067skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003068 nr_options += add_thread_opt(browser, &actions[nr_options],
3069 &options[nr_options], thread);
3070 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003071 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003072 nr_options += add_map_opt(browser, &actions[nr_options],
3073 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003074 browser->selection ?
3075 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003076 nr_options += add_socket_opt(browser, &actions[nr_options],
3077 &options[nr_options],
3078 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003079 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003080 if (!is_report_browser(hbt))
3081 goto skip_scripting;
3082
Feng Tangcdbab7c2012-10-30 11:56:06 +08003083 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003084 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003085 nr_options += add_script_opt(browser,
3086 &actions[nr_options],
3087 &options[nr_options],
3088 thread, NULL);
3089 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003090 /*
3091 * Note that browser->selection != NULL
3092 * when browser->he_selection is not NULL,
3093 * so we don't need to check browser->selection
3094 * before fetching browser->selection->sym like what
3095 * we do before fetching browser->selection->map.
3096 *
3097 * See hist_browser__show_entry.
3098 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003099 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003100 nr_options += add_script_opt(browser,
3101 &actions[nr_options],
3102 &options[nr_options],
3103 NULL, browser->selection->sym);
3104 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003105 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003106 nr_options += add_script_opt(browser, &actions[nr_options],
3107 &options[nr_options], NULL, NULL);
3108 nr_options += add_switch_opt(browser, &actions[nr_options],
3109 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003110skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003111 nr_options += add_exit_opt(browser, &actions[nr_options],
3112 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003113
Namhyung Kimea7cd592015-04-22 16:18:19 +09003114 do {
3115 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003116
Namhyung Kimea7cd592015-04-22 16:18:19 +09003117 choice = ui__popup_menu(nr_options, options);
3118 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003119 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003120
3121 act = &actions[choice];
3122 key = act->fn(browser, act);
3123 } while (key == 1);
3124
3125 if (key == K_SWITCH_INPUT_DATA)
3126 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003127 }
3128out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003129 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003130out:
3131 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003132 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003133 return key;
3134}
3135
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003136struct perf_evsel_menu {
3137 struct ui_browser b;
3138 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003139 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003140 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003141 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003142};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003143
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003144static void perf_evsel_menu__write(struct ui_browser *browser,
3145 void *entry, int row)
3146{
3147 struct perf_evsel_menu *menu = container_of(browser,
3148 struct perf_evsel_menu, b);
3149 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003150 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003151 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003152 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003153 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003154 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003155 const char *warn = " ";
3156 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003157
3158 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3159 HE_COLORSET_NORMAL);
3160
Namhyung Kim759ff492013-03-05 14:53:26 +09003161 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003162 struct perf_evsel *pos;
3163
3164 ev_name = perf_evsel__group_name(evsel);
3165
3166 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003167 struct hists *pos_hists = evsel__hists(pos);
3168 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003169 }
3170 }
3171
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003172 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003173 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003174 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003175 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003176
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003177 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003178 if (nr_events != 0) {
3179 menu->lost_events = true;
3180 if (!current_entry)
3181 ui_browser__set_color(browser, HE_COLORSET_TOP);
3182 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003183 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3184 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003185 warn = bf;
3186 }
3187
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003188 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003189
3190 if (current_entry)
3191 menu->selection = evsel;
3192}
3193
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003194static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3195 int nr_events, const char *help,
Kan Liang06cc1a42018-01-18 13:26:29 -08003196 struct hist_browser_timer *hbt,
3197 bool warn_lost_event)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003198{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003199 struct perf_evlist *evlist = menu->b.priv;
3200 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003201 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003202 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003203 int key;
3204
3205 if (ui_browser__show(&menu->b, title,
3206 "ESC: exit, ENTER|->: Browse histograms") < 0)
3207 return -1;
3208
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003209 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003210 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003211
3212 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003213 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003214 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003215
Kan Liang06cc1a42018-01-18 13:26:29 -08003216 if (!menu->lost_events_warned &&
3217 menu->lost_events &&
3218 warn_lost_event) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003219 ui_browser__warn_lost_events(&menu->b);
3220 menu->lost_events_warned = true;
3221 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003222 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003223 case K_RIGHT:
3224 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003225 if (!menu->selection)
3226 continue;
3227 pos = menu->selection;
3228browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003229 perf_evlist__set_selected(evlist, pos);
3230 /*
3231 * Give the calling tool a chance to populate the non
3232 * default evsel resorted hists tree.
3233 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003234 if (hbt)
3235 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003236 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003237 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003238 menu->min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003239 menu->env,
3240 warn_lost_event);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003241 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003242 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003243 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003244 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003245 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003246 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003247 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003248 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003249 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003250 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003251 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003252 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003253 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003254 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003255 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003256 case 'q':
3257 case CTRL('c'):
3258 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003259 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003260 default:
3261 continue;
3262 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003263 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003264 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003265 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003266 if (!ui_browser__dialog_yesno(&menu->b,
3267 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003268 continue;
3269 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003270 case 'q':
3271 case CTRL('c'):
3272 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003273 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003274 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003275 }
3276 }
3277
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003278out:
3279 ui_browser__hide(&menu->b);
3280 return key;
3281}
3282
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003283static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003284 void *entry)
3285{
3286 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3287
3288 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3289 return true;
3290
3291 return false;
3292}
3293
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003294static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003295 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003296 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003297 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003298 struct perf_env *env,
3299 bool warn_lost_event)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003300{
3301 struct perf_evsel *pos;
3302 struct perf_evsel_menu menu = {
3303 .b = {
3304 .entries = &evlist->entries,
3305 .refresh = ui_browser__list_head_refresh,
3306 .seek = ui_browser__list_head_seek,
3307 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003308 .filter = filter_group_entries,
3309 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003310 .priv = evlist,
3311 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003312 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003313 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003314 };
3315
3316 ui_helpline__push("Press ESC to exit");
3317
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003318 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003319 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003320 size_t line_len = strlen(ev_name) + 7;
3321
3322 if (menu.b.width < line_len)
3323 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003324 }
3325
Kan Liang06cc1a42018-01-18 13:26:29 -08003326 return perf_evsel_menu__run(&menu, nr_entries, help,
3327 hbt, warn_lost_event);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003328}
3329
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003330int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003331 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003332 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003333 struct perf_env *env,
3334 bool warn_lost_event)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003335{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003336 int nr_entries = evlist->nr_entries;
3337
3338single_entry:
3339 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003340 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003341
3342 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003343 false, hbt, min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003344 env, warn_lost_event);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003345 }
3346
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003347 if (symbol_conf.event_group) {
3348 struct perf_evsel *pos;
3349
3350 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003351 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003352 if (perf_evsel__is_group_leader(pos))
3353 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003354 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003355
3356 if (nr_entries == 1)
3357 goto single_entry;
3358 }
3359
3360 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Kan Liang06cc1a42018-01-18 13:26:29 -08003361 hbt, min_pcnt, env,
3362 warn_lost_event);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003363}