blob: 3421ecbdd3f046c42e4b5ef578abf11bfb591b64 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Arnaldo Carvalho de Melo76b31a22017-04-18 12:26:44 -03002#include <dirent.h>
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03003#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03004#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03006#include <stdlib.h>
7#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03008#include <linux/rbtree.h>
Arnaldo Carvalho de Melob0742e92017-04-18 11:08:10 -03009#include <sys/ttydefaults.h>
Andi Kleen1d6c49d2019-03-11 07:44:56 -070010#include <linux/time64.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030011
Arnaldo Carvalho de Melob10ba7f2019-01-29 11:11:04 +010012#include "../../util/callchain.h"
Namhyung Kimaca7a942012-04-04 00:14:26 -070013#include "../../util/evsel.h"
14#include "../../util/evlist.h"
15#include "../../util/hist.h"
Arnaldo Carvalho de Melo1101f692019-01-27 13:42:37 +010016#include "../../util/map.h"
Arnaldo Carvalho de Melodaecf9e2019-01-28 00:03:34 +010017#include "../../util/symbol.h"
Namhyung Kimaca7a942012-04-04 00:14:26 -070018#include "../../util/pstack.h"
19#include "../../util/sort.h"
20#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090021#include "../../util/top.h"
Arnaldo Carvalho de Meloe7ff8922017-04-19 21:34:35 -030022#include "../../util/thread.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090023#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030024
Jiri Olsaf7589902016-06-20 23:58:13 +020025#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030026#include "../helpline.h"
27#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020028#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030029#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020030#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030031#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030032#include "string2.h"
Arnaldo Carvalho de Melo58db1d62017-04-19 16:05:56 -030033#include "units.h"
Andi Kleen1d6c49d2019-03-11 07:44:56 -070034#include "time-utils.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030035
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030036#include "sane_ctype.h"
37
Namhyung Kimf5951d52012-09-03 11:53:09 +090038extern void hist_browser__init_hpp(void);
39
Arnaldo Carvalho de Melof016d242018-04-02 14:00:04 -030040static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090041static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030042
Namhyung Kimc3b78952014-04-22 15:56:17 +090043static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090044 float min_pcnt);
45
Namhyung Kim268397c2014-04-22 14:49:31 +090046static bool hist_browser__has_filter(struct hist_browser *hb)
47{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010048 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090049}
50
He Kuang4fabf3d2015-03-12 15:21:49 +080051static int hist_browser__get_folding(struct hist_browser *browser)
52{
53 struct rb_node *nd;
54 struct hists *hists = browser->hists;
55 int unfolded_rows = 0;
56
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -080057 for (nd = rb_first_cached(&hists->entries);
He Kuang4fabf3d2015-03-12 15:21:49 +080058 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090059 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080060 struct hist_entry *he =
61 rb_entry(nd, struct hist_entry, rb_node);
62
Namhyung Kimf5b763f2016-02-25 00:13:43 +090063 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080064 unfolded_rows += he->nr_rows;
65 }
66 return unfolded_rows;
67}
68
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -030069static void hist_browser__set_title_space(struct hist_browser *hb)
70{
71 struct ui_browser *browser = &hb->b;
72 struct hists *hists = hb->hists;
73 struct perf_hpp_list *hpp_list = hists->hpp_list;
74
75 browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0;
76}
77
Namhyung Kimc3b78952014-04-22 15:56:17 +090078static u32 hist_browser__nr_entries(struct hist_browser *hb)
79{
80 u32 nr_entries;
81
Namhyung Kimf5b763f2016-02-25 00:13:43 +090082 if (symbol_conf.report_hierarchy)
83 nr_entries = hb->nr_hierarchy_entries;
84 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090085 nr_entries = hb->nr_non_filtered_entries;
86 else
87 nr_entries = hb->hists->nr_entries;
88
He Kuang4fabf3d2015-03-12 15:21:49 +080089 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090090 return nr_entries + hb->nr_callchain_rows;
91}
92
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020093static void hist_browser__update_rows(struct hist_browser *hb)
94{
95 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020096 struct hists *hists = hb->hists;
97 struct perf_hpp_list *hpp_list = hists->hpp_list;
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -030098 u16 index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020099
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -0300100 if (!hb->show_headers) {
101 browser->rows += browser->extra_title_lines;
102 browser->extra_title_lines = 0;
103 return;
104 }
105
106 browser->extra_title_lines = hpp_list->nr_header_lines;
107 browser->rows -= browser->extra_title_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200108 /*
109 * Verify if we were at the last line and that line isn't
110 * visibe because we now show the header line(s).
111 */
112 index_row = browser->index - browser->top_idx;
113 if (index_row >= browser->rows)
114 browser->index -= index_row - browser->rows + 1;
115}
116
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300117static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300118{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300119 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
120
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300121 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300122 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
123 /*
124 * FIXME: Just keeping existing behaviour, but this really should be
125 * before updating browser->width, as it will invalidate the
126 * calculation above. Fix this and the fallout in another
127 * changeset.
128 */
129 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300130}
131
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900134 /*
135 * The hists__remove_entry_filter() already folds non-filtered
136 * entries so we can assume it has 0 callchain rows.
137 */
138 browser->nr_callchain_rows = 0;
139
Namhyung Kim268397c2014-04-22 14:49:31 +0900140 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900141 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300142 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300143 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300144}
145
146static char tree__folded_sign(bool unfolded)
147{
148 return unfolded ? '-' : '+';
149}
150
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300151static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300152{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900153 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300154}
155
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300156static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300157{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900158 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300159}
160
Namhyung Kim3698dab2015-05-05 23:55:46 +0900161static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300162{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900163 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300164}
165
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300166static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300167{
Milian Wolff2a704fc2017-10-09 22:32:55 +0200168 int n = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300169 struct rb_node *nd;
170
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300171 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300172 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
173 struct callchain_list *chain;
174 char folded_sign = ' '; /* No children */
175
176 list_for_each_entry(chain, &child->val, list) {
177 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800178
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300179 /* We need this because we may not have children */
180 folded_sign = callchain_list__folded(chain);
181 if (folded_sign == '+')
182 break;
183 }
184
185 if (folded_sign == '-') /* Have children and they're unfolded */
186 n += callchain_node__count_rows_rb_tree(child);
187 }
188
189 return n;
190}
191
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900192static int callchain_node__count_flat_rows(struct callchain_node *node)
193{
194 struct callchain_list *chain;
195 char folded_sign = 0;
196 int n = 0;
197
198 list_for_each_entry(chain, &node->parent_val, list) {
199 if (!folded_sign) {
200 /* only check first chain list entry */
201 folded_sign = callchain_list__folded(chain);
202 if (folded_sign == '+')
203 return 1;
204 }
205 n++;
206 }
207
208 list_for_each_entry(chain, &node->val, list) {
209 if (!folded_sign) {
210 /* node->parent_val list might be empty */
211 folded_sign = callchain_list__folded(chain);
212 if (folded_sign == '+')
213 return 1;
214 }
215 n++;
216 }
217
218 return n;
219}
220
Namhyung Kim8c430a32015-11-09 14:45:44 +0900221static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
222{
223 return 1;
224}
225
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300226static int callchain_node__count_rows(struct callchain_node *node)
227{
228 struct callchain_list *chain;
229 bool unfolded = false;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200230 int n = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300231
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900232 if (callchain_param.mode == CHAIN_FLAT)
233 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900234 else if (callchain_param.mode == CHAIN_FOLDED)
235 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900236
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300237 list_for_each_entry(chain, &node->val, list) {
238 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800239
Namhyung Kim3698dab2015-05-05 23:55:46 +0900240 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300241 }
242
243 if (unfolded)
244 n += callchain_node__count_rows_rb_tree(node);
245
246 return n;
247}
248
249static int callchain__count_rows(struct rb_root *chain)
250{
251 struct rb_node *nd;
252 int n = 0;
253
254 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
255 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
256 n += callchain_node__count_rows(node);
257 }
258
259 return n;
260}
261
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900262static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
263 bool include_children)
264{
265 int count = 0;
266 struct rb_node *node;
267 struct hist_entry *child;
268
269 if (he->leaf)
270 return callchain__count_rows(&he->sorted_chain);
271
Namhyung Kim79dded82016-02-26 21:13:19 +0900272 if (he->has_no_entry)
273 return 1;
274
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -0800275 node = rb_first_cached(&he->hroot_out);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900276 while (node) {
277 float percent;
278
279 child = rb_entry(node, struct hist_entry, rb_node);
280 percent = hist_entry__get_percent_limit(child);
281
282 if (!child->filtered && percent >= hb->min_pcnt) {
283 count++;
284
285 if (include_children && child->unfolded)
286 count += hierarchy_count_rows(hb, child, true);
287 }
288
289 node = rb_next(node);
290 }
291 return count;
292}
293
Namhyung Kim3698dab2015-05-05 23:55:46 +0900294static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300295{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900296 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200297 return false;
298
Namhyung Kim3698dab2015-05-05 23:55:46 +0900299 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300300 return false;
301
Namhyung Kim3698dab2015-05-05 23:55:46 +0900302 he->unfolded = !he->unfolded;
303 return true;
304}
305
306static bool callchain_list__toggle_fold(struct callchain_list *cl)
307{
308 if (!cl)
309 return false;
310
311 if (!cl->has_children)
312 return false;
313
314 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300315 return true;
316}
317
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300318static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300319{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300320 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300321
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300322 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300323 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
324 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300325 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300326
327 list_for_each_entry(chain, &child->val, list) {
328 if (first) {
329 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900330 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300331 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300332 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900333 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300334 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300335 }
336
337 callchain_node__init_have_children_rb_tree(child);
338 }
339}
340
Namhyung Kima7444af2014-11-24 17:13:27 +0900341static void callchain_node__init_have_children(struct callchain_node *node,
342 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300343{
344 struct callchain_list *chain;
345
Namhyung Kima7444af2014-11-24 17:13:27 +0900346 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900347 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900348
Andres Freund90989032016-03-30 21:02:45 +0200349 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900350 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900351 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900352 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300353
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300354 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300355}
356
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300357static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300358{
Namhyung Kima7444af2014-11-24 17:13:27 +0900359 struct rb_node *nd = rb_first(root);
360 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300361
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300362 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900364 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900365 if (callchain_param.mode == CHAIN_FLAT ||
366 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900367 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300368 }
369}
370
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300371static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900373 if (he->init_have_children)
374 return;
375
376 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900377 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300378 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900379 } else {
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -0800380 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out.rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300381 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900382
383 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300384}
385
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300386static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300387{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900388 struct hist_entry *he = browser->he_selection;
389 struct map_symbol *ms = browser->selection;
390 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
391 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300392
Wang Nan4938cf02015-12-07 02:35:44 +0000393 if (!he || !ms)
394 return false;
395
Namhyung Kim3698dab2015-05-05 23:55:46 +0900396 if (ms == &he->ms)
397 has_children = hist_entry__toggle_fold(he);
398 else
399 has_children = callchain_list__toggle_fold(cl);
400
401 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900402 int child_rows = 0;
403
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300404 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900405 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300406
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900407 if (he->leaf)
408 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300409 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900410 browser->nr_hierarchy_entries -= he->nr_rows;
411
412 if (symbol_conf.report_hierarchy)
413 child_rows = hierarchy_count_rows(browser, he, true);
414
415 if (he->unfolded) {
416 if (he->leaf)
Milian Wolff2a704fc2017-10-09 22:32:55 +0200417 he->nr_rows = callchain__count_rows(
418 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900419 else
420 he->nr_rows = hierarchy_count_rows(browser, he, false);
421
422 /* account grand children */
423 if (symbol_conf.report_hierarchy)
424 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900425
426 if (!he->leaf && he->nr_rows == 0) {
427 he->has_no_entry = true;
428 he->nr_rows = 1;
429 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900430 } else {
431 if (symbol_conf.report_hierarchy)
432 browser->b.nr_entries -= child_rows - he->nr_rows;
433
Namhyung Kim79dded82016-02-26 21:13:19 +0900434 if (he->has_no_entry)
435 he->has_no_entry = false;
436
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300437 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900438 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900439
440 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900441
442 if (he->leaf)
443 browser->nr_callchain_rows += he->nr_rows;
444 else
445 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300446
447 return true;
448 }
449
450 /* If it doesn't have children, no toggling performed */
451 return false;
452}
453
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300454static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300455{
456 int n = 0;
457 struct rb_node *nd;
458
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300459 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300460 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
461 struct callchain_list *chain;
462 bool has_children = false;
463
464 list_for_each_entry(chain, &child->val, list) {
465 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900466 callchain_list__set_folding(chain, unfold);
467 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300468 }
469
470 if (has_children)
471 n += callchain_node__set_folding_rb_tree(child, unfold);
472 }
473
474 return n;
475}
476
477static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
478{
479 struct callchain_list *chain;
480 bool has_children = false;
481 int n = 0;
482
483 list_for_each_entry(chain, &node->val, list) {
484 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900485 callchain_list__set_folding(chain, unfold);
486 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300487 }
488
489 if (has_children)
490 n += callchain_node__set_folding_rb_tree(node, unfold);
491
492 return n;
493}
494
495static int callchain__set_folding(struct rb_root *chain, bool unfold)
496{
497 struct rb_node *nd;
498 int n = 0;
499
500 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
501 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
502 n += callchain_node__set_folding(node, unfold);
503 }
504
505 return n;
506}
507
Namhyung Kim492b1012016-02-25 00:13:44 +0900508static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
509 bool unfold __maybe_unused)
510{
511 float percent;
512 struct rb_node *nd;
513 struct hist_entry *child;
514 int n = 0;
515
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -0800516 for (nd = rb_first_cached(&he->hroot_out); nd; nd = rb_next(nd)) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900517 child = rb_entry(nd, struct hist_entry, rb_node);
518 percent = hist_entry__get_percent_limit(child);
519 if (!child->filtered && percent >= hb->min_pcnt)
520 n++;
521 }
522
523 return n;
524}
525
Jiri Olsab33f9222017-01-20 10:20:29 +0100526static void __hist_entry__set_folding(struct hist_entry *he,
527 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300528{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300529 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900530 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300531
Namhyung Kim3698dab2015-05-05 23:55:46 +0900532 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900533 int n;
534
535 if (he->leaf)
536 n = callchain__set_folding(&he->sorted_chain, unfold);
537 else
538 n = hierarchy_set_folding(hb, he, unfold);
539
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300540 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300541 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300542 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300543}
544
Jiri Olsab33f9222017-01-20 10:20:29 +0100545static void hist_entry__set_folding(struct hist_entry *he,
546 struct hist_browser *browser, bool unfold)
547{
548 double percent;
549
550 percent = hist_entry__get_percent_limit(he);
551 if (he->filtered || percent < browser->min_pcnt)
552 return;
553
554 __hist_entry__set_folding(he, browser, unfold);
555
556 if (!he->depth || unfold)
557 browser->nr_hierarchy_entries++;
558 if (he->leaf)
559 browser->nr_callchain_rows += he->nr_rows;
560 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
561 browser->nr_hierarchy_entries++;
562 he->has_no_entry = true;
563 he->nr_rows = 1;
564 } else
565 he->has_no_entry = false;
566}
567
Namhyung Kimc3b78952014-04-22 15:56:17 +0900568static void
569__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300570{
571 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900572 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300573
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -0800574 nd = rb_first_cached(&browser->hists->entries);
Namhyung Kim492b1012016-02-25 00:13:44 +0900575 while (nd) {
576 he = rb_entry(nd, struct hist_entry, rb_node);
577
578 /* set folding state even if it's currently folded */
579 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
580
581 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300582 }
583}
584
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300585static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300586{
Namhyung Kim492b1012016-02-25 00:13:44 +0900587 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900588 browser->nr_callchain_rows = 0;
589 __hist_browser__set_folding(browser, unfold);
590
591 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300592 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300593 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300594}
595
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100596static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
597{
598 if (!browser->he_selection)
599 return;
600
601 hist_entry__set_folding(browser->he_selection, browser, unfold);
602 browser->b.nr_entries = hist_browser__nr_entries(browser);
603}
604
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200605static void ui_browser__warn_lost_events(struct ui_browser *browser)
606{
607 ui_browser__warning(browser, 4,
608 "Events are being lost, check IO/CPU overload!\n\n"
609 "You may want to run 'perf' using a RT scheduler policy:\n\n"
610 " perf top -r 80\n\n"
611 "Or reduce the sampling frequency.");
612}
613
Jiri Olsa5b91a862016-06-20 23:58:15 +0200614static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
615{
616 return browser->title ? browser->title(browser, bf, size) : 0;
617}
618
Kan Liang06cc1a42018-01-18 13:26:29 -0800619int hist_browser__run(struct hist_browser *browser, const char *help,
620 bool warn_lost_event)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300621{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300622 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300623 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900624 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900625 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300626
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300627 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900628 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300629
Jiri Olsa5b91a862016-06-20 23:58:15 +0200630 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300631
Namhyung Kim090cff32016-01-11 19:53:14 +0900632 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300633 return -1;
634
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300635 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300636 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300637
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300638 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900639 case K_TIMER: {
640 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900641 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900642
Namhyung Kimc6111522016-10-07 14:04:12 +0900643 if (hist_browser__has_filter(browser) ||
644 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900645 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900646
Namhyung Kimc3b78952014-04-22 15:56:17 +0900647 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900648 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200649
Kan Liang06cc1a42018-01-18 13:26:29 -0800650 if (warn_lost_event &&
651 (browser->hists->stats.nr_lost_warned !=
652 browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300653 browser->hists->stats.nr_lost_warned =
654 browser->hists->stats.nr_events[PERF_RECORD_LOST];
655 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200656 }
657
Jiri Olsa5b91a862016-06-20 23:58:15 +0200658 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300659 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300660 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900661 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300662 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300663 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300664 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300665 struct hist_entry, rb_node);
666 ui_helpline__pop();
Arnaldo Carvalho de Melofdae6402018-04-06 11:56:11 -0300667 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 -0300668 seq++, browser->b.nr_entries,
669 browser->hists->nr_entries,
Arnaldo Carvalho de Melofdae6402018-04-06 11:56:11 -0300670 browser->b.extra_title_lines,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300671 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300672 browser->b.index,
673 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300674 h->row_offset, h->nr_rows);
675 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300676 break;
677 case 'C':
678 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300679 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300680 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100681 case 'c':
682 /* Collapse the selected entry. */
683 hist_browser__set_folding_selected(browser, false);
684 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300685 case 'E':
686 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300687 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300688 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100689 case 'e':
690 /* Expand the selected entry. */
691 hist_browser__set_folding_selected(browser, true);
692 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200693 case 'H':
694 browser->show_headers = !browser->show_headers;
695 hist_browser__update_rows(browser);
696 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200697 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300698 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300699 break;
700 /* fall thru */
701 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300702 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300703 }
704 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300705out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300706 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300707 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300708}
709
Namhyung Kim39ee5332014-08-22 09:13:21 +0900710struct callchain_print_arg {
711 /* for hists browser */
712 off_t row_offset;
713 bool is_current_entry;
714
715 /* for file dump */
716 FILE *fp;
717 int printed;
718};
719
720typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
721 struct callchain_list *chain,
722 const char *str, int offset,
723 unsigned short row,
724 struct callchain_print_arg *arg);
725
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900726static void hist_browser__show_callchain_entry(struct hist_browser *browser,
727 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900728 const char *str, int offset,
729 unsigned short row,
730 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900731{
732 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900733 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300734 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900735
736 color = HE_COLORSET_NORMAL;
737 width = browser->b.width - (offset + 2);
738 if (ui_browser__is_current_entry(&browser->b, row)) {
739 browser->selection = &chain->ms;
740 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900741 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900742 }
743
744 ui_browser__set_color(&browser->b, color);
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -0300745 ui_browser__gotorc(&browser->b, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300746 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300747 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300748 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300749 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900750}
751
Namhyung Kim39ee5332014-08-22 09:13:21 +0900752static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
753 struct callchain_list *chain,
754 const char *str, int offset,
755 unsigned short row __maybe_unused,
756 struct callchain_print_arg *arg)
757{
758 char folded_sign = callchain_list__folded(chain);
759
760 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
761 folded_sign, str);
762}
763
764typedef bool (*check_output_full_fn)(struct hist_browser *browser,
765 unsigned short row);
766
767static bool hist_browser__check_output_full(struct hist_browser *browser,
768 unsigned short row)
769{
770 return browser->b.rows == row;
771}
772
773static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
774 unsigned short row __maybe_unused)
775{
776 return false;
777}
778
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300779#define LEVEL_OFFSET_STEP 3
780
Namhyung Kim18bb8382015-11-09 14:45:42 +0900781static int hist_browser__show_callchain_list(struct hist_browser *browser,
782 struct callchain_node *node,
783 struct callchain_list *chain,
784 unsigned short row, u64 total,
785 bool need_percent, int offset,
786 print_callchain_entry_fn print,
787 struct callchain_print_arg *arg)
788{
789 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800790 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900791 const char *str;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200792 int ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900793
794 if (arg->row_offset != 0) {
795 arg->row_offset--;
796 return 0;
797 }
798
799 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800800 alloc_str2 = NULL;
801
Namhyung Kim18bb8382015-11-09 14:45:42 +0900802 str = callchain_list__sym_name(chain, bf, sizeof(bf),
803 browser->show_dso);
804
Jin Yaofef51ec2016-10-31 09:19:53 +0800805 if (symbol_conf.show_branchflag_count) {
Jin Yaoc4ee0622017-08-07 21:05:15 +0800806 callchain_list_counts__printf_value(chain, NULL,
807 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900808
Jin Yaofef51ec2016-10-31 09:19:53 +0800809 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
810 str = "Not enough memory!";
811 else
812 str = alloc_str2;
813 }
814
815 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900816 callchain_node__scnprintf_value(node, buf, sizeof(buf),
817 total);
818
819 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
820 str = "Not enough memory!";
821 else
822 str = alloc_str;
823 }
824
825 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900826 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800827 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800828
Milian Wolff2a704fc2017-10-09 22:32:55 +0200829 return ret;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900830}
831
Namhyung Kim59c624e2016-01-28 00:40:56 +0900832static bool check_percent_display(struct rb_node *node, u64 parent_total)
833{
834 struct callchain_node *child;
835
836 if (node == NULL)
837 return false;
838
839 if (rb_next(node))
840 return true;
841
842 child = rb_entry(node, struct callchain_node, rb_node);
843 return callchain_cumul_hits(child) != parent_total;
844}
845
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900846static int hist_browser__show_callchain_flat(struct hist_browser *browser,
847 struct rb_root *root,
848 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900849 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900850 print_callchain_entry_fn print,
851 struct callchain_print_arg *arg,
852 check_output_full_fn is_output_full)
853{
854 struct rb_node *node;
855 int first_row = row, offset = LEVEL_OFFSET_STEP;
856 bool need_percent;
857
858 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900859 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900860
861 while (node) {
862 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
863 struct rb_node *next = rb_next(node);
864 struct callchain_list *chain;
865 char folded_sign = ' ';
866 int first = true;
867 int extra_offset = 0;
868
869 list_for_each_entry(chain, &child->parent_val, list) {
870 bool was_first = first;
871
872 if (first)
873 first = false;
874 else if (need_percent)
875 extra_offset = LEVEL_OFFSET_STEP;
876
877 folded_sign = callchain_list__folded(chain);
878
879 row += hist_browser__show_callchain_list(browser, child,
880 chain, row, total,
881 was_first && need_percent,
882 offset + extra_offset,
883 print, arg);
884
885 if (is_output_full(browser, row))
886 goto out;
887
888 if (folded_sign == '+')
889 goto next;
890 }
891
892 list_for_each_entry(chain, &child->val, list) {
893 bool was_first = first;
894
895 if (first)
896 first = false;
897 else if (need_percent)
898 extra_offset = LEVEL_OFFSET_STEP;
899
900 folded_sign = callchain_list__folded(chain);
901
902 row += hist_browser__show_callchain_list(browser, child,
903 chain, row, total,
904 was_first && need_percent,
905 offset + extra_offset,
906 print, arg);
907
908 if (is_output_full(browser, row))
909 goto out;
910
911 if (folded_sign == '+')
912 break;
913 }
914
915next:
916 if (is_output_full(browser, row))
917 break;
918 node = next;
919 }
920out:
921 return row - first_row;
922}
923
Namhyung Kim8c430a32015-11-09 14:45:44 +0900924static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
925 struct callchain_list *chain,
926 char *value_str, char *old_str)
927{
928 char bf[1024];
929 const char *str;
930 char *new;
931
932 str = callchain_list__sym_name(chain, bf, sizeof(bf),
933 browser->show_dso);
934 if (old_str) {
935 if (asprintf(&new, "%s%s%s", old_str,
936 symbol_conf.field_sep ?: ";", str) < 0)
937 new = NULL;
938 } else {
939 if (value_str) {
940 if (asprintf(&new, "%s %s", value_str, str) < 0)
941 new = NULL;
942 } else {
943 if (asprintf(&new, "%s", str) < 0)
944 new = NULL;
945 }
946 }
947 return new;
948}
949
950static int hist_browser__show_callchain_folded(struct hist_browser *browser,
951 struct rb_root *root,
952 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900953 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900954 print_callchain_entry_fn print,
955 struct callchain_print_arg *arg,
956 check_output_full_fn is_output_full)
957{
958 struct rb_node *node;
959 int first_row = row, offset = LEVEL_OFFSET_STEP;
960 bool need_percent;
961
962 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900963 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900964
965 while (node) {
966 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
967 struct rb_node *next = rb_next(node);
968 struct callchain_list *chain, *first_chain = NULL;
969 int first = true;
970 char *value_str = NULL, *value_str_alloc = NULL;
971 char *chain_str = NULL, *chain_str_alloc = NULL;
972
973 if (arg->row_offset != 0) {
974 arg->row_offset--;
975 goto next;
976 }
977
978 if (need_percent) {
979 char buf[64];
980
981 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
982 if (asprintf(&value_str, "%s", buf) < 0) {
983 value_str = (char *)"<...>";
984 goto do_print;
985 }
986 value_str_alloc = value_str;
987 }
988
989 list_for_each_entry(chain, &child->parent_val, list) {
990 chain_str = hist_browser__folded_callchain_str(browser,
991 chain, value_str, chain_str);
992 if (first) {
993 first = false;
994 first_chain = chain;
995 }
996
997 if (chain_str == NULL) {
998 chain_str = (char *)"Not enough memory!";
999 goto do_print;
1000 }
1001
1002 chain_str_alloc = chain_str;
1003 }
1004
1005 list_for_each_entry(chain, &child->val, list) {
1006 chain_str = hist_browser__folded_callchain_str(browser,
1007 chain, value_str, chain_str);
1008 if (first) {
1009 first = false;
1010 first_chain = chain;
1011 }
1012
1013 if (chain_str == NULL) {
1014 chain_str = (char *)"Not enough memory!";
1015 goto do_print;
1016 }
1017
1018 chain_str_alloc = chain_str;
1019 }
1020
1021do_print:
1022 print(browser, first_chain, chain_str, offset, row++, arg);
1023 free(value_str_alloc);
1024 free(chain_str_alloc);
1025
1026next:
1027 if (is_output_full(browser, row))
1028 break;
1029 node = next;
1030 }
1031
1032 return row - first_row;
1033}
1034
Namhyung Kim0c841c62016-01-28 00:40:54 +09001035static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001036 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001037 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001038 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001039 print_callchain_entry_fn print,
1040 struct callchain_print_arg *arg,
1041 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001042{
1043 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001044 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001045 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001046 u64 percent_total = total;
1047
1048 if (callchain_param.mode == CHAIN_GRAPH_REL)
1049 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001050
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001051 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001052 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001053
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001054 while (node) {
1055 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1056 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001057 struct callchain_list *chain;
1058 char folded_sign = ' ';
1059 int first = true;
1060 int extra_offset = 0;
1061
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001062 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001063 bool was_first = first;
1064
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001065 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001066 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001067 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001068 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001069
1070 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001071
Namhyung Kim18bb8382015-11-09 14:45:42 +09001072 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001073 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001074 was_first && need_percent,
1075 offset + extra_offset,
1076 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001077
Namhyung Kim18bb8382015-11-09 14:45:42 +09001078 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001079 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001080
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001081 if (folded_sign == '+')
1082 break;
1083 }
1084
1085 if (folded_sign == '-') {
1086 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001087
Namhyung Kim0c841c62016-01-28 00:40:54 +09001088 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001089 new_level, row, total,
1090 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001091 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001092 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001093 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001094 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001095 node = next;
1096 }
1097out:
1098 return row - first_row;
1099}
1100
Namhyung Kim0c841c62016-01-28 00:40:54 +09001101static int hist_browser__show_callchain(struct hist_browser *browser,
1102 struct hist_entry *entry, int level,
1103 unsigned short row,
1104 print_callchain_entry_fn print,
1105 struct callchain_print_arg *arg,
1106 check_output_full_fn is_output_full)
1107{
1108 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001109 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001110 int printed;
1111
Namhyung Kim5eca1042016-01-28 00:40:55 +09001112 if (symbol_conf.cumulate_callchain)
1113 parent_total = entry->stat_acc->period;
1114 else
1115 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001116
1117 if (callchain_param.mode == CHAIN_FLAT) {
1118 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001119 &entry->sorted_chain, row,
1120 total, parent_total, print, arg,
1121 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001122 } else if (callchain_param.mode == CHAIN_FOLDED) {
1123 printed = hist_browser__show_callchain_folded(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 {
1128 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001129 &entry->sorted_chain, level, row,
1130 total, parent_total, print, arg,
1131 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001132 }
1133
1134 if (arg->is_current_entry)
1135 browser->he_selection = entry;
1136
1137 return printed;
1138}
1139
Namhyung Kim89701462013-01-22 18:09:38 +09001140struct hpp_arg {
1141 struct ui_browser *b;
1142 char folded_sign;
1143 bool current_entry;
1144};
1145
Jiri Olsa98ba1602016-09-22 17:36:35 +02001146int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001147{
1148 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001149 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001150 va_list args;
1151 double percent;
1152
1153 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001154 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001155 percent = va_arg(args, double);
1156 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001157
Namhyung Kim89701462013-01-22 18:09:38 +09001158 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001159
Namhyung Kimd6751072014-07-31 14:47:36 +09001160 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001161 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001162
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001163 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001164}
1165
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001166#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001167static u64 __hpp_get_##_field(struct hist_entry *he) \
1168{ \
1169 return he->stat._field; \
1170} \
1171 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001172static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001173hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001174 struct perf_hpp *hpp, \
1175 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001176{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001177 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1178 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001179}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001180
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001181#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1182static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1183{ \
1184 return he->stat_acc->_field; \
1185} \
1186 \
1187static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001188hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001189 struct perf_hpp *hpp, \
1190 struct hist_entry *he) \
1191{ \
1192 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001193 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001194 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001195 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001196 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001197 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001198 \
1199 return ret; \
1200 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001201 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1202 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001203}
1204
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001205__HPP_COLOR_PERCENT_FN(overhead, period)
1206__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1207__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1208__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1209__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001210__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001211
1212#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001213#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001214
1215void hist_browser__init_hpp(void)
1216{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001217 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1218 hist_browser__hpp_color_overhead;
1219 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1220 hist_browser__hpp_color_overhead_sys;
1221 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1222 hist_browser__hpp_color_overhead_us;
1223 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1224 hist_browser__hpp_color_overhead_guest_sys;
1225 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1226 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001227 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1228 hist_browser__hpp_color_overhead_acc;
Andi Kleen4968ac82019-03-11 07:44:58 -07001229
1230 res_sample_init();
Namhyung Kimf5951d52012-09-03 11:53:09 +09001231}
1232
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001233static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001234 struct hist_entry *entry,
1235 unsigned short row)
1236{
Jiri Olsa12400052012-10-13 00:06:16 +02001237 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001238 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001239 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001240 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001241 bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001242 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001243 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001244 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001245
1246 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001247 browser->he_selection = entry;
1248 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001249 }
1250
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001251 if (use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001252 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001253 folded_sign = hist_entry__folded(entry);
1254 }
1255
1256 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001257 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001258 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001259 .folded_sign = folded_sign,
1260 .current_entry = current_entry,
1261 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001262 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001263
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03001264 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001265
Jiri Olsaf0786af2016-01-18 10:24:23 +01001266 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001267 char s[2048];
1268 struct perf_hpp hpp = {
1269 .buf = s,
1270 .size = sizeof(s),
1271 .ptr = &arg,
1272 };
1273
Namhyung Kim361459f2015-12-23 02:07:08 +09001274 if (perf_hpp__should_skip(fmt, entry->hists) ||
1275 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001276 continue;
1277
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001278 if (current_entry && browser->b.navkeypressed) {
1279 ui_browser__set_color(&browser->b,
1280 HE_COLORSET_SELECTED);
1281 } else {
1282 ui_browser__set_color(&browser->b,
1283 HE_COLORSET_NORMAL);
1284 }
1285
1286 if (first) {
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001287 if (use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001288 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001289 width -= 2;
1290 }
1291 first = false;
1292 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001293 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001294 width -= 2;
1295 }
1296
Jiri Olsa12400052012-10-13 00:06:16 +02001297 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001298 int ret = fmt->color(fmt, &hpp, entry);
1299 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1300 /*
1301 * fmt->color() already used ui_browser to
1302 * print the non alignment bits, skip it (+ret):
1303 */
1304 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001305 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001306 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001307 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001308 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001309 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001310 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001311
1312 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001313 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001314 width += 1;
1315
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001316 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001317
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001318 ++row;
1319 ++printed;
1320 } else
1321 --row_offset;
1322
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001323 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001324 struct callchain_print_arg arg = {
1325 .row_offset = row_offset,
1326 .is_current_entry = current_entry,
1327 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001328
Milian Wolff2a704fc2017-10-09 22:32:55 +02001329 printed += hist_browser__show_callchain(browser,
1330 entry, 1, row,
1331 hist_browser__show_callchain_entry,
1332 &arg,
1333 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001334 }
1335
1336 return printed;
1337}
1338
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001339static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1340 struct hist_entry *entry,
1341 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001342 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001343{
1344 int printed = 0;
1345 int width = browser->b.width;
1346 char folded_sign = ' ';
1347 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1348 off_t row_offset = entry->row_offset;
1349 bool first = true;
1350 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001351 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001352 struct hpp_arg arg = {
1353 .b = &browser->b,
1354 .current_entry = current_entry,
1355 };
1356 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001357 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001358
1359 if (current_entry) {
1360 browser->he_selection = entry;
1361 browser->selection = &entry->ms;
1362 }
1363
1364 hist_entry__init_have_children(entry);
1365 folded_sign = hist_entry__folded(entry);
1366 arg.folded_sign = folded_sign;
1367
1368 if (entry->leaf && row_offset) {
1369 row_offset--;
1370 goto show_callchain;
1371 }
1372
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03001373 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001374
1375 if (current_entry && browser->b.navkeypressed)
1376 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1377 else
1378 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1379
1380 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1381 width -= level * HIERARCHY_INDENT;
1382
Namhyung Kima61a22f2016-03-07 16:44:50 -03001383 /* the first hpp_list_node is for overhead columns */
1384 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1385 struct perf_hpp_list_node, list);
1386 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001387 char s[2048];
1388 struct perf_hpp hpp = {
1389 .buf = s,
1390 .size = sizeof(s),
1391 .ptr = &arg,
1392 };
1393
1394 if (perf_hpp__should_skip(fmt, entry->hists) ||
1395 column++ < browser->b.horiz_scroll)
1396 continue;
1397
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001398 if (current_entry && browser->b.navkeypressed) {
1399 ui_browser__set_color(&browser->b,
1400 HE_COLORSET_SELECTED);
1401 } else {
1402 ui_browser__set_color(&browser->b,
1403 HE_COLORSET_NORMAL);
1404 }
1405
1406 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001407 ui_browser__printf(&browser->b, "%c ", folded_sign);
1408 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001409 first = false;
1410 } else {
1411 ui_browser__printf(&browser->b, " ");
1412 width -= 2;
1413 }
1414
1415 if (fmt->color) {
1416 int ret = fmt->color(fmt, &hpp, entry);
1417 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1418 /*
1419 * fmt->color() already used ui_browser to
1420 * print the non alignment bits, skip it (+ret):
1421 */
1422 ui_browser__printf(&browser->b, "%s", s + ret);
1423 } else {
1424 int ret = fmt->entry(fmt, &hpp, entry);
1425 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1426 ui_browser__printf(&browser->b, "%s", s);
1427 }
1428 width -= hpp.buf - s;
1429 }
1430
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001431 if (!first) {
1432 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1433 width -= hierarchy_indent;
1434 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001435
1436 if (column >= browser->b.horiz_scroll) {
1437 char s[2048];
1438 struct perf_hpp hpp = {
1439 .buf = s,
1440 .size = sizeof(s),
1441 .ptr = &arg,
1442 };
1443
1444 if (current_entry && browser->b.navkeypressed) {
1445 ui_browser__set_color(&browser->b,
1446 HE_COLORSET_SELECTED);
1447 } else {
1448 ui_browser__set_color(&browser->b,
1449 HE_COLORSET_NORMAL);
1450 }
1451
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001452 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001453 if (first) {
1454 ui_browser__printf(&browser->b, "%c ", folded_sign);
1455 first = false;
1456 } else {
1457 ui_browser__write_nstring(&browser->b, "", 2);
1458 }
1459
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001460 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001461
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001462 /*
1463 * No need to call hist_entry__snprintf_alignment()
1464 * since this fmt is always the last column in the
1465 * hierarchy mode.
1466 */
1467 if (fmt->color) {
1468 width -= fmt->color(fmt, &hpp, entry);
1469 } else {
1470 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001471
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001472 width -= fmt->entry(fmt, &hpp, entry);
1473 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001474
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001475 while (isspace(s[i++]))
1476 width++;
1477 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001478 }
1479 }
1480
1481 /* The scroll bar isn't being used */
1482 if (!browser->b.navkeypressed)
1483 width += 1;
1484
1485 ui_browser__write_nstring(&browser->b, "", width);
1486
1487 ++row;
1488 ++printed;
1489
1490show_callchain:
1491 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1492 struct callchain_print_arg carg = {
1493 .row_offset = row_offset,
1494 };
1495
1496 printed += hist_browser__show_callchain(browser, entry,
1497 level + 1, row,
1498 hist_browser__show_callchain_entry, &carg,
1499 hist_browser__check_output_full);
1500 }
1501
1502 return printed;
1503}
1504
Namhyung Kim79dded82016-02-26 21:13:19 +09001505static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001506 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001507{
1508 int width = browser->b.width;
1509 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1510 bool first = true;
1511 int column = 0;
1512 int ret;
1513 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001514 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001515 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001516
1517 if (current_entry) {
1518 browser->he_selection = NULL;
1519 browser->selection = NULL;
1520 }
1521
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03001522 ui_browser__gotorc(&browser->b, row, 0);
Namhyung Kim79dded82016-02-26 21:13:19 +09001523
1524 if (current_entry && browser->b.navkeypressed)
1525 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1526 else
1527 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1528
1529 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1530 width -= level * HIERARCHY_INDENT;
1531
Namhyung Kima61a22f2016-03-07 16:44:50 -03001532 /* the first hpp_list_node is for overhead columns */
1533 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1534 struct perf_hpp_list_node, list);
1535 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001536 if (perf_hpp__should_skip(fmt, browser->hists) ||
1537 column++ < browser->b.horiz_scroll)
1538 continue;
1539
Jiri Olsada1b0402016-06-14 20:19:20 +02001540 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001541
1542 if (first) {
1543 /* for folded sign */
1544 first = false;
1545 ret++;
1546 } else {
1547 /* space between columns */
1548 ret += 2;
1549 }
1550
1551 ui_browser__write_nstring(&browser->b, "", ret);
1552 width -= ret;
1553 }
1554
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001555 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1556 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001557
1558 if (column >= browser->b.horiz_scroll) {
1559 char buf[32];
1560
1561 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1562 ui_browser__printf(&browser->b, " %s", buf);
1563 width -= ret + 2;
1564 }
1565
1566 /* The scroll bar isn't being used */
1567 if (!browser->b.navkeypressed)
1568 width += 1;
1569
1570 ui_browser__write_nstring(&browser->b, "", width);
1571 return 1;
1572}
1573
Jiri Olsa81a888f2014-06-14 15:44:52 +02001574static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1575{
1576 advance_hpp(hpp, inc);
1577 return hpp->size <= 0;
1578}
1579
Jiri Olsa69705b32016-08-07 17:28:28 +02001580static int
1581hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1582 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001583{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001584 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001585 struct perf_hpp dummy_hpp = {
1586 .buf = buf,
1587 .size = size,
1588 };
1589 struct perf_hpp_fmt *fmt;
1590 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001591 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001592 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001593
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001594 if (hists__has_callchains(hists) && symbol_conf.use_callchain) {
Jiri Olsa81a888f2014-06-14 15:44:52 +02001595 ret = scnprintf(buf, size, " ");
1596 if (advance_hpp_check(&dummy_hpp, ret))
1597 return ret;
1598 }
1599
Jiri Olsaf0786af2016-01-18 10:24:23 +01001600 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001601 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001602 continue;
1603
Jiri Olsa29659ab2016-08-07 17:28:30 +02001604 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001605 if (advance_hpp_check(&dummy_hpp, ret))
1606 break;
1607
Jiri Olsa29659ab2016-08-07 17:28:30 +02001608 if (span)
1609 continue;
1610
Jiri Olsa81a888f2014-06-14 15:44:52 +02001611 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1612 if (advance_hpp_check(&dummy_hpp, ret))
1613 break;
1614 }
1615
1616 return ret;
1617}
1618
Namhyung Kimd8b92402016-02-25 00:13:46 +09001619static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1620{
1621 struct hists *hists = browser->hists;
1622 struct perf_hpp dummy_hpp = {
1623 .buf = buf,
1624 .size = size,
1625 };
1626 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001627 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001628 size_t ret = 0;
1629 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001630 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001631 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001632
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001633 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001634 if (advance_hpp_check(&dummy_hpp, ret))
1635 return ret;
1636
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001637 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001638 /* the first hpp_list_node is for overhead columns */
1639 fmt_node = list_first_entry(&hists->hpp_formats,
1640 struct perf_hpp_list_node, list);
1641 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001642 if (column++ < browser->b.horiz_scroll)
1643 continue;
1644
Jiri Olsa29659ab2016-08-07 17:28:30 +02001645 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001646 if (advance_hpp_check(&dummy_hpp, ret))
1647 break;
1648
1649 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1650 if (advance_hpp_check(&dummy_hpp, ret))
1651 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001652
1653 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001654 }
1655
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001656 if (!first_node) {
1657 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1658 indent * HIERARCHY_INDENT, "");
1659 if (advance_hpp_check(&dummy_hpp, ret))
1660 return ret;
1661 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001662
Namhyung Kima61a22f2016-03-07 16:44:50 -03001663 first_node = true;
1664 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1665 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001666 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1667 if (advance_hpp_check(&dummy_hpp, ret))
1668 break;
1669 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001670 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001671
Namhyung Kima61a22f2016-03-07 16:44:50 -03001672 first_col = true;
1673 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1674 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001675
Namhyung Kima61a22f2016-03-07 16:44:50 -03001676 if (perf_hpp__should_skip(fmt, hists))
1677 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001678
Namhyung Kima61a22f2016-03-07 16:44:50 -03001679 if (!first_col) {
1680 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1681 if (advance_hpp_check(&dummy_hpp, ret))
1682 break;
1683 }
1684 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001685
Jiri Olsa29659ab2016-08-07 17:28:30 +02001686 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001687 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001688
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001689 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001690 ret = strlen(start);
1691
1692 if (start != dummy_hpp.buf)
1693 memmove(dummy_hpp.buf, start, ret + 1);
1694
1695 if (advance_hpp_check(&dummy_hpp, ret))
1696 break;
1697 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001698 }
1699
1700 return ret;
1701}
1702
Jiri Olsa01b47702016-06-14 20:19:13 +02001703static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001704{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001705 char headers[1024];
1706
Jiri Olsa01b47702016-06-14 20:19:13 +02001707 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1708 sizeof(headers));
1709
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001710 ui_browser__gotorc(&browser->b, 0, 0);
1711 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001712 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001713}
1714
Jiri Olsa01b47702016-06-14 20:19:13 +02001715static void hists_browser__headers(struct hist_browser *browser)
1716{
Jiri Olsa69705b32016-08-07 17:28:28 +02001717 struct hists *hists = browser->hists;
1718 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001719
Jiri Olsa69705b32016-08-07 17:28:28 +02001720 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001721
Jiri Olsa69705b32016-08-07 17:28:28 +02001722 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1723 char headers[1024];
1724
1725 hists_browser__scnprintf_headers(browser, headers,
1726 sizeof(headers), line);
1727
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03001728 ui_browser__gotorc_title(&browser->b, line, 0);
Jiri Olsa69705b32016-08-07 17:28:28 +02001729 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1730 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1731 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001732}
1733
1734static void hist_browser__show_headers(struct hist_browser *browser)
1735{
1736 if (symbol_conf.report_hierarchy)
1737 hists_browser__hierarchy_headers(browser);
1738 else
1739 hists_browser__headers(browser);
1740}
1741
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001742static void ui_browser__hists_init_top(struct ui_browser *browser)
1743{
1744 if (browser->top == NULL) {
1745 struct hist_browser *hb;
1746
1747 hb = container_of(browser, struct hist_browser, b);
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08001748 browser->top = rb_first_cached(&hb->hists->entries);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001749 }
1750}
1751
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001752static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001753{
1754 unsigned row = 0;
1755 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001756 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757
Arnaldo Carvalho de Melo94e87a82018-04-06 12:11:11 -03001758 if (hb->show_headers)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001759 hist_browser__show_headers(hb);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001760
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001761 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001762 hb->he_selection = NULL;
1763 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001764
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001765 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001766 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001767 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001768
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001769 if (h->filtered) {
1770 /* let it move to sibling */
1771 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001772 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001773 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001774
Namhyung Kim14135662013-10-31 10:17:39 +09001775 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001776 if (percent < hb->min_pcnt)
1777 continue;
1778
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001779 if (symbol_conf.report_hierarchy) {
1780 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001781 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001782 if (row == browser->rows)
1783 break;
1784
1785 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001786 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001787 row++;
1788 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001789 } else {
1790 row += hist_browser__show_entry(hb, h, row);
1791 }
1792
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001793 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001794 break;
1795 }
1796
Arnaldo Carvalho de Melo94e87a82018-04-06 12:11:11 -03001797 return row;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001798}
1799
Namhyung Kim064f1982013-05-14 11:09:04 +09001800static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001801 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001802{
1803 while (nd != NULL) {
1804 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001805 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001806
Namhyung Kimc0f15272014-04-16 11:16:33 +09001807 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001808 return nd;
1809
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001810 /*
1811 * If it's filtered, its all children also were filtered.
1812 * So move to sibling node.
1813 */
1814 if (rb_next(nd))
1815 nd = rb_next(nd);
1816 else
1817 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001818 }
1819
1820 return NULL;
1821}
1822
Namhyung Kim064f1982013-05-14 11:09:04 +09001823static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001824 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001825{
1826 while (nd != NULL) {
1827 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001828 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001829
1830 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001831 return nd;
1832
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001833 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001834 }
1835
1836 return NULL;
1837}
1838
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001839static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001840 off_t offset, int whence)
1841{
1842 struct hist_entry *h;
1843 struct rb_node *nd;
1844 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001845 struct hist_browser *hb;
1846
1847 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001848
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001849 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001850 return;
1851
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001852 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001853
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001854 switch (whence) {
1855 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001856 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001857 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001858 break;
1859 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001860 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001861 goto do_offset;
1862 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001863 nd = rb_hierarchy_last(rb_last(browser->entries));
1864 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001865 first = false;
1866 break;
1867 default:
1868 return;
1869 }
1870
1871 /*
1872 * Moves not relative to the first visible entry invalidates its
1873 * row_offset:
1874 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001875 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001876 h->row_offset = 0;
1877
1878 /*
1879 * Here we have to check if nd is expanded (+), if it is we can't go
1880 * the next top level hist_entry, instead we must compute an offset of
1881 * what _not_ to show and not change the first visible entry.
1882 *
1883 * This offset increments when we are going from top to bottom and
1884 * decreases when we're going from bottom to top.
1885 *
1886 * As we don't have backpointers to the top level in the callchains
1887 * structure, we need to always print the whole hist_entry callchain,
1888 * skipping the first ones that are before the first visible entry
1889 * and stop when we printed enough lines to fill the screen.
1890 */
1891do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001892 if (!nd)
1893 return;
1894
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001895 if (offset > 0) {
1896 do {
1897 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001898 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001899 u16 remaining = h->nr_rows - h->row_offset;
1900 if (offset > remaining) {
1901 offset -= remaining;
1902 h->row_offset = 0;
1903 } else {
1904 h->row_offset += offset;
1905 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001906 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001907 break;
1908 }
1909 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001910 nd = hists__filter_entries(rb_hierarchy_next(nd),
1911 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001912 if (nd == NULL)
1913 break;
1914 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001915 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001916 } while (offset != 0);
1917 } else if (offset < 0) {
1918 while (1) {
1919 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001920 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001921 if (first) {
1922 if (-offset > h->row_offset) {
1923 offset += h->row_offset;
1924 h->row_offset = 0;
1925 } else {
1926 h->row_offset += offset;
1927 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001928 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001929 break;
1930 }
1931 } else {
1932 if (-offset > h->nr_rows) {
1933 offset += h->nr_rows;
1934 h->row_offset = 0;
1935 } else {
1936 h->row_offset = h->nr_rows + offset;
1937 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001938 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001939 break;
1940 }
1941 }
1942 }
1943
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001944 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001945 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001946 if (nd == NULL)
1947 break;
1948 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001949 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001950 if (offset == 0) {
1951 /*
1952 * Last unfiltered hist_entry, check if it is
1953 * unfolded, if it is then we should have
1954 * row_offset at its last entry.
1955 */
1956 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001957 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001958 h->row_offset = h->nr_rows;
1959 break;
1960 }
1961 first = false;
1962 }
1963 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001964 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001965 h = rb_entry(nd, struct hist_entry, rb_node);
1966 h->row_offset = 0;
1967 }
1968}
1969
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001970static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001971 struct hist_entry *he, FILE *fp,
1972 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001973{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001974 struct callchain_print_arg arg = {
1975 .fp = fp,
1976 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001977
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001978 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001979 hist_browser__fprintf_callchain_entry, &arg,
1980 hist_browser__check_dump_full);
1981 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001982}
1983
1984static int hist_browser__fprintf_entry(struct hist_browser *browser,
1985 struct hist_entry *he, FILE *fp)
1986{
1987 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001988 int printed = 0;
1989 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001990 struct perf_hpp hpp = {
1991 .buf = s,
1992 .size = sizeof(s),
1993 };
1994 struct perf_hpp_fmt *fmt;
1995 bool first = true;
1996 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001997
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03001998 if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001999 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002000 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002001 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002002
Jiri Olsaf0786af2016-01-18 10:24:23 +01002003 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002004 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002005 continue;
2006
Namhyung Kim26d8b332014-03-03 16:16:20 +09002007 if (!first) {
2008 ret = scnprintf(hpp.buf, hpp.size, " ");
2009 advance_hpp(&hpp, ret);
2010 } else
2011 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002012
Namhyung Kim26d8b332014-03-03 16:16:20 +09002013 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002014 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002015 advance_hpp(&hpp, ret);
2016 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002017 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002018
2019 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002020 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2021
2022 return printed;
2023}
2024
2025
2026static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2027 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002028 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002029{
2030 char s[8192];
2031 int printed = 0;
2032 char folded_sign = ' ';
2033 struct perf_hpp hpp = {
2034 .buf = s,
2035 .size = sizeof(s),
2036 };
2037 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002038 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002039 bool first = true;
2040 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002041 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002042
2043 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2044
2045 folded_sign = hist_entry__folded(he);
2046 printed += fprintf(fp, "%c", folded_sign);
2047
Namhyung Kim325a6282016-03-09 22:47:00 +09002048 /* the first hpp_list_node is for overhead columns */
2049 fmt_node = list_first_entry(&he->hists->hpp_formats,
2050 struct perf_hpp_list_node, list);
2051 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002052 if (!first) {
2053 ret = scnprintf(hpp.buf, hpp.size, " ");
2054 advance_hpp(&hpp, ret);
2055 } else
2056 first = false;
2057
2058 ret = fmt->entry(fmt, &hpp, he);
2059 advance_hpp(&hpp, ret);
2060 }
2061
2062 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2063 advance_hpp(&hpp, ret);
2064
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002065 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2066 ret = scnprintf(hpp.buf, hpp.size, " ");
2067 advance_hpp(&hpp, ret);
2068
2069 ret = fmt->entry(fmt, &hpp, he);
2070 advance_hpp(&hpp, ret);
2071 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002072
2073 printed += fprintf(fp, "%s\n", rtrim(s));
2074
2075 if (he->leaf && folded_sign == '-') {
2076 printed += hist_browser__fprintf_callchain(browser, he, fp,
2077 he->depth + 1);
2078 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002079
2080 return printed;
2081}
2082
2083static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2084{
Namhyung Kim064f1982013-05-14 11:09:04 +09002085 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002086 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002087 int printed = 0;
2088
2089 while (nd) {
2090 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2091
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002092 if (symbol_conf.report_hierarchy) {
2093 printed += hist_browser__fprintf_hierarchy_entry(browser,
2094 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002095 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002096 } else {
2097 printed += hist_browser__fprintf_entry(browser, h, fp);
2098 }
2099
2100 nd = hists__filter_entries(rb_hierarchy_next(nd),
2101 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002102 }
2103
2104 return printed;
2105}
2106
2107static int hist_browser__dump(struct hist_browser *browser)
2108{
2109 char filename[64];
2110 FILE *fp;
2111
2112 while (1) {
2113 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2114 if (access(filename, F_OK))
2115 break;
2116 /*
2117 * XXX: Just an arbitrary lazy upper limit
2118 */
2119 if (++browser->print_seq == 8192) {
2120 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2121 return -1;
2122 }
2123 }
2124
2125 fp = fopen(filename, "w");
2126 if (fp == NULL) {
2127 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002128 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002129 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002130 return -1;
2131 }
2132
2133 ++browser->print_seq;
2134 hist_browser__fprintf(browser, fp);
2135 fclose(fp);
2136 ui_helpline__fpush("%s written!", filename);
2137
2138 return 0;
2139}
2140
Jiri Olsafcd86422016-06-20 23:58:18 +02002141void hist_browser__init(struct hist_browser *browser,
2142 struct hists *hists)
2143{
2144 struct perf_hpp_fmt *fmt;
2145
2146 browser->hists = hists;
2147 browser->b.refresh = hist_browser__refresh;
2148 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2149 browser->b.seek = ui_browser__hists_seek;
2150 browser->b.use_navkeypressed = true;
2151 browser->show_headers = symbol_conf.show_hist_headers;
Arnaldo Carvalho de Meloef9ff602018-04-02 15:48:18 -03002152 hist_browser__set_title_space(browser);
Jiri Olsafcd86422016-06-20 23:58:18 +02002153
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002154 if (symbol_conf.report_hierarchy) {
2155 struct perf_hpp_list_node *fmt_node;
2156
2157 /* count overhead columns (in the first node) */
2158 fmt_node = list_first_entry(&hists->hpp_formats,
2159 struct perf_hpp_list_node, list);
2160 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2161 ++browser->b.columns;
2162
2163 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002164 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002165 } else {
2166 hists__for_each_format(hists, fmt)
2167 ++browser->b.columns;
2168 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002169
2170 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002171}
2172
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002173struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002174{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002175 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002176
Jiri Olsafcd86422016-06-20 23:58:18 +02002177 if (browser)
2178 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002179
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002180 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002181}
2182
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002183static struct hist_browser *
2184perf_evsel_browser__new(struct perf_evsel *evsel,
2185 struct hist_browser_timer *hbt,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002186 struct perf_env *env,
2187 struct annotation_options *annotation_opts)
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002188{
2189 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2190
2191 if (browser) {
2192 browser->hbt = hbt;
2193 browser->env = env;
Arnaldo Carvalho de Melof016d242018-04-02 14:00:04 -03002194 browser->title = hists_browser__scnprintf_title;
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002195 browser->annotation_opts = annotation_opts;
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002196 }
2197 return browser;
2198}
2199
Jiri Olsadabd2012016-06-20 23:58:14 +02002200void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002201{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002202 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002203}
2204
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002205static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002206{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002207 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002208}
2209
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002210static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002211{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002212 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002213}
2214
Taeung Song1e378eb2014-10-07 16:13:15 +09002215/* Check whether the browser is for 'top' or 'report' */
2216static inline bool is_report_browser(void *timer)
2217{
2218 return timer == NULL;
2219}
2220
Arnaldo Carvalho de Melo967a4642018-04-02 14:20:20 -03002221static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size)
2222{
2223 struct hist_browser_timer *hbt = browser->hbt;
2224 int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt));
2225
Taeung Song1e378eb2014-10-07 16:13:15 +09002226 if (!is_report_browser(hbt)) {
2227 struct perf_top *top = hbt->arg;
2228
Jiri Olsad24e3c92018-11-06 15:45:14 +01002229 printed += scnprintf(bf + printed, size - printed,
2230 " lost: %" PRIu64 "/%" PRIu64,
2231 top->lost, top->lost_total);
2232
Jiri Olsa97f7e0b2018-11-11 20:02:46 +01002233 printed += scnprintf(bf + printed, size - printed,
2234 " drop: %" PRIu64 "/%" PRIu64,
2235 top->drop, top->drop_total);
2236
Taeung Song1e378eb2014-10-07 16:13:15 +09002237 if (top->zero)
2238 printed += scnprintf(bf + printed, size - printed, " [z]");
Jiri Olsa8aa5c8e2018-11-13 11:15:34 +01002239
2240 perf_top__reset_sample_counters(top);
Taeung Song1e378eb2014-10-07 16:13:15 +09002241 }
2242
Jiri Olsa8aa5c8e2018-11-13 11:15:34 +01002243
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002244 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002245}
2246
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002247static inline void free_popup_options(char **options, int n)
2248{
2249 int i;
2250
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002251 for (i = 0; i < n; ++i)
2252 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002253}
2254
Feng Tang341487ab2013-02-03 14:38:20 +08002255/*
2256 * Only runtime switching of perf data file will make "input_name" point
2257 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2258 * whether we need to call free() for current "input_name" during the switch.
2259 */
2260static bool is_input_name_malloced = false;
2261
2262static int switch_data_file(void)
2263{
2264 char *pwd, *options[32], *abs_path[32], *tmp;
2265 DIR *pwd_dir;
2266 int nr_options = 0, choice = -1, ret = -1;
2267 struct dirent *dent;
2268
2269 pwd = getenv("PWD");
2270 if (!pwd)
2271 return ret;
2272
2273 pwd_dir = opendir(pwd);
2274 if (!pwd_dir)
2275 return ret;
2276
2277 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002278 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002279
2280 while ((dent = readdir(pwd_dir))) {
2281 char path[PATH_MAX];
2282 u64 magic;
2283 char *name = dent->d_name;
2284 FILE *file;
2285
2286 if (!(dent->d_type == DT_REG))
2287 continue;
2288
2289 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2290
2291 file = fopen(path, "r");
2292 if (!file)
2293 continue;
2294
2295 if (fread(&magic, 1, 8, file) < 8)
2296 goto close_file_and_continue;
2297
2298 if (is_perf_magic(magic)) {
2299 options[nr_options] = strdup(name);
2300 if (!options[nr_options])
2301 goto close_file_and_continue;
2302
2303 abs_path[nr_options] = strdup(path);
2304 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002305 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002306 ui__warning("Can't search all data files due to memory shortage.\n");
2307 fclose(file);
2308 break;
2309 }
2310
2311 nr_options++;
2312 }
2313
2314close_file_and_continue:
2315 fclose(file);
2316 if (nr_options >= 32) {
2317 ui__warning("Too many perf data files in PWD!\n"
2318 "Only the first 32 files will be listed.\n");
2319 break;
2320 }
2321 }
2322 closedir(pwd_dir);
2323
2324 if (nr_options) {
2325 choice = ui__popup_menu(nr_options, options);
2326 if (choice < nr_options && choice >= 0) {
2327 tmp = strdup(abs_path[choice]);
2328 if (tmp) {
2329 if (is_input_name_malloced)
2330 free((void *)input_name);
2331 input_name = tmp;
2332 is_input_name_malloced = true;
2333 ret = 0;
2334 } else
2335 ui__warning("Data switch failed due to memory shortage!\n");
2336 }
2337 }
2338
2339 free_popup_options(options, nr_options);
2340 free_popup_options(abs_path, nr_options);
2341 return ret;
2342}
2343
Namhyung Kimea7cd592015-04-22 16:18:19 +09002344struct popup_action {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002345 unsigned long time;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002346 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002347 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002348 int socket;
Andi Kleen6f3da202019-03-11 07:44:57 -07002349 struct perf_evsel *evsel;
Andi Kleen4968ac82019-03-11 07:44:58 -07002350 enum rstype rstype;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002351
2352 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2353};
2354
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002355static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002356do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002357{
2358 struct perf_evsel *evsel;
2359 struct annotation *notes;
2360 struct hist_entry *he;
2361 int err;
2362
Arnaldo Carvalho de Melof178fd22018-05-28 14:24:45 -03002363 if (!browser->annotation_opts->objdump_path &&
2364 perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002365 return 0;
2366
Namhyung Kimea7cd592015-04-22 16:18:19 +09002367 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002368 if (!notes->src)
2369 return 0;
2370
2371 evsel = hists_to_evsel(browser->hists);
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002372 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt,
2373 browser->annotation_opts);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002374 he = hist_browser__selected_entry(browser);
2375 /*
2376 * offer option to annotate the other branch source or target
2377 * (if they exists) when returning from annotate
2378 */
2379 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2380 return 1;
2381
2382 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2383 if (err)
2384 ui_browser__handle_resize(&browser->b);
2385 return 0;
2386}
2387
2388static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002389add_annotate_opt(struct hist_browser *browser __maybe_unused,
2390 struct popup_action *act, char **optstr,
2391 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002392{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002393 if (sym == NULL || map->dso->annotate_warned)
2394 return 0;
2395
2396 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2397 return 0;
2398
2399 act->ms.map = map;
2400 act->ms.sym = sym;
2401 act->fn = do_annotate;
2402 return 1;
2403}
2404
2405static int
2406do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2407{
2408 struct thread *thread = act->thread;
2409
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002410 if ((!hists__has(browser->hists, thread) &&
2411 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002412 return 0;
2413
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002414 if (browser->hists->thread_filter) {
2415 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2416 perf_hpp__set_elide(HISTC_THREAD, false);
2417 thread__zput(browser->hists->thread_filter);
2418 ui_helpline__pop();
2419 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002420 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002421 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2422 thread->comm_set ? thread__comm_str(thread) : "",
2423 thread->tid);
2424 } else {
2425 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2426 thread->comm_set ? thread__comm_str(thread) : "");
2427 }
2428
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002429 browser->hists->thread_filter = thread__get(thread);
2430 perf_hpp__set_elide(HISTC_THREAD, false);
2431 pstack__push(browser->pstack, &browser->hists->thread_filter);
2432 }
2433
2434 hists__filter_by_thread(browser->hists);
2435 hist_browser__reset(browser);
2436 return 0;
2437}
2438
2439static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002440add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2441 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002442{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002443 int ret;
2444
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002445 if ((!hists__has(browser->hists, thread) &&
2446 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002447 return 0;
2448
Jiri Olsafa829112016-05-03 13:54:47 +02002449 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002450 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2451 browser->hists->thread_filter ? "out of" : "into",
2452 thread->comm_set ? thread__comm_str(thread) : "",
2453 thread->tid);
2454 } else {
2455 ret = asprintf(optstr, "Zoom %s %s thread",
2456 browser->hists->thread_filter ? "out of" : "into",
2457 thread->comm_set ? thread__comm_str(thread) : "");
2458 }
2459 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002460 return 0;
2461
2462 act->thread = thread;
2463 act->fn = do_zoom_thread;
2464 return 1;
2465}
2466
2467static int
2468do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2469{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002470 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002471
Jiri Olsa69849fc2016-05-03 13:54:45 +02002472 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002473 return 0;
2474
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002475 if (browser->hists->dso_filter) {
2476 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2477 perf_hpp__set_elide(HISTC_DSO, false);
2478 browser->hists->dso_filter = NULL;
2479 ui_helpline__pop();
2480 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002481 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002482 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2483 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002484 perf_hpp__set_elide(HISTC_DSO, true);
2485 pstack__push(browser->pstack, &browser->hists->dso_filter);
2486 }
2487
2488 hists__filter_by_dso(browser->hists);
2489 hist_browser__reset(browser);
2490 return 0;
2491}
2492
2493static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002494add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002495 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002496{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002497 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002498 return 0;
2499
2500 if (asprintf(optstr, "Zoom %s %s DSO",
2501 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002502 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002503 return 0;
2504
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002505 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002506 act->fn = do_zoom_dso;
2507 return 1;
2508}
2509
2510static int
2511do_browse_map(struct hist_browser *browser __maybe_unused,
2512 struct popup_action *act)
2513{
2514 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002515 return 0;
2516}
2517
2518static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002519add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002520 struct popup_action *act, char **optstr, struct map *map)
2521{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002522 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002523 return 0;
2524
2525 if (asprintf(optstr, "Browse map details") < 0)
2526 return 0;
2527
2528 act->ms.map = map;
2529 act->fn = do_browse_map;
2530 return 1;
2531}
2532
2533static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002534do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002535 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002536{
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002537 char *script_opt;
2538 int len;
2539 int n = 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002540
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002541 len = 100;
2542 if (act->thread)
2543 len += strlen(thread__comm_str(act->thread));
2544 else if (act->ms.sym)
2545 len += strlen(act->ms.sym->name);
2546 script_opt = malloc(len);
2547 if (!script_opt)
2548 return -1;
2549
2550 script_opt[0] = 0;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002551 if (act->thread) {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002552 n = scnprintf(script_opt, len, " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002553 thread__comm_str(act->thread));
2554 } else if (act->ms.sym) {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002555 n = scnprintf(script_opt, len, " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002556 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002557 }
2558
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002559 if (act->time) {
2560 char start[32], end[32];
2561 unsigned long starttime = act->time;
2562 unsigned long endtime = act->time + symbol_conf.time_quantum;
2563
2564 if (starttime == endtime) { /* Display 1ms as fallback */
2565 starttime -= 1*NSEC_PER_MSEC;
2566 endtime += 1*NSEC_PER_MSEC;
2567 }
2568 timestamp__scnprintf_usec(starttime, start, sizeof start);
2569 timestamp__scnprintf_usec(endtime, end, sizeof end);
2570 n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end);
2571 }
2572
Andi Kleen6f3da202019-03-11 07:44:57 -07002573 script_browse(script_opt, act->evsel);
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002574 free(script_opt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002575 return 0;
2576}
2577
2578static int
Andi Kleen4968ac82019-03-11 07:44:58 -07002579do_res_sample_script(struct hist_browser *browser __maybe_unused,
2580 struct popup_action *act)
2581{
2582 struct hist_entry *he;
2583
2584 he = hist_browser__selected_entry(browser);
2585 res_sample_browse(he->res_samples, he->num_res, act->evsel, act->rstype);
2586 return 0;
2587}
2588
2589static int
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002590add_script_opt_2(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002591 struct popup_action *act, char **optstr,
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002592 struct thread *thread, struct symbol *sym,
Andi Kleen6f3da202019-03-11 07:44:57 -07002593 struct perf_evsel *evsel, const char *tstr)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002594{
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002595
Namhyung Kimea7cd592015-04-22 16:18:19 +09002596 if (thread) {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002597 if (asprintf(optstr, "Run scripts for samples of thread [%s]%s",
2598 thread__comm_str(thread), tstr) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002599 return 0;
2600 } else if (sym) {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002601 if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s",
2602 sym->name, tstr) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002603 return 0;
2604 } else {
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002605 if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002606 return 0;
2607 }
2608
2609 act->thread = thread;
2610 act->ms.sym = sym;
Andi Kleen6f3da202019-03-11 07:44:57 -07002611 act->evsel = evsel;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002612 act->fn = do_run_script;
2613 return 1;
2614}
2615
2616static int
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002617add_script_opt(struct hist_browser *browser,
2618 struct popup_action *act, char **optstr,
Andi Kleen6f3da202019-03-11 07:44:57 -07002619 struct thread *thread, struct symbol *sym,
2620 struct perf_evsel *evsel)
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002621{
2622 int n, j;
2623 struct hist_entry *he;
2624
Andi Kleen6f3da202019-03-11 07:44:57 -07002625 n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, "");
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002626
2627 he = hist_browser__selected_entry(browser);
2628 if (sort_order && strstr(sort_order, "time")) {
2629 char tstr[128];
2630
2631 optstr++;
2632 act++;
2633 j = sprintf(tstr, " in ");
2634 j += timestamp__scnprintf_usec(he->time, tstr + j,
2635 sizeof tstr - j);
2636 j += sprintf(tstr + j, "-");
2637 timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum,
Andi Kleen6f3da202019-03-11 07:44:57 -07002638 tstr + j, sizeof tstr - j);
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002639 n += add_script_opt_2(browser, act, optstr, thread, sym,
Andi Kleen6f3da202019-03-11 07:44:57 -07002640 evsel, tstr);
Andi Kleen1d6c49d2019-03-11 07:44:56 -07002641 act->time = he->time;
2642 }
2643 return n;
2644}
2645
2646static int
Andi Kleen4968ac82019-03-11 07:44:58 -07002647add_res_sample_opt(struct hist_browser *browser __maybe_unused,
2648 struct popup_action *act, char **optstr,
2649 struct res_sample *res_sample,
2650 struct perf_evsel *evsel,
2651 enum rstype type)
2652{
2653 if (!res_sample)
2654 return 0;
2655
2656 if (asprintf(optstr, "Show context for individual samples %s",
2657 type == A_ASM ? "with assembler" :
2658 type == A_SOURCE ? "with source" : "") < 0)
2659 return 0;
2660
2661 act->fn = do_res_sample_script;
2662 act->evsel = evsel;
2663 act->rstype = type;
2664 return 1;
2665}
2666
2667static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002668do_switch_data(struct hist_browser *browser __maybe_unused,
2669 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002670{
2671 if (switch_data_file()) {
2672 ui__warning("Won't switch the data files due to\n"
2673 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002674 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002675 }
2676
2677 return K_SWITCH_INPUT_DATA;
2678}
2679
Namhyung Kimea7cd592015-04-22 16:18:19 +09002680static int
2681add_switch_opt(struct hist_browser *browser,
2682 struct popup_action *act, char **optstr)
2683{
2684 if (!is_report_browser(browser->hbt))
2685 return 0;
2686
2687 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2688 return 0;
2689
2690 act->fn = do_switch_data;
2691 return 1;
2692}
2693
2694static int
2695do_exit_browser(struct hist_browser *browser __maybe_unused,
2696 struct popup_action *act __maybe_unused)
2697{
2698 return 0;
2699}
2700
2701static int
2702add_exit_opt(struct hist_browser *browser __maybe_unused,
2703 struct popup_action *act, char **optstr)
2704{
2705 if (asprintf(optstr, "Exit") < 0)
2706 return 0;
2707
2708 act->fn = do_exit_browser;
2709 return 1;
2710}
2711
Kan Liang84734b02015-09-04 10:45:45 -04002712static int
2713do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2714{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002715 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002716 return 0;
2717
Kan Liang84734b02015-09-04 10:45:45 -04002718 if (browser->hists->socket_filter > -1) {
2719 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2720 browser->hists->socket_filter = -1;
2721 perf_hpp__set_elide(HISTC_SOCKET, false);
2722 } else {
2723 browser->hists->socket_filter = act->socket;
2724 perf_hpp__set_elide(HISTC_SOCKET, true);
2725 pstack__push(browser->pstack, &browser->hists->socket_filter);
2726 }
2727
2728 hists__filter_by_socket(browser->hists);
2729 hist_browser__reset(browser);
2730 return 0;
2731}
2732
2733static int
2734add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2735 char **optstr, int socket_id)
2736{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002737 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002738 return 0;
2739
2740 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2741 (browser->hists->socket_filter > -1) ? "out of" : "into",
2742 socket_id) < 0)
2743 return 0;
2744
2745 act->socket = socket_id;
2746 act->fn = do_zoom_socket;
2747 return 1;
2748}
2749
Namhyung Kim112f7612014-04-22 14:05:35 +09002750static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002751{
2752 u64 nr_entries = 0;
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08002753 struct rb_node *nd = rb_first_cached(&hb->hists->entries);
Namhyung Kim064f1982013-05-14 11:09:04 +09002754
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002755 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002756 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2757 return;
2758 }
2759
Namhyung Kim14135662013-10-31 10:17:39 +09002760 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002761 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002762 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002763 }
2764
Namhyung Kim112f7612014-04-22 14:05:35 +09002765 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002766 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002767}
Feng Tang341487ab2013-02-03 14:38:20 +08002768
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002769static void hist_browser__update_percent_limit(struct hist_browser *hb,
2770 double percent)
2771{
2772 struct hist_entry *he;
Davidlohr Bueso2eb3d682018-12-06 11:18:18 -08002773 struct rb_node *nd = rb_first_cached(&hb->hists->entries);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002774 u64 total = hists__total_period(hb->hists);
2775 u64 min_callchain_hits = total * (percent / 100);
2776
2777 hb->min_pcnt = callchain_param.min_percent = percent;
2778
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002779 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2780 he = rb_entry(nd, struct hist_entry, rb_node);
2781
Namhyung Kim79dded82016-02-26 21:13:19 +09002782 if (he->has_no_entry) {
2783 he->has_no_entry = false;
2784 he->nr_rows = 0;
2785 }
2786
Arnaldo Carvalho de Melofabd37b2018-05-29 13:59:24 -03002787 if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002788 goto next;
2789
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002790 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2791 total = he->stat.period;
2792
2793 if (symbol_conf.cumulate_callchain)
2794 total = he->stat_acc->period;
2795
2796 min_callchain_hits = total * (percent / 100);
2797 }
2798
2799 callchain_param.sort(&he->sorted_chain, he->callchain,
2800 min_callchain_hits, &callchain_param);
2801
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002802next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002803 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002804
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002805 /* force to re-evaluate folding state of callchains */
2806 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002807 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002808 }
2809}
2810
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002811static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002812 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002813 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002814 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002815 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08002816 struct perf_env *env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002817 bool warn_lost_event,
2818 struct annotation_options *annotation_opts)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002819{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002820 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03002821 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002822 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002823#define MAX_OPTIONS 16
2824 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002825 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002826 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002827 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002828 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002829 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002830
Namhyung Kime8e684a2013-12-26 14:37:58 +09002831#define HIST_BROWSER_HELP_COMMON \
2832 "h/?/F1 Show this window\n" \
2833 "UP/DOWN/PGUP\n" \
2834 "PGDN/SPACE Navigate\n" \
Andi Kleen6a02f062018-04-06 13:38:10 -07002835 "q/ESC/CTRL+C Exit browser or go back to previous screen\n\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002836 "For multiple event sessions:\n\n" \
2837 "TAB/UNTAB Switch events\n\n" \
2838 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002839 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2840 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002841 "a Annotate current symbol\n" \
2842 "C Collapse all callchains\n" \
2843 "d Zoom into current DSO\n" \
2844 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002845 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002846 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002847 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002848 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002849 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002850
2851 /* help messages are sorted by lexical order of the hotkey */
Rasmus Villemoes49b8e2b2018-11-03 00:06:23 +01002852 static const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002853 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002854 "P Print histograms to perf.hist.N\n"
2855 "r Run available scripts\n"
2856 "s Switch to another data file in PWD\n"
2857 "t Zoom into current Thread\n"
2858 "V Verbose (DSO names in callchains, etc)\n"
2859 "/ Filter symbol by name";
Rasmus Villemoes49b8e2b2018-11-03 00:06:23 +01002860 static const char top_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kime8e684a2013-12-26 14:37:58 +09002861 "P Print histograms to perf.hist.N\n"
2862 "t Zoom into current Thread\n"
2863 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002864 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002865 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002866 "/ Filter symbol by name";
2867
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002868 if (browser == NULL)
2869 return -1;
2870
Namhyung Kimed426912015-05-29 21:53:44 +09002871 /* reset abort key so that it can get Ctrl-C as a key */
2872 SLang_reset_tty();
2873 SLang_init_tty(0, 0, 0);
2874
Namhyung Kim03905042015-11-28 02:32:39 +09002875 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002876 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002877 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002878
Kan Liang84734b02015-09-04 10:45:45 -04002879 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002880 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002881 goto out;
2882
2883 ui_helpline__push(helpline);
2884
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002885 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002886 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002887
Namhyung Kim5b591662014-07-31 14:47:38 +09002888 if (symbol_conf.col_width_list_str)
2889 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2890
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002891 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002892 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002893 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002894 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002895 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002896
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002897 nr_options = 0;
2898
Kan Liang06cc1a42018-01-18 13:26:29 -08002899 key = hist_browser__run(browser, helpline,
2900 warn_lost_event);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002901
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002902 if (browser->he_selection != NULL) {
2903 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002904 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002905 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002906 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002907 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002908 case K_TAB:
2909 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002910 if (nr_events == 1)
2911 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002912 /*
2913 * Exit the browser, let hists__browser_tree
2914 * go to the next or previous
2915 */
2916 goto out_free_stack;
2917 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002918 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002919 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002920 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002921 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002922 continue;
2923 }
2924
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002925 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002926 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002927 browser->selection->map->dso->annotate_warned)
2928 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002929
Namhyung Kimea7cd592015-04-22 16:18:19 +09002930 actions->ms.map = browser->selection->map;
2931 actions->ms.sym = browser->selection->sym;
2932 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002933 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002934 case 'P':
2935 hist_browser__dump(browser);
2936 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002937 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002938 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002939 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002940 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002941 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02002942 verbose = (verbose + 1) % 4;
2943 browser->show_dso = verbose > 0;
2944 ui_helpline__fpush("Verbosity level set to %d\n",
2945 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002946 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002947 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002948 actions->thread = thread;
2949 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002950 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002951 case 'S':
2952 actions->socket = socked_id;
2953 do_zoom_socket(browser, actions);
2954 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002955 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002956 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002957 "Please enter the name of symbol you want to see.\n"
2958 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002959 buf, "ENTER: OK, ESC: Cancel",
2960 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002961 hists->symbol_filter_str = *buf ? buf : NULL;
2962 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002963 hist_browser__reset(browser);
2964 }
2965 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002966 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002967 if (is_report_browser(hbt)) {
2968 actions->thread = NULL;
2969 actions->ms.sym = NULL;
2970 do_run_script(browser, actions);
2971 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002972 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002973 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002974 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002975 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002976 if (key == K_SWITCH_INPUT_DATA)
2977 goto out_free_stack;
2978 }
Feng Tang341487ab2013-02-03 14:38:20 +08002979 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002980 case 'i':
2981 /* env->arch is NULL for live-mode (i.e. perf top) */
2982 if (env->arch)
2983 tui__header_window(env);
2984 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002985 case 'F':
2986 symbol_conf.filter_relative ^= 1;
2987 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002988 case 'z':
2989 if (!is_report_browser(hbt)) {
2990 struct perf_top *top = hbt->arg;
2991
2992 top->zero = !top->zero;
2993 }
2994 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002995 case 'L':
2996 if (ui_browser__input_window("Percent Limit",
2997 "Please enter the value you want to hide entries under that percent.",
2998 buf, "ENTER: OK, ESC: Cancel",
2999 delay_secs * 2) == K_ENTER) {
3000 char *end;
3001 double new_percent = strtod(buf, &end);
3002
3003 if (new_percent < 0 || new_percent > 100) {
3004 ui_browser__warning(&browser->b, delay_secs * 2,
3005 "Invalid percent: %.2f", new_percent);
3006 continue;
3007 }
3008
3009 hist_browser__update_percent_limit(browser, new_percent);
3010 hist_browser__reset(browser);
3011 }
3012 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003013 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003014 case 'h':
3015 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003016 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003017 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003018 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003019 case K_ENTER:
3020 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003021 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003022 /* menu */
3023 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003024 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003025 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003026 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003027
Namhyung Kim01f00a12015-04-22 16:18:16 +09003028 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003029 /*
3030 * Go back to the perf_evsel_menu__run or other user
3031 */
3032 if (left_exits)
3033 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003034
3035 if (key == K_ESC &&
3036 ui_browser__dialog_yesno(&browser->b,
3037 "Do you really want to exit?"))
3038 goto out_free_stack;
3039
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003040 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003041 }
Namhyung Kim64221842015-04-24 10:15:33 +09003042 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003043 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003044 /*
3045 * No need to set actions->dso here since
3046 * it's just to remove the current filter.
3047 * Ditto for thread below.
3048 */
3049 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003050 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003051 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003052 } else if (top == &browser->hists->socket_filter) {
3053 do_zoom_socket(browser, actions);
3054 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003055 continue;
3056 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003057 case 'q':
3058 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003059 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003060 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003061 if (!is_report_browser(hbt)) {
3062 struct perf_top *top = hbt->arg;
3063
3064 perf_evlist__toggle_enable(top->evlist);
3065 /*
3066 * No need to refresh, resort/decay histogram
3067 * entries if we are not collecting samples:
3068 */
3069 if (top->evlist->enabled) {
3070 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3071 hbt->refresh = delay_secs;
3072 } else {
3073 helpline = "Press 'f' again to re-enable the events";
3074 hbt->refresh = 0;
3075 }
3076 continue;
3077 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003078 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003079 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003080 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003081 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003082 }
3083
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003084 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003085 goto skip_annotation;
3086
Namhyung Kim55369fc2013-04-01 20:35:20 +09003087 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003088 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003089
3090 if (bi == NULL)
3091 goto skip_annotation;
3092
Namhyung Kimea7cd592015-04-22 16:18:19 +09003093 nr_options += add_annotate_opt(browser,
3094 &actions[nr_options],
3095 &options[nr_options],
3096 bi->from.map,
3097 bi->from.sym);
3098 if (bi->to.sym != bi->from.sym)
3099 nr_options += add_annotate_opt(browser,
3100 &actions[nr_options],
3101 &options[nr_options],
3102 bi->to.map,
3103 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003104 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003105 nr_options += add_annotate_opt(browser,
3106 &actions[nr_options],
3107 &options[nr_options],
3108 browser->selection->map,
3109 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003110 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003111skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003112 nr_options += add_thread_opt(browser, &actions[nr_options],
3113 &options[nr_options], thread);
3114 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003115 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003116 nr_options += add_map_opt(browser, &actions[nr_options],
3117 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003118 browser->selection ?
3119 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003120 nr_options += add_socket_opt(browser, &actions[nr_options],
3121 &options[nr_options],
3122 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003123 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003124 if (!is_report_browser(hbt))
3125 goto skip_scripting;
3126
Feng Tangcdbab7c2012-10-30 11:56:06 +08003127 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003128 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003129 nr_options += add_script_opt(browser,
3130 &actions[nr_options],
3131 &options[nr_options],
Andi Kleen6f3da202019-03-11 07:44:57 -07003132 thread, NULL, evsel);
Namhyung Kim2eafd412016-01-21 19:13:24 -03003133 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003134 /*
3135 * Note that browser->selection != NULL
3136 * when browser->he_selection is not NULL,
3137 * so we don't need to check browser->selection
3138 * before fetching browser->selection->sym like what
3139 * we do before fetching browser->selection->map.
3140 *
3141 * See hist_browser__show_entry.
3142 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003143 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003144 nr_options += add_script_opt(browser,
3145 &actions[nr_options],
3146 &options[nr_options],
Andi Kleen6f3da202019-03-11 07:44:57 -07003147 NULL, browser->selection->sym,
3148 evsel);
Namhyung Kimc221acb2016-01-21 19:50:09 -03003149 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003150 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003151 nr_options += add_script_opt(browser, &actions[nr_options],
Andi Kleen6f3da202019-03-11 07:44:57 -07003152 &options[nr_options], NULL, NULL, evsel);
Andi Kleen4968ac82019-03-11 07:44:58 -07003153 nr_options += add_res_sample_opt(browser, &actions[nr_options],
3154 &options[nr_options],
3155 hist_browser__selected_entry(browser)->res_samples,
3156 evsel, A_NORMAL);
3157 nr_options += add_res_sample_opt(browser, &actions[nr_options],
3158 &options[nr_options],
3159 hist_browser__selected_entry(browser)->res_samples,
3160 evsel, A_ASM);
3161 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_SOURCE);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003165 nr_options += add_switch_opt(browser, &actions[nr_options],
3166 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003167skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003168 nr_options += add_exit_opt(browser, &actions[nr_options],
3169 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003170
Namhyung Kimea7cd592015-04-22 16:18:19 +09003171 do {
3172 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003173
Namhyung Kimea7cd592015-04-22 16:18:19 +09003174 choice = ui__popup_menu(nr_options, options);
3175 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003176 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003177
3178 act = &actions[choice];
3179 key = act->fn(browser, act);
3180 } while (key == 1);
3181
3182 if (key == K_SWITCH_INPUT_DATA)
3183 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003184 }
3185out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003186 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003187out:
3188 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003189 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003190 return key;
3191}
3192
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003193struct perf_evsel_menu {
3194 struct ui_browser b;
3195 struct perf_evsel *selection;
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003196 struct annotation_options *annotation_opts;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003197 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003198 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003199 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003200};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003201
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003202static void perf_evsel_menu__write(struct ui_browser *browser,
3203 void *entry, int row)
3204{
3205 struct perf_evsel_menu *menu = container_of(browser,
3206 struct perf_evsel_menu, b);
3207 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003208 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003209 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003210 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003211 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003212 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003213 const char *warn = " ";
3214 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003215
3216 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3217 HE_COLORSET_NORMAL);
3218
Namhyung Kim759ff492013-03-05 14:53:26 +09003219 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003220 struct perf_evsel *pos;
3221
3222 ev_name = perf_evsel__group_name(evsel);
3223
3224 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003225 struct hists *pos_hists = evsel__hists(pos);
3226 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003227 }
3228 }
3229
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003230 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003231 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003232 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003233 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003234
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003235 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003236 if (nr_events != 0) {
3237 menu->lost_events = true;
3238 if (!current_entry)
3239 ui_browser__set_color(browser, HE_COLORSET_TOP);
3240 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003241 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3242 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003243 warn = bf;
3244 }
3245
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003246 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003247
3248 if (current_entry)
3249 menu->selection = evsel;
3250}
3251
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003252static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3253 int nr_events, const char *help,
Kan Liang06cc1a42018-01-18 13:26:29 -08003254 struct hist_browser_timer *hbt,
3255 bool warn_lost_event)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003256{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003257 struct perf_evlist *evlist = menu->b.priv;
3258 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003259 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003260 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003261 int key;
3262
3263 if (ui_browser__show(&menu->b, title,
3264 "ESC: exit, ENTER|->: Browse histograms") < 0)
3265 return -1;
3266
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003267 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003268 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003269
3270 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003271 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003272 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003273
Kan Liang06cc1a42018-01-18 13:26:29 -08003274 if (!menu->lost_events_warned &&
3275 menu->lost_events &&
3276 warn_lost_event) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003277 ui_browser__warn_lost_events(&menu->b);
3278 menu->lost_events_warned = true;
3279 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003280 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003281 case K_RIGHT:
3282 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003283 if (!menu->selection)
3284 continue;
3285 pos = menu->selection;
3286browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003287 perf_evlist__set_selected(evlist, pos);
3288 /*
3289 * Give the calling tool a chance to populate the non
3290 * default evsel resorted hists tree.
3291 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003292 if (hbt)
3293 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003294 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003295 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003296 menu->min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003297 menu->env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003298 warn_lost_event,
3299 menu->annotation_opts);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003300 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003301 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003302 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003303 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003304 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003305 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003306 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003307 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003308 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003309 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003310 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003311 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003312 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003313 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003314 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003315 case 'q':
3316 case CTRL('c'):
3317 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003318 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003319 default:
3320 continue;
3321 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003322 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003323 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003324 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003325 if (!ui_browser__dialog_yesno(&menu->b,
3326 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003327 continue;
3328 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003329 case 'q':
3330 case CTRL('c'):
3331 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003332 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003333 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003334 }
3335 }
3336
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003337out:
3338 ui_browser__hide(&menu->b);
3339 return key;
3340}
3341
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003342static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003343 void *entry)
3344{
3345 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3346
3347 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3348 return true;
3349
3350 return false;
3351}
3352
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003353static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003354 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003355 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003356 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003357 struct perf_env *env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003358 bool warn_lost_event,
3359 struct annotation_options *annotation_opts)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003360{
3361 struct perf_evsel *pos;
3362 struct perf_evsel_menu menu = {
3363 .b = {
3364 .entries = &evlist->entries,
3365 .refresh = ui_browser__list_head_refresh,
3366 .seek = ui_browser__list_head_seek,
3367 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003368 .filter = filter_group_entries,
3369 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003370 .priv = evlist,
3371 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003372 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003373 .env = env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003374 .annotation_opts = annotation_opts,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003375 };
3376
3377 ui_helpline__push("Press ESC to exit");
3378
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003379 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003380 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003381 size_t line_len = strlen(ev_name) + 7;
3382
3383 if (menu.b.width < line_len)
3384 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003385 }
3386
Kan Liang06cc1a42018-01-18 13:26:29 -08003387 return perf_evsel_menu__run(&menu, nr_entries, help,
3388 hbt, warn_lost_event);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003389}
3390
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003391int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003392 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003393 float min_pcnt,
Kan Liang06cc1a42018-01-18 13:26:29 -08003394 struct perf_env *env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003395 bool warn_lost_event,
3396 struct annotation_options *annotation_opts)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003397{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003398 int nr_entries = evlist->nr_entries;
3399
3400single_entry:
3401 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003402 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003403
3404 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003405 false, hbt, min_pcnt,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003406 env, warn_lost_event,
3407 annotation_opts);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003408 }
3409
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003410 if (symbol_conf.event_group) {
3411 struct perf_evsel *pos;
3412
3413 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003414 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003415 if (perf_evsel__is_group_leader(pos))
3416 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003417 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003418
3419 if (nr_entries == 1)
3420 goto single_entry;
3421 }
3422
3423 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Kan Liang06cc1a42018-01-18 13:26:29 -08003424 hbt, min_pcnt, env,
Arnaldo Carvalho de Melocd0cccb2018-05-28 13:54:59 -03003425 warn_lost_event,
3426 annotation_opts);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003427}