blob: a94eb0755e8b8bc8ef45a52eec699d5cf9c74cde [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 Melo3ca43b62019-06-26 12:06:20 -03009#include <linux/string.h>
Arnaldo Carvalho de Melob0742e92017-04-18 11:08:10 -030010#include <sys/ttydefaults.h>
Andi Kleen1d6c49d2019-03-11 07:44:56 -070011#include <linux/time64.h>
Arnaldo Carvalho de Melo7f7c5362019-07-04 11:32:27 -030012#include <linux/zalloc.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030013
Arnaldo Carvalho de Melob10ba7f2019-01-29 11:11:04 +010014#include "../../util/callchain.h"
Namhyung Kimaca7a942012-04-04 00:14:26 -070015#include "../../util/evsel.h"
16#include "../../util/evlist.h"
17#include "../../util/hist.h"
Arnaldo Carvalho de Melo1101f692019-01-27 13:42:37 +010018#include "../../util/map.h"
Arnaldo Carvalho de Melodaecf9e2019-01-28 00:03:34 +010019#include "../../util/symbol.h"
Namhyung Kimaca7a942012-04-04 00:14:26 -070020#include "../../util/pstack.h"
21#include "../../util/sort.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090022#include "../../util/top.h"
Arnaldo Carvalho de Meloe7ff8922017-04-19 21:34:35 -030023#include "../../util/thread.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090024#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030025
Jiri Olsaf7589902016-06-20 23:58:13 +020026#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030027#include "../helpline.h"
28#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020029#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030030#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020031#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030032#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030033#include "string2.h"
Arnaldo Carvalho de Melo58db1d62017-04-19 16:05:56 -030034#include "units.h"
Andi Kleen1d6c49d2019-03-11 07:44:56 -070035#include "time-utils.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030036
Arnaldo Carvalho de Melo3052ba52019-06-25 17:27:31 -030037#include <linux/ctype.h>
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030038
Namhyung Kimf5951d52012-09-03 11:53:09 +090039extern void hist_browser__init_hpp(void);
40
Arnaldo Carvalho de Melof016d242018-04-02 14:00:04 -030041static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090042static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030043
Namhyung Kimc3b78952014-04-22 15:56:17 +090044static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090045 float min_pcnt);
46
Namhyung Kim268397c2014-04-22 14:49:31 +090047static bool hist_browser__has_filter(struct hist_browser *hb)
48{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010049 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090050}
51
He Kuang4fabf3d2015-03-12 15:21:49 +080052static int hist_browser__get_folding(struct hist_browser *browser)
53{
54 struct rb_node *nd;
55 struct hists *hists = browser->hists;
56 int unfolded_rows = 0;
57
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -080058 for (nd = rb_first_cached(&hists->entries);
He Kuang4fabf3d2015-03-12 15:21:49 +080059 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090060 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080061 struct hist_entry *he =
62 rb_entry(nd, struct hist_entry, rb_node);
63
Namhyung Kimf5b763f2016-02-25 00:13:43 +090064 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080065 unfolded_rows += he->nr_rows;
66 }
67 return unfolded_rows;
68}
69
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -030070static void hist_browser__set_title_space(struct hist_browser *hb)
71{
72 struct ui_browser *browser = &hb->b;
73 struct hists *hists = hb->hists;
74 struct perf_hpp_list *hpp_list = hists->hpp_list;
75
76 browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0;
77}
78
Namhyung Kimc3b78952014-04-22 15:56:17 +090079static u32 hist_browser__nr_entries(struct hist_browser *hb)
80{
81 u32 nr_entries;
82
Namhyung Kimf5b763f2016-02-25 00:13:43 +090083 if (symbol_conf.report_hierarchy)
84 nr_entries = hb->nr_hierarchy_entries;
85 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090086 nr_entries = hb->nr_non_filtered_entries;
87 else
88 nr_entries = hb->hists->nr_entries;
89
He Kuang4fabf3d2015-03-12 15:21:49 +080090 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090091 return nr_entries + hb->nr_callchain_rows;
92}
93
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020094static void hist_browser__update_rows(struct hist_browser *hb)
95{
96 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020097 struct hists *hists = hb->hists;
98 struct perf_hpp_list *hpp_list = hists->hpp_list;
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -030099 u16 index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200100
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -0300101 if (!hb->show_headers) {
102 browser->rows += browser->extra_title_lines;
103 browser->extra_title_lines = 0;
104 return;
105 }
106
107 browser->extra_title_lines = hpp_list->nr_header_lines;
108 browser->rows -= browser->extra_title_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200109 /*
110 * Verify if we were at the last line and that line isn't
111 * visibe because we now show the header line(s).
112 */
113 index_row = browser->index - browser->top_idx;
114 if (index_row >= browser->rows)
115 browser->index -= index_row - browser->rows + 1;
116}
117
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300118static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300119{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300120 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
121
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300122 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300123 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
124 /*
125 * FIXME: Just keeping existing behaviour, but this really should be
126 * before updating browser->width, as it will invalidate the
127 * calculation above. Fix this and the fallout in another
128 * changeset.
129 */
130 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300131}
132
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300133static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300134{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900135 /*
136 * The hists__remove_entry_filter() already folds non-filtered
137 * entries so we can assume it has 0 callchain rows.
138 */
139 browser->nr_callchain_rows = 0;
140
Namhyung Kim268397c2014-04-22 14:49:31 +0900141 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900142 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300143 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300144 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145}
146
147static char tree__folded_sign(bool unfolded)
148{
149 return unfolded ? '-' : '+';
150}
151
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300152static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300153{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900154 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300155}
156
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300157static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300158{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900159 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300160}
161
Namhyung Kim3698dab2015-05-05 23:55:46 +0900162static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300163{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900164 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300165}
166
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300167static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300168{
Milian Wolff2a704fc2017-10-09 22:32:55 +0200169 int n = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300170 struct rb_node *nd;
171
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300172 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300173 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
174 struct callchain_list *chain;
175 char folded_sign = ' '; /* No children */
176
177 list_for_each_entry(chain, &child->val, list) {
178 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800179
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300180 /* We need this because we may not have children */
181 folded_sign = callchain_list__folded(chain);
182 if (folded_sign == '+')
183 break;
184 }
185
186 if (folded_sign == '-') /* Have children and they're unfolded */
187 n += callchain_node__count_rows_rb_tree(child);
188 }
189
190 return n;
191}
192
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900193static int callchain_node__count_flat_rows(struct callchain_node *node)
194{
195 struct callchain_list *chain;
196 char folded_sign = 0;
197 int n = 0;
198
199 list_for_each_entry(chain, &node->parent_val, list) {
200 if (!folded_sign) {
201 /* only check first chain list entry */
202 folded_sign = callchain_list__folded(chain);
203 if (folded_sign == '+')
204 return 1;
205 }
206 n++;
207 }
208
209 list_for_each_entry(chain, &node->val, list) {
210 if (!folded_sign) {
211 /* node->parent_val list might be empty */
212 folded_sign = callchain_list__folded(chain);
213 if (folded_sign == '+')
214 return 1;
215 }
216 n++;
217 }
218
219 return n;
220}
221
Namhyung Kim8c430a32015-11-09 14:45:44 +0900222static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
223{
224 return 1;
225}
226
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300227static int callchain_node__count_rows(struct callchain_node *node)
228{
229 struct callchain_list *chain;
230 bool unfolded = false;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200231 int n = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300232
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900233 if (callchain_param.mode == CHAIN_FLAT)
234 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900235 else if (callchain_param.mode == CHAIN_FOLDED)
236 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900237
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300238 list_for_each_entry(chain, &node->val, list) {
239 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800240
Namhyung Kim3698dab2015-05-05 23:55:46 +0900241 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300242 }
243
244 if (unfolded)
245 n += callchain_node__count_rows_rb_tree(node);
246
247 return n;
248}
249
250static int callchain__count_rows(struct rb_root *chain)
251{
252 struct rb_node *nd;
253 int n = 0;
254
255 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
256 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
257 n += callchain_node__count_rows(node);
258 }
259
260 return n;
261}
262
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900263static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
264 bool include_children)
265{
266 int count = 0;
267 struct rb_node *node;
268 struct hist_entry *child;
269
270 if (he->leaf)
271 return callchain__count_rows(&he->sorted_chain);
272
Namhyung Kim79dded82016-02-26 21:13:19 +0900273 if (he->has_no_entry)
274 return 1;
275
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -0800276 node = rb_first_cached(&he->hroot_out);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900277 while (node) {
278 float percent;
279
280 child = rb_entry(node, struct hist_entry, rb_node);
281 percent = hist_entry__get_percent_limit(child);
282
283 if (!child->filtered && percent >= hb->min_pcnt) {
284 count++;
285
286 if (include_children && child->unfolded)
287 count += hierarchy_count_rows(hb, child, true);
288 }
289
290 node = rb_next(node);
291 }
292 return count;
293}
294
Namhyung Kim3698dab2015-05-05 23:55:46 +0900295static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300296{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900297 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200298 return false;
299
Namhyung Kim3698dab2015-05-05 23:55:46 +0900300 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300301 return false;
302
Namhyung Kim3698dab2015-05-05 23:55:46 +0900303 he->unfolded = !he->unfolded;
304 return true;
305}
306
307static bool callchain_list__toggle_fold(struct callchain_list *cl)
308{
309 if (!cl)
310 return false;
311
312 if (!cl->has_children)
313 return false;
314
315 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300316 return true;
317}
318
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300319static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300320{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300321 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300322
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300323 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300324 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
325 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300326 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300327
328 list_for_each_entry(chain, &child->val, list) {
329 if (first) {
330 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900331 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300332 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300333 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900334 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300335 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300336 }
337
338 callchain_node__init_have_children_rb_tree(child);
339 }
340}
341
Namhyung Kima7444af2014-11-24 17:13:27 +0900342static void callchain_node__init_have_children(struct callchain_node *node,
343 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300344{
345 struct callchain_list *chain;
346
Namhyung Kima7444af2014-11-24 17:13:27 +0900347 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900348 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900349
Andres Freund90989032016-03-30 21:02:45 +0200350 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900351 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900352 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900353 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300354
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300355 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300356}
357
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300358static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300359{
Namhyung Kima7444af2014-11-24 17:13:27 +0900360 struct rb_node *nd = rb_first(root);
361 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300362
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300363 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300364 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900365 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900366 if (callchain_param.mode == CHAIN_FLAT ||
367 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900368 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300369 }
370}
371
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300372static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300373{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900374 if (he->init_have_children)
375 return;
376
377 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900378 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300379 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900380 } else {
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -0800381 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out.rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300382 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900383
384 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385}
386
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300387static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300388{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900389 struct hist_entry *he = browser->he_selection;
390 struct map_symbol *ms = browser->selection;
391 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
392 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300393
Wang Nan4938cf02015-12-07 02:35:44 +0000394 if (!he || !ms)
395 return false;
396
Namhyung Kim3698dab2015-05-05 23:55:46 +0900397 if (ms == &he->ms)
398 has_children = hist_entry__toggle_fold(he);
399 else
400 has_children = callchain_list__toggle_fold(cl);
401
402 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900403 int child_rows = 0;
404
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300405 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900406 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300407
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900408 if (he->leaf)
409 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300410 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900411 browser->nr_hierarchy_entries -= he->nr_rows;
412
413 if (symbol_conf.report_hierarchy)
414 child_rows = hierarchy_count_rows(browser, he, true);
415
416 if (he->unfolded) {
417 if (he->leaf)
Milian Wolff2a704fc2017-10-09 22:32:55 +0200418 he->nr_rows = callchain__count_rows(
419 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900420 else
421 he->nr_rows = hierarchy_count_rows(browser, he, false);
422
423 /* account grand children */
424 if (symbol_conf.report_hierarchy)
425 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900426
427 if (!he->leaf && he->nr_rows == 0) {
428 he->has_no_entry = true;
429 he->nr_rows = 1;
430 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900431 } else {
432 if (symbol_conf.report_hierarchy)
433 browser->b.nr_entries -= child_rows - he->nr_rows;
434
Namhyung Kim79dded82016-02-26 21:13:19 +0900435 if (he->has_no_entry)
436 he->has_no_entry = false;
437
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300438 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900439 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900440
441 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900442
443 if (he->leaf)
444 browser->nr_callchain_rows += he->nr_rows;
445 else
446 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300447
448 return true;
449 }
450
451 /* If it doesn't have children, no toggling performed */
452 return false;
453}
454
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300455static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300456{
457 int n = 0;
458 struct rb_node *nd;
459
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300460 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300461 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
462 struct callchain_list *chain;
463 bool has_children = false;
464
465 list_for_each_entry(chain, &child->val, list) {
466 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900467 callchain_list__set_folding(chain, unfold);
468 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300469 }
470
471 if (has_children)
472 n += callchain_node__set_folding_rb_tree(child, unfold);
473 }
474
475 return n;
476}
477
478static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
479{
480 struct callchain_list *chain;
481 bool has_children = false;
482 int n = 0;
483
484 list_for_each_entry(chain, &node->val, list) {
485 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900486 callchain_list__set_folding(chain, unfold);
487 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300488 }
489
490 if (has_children)
491 n += callchain_node__set_folding_rb_tree(node, unfold);
492
493 return n;
494}
495
496static int callchain__set_folding(struct rb_root *chain, bool unfold)
497{
498 struct rb_node *nd;
499 int n = 0;
500
501 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
502 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
503 n += callchain_node__set_folding(node, unfold);
504 }
505
506 return n;
507}
508
Namhyung Kim492b1012016-02-25 00:13:44 +0900509static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
510 bool unfold __maybe_unused)
511{
512 float percent;
513 struct rb_node *nd;
514 struct hist_entry *child;
515 int n = 0;
516
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -0800517 for (nd = rb_first_cached(&he->hroot_out); nd; nd = rb_next(nd)) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900518 child = rb_entry(nd, struct hist_entry, rb_node);
519 percent = hist_entry__get_percent_limit(child);
520 if (!child->filtered && percent >= hb->min_pcnt)
521 n++;
522 }
523
524 return n;
525}
526
Jiri Olsab33f9222017-01-20 10:20:29 +0100527static void __hist_entry__set_folding(struct hist_entry *he,
528 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300529{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300530 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900531 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300532
Namhyung Kim3698dab2015-05-05 23:55:46 +0900533 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900534 int n;
535
536 if (he->leaf)
537 n = callchain__set_folding(&he->sorted_chain, unfold);
538 else
539 n = hierarchy_set_folding(hb, he, unfold);
540
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300541 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300542 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300543 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300544}
545
Jiri Olsab33f9222017-01-20 10:20:29 +0100546static void hist_entry__set_folding(struct hist_entry *he,
547 struct hist_browser *browser, bool unfold)
548{
549 double percent;
550
551 percent = hist_entry__get_percent_limit(he);
552 if (he->filtered || percent < browser->min_pcnt)
553 return;
554
555 __hist_entry__set_folding(he, browser, unfold);
556
557 if (!he->depth || unfold)
558 browser->nr_hierarchy_entries++;
559 if (he->leaf)
560 browser->nr_callchain_rows += he->nr_rows;
561 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
562 browser->nr_hierarchy_entries++;
563 he->has_no_entry = true;
564 he->nr_rows = 1;
565 } else
566 he->has_no_entry = false;
567}
568
Namhyung Kimc3b78952014-04-22 15:56:17 +0900569static void
570__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300571{
572 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900573 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300574
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -0800575 nd = rb_first_cached(&browser->hists->entries);
Namhyung Kim492b1012016-02-25 00:13:44 +0900576 while (nd) {
577 he = rb_entry(nd, struct hist_entry, rb_node);
578
579 /* set folding state even if it's currently folded */
580 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
581
582 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300583 }
584}
585
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300586static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300587{
Namhyung Kim492b1012016-02-25 00:13:44 +0900588 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900589 browser->nr_callchain_rows = 0;
590 __hist_browser__set_folding(browser, unfold);
591
592 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300593 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300594 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300595}
596
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100597static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
598{
599 if (!browser->he_selection)
600 return;
601
602 hist_entry__set_folding(browser->he_selection, browser, unfold);
603 browser->b.nr_entries = hist_browser__nr_entries(browser);
604}
605
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200606static void ui_browser__warn_lost_events(struct ui_browser *browser)
607{
608 ui_browser__warning(browser, 4,
609 "Events are being lost, check IO/CPU overload!\n\n"
610 "You may want to run 'perf' using a RT scheduler policy:\n\n"
611 " perf top -r 80\n\n"
612 "Or reduce the sampling frequency.");
613}
614
Jiri Olsa5b91a862016-06-20 23:58:15 +0200615static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
616{
617 return browser->title ? browser->title(browser, bf, size) : 0;
618}
619
Kan Liang06cc1a42018-01-18 13:26:29 -0800620int hist_browser__run(struct hist_browser *browser, const char *help,
621 bool warn_lost_event)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300622{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300623 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300624 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900625 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900626 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300627
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300628 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900629 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300630
Jiri Olsa5b91a862016-06-20 23:58:15 +0200631 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300632
Namhyung Kim090cff32016-01-11 19:53:14 +0900633 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300634 return -1;
635
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300636 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300637 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300638
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300639 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900640 case K_TIMER: {
641 u64 nr_entries;
Leo Yanceb75472019-07-08 22:39:34 +0800642
643 WARN_ON_ONCE(!hbt);
644
645 if (hbt)
646 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900647
Namhyung Kimc6111522016-10-07 14:04:12 +0900648 if (hist_browser__has_filter(browser) ||
649 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900650 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900651
Namhyung Kimc3b78952014-04-22 15:56:17 +0900652 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900653 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200654
Kan Liang06cc1a42018-01-18 13:26:29 -0800655 if (warn_lost_event &&
656 (browser->hists->stats.nr_lost_warned !=
657 browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300658 browser->hists->stats.nr_lost_warned =
659 browser->hists->stats.nr_events[PERF_RECORD_LOST];
660 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200661 }
662
Jiri Olsa5b91a862016-06-20 23:58:15 +0200663 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300664 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300665 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900666 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300667 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300668 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300669 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300670 struct hist_entry, rb_node);
671 ui_helpline__pop();
Arnaldo Carvalho de Melofdae6402018-04-06 11:56:11 -0300672 ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300673 seq++, browser->b.nr_entries,
674 browser->hists->nr_entries,
Arnaldo Carvalho de Melofdae6402018-04-06 11:56:11 -0300675 browser->b.extra_title_lines,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300676 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300677 browser->b.index,
678 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300679 h->row_offset, h->nr_rows);
680 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300681 break;
682 case 'C':
683 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300684 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300685 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100686 case 'c':
687 /* Collapse the selected entry. */
688 hist_browser__set_folding_selected(browser, false);
689 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300690 case 'E':
691 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300692 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300693 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100694 case 'e':
695 /* Expand the selected entry. */
696 hist_browser__set_folding_selected(browser, true);
697 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200698 case 'H':
699 browser->show_headers = !browser->show_headers;
700 hist_browser__update_rows(browser);
701 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200702 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300703 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300704 break;
705 /* fall thru */
706 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300707 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300708 }
709 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300710out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300711 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300712 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300713}
714
Namhyung Kim39ee5332014-08-22 09:13:21 +0900715struct callchain_print_arg {
716 /* for hists browser */
717 off_t row_offset;
718 bool is_current_entry;
719
720 /* for file dump */
721 FILE *fp;
722 int printed;
723};
724
725typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
726 struct callchain_list *chain,
727 const char *str, int offset,
728 unsigned short row,
729 struct callchain_print_arg *arg);
730
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900731static void hist_browser__show_callchain_entry(struct hist_browser *browser,
732 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900733 const char *str, int offset,
734 unsigned short row,
735 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900736{
737 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900738 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300739 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900740
741 color = HE_COLORSET_NORMAL;
742 width = browser->b.width - (offset + 2);
743 if (ui_browser__is_current_entry(&browser->b, row)) {
744 browser->selection = &chain->ms;
745 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900746 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900747 }
748
749 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -0300750 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300751 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300752 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300753 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300754 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900755}
756
Namhyung Kim39ee5332014-08-22 09:13:21 +0900757static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
758 struct callchain_list *chain,
759 const char *str, int offset,
760 unsigned short row __maybe_unused,
761 struct callchain_print_arg *arg)
762{
763 char folded_sign = callchain_list__folded(chain);
764
765 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
766 folded_sign, str);
767}
768
769typedef bool (*check_output_full_fn)(struct hist_browser *browser,
770 unsigned short row);
771
772static bool hist_browser__check_output_full(struct hist_browser *browser,
773 unsigned short row)
774{
775 return browser->b.rows == row;
776}
777
778static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
779 unsigned short row __maybe_unused)
780{
781 return false;
782}
783
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300784#define LEVEL_OFFSET_STEP 3
785
Namhyung Kim18bb8382015-11-09 14:45:42 +0900786static int hist_browser__show_callchain_list(struct hist_browser *browser,
787 struct callchain_node *node,
788 struct callchain_list *chain,
789 unsigned short row, u64 total,
790 bool need_percent, int offset,
791 print_callchain_entry_fn print,
792 struct callchain_print_arg *arg)
793{
794 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800795 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900796 const char *str;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200797 int ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900798
799 if (arg->row_offset != 0) {
800 arg->row_offset--;
801 return 0;
802 }
803
804 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800805 alloc_str2 = NULL;
806
Namhyung Kim18bb8382015-11-09 14:45:42 +0900807 str = callchain_list__sym_name(chain, bf, sizeof(bf),
808 browser->show_dso);
809
Jin Yaofef51ec2016-10-31 09:19:53 +0800810 if (symbol_conf.show_branchflag_count) {
Jin Yaoc4ee0622017-08-07 21:05:15 +0800811 callchain_list_counts__printf_value(chain, NULL,
812 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900813
Jin Yaofef51ec2016-10-31 09:19:53 +0800814 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
815 str = "Not enough memory!";
816 else
817 str = alloc_str2;
818 }
819
820 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900821 callchain_node__scnprintf_value(node, buf, sizeof(buf),
822 total);
823
824 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
825 str = "Not enough memory!";
826 else
827 str = alloc_str;
828 }
829
830 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900831 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800832 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800833
Milian Wolff2a704fc2017-10-09 22:32:55 +0200834 return ret;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900835}
836
Namhyung Kim59c624e2016-01-28 00:40:56 +0900837static bool check_percent_display(struct rb_node *node, u64 parent_total)
838{
839 struct callchain_node *child;
840
841 if (node == NULL)
842 return false;
843
844 if (rb_next(node))
845 return true;
846
847 child = rb_entry(node, struct callchain_node, rb_node);
848 return callchain_cumul_hits(child) != parent_total;
849}
850
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900851static int hist_browser__show_callchain_flat(struct hist_browser *browser,
852 struct rb_root *root,
853 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900854 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900855 print_callchain_entry_fn print,
856 struct callchain_print_arg *arg,
857 check_output_full_fn is_output_full)
858{
859 struct rb_node *node;
860 int first_row = row, offset = LEVEL_OFFSET_STEP;
861 bool need_percent;
862
863 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900864 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900865
866 while (node) {
867 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
868 struct rb_node *next = rb_next(node);
869 struct callchain_list *chain;
870 char folded_sign = ' ';
871 int first = true;
872 int extra_offset = 0;
873
874 list_for_each_entry(chain, &child->parent_val, list) {
875 bool was_first = first;
876
877 if (first)
878 first = false;
879 else if (need_percent)
880 extra_offset = LEVEL_OFFSET_STEP;
881
882 folded_sign = callchain_list__folded(chain);
883
884 row += hist_browser__show_callchain_list(browser, child,
885 chain, row, total,
886 was_first && need_percent,
887 offset + extra_offset,
888 print, arg);
889
890 if (is_output_full(browser, row))
891 goto out;
892
893 if (folded_sign == '+')
894 goto next;
895 }
896
897 list_for_each_entry(chain, &child->val, list) {
898 bool was_first = first;
899
900 if (first)
901 first = false;
902 else if (need_percent)
903 extra_offset = LEVEL_OFFSET_STEP;
904
905 folded_sign = callchain_list__folded(chain);
906
907 row += hist_browser__show_callchain_list(browser, child,
908 chain, row, total,
909 was_first && need_percent,
910 offset + extra_offset,
911 print, arg);
912
913 if (is_output_full(browser, row))
914 goto out;
915
916 if (folded_sign == '+')
917 break;
918 }
919
920next:
921 if (is_output_full(browser, row))
922 break;
923 node = next;
924 }
925out:
926 return row - first_row;
927}
928
Namhyung Kim8c430a32015-11-09 14:45:44 +0900929static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
930 struct callchain_list *chain,
931 char *value_str, char *old_str)
932{
933 char bf[1024];
934 const char *str;
935 char *new;
936
937 str = callchain_list__sym_name(chain, bf, sizeof(bf),
938 browser->show_dso);
939 if (old_str) {
940 if (asprintf(&new, "%s%s%s", old_str,
941 symbol_conf.field_sep ?: ";", str) < 0)
942 new = NULL;
943 } else {
944 if (value_str) {
945 if (asprintf(&new, "%s %s", value_str, str) < 0)
946 new = NULL;
947 } else {
948 if (asprintf(&new, "%s", str) < 0)
949 new = NULL;
950 }
951 }
952 return new;
953}
954
955static int hist_browser__show_callchain_folded(struct hist_browser *browser,
956 struct rb_root *root,
957 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900958 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900959 print_callchain_entry_fn print,
960 struct callchain_print_arg *arg,
961 check_output_full_fn is_output_full)
962{
963 struct rb_node *node;
964 int first_row = row, offset = LEVEL_OFFSET_STEP;
965 bool need_percent;
966
967 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900968 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900969
970 while (node) {
971 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
972 struct rb_node *next = rb_next(node);
973 struct callchain_list *chain, *first_chain = NULL;
974 int first = true;
975 char *value_str = NULL, *value_str_alloc = NULL;
976 char *chain_str = NULL, *chain_str_alloc = NULL;
977
978 if (arg->row_offset != 0) {
979 arg->row_offset--;
980 goto next;
981 }
982
983 if (need_percent) {
984 char buf[64];
985
986 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
987 if (asprintf(&value_str, "%s", buf) < 0) {
988 value_str = (char *)"<...>";
989 goto do_print;
990 }
991 value_str_alloc = value_str;
992 }
993
994 list_for_each_entry(chain, &child->parent_val, list) {
995 chain_str = hist_browser__folded_callchain_str(browser,
996 chain, value_str, chain_str);
997 if (first) {
998 first = false;
999 first_chain = chain;
1000 }
1001
1002 if (chain_str == NULL) {
1003 chain_str = (char *)"Not enough memory!";
1004 goto do_print;
1005 }
1006
1007 chain_str_alloc = chain_str;
1008 }
1009
1010 list_for_each_entry(chain, &child->val, list) {
1011 chain_str = hist_browser__folded_callchain_str(browser,
1012 chain, value_str, chain_str);
1013 if (first) {
1014 first = false;
1015 first_chain = chain;
1016 }
1017
1018 if (chain_str == NULL) {
1019 chain_str = (char *)"Not enough memory!";
1020 goto do_print;
1021 }
1022
1023 chain_str_alloc = chain_str;
1024 }
1025
1026do_print:
1027 print(browser, first_chain, chain_str, offset, row++, arg);
1028 free(value_str_alloc);
1029 free(chain_str_alloc);
1030
1031next:
1032 if (is_output_full(browser, row))
1033 break;
1034 node = next;
1035 }
1036
1037 return row - first_row;
1038}
1039
Namhyung Kim0c841c62016-01-28 00:40:54 +09001040static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001041 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001042 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001043 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001044 print_callchain_entry_fn print,
1045 struct callchain_print_arg *arg,
1046 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001047{
1048 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001049 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001050 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001051 u64 percent_total = total;
1052
1053 if (callchain_param.mode == CHAIN_GRAPH_REL)
1054 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001055
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001056 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001057 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001058
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001059 while (node) {
1060 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1061 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001062 struct callchain_list *chain;
1063 char folded_sign = ' ';
1064 int first = true;
1065 int extra_offset = 0;
1066
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001067 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001068 bool was_first = first;
1069
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001070 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001071 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001072 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001073 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001074
1075 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001076
Namhyung Kim18bb8382015-11-09 14:45:42 +09001077 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001078 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001079 was_first && need_percent,
1080 offset + extra_offset,
1081 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001082
Namhyung Kim18bb8382015-11-09 14:45:42 +09001083 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001084 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001085
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001086 if (folded_sign == '+')
1087 break;
1088 }
1089
1090 if (folded_sign == '-') {
1091 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001092
Namhyung Kim0c841c62016-01-28 00:40:54 +09001093 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001094 new_level, row, total,
1095 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001096 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001097 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001098 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001099 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001100 node = next;
1101 }
1102out:
1103 return row - first_row;
1104}
1105
Namhyung Kim0c841c62016-01-28 00:40:54 +09001106static int hist_browser__show_callchain(struct hist_browser *browser,
1107 struct hist_entry *entry, int level,
1108 unsigned short row,
1109 print_callchain_entry_fn print,
1110 struct callchain_print_arg *arg,
1111 check_output_full_fn is_output_full)
1112{
1113 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001114 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001115 int printed;
1116
Namhyung Kim5eca1042016-01-28 00:40:55 +09001117 if (symbol_conf.cumulate_callchain)
1118 parent_total = entry->stat_acc->period;
1119 else
1120 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001121
1122 if (callchain_param.mode == CHAIN_FLAT) {
1123 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001124 &entry->sorted_chain, row,
1125 total, parent_total, print, arg,
1126 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001127 } else if (callchain_param.mode == CHAIN_FOLDED) {
1128 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001129 &entry->sorted_chain, row,
1130 total, parent_total, print, arg,
1131 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001132 } else {
1133 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001134 &entry->sorted_chain, level, row,
1135 total, parent_total, print, arg,
1136 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001137 }
1138
1139 if (arg->is_current_entry)
1140 browser->he_selection = entry;
1141
1142 return printed;
1143}
1144
Namhyung Kim89701462013-01-22 18:09:38 +09001145struct hpp_arg {
1146 struct ui_browser *b;
1147 char folded_sign;
1148 bool current_entry;
1149};
1150
Jiri Olsa98ba1602016-09-22 17:36:35 +02001151int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001152{
1153 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd675107c2014-07-31 14:47:36 +09001154 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001155 va_list args;
1156 double percent;
1157
1158 va_start(args, fmt);
Namhyung Kimd675107c2014-07-31 14:47:36 +09001159 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001160 percent = va_arg(args, double);
1161 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001162
Namhyung Kim89701462013-01-22 18:09:38 +09001163 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001164
Namhyung Kimd675107c2014-07-31 14:47:36 +09001165 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001166 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001167
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001168 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001169}
1170
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001171#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001172static u64 __hpp_get_##_field(struct hist_entry *he) \
1173{ \
1174 return he->stat._field; \
1175} \
1176 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001177static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001178hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001179 struct perf_hpp *hpp, \
1180 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001181{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001182 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1183 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001184}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001185
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001186#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1187static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1188{ \
1189 return he->stat_acc->_field; \
1190} \
1191 \
1192static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001193hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001194 struct perf_hpp *hpp, \
1195 struct hist_entry *he) \
1196{ \
1197 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001198 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001199 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd675107c2014-07-31 14:47:36 +09001200 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001201 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001202 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001203 \
1204 return ret; \
1205 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001206 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1207 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001208}
1209
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001210__HPP_COLOR_PERCENT_FN(overhead, period)
1211__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1212__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1213__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1214__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001215__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001216
1217#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001218#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001219
1220void hist_browser__init_hpp(void)
1221{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001222 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1223 hist_browser__hpp_color_overhead;
1224 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1225 hist_browser__hpp_color_overhead_sys;
1226 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1227 hist_browser__hpp_color_overhead_us;
1228 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1229 hist_browser__hpp_color_overhead_guest_sys;
1230 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1231 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001232 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1233 hist_browser__hpp_color_overhead_acc;
Andi Kleen4968ac82019-03-11 07:44:58 -07001234
1235 res_sample_init();
Namhyung Kimf5951d52012-09-03 11:53:09 +09001236}
1237
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001238static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001239 struct hist_entry *entry,
1240 unsigned short row)
1241{
Jiri Olsa12400052012-10-13 00:06:16 +02001242 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001243 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001244 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001245 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001246 bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001247 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001248 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001249 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001250
1251 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001252 browser->he_selection = entry;
1253 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001254 }
1255
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001256 if (use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001257 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001258 folded_sign = hist_entry__folded(entry);
1259 }
1260
1261 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001262 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001263 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001264 .folded_sign = folded_sign,
1265 .current_entry = current_entry,
1266 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001267 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001268
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03001269 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001270
Jiri Olsaf0786af2016-01-18 10:24:23 +01001271 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001272 char s[2048];
1273 struct perf_hpp hpp = {
1274 .buf = s,
1275 .size = sizeof(s),
1276 .ptr = &arg,
1277 };
1278
Namhyung Kim361459f2015-12-23 02:07:08 +09001279 if (perf_hpp__should_skip(fmt, entry->hists) ||
1280 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001281 continue;
1282
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001283 if (current_entry && browser->b.navkeypressed) {
1284 ui_browser__set_color(&browser->b,
1285 HE_COLORSET_SELECTED);
1286 } else {
1287 ui_browser__set_color(&browser->b,
1288 HE_COLORSET_NORMAL);
1289 }
1290
1291 if (first) {
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001292 if (use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001293 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001294 width -= 2;
1295 }
1296 first = false;
1297 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001298 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001299 width -= 2;
1300 }
1301
Jiri Olsa12400052012-10-13 00:06:16 +02001302 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001303 int ret = fmt->color(fmt, &hpp, entry);
1304 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1305 /*
1306 * fmt->color() already used ui_browser to
1307 * print the non alignment bits, skip it (+ret):
1308 */
1309 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001310 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001311 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001312 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001313 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001314 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001315 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001316
1317 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001318 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001319 width += 1;
1320
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001321 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001322
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001323 ++row;
1324 ++printed;
1325 } else
1326 --row_offset;
1327
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001328 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001329 struct callchain_print_arg arg = {
1330 .row_offset = row_offset,
1331 .is_current_entry = current_entry,
1332 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001333
Milian Wolff2a704fc2017-10-09 22:32:55 +02001334 printed += hist_browser__show_callchain(browser,
1335 entry, 1, row,
1336 hist_browser__show_callchain_entry,
1337 &arg,
1338 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001339 }
1340
1341 return printed;
1342}
1343
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001344static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1345 struct hist_entry *entry,
1346 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001347 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001348{
1349 int printed = 0;
1350 int width = browser->b.width;
1351 char folded_sign = ' ';
1352 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1353 off_t row_offset = entry->row_offset;
1354 bool first = true;
1355 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001356 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001357 struct hpp_arg arg = {
1358 .b = &browser->b,
1359 .current_entry = current_entry,
1360 };
1361 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001362 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001363
1364 if (current_entry) {
1365 browser->he_selection = entry;
1366 browser->selection = &entry->ms;
1367 }
1368
1369 hist_entry__init_have_children(entry);
1370 folded_sign = hist_entry__folded(entry);
1371 arg.folded_sign = folded_sign;
1372
1373 if (entry->leaf && row_offset) {
1374 row_offset--;
1375 goto show_callchain;
1376 }
1377
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03001378 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001379
1380 if (current_entry && browser->b.navkeypressed)
1381 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1382 else
1383 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1384
1385 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1386 width -= level * HIERARCHY_INDENT;
1387
Namhyung Kima61a22f2016-03-07 16:44:50 -03001388 /* the first hpp_list_node is for overhead columns */
1389 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1390 struct perf_hpp_list_node, list);
1391 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001392 char s[2048];
1393 struct perf_hpp hpp = {
1394 .buf = s,
1395 .size = sizeof(s),
1396 .ptr = &arg,
1397 };
1398
1399 if (perf_hpp__should_skip(fmt, entry->hists) ||
1400 column++ < browser->b.horiz_scroll)
1401 continue;
1402
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001403 if (current_entry && browser->b.navkeypressed) {
1404 ui_browser__set_color(&browser->b,
1405 HE_COLORSET_SELECTED);
1406 } else {
1407 ui_browser__set_color(&browser->b,
1408 HE_COLORSET_NORMAL);
1409 }
1410
1411 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001412 ui_browser__printf(&browser->b, "%c ", folded_sign);
1413 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001414 first = false;
1415 } else {
1416 ui_browser__printf(&browser->b, " ");
1417 width -= 2;
1418 }
1419
1420 if (fmt->color) {
1421 int ret = fmt->color(fmt, &hpp, entry);
1422 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1423 /*
1424 * fmt->color() already used ui_browser to
1425 * print the non alignment bits, skip it (+ret):
1426 */
1427 ui_browser__printf(&browser->b, "%s", s + ret);
1428 } else {
1429 int ret = fmt->entry(fmt, &hpp, entry);
1430 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1431 ui_browser__printf(&browser->b, "%s", s);
1432 }
1433 width -= hpp.buf - s;
1434 }
1435
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001436 if (!first) {
1437 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1438 width -= hierarchy_indent;
1439 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001440
1441 if (column >= browser->b.horiz_scroll) {
1442 char s[2048];
1443 struct perf_hpp hpp = {
1444 .buf = s,
1445 .size = sizeof(s),
1446 .ptr = &arg,
1447 };
1448
1449 if (current_entry && browser->b.navkeypressed) {
1450 ui_browser__set_color(&browser->b,
1451 HE_COLORSET_SELECTED);
1452 } else {
1453 ui_browser__set_color(&browser->b,
1454 HE_COLORSET_NORMAL);
1455 }
1456
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001457 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001458 if (first) {
1459 ui_browser__printf(&browser->b, "%c ", folded_sign);
1460 first = false;
1461 } else {
1462 ui_browser__write_nstring(&browser->b, "", 2);
1463 }
1464
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001465 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001466
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001467 /*
1468 * No need to call hist_entry__snprintf_alignment()
1469 * since this fmt is always the last column in the
1470 * hierarchy mode.
1471 */
1472 if (fmt->color) {
1473 width -= fmt->color(fmt, &hpp, entry);
1474 } else {
1475 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001476
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001477 width -= fmt->entry(fmt, &hpp, entry);
Arnaldo Carvalho de Melo32858482019-06-26 11:42:03 -03001478 ui_browser__printf(&browser->b, "%s", skip_spaces(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001479
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001480 while (isspace(s[i++]))
1481 width++;
1482 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001483 }
1484 }
1485
1486 /* The scroll bar isn't being used */
1487 if (!browser->b.navkeypressed)
1488 width += 1;
1489
1490 ui_browser__write_nstring(&browser->b, "", width);
1491
1492 ++row;
1493 ++printed;
1494
1495show_callchain:
1496 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1497 struct callchain_print_arg carg = {
1498 .row_offset = row_offset,
1499 };
1500
1501 printed += hist_browser__show_callchain(browser, entry,
1502 level + 1, row,
1503 hist_browser__show_callchain_entry, &carg,
1504 hist_browser__check_output_full);
1505 }
1506
1507 return printed;
1508}
1509
Namhyung Kim79dded82016-02-26 21:13:19 +09001510static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001511 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001512{
1513 int width = browser->b.width;
1514 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1515 bool first = true;
1516 int column = 0;
1517 int ret;
1518 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001519 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001520 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001521
1522 if (current_entry) {
1523 browser->he_selection = NULL;
1524 browser->selection = NULL;
1525 }
1526
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03001527 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kim79dded82016-02-26 21:13:19 +09001528
1529 if (current_entry && browser->b.navkeypressed)
1530 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1531 else
1532 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1533
1534 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1535 width -= level * HIERARCHY_INDENT;
1536
Namhyung Kima61a22f2016-03-07 16:44:50 -03001537 /* the first hpp_list_node is for overhead columns */
1538 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1539 struct perf_hpp_list_node, list);
1540 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001541 if (perf_hpp__should_skip(fmt, browser->hists) ||
1542 column++ < browser->b.horiz_scroll)
1543 continue;
1544
Jiri Olsada1b0402016-06-14 20:19:20 +02001545 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001546
1547 if (first) {
1548 /* for folded sign */
1549 first = false;
1550 ret++;
1551 } else {
1552 /* space between columns */
1553 ret += 2;
1554 }
1555
1556 ui_browser__write_nstring(&browser->b, "", ret);
1557 width -= ret;
1558 }
1559
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001560 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1561 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001562
1563 if (column >= browser->b.horiz_scroll) {
1564 char buf[32];
1565
1566 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1567 ui_browser__printf(&browser->b, " %s", buf);
1568 width -= ret + 2;
1569 }
1570
1571 /* The scroll bar isn't being used */
1572 if (!browser->b.navkeypressed)
1573 width += 1;
1574
1575 ui_browser__write_nstring(&browser->b, "", width);
1576 return 1;
1577}
1578
Jiri Olsa81a888f2014-06-14 15:44:52 +02001579static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1580{
1581 advance_hpp(hpp, inc);
1582 return hpp->size <= 0;
1583}
1584
Jiri Olsa69705b352016-08-07 17:28:28 +02001585static int
1586hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1587 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001588{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001589 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001590 struct perf_hpp dummy_hpp = {
1591 .buf = buf,
1592 .size = size,
1593 };
1594 struct perf_hpp_fmt *fmt;
1595 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001596 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001597 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001598
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001599 if (hists__has_callchains(hists) && symbol_conf.use_callchain) {
Jiri Olsa81a888f2014-06-14 15:44:52 +02001600 ret = scnprintf(buf, size, " ");
1601 if (advance_hpp_check(&dummy_hpp, ret))
1602 return ret;
1603 }
1604
Jiri Olsaf0786af2016-01-18 10:24:23 +01001605 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001606 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001607 continue;
1608
Jiri Olsa29659ab2016-08-07 17:28:30 +02001609 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001610 if (advance_hpp_check(&dummy_hpp, ret))
1611 break;
1612
Jiri Olsa29659ab2016-08-07 17:28:30 +02001613 if (span)
1614 continue;
1615
Jiri Olsa81a888f2014-06-14 15:44:52 +02001616 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1617 if (advance_hpp_check(&dummy_hpp, ret))
1618 break;
1619 }
1620
1621 return ret;
1622}
1623
Namhyung Kimd8b92402016-02-25 00:13:46 +09001624static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1625{
1626 struct hists *hists = browser->hists;
1627 struct perf_hpp dummy_hpp = {
1628 .buf = buf,
1629 .size = size,
1630 };
1631 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001632 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001633 size_t ret = 0;
1634 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001635 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001636 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001637
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001638 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001639 if (advance_hpp_check(&dummy_hpp, ret))
1640 return ret;
1641
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001642 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001643 /* the first hpp_list_node is for overhead columns */
1644 fmt_node = list_first_entry(&hists->hpp_formats,
1645 struct perf_hpp_list_node, list);
1646 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001647 if (column++ < browser->b.horiz_scroll)
1648 continue;
1649
Jiri Olsa29659ab2016-08-07 17:28:30 +02001650 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001651 if (advance_hpp_check(&dummy_hpp, ret))
1652 break;
1653
1654 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1655 if (advance_hpp_check(&dummy_hpp, ret))
1656 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001657
1658 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001659 }
1660
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001661 if (!first_node) {
1662 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1663 indent * HIERARCHY_INDENT, "");
1664 if (advance_hpp_check(&dummy_hpp, ret))
1665 return ret;
1666 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001667
Namhyung Kima61a22f2016-03-07 16:44:50 -03001668 first_node = true;
1669 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1670 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001671 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1672 if (advance_hpp_check(&dummy_hpp, ret))
1673 break;
1674 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001675 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001676
Namhyung Kima61a22f2016-03-07 16:44:50 -03001677 first_col = true;
1678 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1679 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001680
Namhyung Kima61a22f2016-03-07 16:44:50 -03001681 if (perf_hpp__should_skip(fmt, hists))
1682 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001683
Namhyung Kima61a22f2016-03-07 16:44:50 -03001684 if (!first_col) {
1685 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1686 if (advance_hpp_check(&dummy_hpp, ret))
1687 break;
1688 }
1689 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001690
Jiri Olsa29659ab2016-08-07 17:28:30 +02001691 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001692 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001693
Arnaldo Carvalho de Melo3ca43b62019-06-26 12:06:20 -03001694 start = strim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001695 ret = strlen(start);
1696
1697 if (start != dummy_hpp.buf)
1698 memmove(dummy_hpp.buf, start, ret + 1);
1699
1700 if (advance_hpp_check(&dummy_hpp, ret))
1701 break;
1702 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001703 }
1704
1705 return ret;
1706}
1707
Jiri Olsa01b47702016-06-14 20:19:13 +02001708static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001709{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001710 char headers[1024];
1711
Jiri Olsa01b47702016-06-14 20:19:13 +02001712 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1713 sizeof(headers));
1714
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001715 ui_browser__gotorc(&browser->b, 0, 0);
1716 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001717 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001718}
1719
Jiri Olsa01b47702016-06-14 20:19:13 +02001720static void hists_browser__headers(struct hist_browser *browser)
1721{
Jiri Olsa69705b352016-08-07 17:28:28 +02001722 struct hists *hists = browser->hists;
1723 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001724
Jiri Olsa69705b352016-08-07 17:28:28 +02001725 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001726
Jiri Olsa69705b352016-08-07 17:28:28 +02001727 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1728 char headers[1024];
1729
1730 hists_browser__scnprintf_headers(browser, headers,
1731 sizeof(headers), line);
1732
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03001733 ui_browser__gotorc_title(&browser->b, line, 0);
Jiri Olsa69705b352016-08-07 17:28:28 +02001734 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1735 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1736 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001737}
1738
1739static void hist_browser__show_headers(struct hist_browser *browser)
1740{
1741 if (symbol_conf.report_hierarchy)
1742 hists_browser__hierarchy_headers(browser);
1743 else
1744 hists_browser__headers(browser);
1745}
1746
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001747static void ui_browser__hists_init_top(struct ui_browser *browser)
1748{
1749 if (browser->top == NULL) {
1750 struct hist_browser *hb;
1751
1752 hb = container_of(browser, struct hist_browser, b);
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08001753 browser->top = rb_first_cached(&hb->hists->entries);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001754 }
1755}
1756
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001757static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758{
1759 unsigned row = 0;
1760 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001761 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001762
Arnaldo Carvalho de Melo94e87a82018-04-06 12:11:11 -03001763 if (hb->show_headers)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001764 hist_browser__show_headers(hb);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001765
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001766 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001767 hb->he_selection = NULL;
1768 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001770 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001771 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001772 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001773
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001774 if (h->filtered) {
1775 /* let it move to sibling */
1776 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001777 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001778 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001779
Namhyung Kim14135662013-10-31 10:17:39 +09001780 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001781 if (percent < hb->min_pcnt)
1782 continue;
1783
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001784 if (symbol_conf.report_hierarchy) {
1785 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001786 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001787 if (row == browser->rows)
1788 break;
1789
1790 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001791 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001792 row++;
1793 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001794 } else {
1795 row += hist_browser__show_entry(hb, h, row);
1796 }
1797
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001798 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001799 break;
1800 }
1801
Arnaldo Carvalho de Melo94e87a82018-04-06 12:11:11 -03001802 return row;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001803}
1804
Namhyung Kim064f1982013-05-14 11:09:04 +09001805static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001806 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001807{
1808 while (nd != NULL) {
1809 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001810 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001811
Namhyung Kimc0f15272014-04-16 11:16:33 +09001812 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001813 return nd;
1814
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001815 /*
1816 * If it's filtered, its all children also were filtered.
1817 * So move to sibling node.
1818 */
1819 if (rb_next(nd))
1820 nd = rb_next(nd);
1821 else
1822 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001823 }
1824
1825 return NULL;
1826}
1827
Namhyung Kim064f1982013-05-14 11:09:04 +09001828static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001829 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001830{
1831 while (nd != NULL) {
1832 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001833 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001834
1835 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001836 return nd;
1837
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001838 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001839 }
1840
1841 return NULL;
1842}
1843
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001844static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001845 off_t offset, int whence)
1846{
1847 struct hist_entry *h;
1848 struct rb_node *nd;
1849 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001850 struct hist_browser *hb;
1851
1852 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001853
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001854 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001855 return;
1856
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001857 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001858
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001859 switch (whence) {
1860 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001861 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001862 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001863 break;
1864 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001865 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001866 goto do_offset;
1867 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001868 nd = rb_hierarchy_last(rb_last(browser->entries));
1869 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001870 first = false;
1871 break;
1872 default:
1873 return;
1874 }
1875
1876 /*
1877 * Moves not relative to the first visible entry invalidates its
1878 * row_offset:
1879 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001880 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001881 h->row_offset = 0;
1882
1883 /*
1884 * Here we have to check if nd is expanded (+), if it is we can't go
1885 * the next top level hist_entry, instead we must compute an offset of
1886 * what _not_ to show and not change the first visible entry.
1887 *
1888 * This offset increments when we are going from top to bottom and
1889 * decreases when we're going from bottom to top.
1890 *
1891 * As we don't have backpointers to the top level in the callchains
1892 * structure, we need to always print the whole hist_entry callchain,
1893 * skipping the first ones that are before the first visible entry
1894 * and stop when we printed enough lines to fill the screen.
1895 */
1896do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001897 if (!nd)
1898 return;
1899
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001900 if (offset > 0) {
1901 do {
1902 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001903 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001904 u16 remaining = h->nr_rows - h->row_offset;
1905 if (offset > remaining) {
1906 offset -= remaining;
1907 h->row_offset = 0;
1908 } else {
1909 h->row_offset += offset;
1910 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001911 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001912 break;
1913 }
1914 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001915 nd = hists__filter_entries(rb_hierarchy_next(nd),
1916 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001917 if (nd == NULL)
1918 break;
1919 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001920 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001921 } while (offset != 0);
1922 } else if (offset < 0) {
1923 while (1) {
1924 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001925 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001926 if (first) {
1927 if (-offset > h->row_offset) {
1928 offset += h->row_offset;
1929 h->row_offset = 0;
1930 } else {
1931 h->row_offset += offset;
1932 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001933 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001934 break;
1935 }
1936 } else {
1937 if (-offset > h->nr_rows) {
1938 offset += h->nr_rows;
1939 h->row_offset = 0;
1940 } else {
1941 h->row_offset = h->nr_rows + offset;
1942 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001943 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001944 break;
1945 }
1946 }
1947 }
1948
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001949 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001950 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001951 if (nd == NULL)
1952 break;
1953 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001954 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001955 if (offset == 0) {
1956 /*
1957 * Last unfiltered hist_entry, check if it is
1958 * unfolded, if it is then we should have
1959 * row_offset at its last entry.
1960 */
1961 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001962 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001963 h->row_offset = h->nr_rows;
1964 break;
1965 }
1966 first = false;
1967 }
1968 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001969 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001970 h = rb_entry(nd, struct hist_entry, rb_node);
1971 h->row_offset = 0;
1972 }
1973}
1974
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001975static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001976 struct hist_entry *he, FILE *fp,
1977 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001978{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001979 struct callchain_print_arg arg = {
1980 .fp = fp,
1981 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001982
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001983 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001984 hist_browser__fprintf_callchain_entry, &arg,
1985 hist_browser__check_dump_full);
1986 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001987}
1988
1989static int hist_browser__fprintf_entry(struct hist_browser *browser,
1990 struct hist_entry *he, FILE *fp)
1991{
1992 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001993 int printed = 0;
1994 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001995 struct perf_hpp hpp = {
1996 .buf = s,
1997 .size = sizeof(s),
1998 };
1999 struct perf_hpp_fmt *fmt;
2000 bool first = true;
2001 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002002
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03002003 if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002004 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002005 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002006 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002007
Jiri Olsaf0786af2016-01-18 10:24:23 +01002008 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002009 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002010 continue;
2011
Namhyung Kim26d8b332014-03-03 16:16:20 +09002012 if (!first) {
2013 ret = scnprintf(hpp.buf, hpp.size, " ");
2014 advance_hpp(&hpp, ret);
2015 } else
2016 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002017
Namhyung Kim26d8b332014-03-03 16:16:20 +09002018 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002019 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002020 advance_hpp(&hpp, ret);
2021 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002022 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002023
2024 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002025 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2026
2027 return printed;
2028}
2029
2030
2031static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2032 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002033 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002034{
2035 char s[8192];
2036 int printed = 0;
2037 char folded_sign = ' ';
2038 struct perf_hpp hpp = {
2039 .buf = s,
2040 .size = sizeof(s),
2041 };
2042 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002043 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002044 bool first = true;
2045 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002046 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002047
2048 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2049
2050 folded_sign = hist_entry__folded(he);
2051 printed += fprintf(fp, "%c", folded_sign);
2052
Namhyung Kim325a6282016-03-09 22:47:00 +09002053 /* the first hpp_list_node is for overhead columns */
2054 fmt_node = list_first_entry(&he->hists->hpp_formats,
2055 struct perf_hpp_list_node, list);
2056 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002057 if (!first) {
2058 ret = scnprintf(hpp.buf, hpp.size, " ");
2059 advance_hpp(&hpp, ret);
2060 } else
2061 first = false;
2062
2063 ret = fmt->entry(fmt, &hpp, he);
2064 advance_hpp(&hpp, ret);
2065 }
2066
2067 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2068 advance_hpp(&hpp, ret);
2069
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002070 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2071 ret = scnprintf(hpp.buf, hpp.size, " ");
2072 advance_hpp(&hpp, ret);
2073
2074 ret = fmt->entry(fmt, &hpp, he);
2075 advance_hpp(&hpp, ret);
2076 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002077
Arnaldo Carvalho de Melo13c230a2019-06-26 12:13:13 -03002078 strim(s);
2079 printed += fprintf(fp, "%s\n", s);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002080
2081 if (he->leaf && folded_sign == '-') {
2082 printed += hist_browser__fprintf_callchain(browser, he, fp,
2083 he->depth + 1);
2084 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002085
2086 return printed;
2087}
2088
2089static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2090{
Namhyung Kim064f1982013-05-14 11:09:04 +09002091 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002092 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002093 int printed = 0;
2094
2095 while (nd) {
2096 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2097
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002098 if (symbol_conf.report_hierarchy) {
2099 printed += hist_browser__fprintf_hierarchy_entry(browser,
2100 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002101 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002102 } else {
2103 printed += hist_browser__fprintf_entry(browser, h, fp);
2104 }
2105
2106 nd = hists__filter_entries(rb_hierarchy_next(nd),
2107 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002108 }
2109
2110 return printed;
2111}
2112
2113static int hist_browser__dump(struct hist_browser *browser)
2114{
2115 char filename[64];
2116 FILE *fp;
2117
2118 while (1) {
2119 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2120 if (access(filename, F_OK))
2121 break;
2122 /*
2123 * XXX: Just an arbitrary lazy upper limit
2124 */
2125 if (++browser->print_seq == 8192) {
2126 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2127 return -1;
2128 }
2129 }
2130
2131 fp = fopen(filename, "w");
2132 if (fp == NULL) {
2133 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002134 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002135 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002136 return -1;
2137 }
2138
2139 ++browser->print_seq;
2140 hist_browser__fprintf(browser, fp);
2141 fclose(fp);
2142 ui_helpline__fpush("%s written!", filename);
2143
2144 return 0;
2145}
2146
Jiri Olsafcd86422016-06-20 23:58:18 +02002147void hist_browser__init(struct hist_browser *browser,
2148 struct hists *hists)
2149{
2150 struct perf_hpp_fmt *fmt;
2151
2152 browser->hists = hists;
2153 browser->b.refresh = hist_browser__refresh;
2154 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2155 browser->b.seek = ui_browser__hists_seek;
2156 browser->b.use_navkeypressed = true;
2157 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03002158 hist_browser__set_title_space(browser);
Jiri Olsafcd86422016-06-20 23:58:18 +02002159
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002160 if (symbol_conf.report_hierarchy) {
2161 struct perf_hpp_list_node *fmt_node;
2162
2163 /* count overhead columns (in the first node) */
2164 fmt_node = list_first_entry(&hists->hpp_formats,
2165 struct perf_hpp_list_node, list);
2166 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2167 ++browser->b.columns;
2168
2169 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002170 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002171 } else {
2172 hists__for_each_format(hists, fmt)
2173 ++browser->b.columns;
2174 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002175
2176 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002177}
2178
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002179struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002180{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002181 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002182
Jiri Olsafcd86422016-06-20 23:58:18 +02002183 if (browser)
2184 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002185
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002186 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002187}
2188
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002189static struct hist_browser *
2190perf_evsel_browser__new(struct perf_evsel *evsel,
2191 struct hist_browser_timer *hbt,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002192 struct perf_env *env,
2193 struct annotation_options *annotation_opts)
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002194{
2195 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2196
2197 if (browser) {
2198 browser->hbt = hbt;
2199 browser->env = env;
Arnaldo Carvalho de Melof016d242018-04-02 14:00:04 -03002200 browser->title = hists_browser__scnprintf_title;
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002201 browser->annotation_opts = annotation_opts;
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002202 }
2203 return browser;
2204}
2205
Jiri Olsadabd2012016-06-20 23:58:14 +02002206void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002207{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002208 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002209}
2210
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002211static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002212{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002213 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002214}
2215
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002216static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002217{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002218 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002219}
2220
Taeung Song1e378eb2014-10-07 16:13:15 +09002221/* Check whether the browser is for 'top' or 'report' */
2222static inline bool is_report_browser(void *timer)
2223{
2224 return timer == NULL;
2225}
2226
Arnaldo Carvalho de Melo967a4642018-04-02 14:20:20 -03002227static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size)
2228{
2229 struct hist_browser_timer *hbt = browser->hbt;
2230 int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt));
2231
Taeung Song1e378eb2014-10-07 16:13:15 +09002232 if (!is_report_browser(hbt)) {
2233 struct perf_top *top = hbt->arg;
2234
Jiri Olsad24e3c92018-11-06 15:45:14 +01002235 printed += scnprintf(bf + printed, size - printed,
2236 " lost: %" PRIu64 "/%" PRIu64,
2237 top->lost, top->lost_total);
2238
Jiri Olsa97f7e0b2018-11-11 20:02:46 +01002239 printed += scnprintf(bf + printed, size - printed,
2240 " drop: %" PRIu64 "/%" PRIu64,
2241 top->drop, top->drop_total);
2242
Taeung Song1e378eb2014-10-07 16:13:15 +09002243 if (top->zero)
2244 printed += scnprintf(bf + printed, size - printed, " [z]");
Jiri Olsa8aa5c8e2018-11-13 11:15:34 +01002245
2246 perf_top__reset_sample_counters(top);
Taeung Song1e378eb2014-10-07 16:13:15 +09002247 }
2248
Jiri Olsa8aa5c8e2018-11-13 11:15:34 +01002249
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002250 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002251}
2252
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002253static inline void free_popup_options(char **options, int n)
2254{
2255 int i;
2256
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002257 for (i = 0; i < n; ++i)
2258 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002259}
2260
Feng Tang341487ab2013-02-03 14:38:20 +08002261/*
2262 * Only runtime switching of perf data file will make "input_name" point
2263 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2264 * whether we need to call free() for current "input_name" during the switch.
2265 */
2266static bool is_input_name_malloced = false;
2267
2268static int switch_data_file(void)
2269{
2270 char *pwd, *options[32], *abs_path[32], *tmp;
2271 DIR *pwd_dir;
2272 int nr_options = 0, choice = -1, ret = -1;
2273 struct dirent *dent;
2274
2275 pwd = getenv("PWD");
2276 if (!pwd)
2277 return ret;
2278
2279 pwd_dir = opendir(pwd);
2280 if (!pwd_dir)
2281 return ret;
2282
2283 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002284 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002285
2286 while ((dent = readdir(pwd_dir))) {
2287 char path[PATH_MAX];
2288 u64 magic;
2289 char *name = dent->d_name;
2290 FILE *file;
2291
2292 if (!(dent->d_type == DT_REG))
2293 continue;
2294
2295 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2296
2297 file = fopen(path, "r");
2298 if (!file)
2299 continue;
2300
2301 if (fread(&magic, 1, 8, file) < 8)
2302 goto close_file_and_continue;
2303
2304 if (is_perf_magic(magic)) {
2305 options[nr_options] = strdup(name);
2306 if (!options[nr_options])
2307 goto close_file_and_continue;
2308
2309 abs_path[nr_options] = strdup(path);
2310 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002311 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002312 ui__warning("Can't search all data files due to memory shortage.\n");
2313 fclose(file);
2314 break;
2315 }
2316
2317 nr_options++;
2318 }
2319
2320close_file_and_continue:
2321 fclose(file);
2322 if (nr_options >= 32) {
2323 ui__warning("Too many perf data files in PWD!\n"
2324 "Only the first 32 files will be listed.\n");
2325 break;
2326 }
2327 }
2328 closedir(pwd_dir);
2329
2330 if (nr_options) {
2331 choice = ui__popup_menu(nr_options, options);
2332 if (choice < nr_options && choice >= 0) {
2333 tmp = strdup(abs_path[choice]);
2334 if (tmp) {
2335 if (is_input_name_malloced)
2336 free((void *)input_name);
2337 input_name = tmp;
2338 is_input_name_malloced = true;
2339 ret = 0;
2340 } else
2341 ui__warning("Data switch failed due to memory shortage!\n");
2342 }
2343 }
2344
2345 free_popup_options(options, nr_options);
2346 free_popup_options(abs_path, nr_options);
2347 return ret;
2348}
2349
Namhyung Kimea7cd592015-04-22 16:18:19 +09002350struct popup_action {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002351 unsigned long time;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002352 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002353 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002354 int socket;
Andi Kleen6f3da202019-03-11 07:44:57 -07002355 struct perf_evsel *evsel;
Andi Kleen4968ac82019-03-11 07:44:58 -07002356 enum rstype rstype;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002357
2358 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2359};
2360
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002361static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002362do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002363{
2364 struct perf_evsel *evsel;
2365 struct annotation *notes;
2366 struct hist_entry *he;
2367 int err;
2368
Arnaldo Carvalho de Melof178fd22018-05-28 14:24:45 -03002369 if (!browser->annotation_opts->objdump_path &&
2370 perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002371 return 0;
2372
Namhyung Kimea7cd592015-04-22 16:18:19 +09002373 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002374 if (!notes->src)
2375 return 0;
2376
2377 evsel = hists_to_evsel(browser->hists);
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002378 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt,
2379 browser->annotation_opts);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002380 he = hist_browser__selected_entry(browser);
2381 /*
2382 * offer option to annotate the other branch source or target
2383 * (if they exists) when returning from annotate
2384 */
2385 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2386 return 1;
2387
2388 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2389 if (err)
2390 ui_browser__handle_resize(&browser->b);
2391 return 0;
2392}
2393
2394static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002395add_annotate_opt(struct hist_browser *browser __maybe_unused,
2396 struct popup_action *act, char **optstr,
2397 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002398{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002399 if (sym == NULL || map->dso->annotate_warned)
2400 return 0;
2401
2402 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2403 return 0;
2404
2405 act->ms.map = map;
2406 act->ms.sym = sym;
2407 act->fn = do_annotate;
2408 return 1;
2409}
2410
2411static int
2412do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2413{
2414 struct thread *thread = act->thread;
2415
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002416 if ((!hists__has(browser->hists, thread) &&
2417 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002418 return 0;
2419
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002420 if (browser->hists->thread_filter) {
2421 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2422 perf_hpp__set_elide(HISTC_THREAD, false);
2423 thread__zput(browser->hists->thread_filter);
2424 ui_helpline__pop();
2425 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002426 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002427 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2428 thread->comm_set ? thread__comm_str(thread) : "",
2429 thread->tid);
2430 } else {
2431 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2432 thread->comm_set ? thread__comm_str(thread) : "");
2433 }
2434
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002435 browser->hists->thread_filter = thread__get(thread);
2436 perf_hpp__set_elide(HISTC_THREAD, false);
2437 pstack__push(browser->pstack, &browser->hists->thread_filter);
2438 }
2439
2440 hists__filter_by_thread(browser->hists);
2441 hist_browser__reset(browser);
2442 return 0;
2443}
2444
2445static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002446add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2447 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002448{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002449 int ret;
2450
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002451 if ((!hists__has(browser->hists, thread) &&
2452 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002453 return 0;
2454
Jiri Olsafa829112016-05-03 13:54:47 +02002455 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002456 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2457 browser->hists->thread_filter ? "out of" : "into",
2458 thread->comm_set ? thread__comm_str(thread) : "",
2459 thread->tid);
2460 } else {
2461 ret = asprintf(optstr, "Zoom %s %s thread",
2462 browser->hists->thread_filter ? "out of" : "into",
2463 thread->comm_set ? thread__comm_str(thread) : "");
2464 }
2465 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002466 return 0;
2467
2468 act->thread = thread;
2469 act->fn = do_zoom_thread;
2470 return 1;
2471}
2472
2473static int
2474do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2475{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002476 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002477
Jiri Olsa69849fc2016-05-03 13:54:45 +02002478 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002479 return 0;
2480
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002481 if (browser->hists->dso_filter) {
2482 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2483 perf_hpp__set_elide(HISTC_DSO, false);
2484 browser->hists->dso_filter = NULL;
2485 ui_helpline__pop();
2486 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002487 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002488 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2489 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002490 perf_hpp__set_elide(HISTC_DSO, true);
2491 pstack__push(browser->pstack, &browser->hists->dso_filter);
2492 }
2493
2494 hists__filter_by_dso(browser->hists);
2495 hist_browser__reset(browser);
2496 return 0;
2497}
2498
2499static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002500add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002501 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002502{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002503 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002504 return 0;
2505
2506 if (asprintf(optstr, "Zoom %s %s DSO",
2507 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002508 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002509 return 0;
2510
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002511 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002512 act->fn = do_zoom_dso;
2513 return 1;
2514}
2515
2516static int
2517do_browse_map(struct hist_browser *browser __maybe_unused,
2518 struct popup_action *act)
2519{
2520 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002521 return 0;
2522}
2523
2524static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002525add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002526 struct popup_action *act, char **optstr, struct map *map)
2527{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002528 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002529 return 0;
2530
2531 if (asprintf(optstr, "Browse map details") < 0)
2532 return 0;
2533
2534 act->ms.map = map;
2535 act->fn = do_browse_map;
2536 return 1;
2537}
2538
2539static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002540do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002541 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002542{
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002543 char *script_opt;
2544 int len;
2545 int n = 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002546
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002547 len = 100;
2548 if (act->thread)
2549 len += strlen(thread__comm_str(act->thread));
2550 else if (act->ms.sym)
2551 len += strlen(act->ms.sym->name);
2552 script_opt = malloc(len);
2553 if (!script_opt)
2554 return -1;
2555
2556 script_opt[0] = 0;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002557 if (act->thread) {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002558 n = scnprintf(script_opt, len, " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002559 thread__comm_str(act->thread));
2560 } else if (act->ms.sym) {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002561 n = scnprintf(script_opt, len, " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002562 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002563 }
2564
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002565 if (act->time) {
2566 char start[32], end[32];
2567 unsigned long starttime = act->time;
2568 unsigned long endtime = act->time + symbol_conf.time_quantum;
2569
2570 if (starttime == endtime) { /* Display 1ms as fallback */
2571 starttime -= 1*NSEC_PER_MSEC;
2572 endtime += 1*NSEC_PER_MSEC;
2573 }
2574 timestamp__scnprintf_usec(starttime, start, sizeof start);
2575 timestamp__scnprintf_usec(endtime, end, sizeof end);
2576 n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end);
2577 }
2578
Andi Kleen6f3da202019-03-11 07:44:57 -07002579 script_browse(script_opt, act->evsel);
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002580 free(script_opt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002581 return 0;
2582}
2583
2584static int
Andi Kleen4968ac82019-03-11 07:44:58 -07002585do_res_sample_script(struct hist_browser *browser __maybe_unused,
2586 struct popup_action *act)
2587{
2588 struct hist_entry *he;
2589
2590 he = hist_browser__selected_entry(browser);
2591 res_sample_browse(he->res_samples, he->num_res, act->evsel, act->rstype);
2592 return 0;
2593}
2594
2595static int
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002596add_script_opt_2(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002597 struct popup_action *act, char **optstr,
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002598 struct thread *thread, struct symbol *sym,
Andi Kleen6f3da202019-03-11 07:44:57 -07002599 struct perf_evsel *evsel, const char *tstr)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002600{
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002601
Namhyung Kimea7cd592015-04-22 16:18:19 +09002602 if (thread) {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002603 if (asprintf(optstr, "Run scripts for samples of thread [%s]%s",
2604 thread__comm_str(thread), tstr) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002605 return 0;
2606 } else if (sym) {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002607 if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s",
2608 sym->name, tstr) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002609 return 0;
2610 } else {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002611 if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002612 return 0;
2613 }
2614
2615 act->thread = thread;
2616 act->ms.sym = sym;
Andi Kleen6f3da202019-03-11 07:44:57 -07002617 act->evsel = evsel;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002618 act->fn = do_run_script;
2619 return 1;
2620}
2621
2622static int
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002623add_script_opt(struct hist_browser *browser,
2624 struct popup_action *act, char **optstr,
Andi Kleen6f3da202019-03-11 07:44:57 -07002625 struct thread *thread, struct symbol *sym,
2626 struct perf_evsel *evsel)
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002627{
2628 int n, j;
2629 struct hist_entry *he;
2630
Andi Kleen6f3da202019-03-11 07:44:57 -07002631 n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, "");
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002632
2633 he = hist_browser__selected_entry(browser);
2634 if (sort_order && strstr(sort_order, "time")) {
2635 char tstr[128];
2636
2637 optstr++;
2638 act++;
2639 j = sprintf(tstr, " in ");
2640 j += timestamp__scnprintf_usec(he->time, tstr + j,
2641 sizeof tstr - j);
2642 j += sprintf(tstr + j, "-");
2643 timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum,
Andi Kleen6f3da202019-03-11 07:44:57 -07002644 tstr + j, sizeof tstr - j);
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002645 n += add_script_opt_2(browser, act, optstr, thread, sym,
Andi Kleen6f3da202019-03-11 07:44:57 -07002646 evsel, tstr);
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002647 act->time = he->time;
2648 }
2649 return n;
2650}
2651
2652static int
Andi Kleen4968ac82019-03-11 07:44:58 -07002653add_res_sample_opt(struct hist_browser *browser __maybe_unused,
2654 struct popup_action *act, char **optstr,
2655 struct res_sample *res_sample,
2656 struct perf_evsel *evsel,
2657 enum rstype type)
2658{
2659 if (!res_sample)
2660 return 0;
2661
2662 if (asprintf(optstr, "Show context for individual samples %s",
2663 type == A_ASM ? "with assembler" :
2664 type == A_SOURCE ? "with source" : "") < 0)
2665 return 0;
2666
2667 act->fn = do_res_sample_script;
2668 act->evsel = evsel;
2669 act->rstype = type;
2670 return 1;
2671}
2672
2673static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002674do_switch_data(struct hist_browser *browser __maybe_unused,
2675 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002676{
2677 if (switch_data_file()) {
2678 ui__warning("Won't switch the data files due to\n"
2679 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002680 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002681 }
2682
2683 return K_SWITCH_INPUT_DATA;
2684}
2685
Namhyung Kimea7cd592015-04-22 16:18:19 +09002686static int
2687add_switch_opt(struct hist_browser *browser,
2688 struct popup_action *act, char **optstr)
2689{
2690 if (!is_report_browser(browser->hbt))
2691 return 0;
2692
2693 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2694 return 0;
2695
2696 act->fn = do_switch_data;
2697 return 1;
2698}
2699
2700static int
2701do_exit_browser(struct hist_browser *browser __maybe_unused,
2702 struct popup_action *act __maybe_unused)
2703{
2704 return 0;
2705}
2706
2707static int
2708add_exit_opt(struct hist_browser *browser __maybe_unused,
2709 struct popup_action *act, char **optstr)
2710{
2711 if (asprintf(optstr, "Exit") < 0)
2712 return 0;
2713
2714 act->fn = do_exit_browser;
2715 return 1;
2716}
2717
Kan Liang84734b02015-09-04 10:45:45 -04002718static int
2719do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2720{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002721 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002722 return 0;
2723
Kan Liang84734b02015-09-04 10:45:45 -04002724 if (browser->hists->socket_filter > -1) {
2725 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2726 browser->hists->socket_filter = -1;
2727 perf_hpp__set_elide(HISTC_SOCKET, false);
2728 } else {
2729 browser->hists->socket_filter = act->socket;
2730 perf_hpp__set_elide(HISTC_SOCKET, true);
2731 pstack__push(browser->pstack, &browser->hists->socket_filter);
2732 }
2733
2734 hists__filter_by_socket(browser->hists);
2735 hist_browser__reset(browser);
2736 return 0;
2737}
2738
2739static int
2740add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2741 char **optstr, int socket_id)
2742{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002743 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002744 return 0;
2745
2746 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2747 (browser->hists->socket_filter > -1) ? "out of" : "into",
2748 socket_id) < 0)
2749 return 0;
2750
2751 act->socket = socket_id;
2752 act->fn = do_zoom_socket;
2753 return 1;
2754}
2755
Namhyung Kim112f7612014-04-22 14:05:35 +09002756static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002757{
2758 u64 nr_entries = 0;
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08002759 struct rb_node *nd = rb_first_cached(&hb->hists->entries);
Namhyung Kim064f1982013-05-14 11:09:04 +09002760
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002761 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002762 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2763 return;
2764 }
2765
Namhyung Kim14135662013-10-31 10:17:39 +09002766 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002767 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002768 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002769 }
2770
Namhyung Kim112f7612014-04-22 14:05:35 +09002771 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002772 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002773}
Feng Tang341487ab2013-02-03 14:38:20 +08002774
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002775static void hist_browser__update_percent_limit(struct hist_browser *hb,
2776 double percent)
2777{
2778 struct hist_entry *he;
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08002779 struct rb_node *nd = rb_first_cached(&hb->hists->entries);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002780 u64 total = hists__total_period(hb->hists);
2781 u64 min_callchain_hits = total * (percent / 100);
2782
2783 hb->min_pcnt = callchain_param.min_percent = percent;
2784
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002785 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2786 he = rb_entry(nd, struct hist_entry, rb_node);
2787
Namhyung Kim79dded82016-02-26 21:13:19 +09002788 if (he->has_no_entry) {
2789 he->has_no_entry = false;
2790 he->nr_rows = 0;
2791 }
2792
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03002793 if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002794 goto next;
2795
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002796 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2797 total = he->stat.period;
2798
2799 if (symbol_conf.cumulate_callchain)
2800 total = he->stat_acc->period;
2801
2802 min_callchain_hits = total * (percent / 100);
2803 }
2804
2805 callchain_param.sort(&he->sorted_chain, he->callchain,
2806 min_callchain_hits, &callchain_param);
2807
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002808next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002809 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002810
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002811 /* force to re-evaluate folding state of callchains */
2812 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002813 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002814 }
2815}
2816
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002817static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002818 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002819 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002820 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002821 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08002822 struct perf_env *env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002823 bool warn_lost_event,
2824 struct annotation_options *annotation_opts)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002825{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002826 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002827 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts);
Leo Yanceb75472019-07-08 22:39:34 +08002828 struct branch_info *bi = NULL;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002829#define MAX_OPTIONS 16
2830 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002831 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002832 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002833 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002834 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002835 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002836
Namhyung Kime8e684a2013-12-26 14:37:58 +09002837#define HIST_BROWSER_HELP_COMMON \
2838 "h/?/F1 Show this window\n" \
2839 "UP/DOWN/PGUP\n" \
2840 "PGDN/SPACE Navigate\n" \
Andi Kleen6a02f062018-04-06 13:38:10 -07002841 "q/ESC/CTRL+C Exit browser or go back to previous screen\n\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002842 "For multiple event sessions:\n\n" \
2843 "TAB/UNTAB Switch events\n\n" \
2844 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002845 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2846 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002847 "a Annotate current symbol\n" \
2848 "C Collapse all callchains\n" \
2849 "d Zoom into current DSO\n" \
2850 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002851 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002852 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002853 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002854 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002855 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002856
2857 /* help messages are sorted by lexical order of the hotkey */
Rasmus Villemoes49b8e2b2018-11-03 00:06:23 +01002858 static const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002859 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002860 "P Print histograms to perf.hist.N\n"
2861 "r Run available scripts\n"
2862 "s Switch to another data file in PWD\n"
2863 "t Zoom into current Thread\n"
2864 "V Verbose (DSO names in callchains, etc)\n"
2865 "/ Filter symbol by name";
Rasmus Villemoes49b8e2b2018-11-03 00:06:23 +01002866 static const char top_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kime8e684a2013-12-26 14:37:58 +09002867 "P Print histograms to perf.hist.N\n"
2868 "t Zoom into current Thread\n"
2869 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002870 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002871 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002872 "/ Filter symbol by name";
2873
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002874 if (browser == NULL)
2875 return -1;
2876
Namhyung Kimed426912015-05-29 21:53:44 +09002877 /* reset abort key so that it can get Ctrl-C as a key */
2878 SLang_reset_tty();
2879 SLang_init_tty(0, 0, 0);
2880
Namhyung Kim03905042015-11-28 02:32:39 +09002881 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002882 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002883 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002884
Kan Liang84734b02015-09-04 10:45:45 -04002885 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002886 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002887 goto out;
2888
2889 ui_helpline__push(helpline);
2890
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002891 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002892 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002893
Namhyung Kim5b591662014-07-31 14:47:38 +09002894 if (symbol_conf.col_width_list_str)
2895 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2896
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002897 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002898 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002899 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002900 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002901 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002902
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002903 nr_options = 0;
2904
Kan Liang06cc1a42018-01-18 13:26:29 -08002905 key = hist_browser__run(browser, helpline,
2906 warn_lost_event);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002907
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002908 if (browser->he_selection != NULL) {
2909 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002910 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002911 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002912 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002913 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002914 case K_TAB:
2915 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002916 if (nr_events == 1)
2917 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002918 /*
2919 * Exit the browser, let hists__browser_tree
2920 * go to the next or previous
2921 */
2922 goto out_free_stack;
2923 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002924 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002925 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002926 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002927 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002928 continue;
2929 }
2930
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002931 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002932 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002933 browser->selection->map->dso->annotate_warned)
2934 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002935
Namhyung Kimea7cd592015-04-22 16:18:19 +09002936 actions->ms.map = browser->selection->map;
2937 actions->ms.sym = browser->selection->sym;
2938 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002939 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002940 case 'P':
2941 hist_browser__dump(browser);
2942 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002943 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002944 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002945 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002946 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002947 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02002948 verbose = (verbose + 1) % 4;
2949 browser->show_dso = verbose > 0;
2950 ui_helpline__fpush("Verbosity level set to %d\n",
2951 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002952 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002953 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002954 actions->thread = thread;
2955 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002956 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002957 case 'S':
2958 actions->socket = socked_id;
2959 do_zoom_socket(browser, actions);
2960 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002961 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002962 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002963 "Please enter the name of symbol you want to see.\n"
2964 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002965 buf, "ENTER: OK, ESC: Cancel",
2966 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002967 hists->symbol_filter_str = *buf ? buf : NULL;
2968 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002969 hist_browser__reset(browser);
2970 }
2971 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002972 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002973 if (is_report_browser(hbt)) {
2974 actions->thread = NULL;
2975 actions->ms.sym = NULL;
2976 do_run_script(browser, actions);
2977 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002978 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002979 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002980 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002981 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002982 if (key == K_SWITCH_INPUT_DATA)
2983 goto out_free_stack;
2984 }
Feng Tang341487ab2013-02-03 14:38:20 +08002985 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002986 case 'i':
2987 /* env->arch is NULL for live-mode (i.e. perf top) */
2988 if (env->arch)
2989 tui__header_window(env);
2990 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002991 case 'F':
2992 symbol_conf.filter_relative ^= 1;
2993 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002994 case 'z':
2995 if (!is_report_browser(hbt)) {
2996 struct perf_top *top = hbt->arg;
2997
2998 top->zero = !top->zero;
2999 }
3000 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003001 case 'L':
3002 if (ui_browser__input_window("Percent Limit",
3003 "Please enter the value you want to hide entries under that percent.",
3004 buf, "ENTER: OK, ESC: Cancel",
3005 delay_secs * 2) == K_ENTER) {
3006 char *end;
3007 double new_percent = strtod(buf, &end);
3008
3009 if (new_percent < 0 || new_percent > 100) {
3010 ui_browser__warning(&browser->b, delay_secs * 2,
3011 "Invalid percent: %.2f", new_percent);
3012 continue;
3013 }
3014
3015 hist_browser__update_percent_limit(browser, new_percent);
3016 hist_browser__reset(browser);
3017 }
3018 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003019 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003020 case 'h':
3021 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003022 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003023 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003024 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003025 case K_ENTER:
3026 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003027 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003028 /* menu */
3029 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003030 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003031 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003032 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003033
Namhyung Kim01f00a12015-04-22 16:18:16 +09003034 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003035 /*
3036 * Go back to the perf_evsel_menu__run or other user
3037 */
3038 if (left_exits)
3039 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003040
3041 if (key == K_ESC &&
3042 ui_browser__dialog_yesno(&browser->b,
3043 "Do you really want to exit?"))
3044 goto out_free_stack;
3045
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003046 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003047 }
Namhyung Kim64221842015-04-24 10:15:33 +09003048 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003049 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003050 /*
3051 * No need to set actions->dso here since
3052 * it's just to remove the current filter.
3053 * Ditto for thread below.
3054 */
3055 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003056 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003057 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003058 } else if (top == &browser->hists->socket_filter) {
3059 do_zoom_socket(browser, actions);
3060 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003061 continue;
3062 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003063 case 'q':
3064 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003065 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003066 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003067 if (!is_report_browser(hbt)) {
3068 struct perf_top *top = hbt->arg;
3069
3070 perf_evlist__toggle_enable(top->evlist);
3071 /*
3072 * No need to refresh, resort/decay histogram
3073 * entries if we are not collecting samples:
3074 */
3075 if (top->evlist->enabled) {
3076 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3077 hbt->refresh = delay_secs;
3078 } else {
3079 helpline = "Press 'f' again to re-enable the events";
3080 hbt->refresh = 0;
3081 }
3082 continue;
3083 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003084 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003085 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003086 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003087 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003088 }
3089
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003090 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003091 goto skip_annotation;
3092
Namhyung Kim55369fc2013-04-01 20:35:20 +09003093 if (sort__mode == SORT_MODE__BRANCH) {
Leo Yanceb75472019-07-08 22:39:34 +08003094
3095 if (browser->he_selection)
3096 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003097
3098 if (bi == NULL)
3099 goto skip_annotation;
3100
Namhyung Kimea7cd592015-04-22 16:18:19 +09003101 nr_options += add_annotate_opt(browser,
3102 &actions[nr_options],
3103 &options[nr_options],
3104 bi->from.map,
3105 bi->from.sym);
3106 if (bi->to.sym != bi->from.sym)
3107 nr_options += add_annotate_opt(browser,
3108 &actions[nr_options],
3109 &options[nr_options],
3110 bi->to.map,
3111 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003112 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003113 nr_options += add_annotate_opt(browser,
3114 &actions[nr_options],
3115 &options[nr_options],
3116 browser->selection->map,
3117 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003118 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003119skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003120 nr_options += add_thread_opt(browser, &actions[nr_options],
3121 &options[nr_options], thread);
3122 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003123 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003124 nr_options += add_map_opt(browser, &actions[nr_options],
3125 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003126 browser->selection ?
3127 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003128 nr_options += add_socket_opt(browser, &actions[nr_options],
3129 &options[nr_options],
3130 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003131 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003132 if (!is_report_browser(hbt))
3133 goto skip_scripting;
3134
Feng Tangcdbab7c2012-10-30 11:56:06 +08003135 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003136 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003137 nr_options += add_script_opt(browser,
3138 &actions[nr_options],
3139 &options[nr_options],
Andi Kleen6f3da202019-03-11 07:44:57 -07003140 thread, NULL, evsel);
Namhyung Kim2eafd412016-01-21 19:13:24 -03003141 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003142 /*
3143 * Note that browser->selection != NULL
3144 * when browser->he_selection is not NULL,
3145 * so we don't need to check browser->selection
3146 * before fetching browser->selection->sym like what
3147 * we do before fetching browser->selection->map.
3148 *
3149 * See hist_browser__show_entry.
3150 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003151 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003152 nr_options += add_script_opt(browser,
3153 &actions[nr_options],
3154 &options[nr_options],
Andi Kleen6f3da202019-03-11 07:44:57 -07003155 NULL, browser->selection->sym,
3156 evsel);
Namhyung Kimc221acb2016-01-21 19:50:09 -03003157 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003158 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003159 nr_options += add_script_opt(browser, &actions[nr_options],
Andi Kleen6f3da202019-03-11 07:44:57 -07003160 &options[nr_options], NULL, NULL, evsel);
Andi Kleen4968ac82019-03-11 07:44:58 -07003161 nr_options += add_res_sample_opt(browser, &actions[nr_options],
3162 &options[nr_options],
3163 hist_browser__selected_entry(browser)->res_samples,
3164 evsel, A_NORMAL);
3165 nr_options += add_res_sample_opt(browser, &actions[nr_options],
3166 &options[nr_options],
3167 hist_browser__selected_entry(browser)->res_samples,
3168 evsel, A_ASM);
3169 nr_options += add_res_sample_opt(browser, &actions[nr_options],
3170 &options[nr_options],
3171 hist_browser__selected_entry(browser)->res_samples,
3172 evsel, A_SOURCE);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003173 nr_options += add_switch_opt(browser, &actions[nr_options],
3174 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003175skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003176 nr_options += add_exit_opt(browser, &actions[nr_options],
3177 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003178
Namhyung Kimea7cd592015-04-22 16:18:19 +09003179 do {
3180 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003181
Namhyung Kimea7cd592015-04-22 16:18:19 +09003182 choice = ui__popup_menu(nr_options, options);
3183 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003184 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003185
3186 act = &actions[choice];
3187 key = act->fn(browser, act);
3188 } while (key == 1);
3189
3190 if (key == K_SWITCH_INPUT_DATA)
3191 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003192 }
3193out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003194 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003195out:
3196 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003197 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003198 return key;
3199}
3200
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003201struct perf_evsel_menu {
3202 struct ui_browser b;
3203 struct perf_evsel *selection;
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003204 struct annotation_options *annotation_opts;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003205 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003206 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003207 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003208};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003209
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003210static void perf_evsel_menu__write(struct ui_browser *browser,
3211 void *entry, int row)
3212{
3213 struct perf_evsel_menu *menu = container_of(browser,
3214 struct perf_evsel_menu, b);
3215 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003216 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003217 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003218 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003219 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003220 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003221 const char *warn = " ";
3222 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003223
3224 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3225 HE_COLORSET_NORMAL);
3226
Namhyung Kim759ff492013-03-05 14:53:26 +09003227 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003228 struct perf_evsel *pos;
3229
3230 ev_name = perf_evsel__group_name(evsel);
3231
3232 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003233 struct hists *pos_hists = evsel__hists(pos);
3234 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003235 }
3236 }
3237
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003238 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003239 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003240 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003241 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003242
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003243 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003244 if (nr_events != 0) {
3245 menu->lost_events = true;
3246 if (!current_entry)
3247 ui_browser__set_color(browser, HE_COLORSET_TOP);
3248 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003249 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3250 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003251 warn = bf;
3252 }
3253
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003254 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003255
3256 if (current_entry)
3257 menu->selection = evsel;
3258}
3259
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003260static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3261 int nr_events, const char *help,
Kan Liang06cc1a42018-01-18 13:26:29 -08003262 struct hist_browser_timer *hbt,
3263 bool warn_lost_event)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003264{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003265 struct perf_evlist *evlist = menu->b.priv;
3266 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003267 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003268 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003269 int key;
3270
3271 if (ui_browser__show(&menu->b, title,
3272 "ESC: exit, ENTER|->: Browse histograms") < 0)
3273 return -1;
3274
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003275 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003276 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003277
3278 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003279 case K_TIMER:
Leo Yanceb75472019-07-08 22:39:34 +08003280 if (hbt)
3281 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003282
Kan Liang06cc1a42018-01-18 13:26:29 -08003283 if (!menu->lost_events_warned &&
3284 menu->lost_events &&
3285 warn_lost_event) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003286 ui_browser__warn_lost_events(&menu->b);
3287 menu->lost_events_warned = true;
3288 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003289 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003290 case K_RIGHT:
3291 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003292 if (!menu->selection)
3293 continue;
3294 pos = menu->selection;
3295browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003296 perf_evlist__set_selected(evlist, pos);
3297 /*
3298 * Give the calling tool a chance to populate the non
3299 * default evsel resorted hists tree.
3300 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003301 if (hbt)
3302 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003303 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003304 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003305 menu->min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003306 menu->env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003307 warn_lost_event,
3308 menu->annotation_opts);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003309 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003310 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003311 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003312 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003313 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003314 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003315 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003316 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003317 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003318 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003319 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003320 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003321 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003322 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003323 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003324 case 'q':
3325 case CTRL('c'):
3326 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003327 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003328 default:
3329 continue;
3330 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003331 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003332 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003333 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003334 if (!ui_browser__dialog_yesno(&menu->b,
3335 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003336 continue;
3337 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003338 case 'q':
3339 case CTRL('c'):
3340 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003341 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003342 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003343 }
3344 }
3345
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003346out:
3347 ui_browser__hide(&menu->b);
3348 return key;
3349}
3350
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003351static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003352 void *entry)
3353{
3354 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3355
3356 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3357 return true;
3358
3359 return false;
3360}
3361
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003362static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003363 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003364 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003365 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003366 struct perf_env *env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003367 bool warn_lost_event,
3368 struct annotation_options *annotation_opts)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003369{
3370 struct perf_evsel *pos;
3371 struct perf_evsel_menu menu = {
3372 .b = {
3373 .entries = &evlist->entries,
3374 .refresh = ui_browser__list_head_refresh,
3375 .seek = ui_browser__list_head_seek,
3376 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003377 .filter = filter_group_entries,
3378 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003379 .priv = evlist,
3380 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003381 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003382 .env = env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003383 .annotation_opts = annotation_opts,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003384 };
3385
3386 ui_helpline__push("Press ESC to exit");
3387
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003388 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003389 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003390 size_t line_len = strlen(ev_name) + 7;
3391
3392 if (menu.b.width < line_len)
3393 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003394 }
3395
Kan Liang06cc1a42018-01-18 13:26:29 -08003396 return perf_evsel_menu__run(&menu, nr_entries, help,
3397 hbt, warn_lost_event);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003398}
3399
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003400int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003401 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003402 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003403 struct perf_env *env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003404 bool warn_lost_event,
3405 struct annotation_options *annotation_opts)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003406{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003407 int nr_entries = evlist->nr_entries;
3408
3409single_entry:
3410 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003411 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003412
3413 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003414 false, hbt, min_pcnt,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003415 env, warn_lost_event,
3416 annotation_opts);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003417 }
3418
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003419 if (symbol_conf.event_group) {
3420 struct perf_evsel *pos;
3421
3422 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003423 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003424 if (perf_evsel__is_group_leader(pos))
3425 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003426 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003427
3428 if (nr_entries == 1)
3429 goto single_entry;
3430 }
3431
3432 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Kan Liang06cc1a42018-01-18 13:26:29 -08003433 hbt, min_pcnt, env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003434 warn_lost_event,
3435 annotation_opts);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003436}