blob: 3a433f370e7fd0fed48538f45b46dd1cefd52639 [file] [log] [blame]
Arnaldo Carvalho de Melo76b31a22017-04-18 12:26:44 -03001#include <dirent.h>
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03002#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03003#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <stdlib.h>
6#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03007#include <linux/rbtree.h>
Arnaldo Carvalho de Melob0742e92017-04-18 11:08:10 -03008#include <sys/ttydefaults.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03009
Namhyung Kimaca7a942012-04-04 00:14:26 -070010#include "../../util/evsel.h"
11#include "../../util/evlist.h"
12#include "../../util/hist.h"
13#include "../../util/pstack.h"
14#include "../../util/sort.h"
15#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090016#include "../../util/top.h"
Arnaldo Carvalho de Meloe7ff8922017-04-19 21:34:35 -030017#include "../../util/thread.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090018#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019
Jiri Olsaf7589902016-06-20 23:58:13 +020020#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021#include "../helpline.h"
22#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020023#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030024#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020025#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030026#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030027#include "string2.h"
Arnaldo Carvalho de Melo58db1d62017-04-19 16:05:56 -030028#include "units.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030029
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030030#include "sane_ctype.h"
31
Namhyung Kimf5951d52012-09-03 11:53:09 +090032extern void hist_browser__init_hpp(void);
33
Jiri Olsa5b91a862016-06-20 23:58:15 +020034static int perf_evsel_browser_title(struct hist_browser *browser,
35 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090036static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030037
Namhyung Kimc3b78952014-04-22 15:56:17 +090038static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090039 float min_pcnt);
40
Namhyung Kim268397c2014-04-22 14:49:31 +090041static bool hist_browser__has_filter(struct hist_browser *hb)
42{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010043 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090044}
45
He Kuang4fabf3d2015-03-12 15:21:49 +080046static int hist_browser__get_folding(struct hist_browser *browser)
47{
48 struct rb_node *nd;
49 struct hists *hists = browser->hists;
50 int unfolded_rows = 0;
51
52 for (nd = rb_first(&hists->entries);
53 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090054 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080055 struct hist_entry *he =
56 rb_entry(nd, struct hist_entry, rb_node);
57
Namhyung Kimf5b763f2016-02-25 00:13:43 +090058 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080059 unfolded_rows += he->nr_rows;
60 }
61 return unfolded_rows;
62}
63
Namhyung Kimc3b78952014-04-22 15:56:17 +090064static u32 hist_browser__nr_entries(struct hist_browser *hb)
65{
66 u32 nr_entries;
67
Namhyung Kimf5b763f2016-02-25 00:13:43 +090068 if (symbol_conf.report_hierarchy)
69 nr_entries = hb->nr_hierarchy_entries;
70 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090071 nr_entries = hb->nr_non_filtered_entries;
72 else
73 nr_entries = hb->hists->nr_entries;
74
He Kuang4fabf3d2015-03-12 15:21:49 +080075 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090076 return nr_entries + hb->nr_callchain_rows;
77}
78
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020079static void hist_browser__update_rows(struct hist_browser *hb)
80{
81 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020082 struct hists *hists = hb->hists;
83 struct perf_hpp_list *hpp_list = hists->hpp_list;
84 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020085
Jiri Olsaf8e67102016-08-07 17:28:26 +020086 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020087 browser->rows = browser->height - header_offset;
88 /*
89 * Verify if we were at the last line and that line isn't
90 * visibe because we now show the header line(s).
91 */
92 index_row = browser->index - browser->top_idx;
93 if (index_row >= browser->rows)
94 browser->index -= index_row - browser->rows + 1;
95}
96
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030097static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030098{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030099 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
100
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300101 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300102 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
103 /*
104 * FIXME: Just keeping existing behaviour, but this really should be
105 * before updating browser->width, as it will invalidate the
106 * calculation above. Fix this and the fallout in another
107 * changeset.
108 */
109 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200110 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300111}
112
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300113static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
114{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200115 struct hists *hists = browser->hists;
116 struct perf_hpp_list *hpp_list = hists->hpp_list;
117 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200118
Jiri Olsaf8e67102016-08-07 17:28:26 +0200119 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200120 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300121}
122
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300123static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300124{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900125 /*
126 * The hists__remove_entry_filter() already folds non-filtered
127 * entries so we can assume it has 0 callchain rows.
128 */
129 browser->nr_callchain_rows = 0;
130
Namhyung Kim268397c2014-04-22 14:49:31 +0900131 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900132 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300133 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300134 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300135}
136
137static char tree__folded_sign(bool unfolded)
138{
139 return unfolded ? '-' : '+';
140}
141
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300142static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900144 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300145}
146
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300147static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900149 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300150}
151
Namhyung Kim3698dab2015-05-05 23:55:46 +0900152static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300153{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900154 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300155}
156
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300157static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300158{
Milian Wolff2a704fc2017-10-09 22:32:55 +0200159 int n = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300160 struct rb_node *nd;
161
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300162 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300163 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
164 struct callchain_list *chain;
165 char folded_sign = ' '; /* No children */
166
167 list_for_each_entry(chain, &child->val, list) {
168 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800169
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300170 /* We need this because we may not have children */
171 folded_sign = callchain_list__folded(chain);
172 if (folded_sign == '+')
173 break;
174 }
175
176 if (folded_sign == '-') /* Have children and they're unfolded */
177 n += callchain_node__count_rows_rb_tree(child);
178 }
179
180 return n;
181}
182
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900183static int callchain_node__count_flat_rows(struct callchain_node *node)
184{
185 struct callchain_list *chain;
186 char folded_sign = 0;
187 int n = 0;
188
189 list_for_each_entry(chain, &node->parent_val, list) {
190 if (!folded_sign) {
191 /* only check first chain list entry */
192 folded_sign = callchain_list__folded(chain);
193 if (folded_sign == '+')
194 return 1;
195 }
196 n++;
197 }
198
199 list_for_each_entry(chain, &node->val, list) {
200 if (!folded_sign) {
201 /* node->parent_val list might be empty */
202 folded_sign = callchain_list__folded(chain);
203 if (folded_sign == '+')
204 return 1;
205 }
206 n++;
207 }
208
209 return n;
210}
211
Namhyung Kim8c430a32015-11-09 14:45:44 +0900212static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
213{
214 return 1;
215}
216
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300217static int callchain_node__count_rows(struct callchain_node *node)
218{
219 struct callchain_list *chain;
220 bool unfolded = false;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200221 int n = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300222
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900223 if (callchain_param.mode == CHAIN_FLAT)
224 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900225 else if (callchain_param.mode == CHAIN_FOLDED)
226 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900227
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300228 list_for_each_entry(chain, &node->val, list) {
229 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800230
Namhyung Kim3698dab2015-05-05 23:55:46 +0900231 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300232 }
233
234 if (unfolded)
235 n += callchain_node__count_rows_rb_tree(node);
236
237 return n;
238}
239
240static int callchain__count_rows(struct rb_root *chain)
241{
242 struct rb_node *nd;
243 int n = 0;
244
245 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
246 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
247 n += callchain_node__count_rows(node);
248 }
249
250 return n;
251}
252
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900253static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
254 bool include_children)
255{
256 int count = 0;
257 struct rb_node *node;
258 struct hist_entry *child;
259
260 if (he->leaf)
261 return callchain__count_rows(&he->sorted_chain);
262
Namhyung Kim79dded82016-02-26 21:13:19 +0900263 if (he->has_no_entry)
264 return 1;
265
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900266 node = rb_first(&he->hroot_out);
267 while (node) {
268 float percent;
269
270 child = rb_entry(node, struct hist_entry, rb_node);
271 percent = hist_entry__get_percent_limit(child);
272
273 if (!child->filtered && percent >= hb->min_pcnt) {
274 count++;
275
276 if (include_children && child->unfolded)
277 count += hierarchy_count_rows(hb, child, true);
278 }
279
280 node = rb_next(node);
281 }
282 return count;
283}
284
Namhyung Kim3698dab2015-05-05 23:55:46 +0900285static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300286{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900287 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200288 return false;
289
Namhyung Kim3698dab2015-05-05 23:55:46 +0900290 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300291 return false;
292
Namhyung Kim3698dab2015-05-05 23:55:46 +0900293 he->unfolded = !he->unfolded;
294 return true;
295}
296
297static bool callchain_list__toggle_fold(struct callchain_list *cl)
298{
299 if (!cl)
300 return false;
301
302 if (!cl->has_children)
303 return false;
304
305 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300306 return true;
307}
308
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300309static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300310{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300311 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300312
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300313 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300314 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
315 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300316 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300317
318 list_for_each_entry(chain, &child->val, list) {
319 if (first) {
320 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900321 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300322 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300323 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900324 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300325 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300326 }
327
328 callchain_node__init_have_children_rb_tree(child);
329 }
330}
331
Namhyung Kima7444af2014-11-24 17:13:27 +0900332static void callchain_node__init_have_children(struct callchain_node *node,
333 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300334{
335 struct callchain_list *chain;
336
Namhyung Kima7444af2014-11-24 17:13:27 +0900337 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900338 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900339
Andres Freund90989032016-03-30 21:02:45 +0200340 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900341 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900342 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900343 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300344
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300345 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300346}
347
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300348static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300349{
Namhyung Kima7444af2014-11-24 17:13:27 +0900350 struct rb_node *nd = rb_first(root);
351 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300352
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300353 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300354 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900355 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900356 if (callchain_param.mode == CHAIN_FLAT ||
357 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900358 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300359 }
360}
361
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300362static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300363{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900364 if (he->init_have_children)
365 return;
366
367 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900368 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300369 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900370 } else {
371 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300372 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900373
374 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300375}
376
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300377static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300378{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900379 struct hist_entry *he = browser->he_selection;
380 struct map_symbol *ms = browser->selection;
381 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
382 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300383
Wang Nan4938cf02015-12-07 02:35:44 +0000384 if (!he || !ms)
385 return false;
386
Namhyung Kim3698dab2015-05-05 23:55:46 +0900387 if (ms == &he->ms)
388 has_children = hist_entry__toggle_fold(he);
389 else
390 has_children = callchain_list__toggle_fold(cl);
391
392 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900393 int child_rows = 0;
394
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300395 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900396 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300397
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900398 if (he->leaf)
399 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300400 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900401 browser->nr_hierarchy_entries -= he->nr_rows;
402
403 if (symbol_conf.report_hierarchy)
404 child_rows = hierarchy_count_rows(browser, he, true);
405
406 if (he->unfolded) {
407 if (he->leaf)
Milian Wolff2a704fc2017-10-09 22:32:55 +0200408 he->nr_rows = callchain__count_rows(
409 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900410 else
411 he->nr_rows = hierarchy_count_rows(browser, he, false);
412
413 /* account grand children */
414 if (symbol_conf.report_hierarchy)
415 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900416
417 if (!he->leaf && he->nr_rows == 0) {
418 he->has_no_entry = true;
419 he->nr_rows = 1;
420 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900421 } else {
422 if (symbol_conf.report_hierarchy)
423 browser->b.nr_entries -= child_rows - he->nr_rows;
424
Namhyung Kim79dded82016-02-26 21:13:19 +0900425 if (he->has_no_entry)
426 he->has_no_entry = false;
427
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300428 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900429 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900430
431 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900432
433 if (he->leaf)
434 browser->nr_callchain_rows += he->nr_rows;
435 else
436 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300437
438 return true;
439 }
440
441 /* If it doesn't have children, no toggling performed */
442 return false;
443}
444
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300445static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300446{
447 int n = 0;
448 struct rb_node *nd;
449
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300450 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300451 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
452 struct callchain_list *chain;
453 bool has_children = false;
454
455 list_for_each_entry(chain, &child->val, list) {
456 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900457 callchain_list__set_folding(chain, unfold);
458 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300459 }
460
461 if (has_children)
462 n += callchain_node__set_folding_rb_tree(child, unfold);
463 }
464
465 return n;
466}
467
468static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
469{
470 struct callchain_list *chain;
471 bool has_children = false;
472 int n = 0;
473
474 list_for_each_entry(chain, &node->val, list) {
475 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900476 callchain_list__set_folding(chain, unfold);
477 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300478 }
479
480 if (has_children)
481 n += callchain_node__set_folding_rb_tree(node, unfold);
482
483 return n;
484}
485
486static int callchain__set_folding(struct rb_root *chain, bool unfold)
487{
488 struct rb_node *nd;
489 int n = 0;
490
491 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
492 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
493 n += callchain_node__set_folding(node, unfold);
494 }
495
496 return n;
497}
498
Namhyung Kim492b1012016-02-25 00:13:44 +0900499static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
500 bool unfold __maybe_unused)
501{
502 float percent;
503 struct rb_node *nd;
504 struct hist_entry *child;
505 int n = 0;
506
507 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
508 child = rb_entry(nd, struct hist_entry, rb_node);
509 percent = hist_entry__get_percent_limit(child);
510 if (!child->filtered && percent >= hb->min_pcnt)
511 n++;
512 }
513
514 return n;
515}
516
Jiri Olsab33f9222017-01-20 10:20:29 +0100517static void __hist_entry__set_folding(struct hist_entry *he,
518 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300519{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300520 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900521 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300522
Namhyung Kim3698dab2015-05-05 23:55:46 +0900523 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900524 int n;
525
526 if (he->leaf)
527 n = callchain__set_folding(&he->sorted_chain, unfold);
528 else
529 n = hierarchy_set_folding(hb, he, unfold);
530
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300531 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300532 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300533 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300534}
535
Jiri Olsab33f9222017-01-20 10:20:29 +0100536static void hist_entry__set_folding(struct hist_entry *he,
537 struct hist_browser *browser, bool unfold)
538{
539 double percent;
540
541 percent = hist_entry__get_percent_limit(he);
542 if (he->filtered || percent < browser->min_pcnt)
543 return;
544
545 __hist_entry__set_folding(he, browser, unfold);
546
547 if (!he->depth || unfold)
548 browser->nr_hierarchy_entries++;
549 if (he->leaf)
550 browser->nr_callchain_rows += he->nr_rows;
551 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
552 browser->nr_hierarchy_entries++;
553 he->has_no_entry = true;
554 he->nr_rows = 1;
555 } else
556 he->has_no_entry = false;
557}
558
Namhyung Kimc3b78952014-04-22 15:56:17 +0900559static void
560__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300561{
562 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900563 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300564
Namhyung Kim492b1012016-02-25 00:13:44 +0900565 nd = rb_first(&browser->hists->entries);
566 while (nd) {
567 he = rb_entry(nd, struct hist_entry, rb_node);
568
569 /* set folding state even if it's currently folded */
570 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
571
572 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300573 }
574}
575
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300576static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300577{
Namhyung Kim492b1012016-02-25 00:13:44 +0900578 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900579 browser->nr_callchain_rows = 0;
580 __hist_browser__set_folding(browser, unfold);
581
582 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300583 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300584 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300585}
586
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100587static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
588{
589 if (!browser->he_selection)
590 return;
591
592 hist_entry__set_folding(browser->he_selection, browser, unfold);
593 browser->b.nr_entries = hist_browser__nr_entries(browser);
594}
595
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200596static void ui_browser__warn_lost_events(struct ui_browser *browser)
597{
598 ui_browser__warning(browser, 4,
599 "Events are being lost, check IO/CPU overload!\n\n"
600 "You may want to run 'perf' using a RT scheduler policy:\n\n"
601 " perf top -r 80\n\n"
602 "Or reduce the sampling frequency.");
603}
604
Jiri Olsa5b91a862016-06-20 23:58:15 +0200605static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
606{
607 return browser->title ? browser->title(browser, bf, size) : 0;
608}
609
Jiri Olsadabd2012016-06-20 23:58:14 +0200610int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300611{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300612 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300613 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900614 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900615 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300616
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300617 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900618 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300619
Jiri Olsa5b91a862016-06-20 23:58:15 +0200620 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300621
Namhyung Kim090cff32016-01-11 19:53:14 +0900622 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300623 return -1;
624
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300625 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300626 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300627
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300628 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900629 case K_TIMER: {
630 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900631 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900632
Namhyung Kimc6111522016-10-07 14:04:12 +0900633 if (hist_browser__has_filter(browser) ||
634 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900635 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900636
Namhyung Kimc3b78952014-04-22 15:56:17 +0900637 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900638 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200639
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300640 if (browser->hists->stats.nr_lost_warned !=
641 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
642 browser->hists->stats.nr_lost_warned =
643 browser->hists->stats.nr_events[PERF_RECORD_LOST];
644 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200645 }
646
Jiri Olsa5b91a862016-06-20 23:58:15 +0200647 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300648 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300649 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900650 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300651 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300652 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300653 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300654 struct hist_entry, rb_node);
655 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300656 ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300657 seq++, browser->b.nr_entries,
658 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300659 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300660 browser->b.index,
661 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300662 h->row_offset, h->nr_rows);
663 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300664 break;
665 case 'C':
666 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300667 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300668 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100669 case 'c':
670 /* Collapse the selected entry. */
671 hist_browser__set_folding_selected(browser, false);
672 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300673 case 'E':
674 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300675 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300676 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100677 case 'e':
678 /* Expand the selected entry. */
679 hist_browser__set_folding_selected(browser, true);
680 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200681 case 'H':
682 browser->show_headers = !browser->show_headers;
683 hist_browser__update_rows(browser);
684 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200685 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300686 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300687 break;
688 /* fall thru */
689 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300690 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300691 }
692 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300693out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300694 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300695 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300696}
697
Namhyung Kim39ee5332014-08-22 09:13:21 +0900698struct callchain_print_arg {
699 /* for hists browser */
700 off_t row_offset;
701 bool is_current_entry;
702
703 /* for file dump */
704 FILE *fp;
705 int printed;
706};
707
708typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
709 struct callchain_list *chain,
710 const char *str, int offset,
711 unsigned short row,
712 struct callchain_print_arg *arg);
713
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900714static void hist_browser__show_callchain_entry(struct hist_browser *browser,
715 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900716 const char *str, int offset,
717 unsigned short row,
718 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900719{
720 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900721 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300722 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900723
724 color = HE_COLORSET_NORMAL;
725 width = browser->b.width - (offset + 2);
726 if (ui_browser__is_current_entry(&browser->b, row)) {
727 browser->selection = &chain->ms;
728 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900729 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900730 }
731
732 ui_browser__set_color(&browser->b, color);
733 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300734 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300735 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300736 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300737 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900738}
739
Namhyung Kim39ee5332014-08-22 09:13:21 +0900740static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
741 struct callchain_list *chain,
742 const char *str, int offset,
743 unsigned short row __maybe_unused,
744 struct callchain_print_arg *arg)
745{
746 char folded_sign = callchain_list__folded(chain);
747
748 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
749 folded_sign, str);
750}
751
752typedef bool (*check_output_full_fn)(struct hist_browser *browser,
753 unsigned short row);
754
755static bool hist_browser__check_output_full(struct hist_browser *browser,
756 unsigned short row)
757{
758 return browser->b.rows == row;
759}
760
761static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
762 unsigned short row __maybe_unused)
763{
764 return false;
765}
766
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300767#define LEVEL_OFFSET_STEP 3
768
Namhyung Kim18bb8382015-11-09 14:45:42 +0900769static int hist_browser__show_callchain_list(struct hist_browser *browser,
770 struct callchain_node *node,
771 struct callchain_list *chain,
772 unsigned short row, u64 total,
773 bool need_percent, int offset,
774 print_callchain_entry_fn print,
775 struct callchain_print_arg *arg)
776{
777 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800778 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900779 const char *str;
Milian Wolff2a704fc2017-10-09 22:32:55 +0200780 int ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900781
782 if (arg->row_offset != 0) {
783 arg->row_offset--;
784 return 0;
785 }
786
787 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800788 alloc_str2 = NULL;
789
Namhyung Kim18bb8382015-11-09 14:45:42 +0900790 str = callchain_list__sym_name(chain, bf, sizeof(bf),
791 browser->show_dso);
792
Jin Yaofef51ec2016-10-31 09:19:53 +0800793 if (symbol_conf.show_branchflag_count) {
Jin Yaoc4ee0622017-08-07 21:05:15 +0800794 callchain_list_counts__printf_value(chain, NULL,
795 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900796
Jin Yaofef51ec2016-10-31 09:19:53 +0800797 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
798 str = "Not enough memory!";
799 else
800 str = alloc_str2;
801 }
802
803 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900804 callchain_node__scnprintf_value(node, buf, sizeof(buf),
805 total);
806
807 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
808 str = "Not enough memory!";
809 else
810 str = alloc_str;
811 }
812
813 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900814 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800815 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800816
Milian Wolff2a704fc2017-10-09 22:32:55 +0200817 return ret;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900818}
819
Namhyung Kim59c624e2016-01-28 00:40:56 +0900820static bool check_percent_display(struct rb_node *node, u64 parent_total)
821{
822 struct callchain_node *child;
823
824 if (node == NULL)
825 return false;
826
827 if (rb_next(node))
828 return true;
829
830 child = rb_entry(node, struct callchain_node, rb_node);
831 return callchain_cumul_hits(child) != parent_total;
832}
833
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900834static int hist_browser__show_callchain_flat(struct hist_browser *browser,
835 struct rb_root *root,
836 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900837 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900838 print_callchain_entry_fn print,
839 struct callchain_print_arg *arg,
840 check_output_full_fn is_output_full)
841{
842 struct rb_node *node;
843 int first_row = row, offset = LEVEL_OFFSET_STEP;
844 bool need_percent;
845
846 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900847 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900848
849 while (node) {
850 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
851 struct rb_node *next = rb_next(node);
852 struct callchain_list *chain;
853 char folded_sign = ' ';
854 int first = true;
855 int extra_offset = 0;
856
857 list_for_each_entry(chain, &child->parent_val, list) {
858 bool was_first = first;
859
860 if (first)
861 first = false;
862 else if (need_percent)
863 extra_offset = LEVEL_OFFSET_STEP;
864
865 folded_sign = callchain_list__folded(chain);
866
867 row += hist_browser__show_callchain_list(browser, child,
868 chain, row, total,
869 was_first && need_percent,
870 offset + extra_offset,
871 print, arg);
872
873 if (is_output_full(browser, row))
874 goto out;
875
876 if (folded_sign == '+')
877 goto next;
878 }
879
880 list_for_each_entry(chain, &child->val, list) {
881 bool was_first = first;
882
883 if (first)
884 first = false;
885 else if (need_percent)
886 extra_offset = LEVEL_OFFSET_STEP;
887
888 folded_sign = callchain_list__folded(chain);
889
890 row += hist_browser__show_callchain_list(browser, child,
891 chain, row, total,
892 was_first && need_percent,
893 offset + extra_offset,
894 print, arg);
895
896 if (is_output_full(browser, row))
897 goto out;
898
899 if (folded_sign == '+')
900 break;
901 }
902
903next:
904 if (is_output_full(browser, row))
905 break;
906 node = next;
907 }
908out:
909 return row - first_row;
910}
911
Namhyung Kim8c430a32015-11-09 14:45:44 +0900912static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
913 struct callchain_list *chain,
914 char *value_str, char *old_str)
915{
916 char bf[1024];
917 const char *str;
918 char *new;
919
920 str = callchain_list__sym_name(chain, bf, sizeof(bf),
921 browser->show_dso);
922 if (old_str) {
923 if (asprintf(&new, "%s%s%s", old_str,
924 symbol_conf.field_sep ?: ";", str) < 0)
925 new = NULL;
926 } else {
927 if (value_str) {
928 if (asprintf(&new, "%s %s", value_str, str) < 0)
929 new = NULL;
930 } else {
931 if (asprintf(&new, "%s", str) < 0)
932 new = NULL;
933 }
934 }
935 return new;
936}
937
938static int hist_browser__show_callchain_folded(struct hist_browser *browser,
939 struct rb_root *root,
940 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900941 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900942 print_callchain_entry_fn print,
943 struct callchain_print_arg *arg,
944 check_output_full_fn is_output_full)
945{
946 struct rb_node *node;
947 int first_row = row, offset = LEVEL_OFFSET_STEP;
948 bool need_percent;
949
950 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900951 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900952
953 while (node) {
954 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
955 struct rb_node *next = rb_next(node);
956 struct callchain_list *chain, *first_chain = NULL;
957 int first = true;
958 char *value_str = NULL, *value_str_alloc = NULL;
959 char *chain_str = NULL, *chain_str_alloc = NULL;
960
961 if (arg->row_offset != 0) {
962 arg->row_offset--;
963 goto next;
964 }
965
966 if (need_percent) {
967 char buf[64];
968
969 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
970 if (asprintf(&value_str, "%s", buf) < 0) {
971 value_str = (char *)"<...>";
972 goto do_print;
973 }
974 value_str_alloc = value_str;
975 }
976
977 list_for_each_entry(chain, &child->parent_val, list) {
978 chain_str = hist_browser__folded_callchain_str(browser,
979 chain, value_str, chain_str);
980 if (first) {
981 first = false;
982 first_chain = chain;
983 }
984
985 if (chain_str == NULL) {
986 chain_str = (char *)"Not enough memory!";
987 goto do_print;
988 }
989
990 chain_str_alloc = chain_str;
991 }
992
993 list_for_each_entry(chain, &child->val, list) {
994 chain_str = hist_browser__folded_callchain_str(browser,
995 chain, value_str, chain_str);
996 if (first) {
997 first = false;
998 first_chain = chain;
999 }
1000
1001 if (chain_str == NULL) {
1002 chain_str = (char *)"Not enough memory!";
1003 goto do_print;
1004 }
1005
1006 chain_str_alloc = chain_str;
1007 }
1008
1009do_print:
1010 print(browser, first_chain, chain_str, offset, row++, arg);
1011 free(value_str_alloc);
1012 free(chain_str_alloc);
1013
1014next:
1015 if (is_output_full(browser, row))
1016 break;
1017 node = next;
1018 }
1019
1020 return row - first_row;
1021}
1022
Namhyung Kim0c841c62016-01-28 00:40:54 +09001023static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001024 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001025 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001026 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001027 print_callchain_entry_fn print,
1028 struct callchain_print_arg *arg,
1029 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001030{
1031 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001032 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001033 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001034 u64 percent_total = total;
1035
1036 if (callchain_param.mode == CHAIN_GRAPH_REL)
1037 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001038
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001039 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001040 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001041
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001042 while (node) {
1043 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1044 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001045 struct callchain_list *chain;
1046 char folded_sign = ' ';
1047 int first = true;
1048 int extra_offset = 0;
1049
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001050 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001051 bool was_first = first;
1052
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001053 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001054 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001055 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001056 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001057
1058 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001059
Namhyung Kim18bb8382015-11-09 14:45:42 +09001060 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001061 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001062 was_first && need_percent,
1063 offset + extra_offset,
1064 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001065
Namhyung Kim18bb8382015-11-09 14:45:42 +09001066 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001067 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001068
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001069 if (folded_sign == '+')
1070 break;
1071 }
1072
1073 if (folded_sign == '-') {
1074 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001075
Namhyung Kim0c841c62016-01-28 00:40:54 +09001076 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001077 new_level, row, total,
1078 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001079 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001080 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001081 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001082 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001083 node = next;
1084 }
1085out:
1086 return row - first_row;
1087}
1088
Namhyung Kim0c841c62016-01-28 00:40:54 +09001089static int hist_browser__show_callchain(struct hist_browser *browser,
1090 struct hist_entry *entry, int level,
1091 unsigned short row,
1092 print_callchain_entry_fn print,
1093 struct callchain_print_arg *arg,
1094 check_output_full_fn is_output_full)
1095{
1096 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001097 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001098 int printed;
1099
Namhyung Kim5eca1042016-01-28 00:40:55 +09001100 if (symbol_conf.cumulate_callchain)
1101 parent_total = entry->stat_acc->period;
1102 else
1103 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001104
1105 if (callchain_param.mode == CHAIN_FLAT) {
1106 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001107 &entry->sorted_chain, row,
1108 total, parent_total, print, arg,
1109 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001110 } else if (callchain_param.mode == CHAIN_FOLDED) {
1111 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001112 &entry->sorted_chain, row,
1113 total, parent_total, print, arg,
1114 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001115 } else {
1116 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001117 &entry->sorted_chain, level, row,
1118 total, parent_total, print, arg,
1119 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001120 }
1121
1122 if (arg->is_current_entry)
1123 browser->he_selection = entry;
1124
1125 return printed;
1126}
1127
Namhyung Kim89701462013-01-22 18:09:38 +09001128struct hpp_arg {
1129 struct ui_browser *b;
1130 char folded_sign;
1131 bool current_entry;
1132};
1133
Jiri Olsa98ba1602016-09-22 17:36:35 +02001134int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001135{
1136 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001137 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001138 va_list args;
1139 double percent;
1140
1141 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001142 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001143 percent = va_arg(args, double);
1144 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001145
Namhyung Kim89701462013-01-22 18:09:38 +09001146 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001147
Namhyung Kimd6751072014-07-31 14:47:36 +09001148 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001149 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001150
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001151 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001152}
1153
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001154#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001155static u64 __hpp_get_##_field(struct hist_entry *he) \
1156{ \
1157 return he->stat._field; \
1158} \
1159 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001160static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001161hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001162 struct perf_hpp *hpp, \
1163 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001164{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001165 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1166 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001167}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001168
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001169#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1170static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1171{ \
1172 return he->stat_acc->_field; \
1173} \
1174 \
1175static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001176hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001177 struct perf_hpp *hpp, \
1178 struct hist_entry *he) \
1179{ \
1180 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001181 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001182 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001183 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001184 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001185 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001186 \
1187 return ret; \
1188 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001189 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1190 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001191}
1192
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001193__HPP_COLOR_PERCENT_FN(overhead, period)
1194__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1195__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1196__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1197__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001198__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001199
1200#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001201#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001202
1203void hist_browser__init_hpp(void)
1204{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001205 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1206 hist_browser__hpp_color_overhead;
1207 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1208 hist_browser__hpp_color_overhead_sys;
1209 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1210 hist_browser__hpp_color_overhead_us;
1211 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1212 hist_browser__hpp_color_overhead_guest_sys;
1213 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1214 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001215 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1216 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001217}
1218
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001219static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001220 struct hist_entry *entry,
1221 unsigned short row)
1222{
Jiri Olsa12400052012-10-13 00:06:16 +02001223 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001224 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001225 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001226 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001227 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001228 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001229 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001230
1231 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001232 browser->he_selection = entry;
1233 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001234 }
1235
1236 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001237 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001238 folded_sign = hist_entry__folded(entry);
1239 }
1240
1241 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001242 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001243 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001244 .folded_sign = folded_sign,
1245 .current_entry = current_entry,
1246 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001247 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001248
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001249 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001250
Jiri Olsaf0786af2016-01-18 10:24:23 +01001251 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001252 char s[2048];
1253 struct perf_hpp hpp = {
1254 .buf = s,
1255 .size = sizeof(s),
1256 .ptr = &arg,
1257 };
1258
Namhyung Kim361459f2015-12-23 02:07:08 +09001259 if (perf_hpp__should_skip(fmt, entry->hists) ||
1260 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001261 continue;
1262
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001263 if (current_entry && browser->b.navkeypressed) {
1264 ui_browser__set_color(&browser->b,
1265 HE_COLORSET_SELECTED);
1266 } else {
1267 ui_browser__set_color(&browser->b,
1268 HE_COLORSET_NORMAL);
1269 }
1270
1271 if (first) {
Milian Wolff2a704fc2017-10-09 22:32:55 +02001272 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001273 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001274 width -= 2;
1275 }
1276 first = false;
1277 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001278 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001279 width -= 2;
1280 }
1281
Jiri Olsa12400052012-10-13 00:06:16 +02001282 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001283 int ret = fmt->color(fmt, &hpp, entry);
1284 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1285 /*
1286 * fmt->color() already used ui_browser to
1287 * print the non alignment bits, skip it (+ret):
1288 */
1289 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001290 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001291 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001292 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001293 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001294 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001295 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001296
1297 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001298 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001299 width += 1;
1300
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001301 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001302
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001303 ++row;
1304 ++printed;
1305 } else
1306 --row_offset;
1307
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001308 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001309 struct callchain_print_arg arg = {
1310 .row_offset = row_offset,
1311 .is_current_entry = current_entry,
1312 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001313
Milian Wolff2a704fc2017-10-09 22:32:55 +02001314 printed += hist_browser__show_callchain(browser,
1315 entry, 1, row,
1316 hist_browser__show_callchain_entry,
1317 &arg,
1318 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001319 }
1320
1321 return printed;
1322}
1323
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001324static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1325 struct hist_entry *entry,
1326 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001327 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001328{
1329 int printed = 0;
1330 int width = browser->b.width;
1331 char folded_sign = ' ';
1332 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1333 off_t row_offset = entry->row_offset;
1334 bool first = true;
1335 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001336 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001337 struct hpp_arg arg = {
1338 .b = &browser->b,
1339 .current_entry = current_entry,
1340 };
1341 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001342 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001343
1344 if (current_entry) {
1345 browser->he_selection = entry;
1346 browser->selection = &entry->ms;
1347 }
1348
1349 hist_entry__init_have_children(entry);
1350 folded_sign = hist_entry__folded(entry);
1351 arg.folded_sign = folded_sign;
1352
1353 if (entry->leaf && row_offset) {
1354 row_offset--;
1355 goto show_callchain;
1356 }
1357
1358 hist_browser__gotorc(browser, row, 0);
1359
1360 if (current_entry && browser->b.navkeypressed)
1361 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1362 else
1363 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1364
1365 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1366 width -= level * HIERARCHY_INDENT;
1367
Namhyung Kima61a22f2016-03-07 16:44:50 -03001368 /* the first hpp_list_node is for overhead columns */
1369 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1370 struct perf_hpp_list_node, list);
1371 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001372 char s[2048];
1373 struct perf_hpp hpp = {
1374 .buf = s,
1375 .size = sizeof(s),
1376 .ptr = &arg,
1377 };
1378
1379 if (perf_hpp__should_skip(fmt, entry->hists) ||
1380 column++ < browser->b.horiz_scroll)
1381 continue;
1382
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001383 if (current_entry && browser->b.navkeypressed) {
1384 ui_browser__set_color(&browser->b,
1385 HE_COLORSET_SELECTED);
1386 } else {
1387 ui_browser__set_color(&browser->b,
1388 HE_COLORSET_NORMAL);
1389 }
1390
1391 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001392 ui_browser__printf(&browser->b, "%c ", folded_sign);
1393 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001394 first = false;
1395 } else {
1396 ui_browser__printf(&browser->b, " ");
1397 width -= 2;
1398 }
1399
1400 if (fmt->color) {
1401 int ret = fmt->color(fmt, &hpp, entry);
1402 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1403 /*
1404 * fmt->color() already used ui_browser to
1405 * print the non alignment bits, skip it (+ret):
1406 */
1407 ui_browser__printf(&browser->b, "%s", s + ret);
1408 } else {
1409 int ret = fmt->entry(fmt, &hpp, entry);
1410 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1411 ui_browser__printf(&browser->b, "%s", s);
1412 }
1413 width -= hpp.buf - s;
1414 }
1415
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001416 if (!first) {
1417 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1418 width -= hierarchy_indent;
1419 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001420
1421 if (column >= browser->b.horiz_scroll) {
1422 char s[2048];
1423 struct perf_hpp hpp = {
1424 .buf = s,
1425 .size = sizeof(s),
1426 .ptr = &arg,
1427 };
1428
1429 if (current_entry && browser->b.navkeypressed) {
1430 ui_browser__set_color(&browser->b,
1431 HE_COLORSET_SELECTED);
1432 } else {
1433 ui_browser__set_color(&browser->b,
1434 HE_COLORSET_NORMAL);
1435 }
1436
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001437 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001438 if (first) {
1439 ui_browser__printf(&browser->b, "%c ", folded_sign);
1440 first = false;
1441 } else {
1442 ui_browser__write_nstring(&browser->b, "", 2);
1443 }
1444
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001445 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001446
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001447 /*
1448 * No need to call hist_entry__snprintf_alignment()
1449 * since this fmt is always the last column in the
1450 * hierarchy mode.
1451 */
1452 if (fmt->color) {
1453 width -= fmt->color(fmt, &hpp, entry);
1454 } else {
1455 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001456
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001457 width -= fmt->entry(fmt, &hpp, entry);
1458 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001459
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001460 while (isspace(s[i++]))
1461 width++;
1462 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001463 }
1464 }
1465
1466 /* The scroll bar isn't being used */
1467 if (!browser->b.navkeypressed)
1468 width += 1;
1469
1470 ui_browser__write_nstring(&browser->b, "", width);
1471
1472 ++row;
1473 ++printed;
1474
1475show_callchain:
1476 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1477 struct callchain_print_arg carg = {
1478 .row_offset = row_offset,
1479 };
1480
1481 printed += hist_browser__show_callchain(browser, entry,
1482 level + 1, row,
1483 hist_browser__show_callchain_entry, &carg,
1484 hist_browser__check_output_full);
1485 }
1486
1487 return printed;
1488}
1489
Namhyung Kim79dded82016-02-26 21:13:19 +09001490static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001491 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001492{
1493 int width = browser->b.width;
1494 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1495 bool first = true;
1496 int column = 0;
1497 int ret;
1498 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001499 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001500 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001501
1502 if (current_entry) {
1503 browser->he_selection = NULL;
1504 browser->selection = NULL;
1505 }
1506
1507 hist_browser__gotorc(browser, row, 0);
1508
1509 if (current_entry && browser->b.navkeypressed)
1510 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1511 else
1512 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1513
1514 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1515 width -= level * HIERARCHY_INDENT;
1516
Namhyung Kima61a22f2016-03-07 16:44:50 -03001517 /* the first hpp_list_node is for overhead columns */
1518 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1519 struct perf_hpp_list_node, list);
1520 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001521 if (perf_hpp__should_skip(fmt, browser->hists) ||
1522 column++ < browser->b.horiz_scroll)
1523 continue;
1524
Jiri Olsada1b0402016-06-14 20:19:20 +02001525 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001526
1527 if (first) {
1528 /* for folded sign */
1529 first = false;
1530 ret++;
1531 } else {
1532 /* space between columns */
1533 ret += 2;
1534 }
1535
1536 ui_browser__write_nstring(&browser->b, "", ret);
1537 width -= ret;
1538 }
1539
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001540 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1541 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001542
1543 if (column >= browser->b.horiz_scroll) {
1544 char buf[32];
1545
1546 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1547 ui_browser__printf(&browser->b, " %s", buf);
1548 width -= ret + 2;
1549 }
1550
1551 /* The scroll bar isn't being used */
1552 if (!browser->b.navkeypressed)
1553 width += 1;
1554
1555 ui_browser__write_nstring(&browser->b, "", width);
1556 return 1;
1557}
1558
Jiri Olsa81a888f2014-06-14 15:44:52 +02001559static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1560{
1561 advance_hpp(hpp, inc);
1562 return hpp->size <= 0;
1563}
1564
Jiri Olsa69705b32016-08-07 17:28:28 +02001565static int
1566hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1567 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001568{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001569 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001570 struct perf_hpp dummy_hpp = {
1571 .buf = buf,
1572 .size = size,
1573 };
1574 struct perf_hpp_fmt *fmt;
1575 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001576 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001577 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001578
1579 if (symbol_conf.use_callchain) {
1580 ret = scnprintf(buf, size, " ");
1581 if (advance_hpp_check(&dummy_hpp, ret))
1582 return ret;
1583 }
1584
Jiri Olsaf0786af2016-01-18 10:24:23 +01001585 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001586 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001587 continue;
1588
Jiri Olsa29659ab2016-08-07 17:28:30 +02001589 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001590 if (advance_hpp_check(&dummy_hpp, ret))
1591 break;
1592
Jiri Olsa29659ab2016-08-07 17:28:30 +02001593 if (span)
1594 continue;
1595
Jiri Olsa81a888f2014-06-14 15:44:52 +02001596 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1597 if (advance_hpp_check(&dummy_hpp, ret))
1598 break;
1599 }
1600
1601 return ret;
1602}
1603
Namhyung Kimd8b92402016-02-25 00:13:46 +09001604static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1605{
1606 struct hists *hists = browser->hists;
1607 struct perf_hpp dummy_hpp = {
1608 .buf = buf,
1609 .size = size,
1610 };
1611 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001612 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001613 size_t ret = 0;
1614 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001615 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001616 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001617
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001618 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001619 if (advance_hpp_check(&dummy_hpp, ret))
1620 return ret;
1621
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001622 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001623 /* the first hpp_list_node is for overhead columns */
1624 fmt_node = list_first_entry(&hists->hpp_formats,
1625 struct perf_hpp_list_node, list);
1626 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001627 if (column++ < browser->b.horiz_scroll)
1628 continue;
1629
Jiri Olsa29659ab2016-08-07 17:28:30 +02001630 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001631 if (advance_hpp_check(&dummy_hpp, ret))
1632 break;
1633
1634 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1635 if (advance_hpp_check(&dummy_hpp, ret))
1636 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001637
1638 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001639 }
1640
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001641 if (!first_node) {
1642 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1643 indent * HIERARCHY_INDENT, "");
1644 if (advance_hpp_check(&dummy_hpp, ret))
1645 return ret;
1646 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001647
Namhyung Kima61a22f2016-03-07 16:44:50 -03001648 first_node = true;
1649 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1650 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001651 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1652 if (advance_hpp_check(&dummy_hpp, ret))
1653 break;
1654 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001655 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001656
Namhyung Kima61a22f2016-03-07 16:44:50 -03001657 first_col = true;
1658 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1659 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001660
Namhyung Kima61a22f2016-03-07 16:44:50 -03001661 if (perf_hpp__should_skip(fmt, hists))
1662 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001663
Namhyung Kima61a22f2016-03-07 16:44:50 -03001664 if (!first_col) {
1665 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1666 if (advance_hpp_check(&dummy_hpp, ret))
1667 break;
1668 }
1669 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001670
Jiri Olsa29659ab2016-08-07 17:28:30 +02001671 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001672 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001673
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001674 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001675 ret = strlen(start);
1676
1677 if (start != dummy_hpp.buf)
1678 memmove(dummy_hpp.buf, start, ret + 1);
1679
1680 if (advance_hpp_check(&dummy_hpp, ret))
1681 break;
1682 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001683 }
1684
1685 return ret;
1686}
1687
Jiri Olsa01b47702016-06-14 20:19:13 +02001688static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001689{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001690 char headers[1024];
1691
Jiri Olsa01b47702016-06-14 20:19:13 +02001692 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1693 sizeof(headers));
1694
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001695 ui_browser__gotorc(&browser->b, 0, 0);
1696 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001697 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001698}
1699
Jiri Olsa01b47702016-06-14 20:19:13 +02001700static void hists_browser__headers(struct hist_browser *browser)
1701{
Jiri Olsa69705b32016-08-07 17:28:28 +02001702 struct hists *hists = browser->hists;
1703 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001704
Jiri Olsa69705b32016-08-07 17:28:28 +02001705 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001706
Jiri Olsa69705b32016-08-07 17:28:28 +02001707 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1708 char headers[1024];
1709
1710 hists_browser__scnprintf_headers(browser, headers,
1711 sizeof(headers), line);
1712
1713 ui_browser__gotorc(&browser->b, line, 0);
1714 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1715 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1716 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001717}
1718
1719static void hist_browser__show_headers(struct hist_browser *browser)
1720{
1721 if (symbol_conf.report_hierarchy)
1722 hists_browser__hierarchy_headers(browser);
1723 else
1724 hists_browser__headers(browser);
1725}
1726
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001727static void ui_browser__hists_init_top(struct ui_browser *browser)
1728{
1729 if (browser->top == NULL) {
1730 struct hist_browser *hb;
1731
1732 hb = container_of(browser, struct hist_browser, b);
1733 browser->top = rb_first(&hb->hists->entries);
1734 }
1735}
1736
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001737static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001738{
1739 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001740 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001741 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001742 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001743 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001744
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001745 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001746 struct perf_hpp_list *hpp_list = hists->hpp_list;
1747
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001748 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001749 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001750 }
1751
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001752 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001753 hb->he_selection = NULL;
1754 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001755
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001756 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001757 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001758 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001759
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001760 if (h->filtered) {
1761 /* let it move to sibling */
1762 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001763 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001764 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001765
Namhyung Kim14135662013-10-31 10:17:39 +09001766 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001767 if (percent < hb->min_pcnt)
1768 continue;
1769
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001770 if (symbol_conf.report_hierarchy) {
1771 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001772 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001773 if (row == browser->rows)
1774 break;
1775
1776 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001777 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001778 row++;
1779 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001780 } else {
1781 row += hist_browser__show_entry(hb, h, row);
1782 }
1783
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001784 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001785 break;
1786 }
1787
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001788 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001789}
1790
Namhyung Kim064f1982013-05-14 11:09:04 +09001791static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001792 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001793{
1794 while (nd != NULL) {
1795 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001796 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001797
Namhyung Kimc0f15272014-04-16 11:16:33 +09001798 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001799 return nd;
1800
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001801 /*
1802 * If it's filtered, its all children also were filtered.
1803 * So move to sibling node.
1804 */
1805 if (rb_next(nd))
1806 nd = rb_next(nd);
1807 else
1808 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001809 }
1810
1811 return NULL;
1812}
1813
Namhyung Kim064f1982013-05-14 11:09:04 +09001814static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001815 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001816{
1817 while (nd != NULL) {
1818 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001819 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001820
1821 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001822 return nd;
1823
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001824 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001825 }
1826
1827 return NULL;
1828}
1829
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001830static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001831 off_t offset, int whence)
1832{
1833 struct hist_entry *h;
1834 struct rb_node *nd;
1835 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001836 struct hist_browser *hb;
1837
1838 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001839
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001840 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001841 return;
1842
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001843 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001844
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001845 switch (whence) {
1846 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001847 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001848 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001849 break;
1850 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001851 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001852 goto do_offset;
1853 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001854 nd = rb_hierarchy_last(rb_last(browser->entries));
1855 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001856 first = false;
1857 break;
1858 default:
1859 return;
1860 }
1861
1862 /*
1863 * Moves not relative to the first visible entry invalidates its
1864 * row_offset:
1865 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001866 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001867 h->row_offset = 0;
1868
1869 /*
1870 * Here we have to check if nd is expanded (+), if it is we can't go
1871 * the next top level hist_entry, instead we must compute an offset of
1872 * what _not_ to show and not change the first visible entry.
1873 *
1874 * This offset increments when we are going from top to bottom and
1875 * decreases when we're going from bottom to top.
1876 *
1877 * As we don't have backpointers to the top level in the callchains
1878 * structure, we need to always print the whole hist_entry callchain,
1879 * skipping the first ones that are before the first visible entry
1880 * and stop when we printed enough lines to fill the screen.
1881 */
1882do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001883 if (!nd)
1884 return;
1885
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001886 if (offset > 0) {
1887 do {
1888 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001889 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001890 u16 remaining = h->nr_rows - h->row_offset;
1891 if (offset > remaining) {
1892 offset -= remaining;
1893 h->row_offset = 0;
1894 } else {
1895 h->row_offset += offset;
1896 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001897 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001898 break;
1899 }
1900 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001901 nd = hists__filter_entries(rb_hierarchy_next(nd),
1902 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001903 if (nd == NULL)
1904 break;
1905 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001906 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001907 } while (offset != 0);
1908 } else if (offset < 0) {
1909 while (1) {
1910 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001911 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001912 if (first) {
1913 if (-offset > h->row_offset) {
1914 offset += h->row_offset;
1915 h->row_offset = 0;
1916 } else {
1917 h->row_offset += offset;
1918 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001919 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001920 break;
1921 }
1922 } else {
1923 if (-offset > h->nr_rows) {
1924 offset += h->nr_rows;
1925 h->row_offset = 0;
1926 } else {
1927 h->row_offset = h->nr_rows + offset;
1928 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001929 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001930 break;
1931 }
1932 }
1933 }
1934
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001935 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001936 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001937 if (nd == NULL)
1938 break;
1939 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001940 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001941 if (offset == 0) {
1942 /*
1943 * Last unfiltered hist_entry, check if it is
1944 * unfolded, if it is then we should have
1945 * row_offset at its last entry.
1946 */
1947 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001948 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001949 h->row_offset = h->nr_rows;
1950 break;
1951 }
1952 first = false;
1953 }
1954 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001955 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001956 h = rb_entry(nd, struct hist_entry, rb_node);
1957 h->row_offset = 0;
1958 }
1959}
1960
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001961static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001962 struct hist_entry *he, FILE *fp,
1963 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001964{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001965 struct callchain_print_arg arg = {
1966 .fp = fp,
1967 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001968
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001969 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001970 hist_browser__fprintf_callchain_entry, &arg,
1971 hist_browser__check_dump_full);
1972 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001973}
1974
1975static int hist_browser__fprintf_entry(struct hist_browser *browser,
1976 struct hist_entry *he, FILE *fp)
1977{
1978 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001979 int printed = 0;
1980 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001981 struct perf_hpp hpp = {
1982 .buf = s,
1983 .size = sizeof(s),
1984 };
1985 struct perf_hpp_fmt *fmt;
1986 bool first = true;
1987 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001988
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001989 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001990 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001991 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001992 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001993
Jiri Olsaf0786af2016-01-18 10:24:23 +01001994 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001995 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001996 continue;
1997
Namhyung Kim26d8b332014-03-03 16:16:20 +09001998 if (!first) {
1999 ret = scnprintf(hpp.buf, hpp.size, " ");
2000 advance_hpp(&hpp, ret);
2001 } else
2002 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002003
Namhyung Kim26d8b332014-03-03 16:16:20 +09002004 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002005 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002006 advance_hpp(&hpp, ret);
2007 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002008 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002009
2010 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002011 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2012
2013 return printed;
2014}
2015
2016
2017static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2018 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002019 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002020{
2021 char s[8192];
2022 int printed = 0;
2023 char folded_sign = ' ';
2024 struct perf_hpp hpp = {
2025 .buf = s,
2026 .size = sizeof(s),
2027 };
2028 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002029 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002030 bool first = true;
2031 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002032 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002033
2034 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2035
2036 folded_sign = hist_entry__folded(he);
2037 printed += fprintf(fp, "%c", folded_sign);
2038
Namhyung Kim325a6282016-03-09 22:47:00 +09002039 /* the first hpp_list_node is for overhead columns */
2040 fmt_node = list_first_entry(&he->hists->hpp_formats,
2041 struct perf_hpp_list_node, list);
2042 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002043 if (!first) {
2044 ret = scnprintf(hpp.buf, hpp.size, " ");
2045 advance_hpp(&hpp, ret);
2046 } else
2047 first = false;
2048
2049 ret = fmt->entry(fmt, &hpp, he);
2050 advance_hpp(&hpp, ret);
2051 }
2052
2053 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2054 advance_hpp(&hpp, ret);
2055
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002056 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2057 ret = scnprintf(hpp.buf, hpp.size, " ");
2058 advance_hpp(&hpp, ret);
2059
2060 ret = fmt->entry(fmt, &hpp, he);
2061 advance_hpp(&hpp, ret);
2062 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002063
2064 printed += fprintf(fp, "%s\n", rtrim(s));
2065
2066 if (he->leaf && folded_sign == '-') {
2067 printed += hist_browser__fprintf_callchain(browser, he, fp,
2068 he->depth + 1);
2069 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002070
2071 return printed;
2072}
2073
2074static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2075{
Namhyung Kim064f1982013-05-14 11:09:04 +09002076 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002077 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002078 int printed = 0;
2079
2080 while (nd) {
2081 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2082
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002083 if (symbol_conf.report_hierarchy) {
2084 printed += hist_browser__fprintf_hierarchy_entry(browser,
2085 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002086 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002087 } else {
2088 printed += hist_browser__fprintf_entry(browser, h, fp);
2089 }
2090
2091 nd = hists__filter_entries(rb_hierarchy_next(nd),
2092 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002093 }
2094
2095 return printed;
2096}
2097
2098static int hist_browser__dump(struct hist_browser *browser)
2099{
2100 char filename[64];
2101 FILE *fp;
2102
2103 while (1) {
2104 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2105 if (access(filename, F_OK))
2106 break;
2107 /*
2108 * XXX: Just an arbitrary lazy upper limit
2109 */
2110 if (++browser->print_seq == 8192) {
2111 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2112 return -1;
2113 }
2114 }
2115
2116 fp = fopen(filename, "w");
2117 if (fp == NULL) {
2118 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002119 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002120 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002121 return -1;
2122 }
2123
2124 ++browser->print_seq;
2125 hist_browser__fprintf(browser, fp);
2126 fclose(fp);
2127 ui_helpline__fpush("%s written!", filename);
2128
2129 return 0;
2130}
2131
Jiri Olsafcd86422016-06-20 23:58:18 +02002132void hist_browser__init(struct hist_browser *browser,
2133 struct hists *hists)
2134{
2135 struct perf_hpp_fmt *fmt;
2136
2137 browser->hists = hists;
2138 browser->b.refresh = hist_browser__refresh;
2139 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2140 browser->b.seek = ui_browser__hists_seek;
2141 browser->b.use_navkeypressed = true;
2142 browser->show_headers = symbol_conf.show_hist_headers;
2143
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002144 if (symbol_conf.report_hierarchy) {
2145 struct perf_hpp_list_node *fmt_node;
2146
2147 /* count overhead columns (in the first node) */
2148 fmt_node = list_first_entry(&hists->hpp_formats,
2149 struct perf_hpp_list_node, list);
2150 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2151 ++browser->b.columns;
2152
2153 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002154 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002155 } else {
2156 hists__for_each_format(hists, fmt)
2157 ++browser->b.columns;
2158 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002159
2160 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002161}
2162
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002163struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002164{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002165 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002166
Jiri Olsafcd86422016-06-20 23:58:18 +02002167 if (browser)
2168 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002169
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002170 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002171}
2172
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002173static struct hist_browser *
2174perf_evsel_browser__new(struct perf_evsel *evsel,
2175 struct hist_browser_timer *hbt,
2176 struct perf_env *env)
2177{
2178 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2179
2180 if (browser) {
2181 browser->hbt = hbt;
2182 browser->env = env;
2183 browser->title = perf_evsel_browser_title;
2184 }
2185 return browser;
2186}
2187
Jiri Olsadabd2012016-06-20 23:58:14 +02002188void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002189{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002190 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002191}
2192
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002193static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002194{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002195 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002196}
2197
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002198static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002199{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002200 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002201}
2202
Taeung Song1e378eb2014-10-07 16:13:15 +09002203/* Check whether the browser is for 'top' or 'report' */
2204static inline bool is_report_browser(void *timer)
2205{
2206 return timer == NULL;
2207}
2208
Jiri Olsa5b91a862016-06-20 23:58:15 +02002209static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002210 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002211{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002212 struct hist_browser_timer *hbt = browser->hbt;
2213 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002214 char unit;
2215 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002216 const struct dso *dso = hists->dso_filter;
2217 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002218 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002219 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2220 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002221 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002222 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002223 char buf[512];
2224 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002225 char ref[30] = " show reference callgraph, ";
2226 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002227
Namhyung Kimf2148332014-01-14 11:52:48 +09002228 if (symbol_conf.filter_relative) {
2229 nr_samples = hists->stats.nr_non_filtered_samples;
2230 nr_events = hists->stats.total_non_filtered_period;
2231 }
2232
Namhyung Kim759ff492013-03-05 14:53:26 +09002233 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002234 struct perf_evsel *pos;
2235
2236 perf_evsel__group_desc(evsel, buf, buflen);
2237 ev_name = buf;
2238
2239 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002240 struct hists *pos_hists = evsel__hists(pos);
2241
Namhyung Kimf2148332014-01-14 11:52:48 +09002242 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002243 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2244 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002245 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002246 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2247 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002248 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002249 }
2250 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002251
Kan Liang9e207dd2015-08-11 06:30:49 -04002252 if (symbol_conf.show_ref_callgraph &&
2253 strstr(ev_name, "call-graph=no"))
2254 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002255 nr_samples = convert_unit(nr_samples, &unit);
2256 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002257 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2258 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002259
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002260
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002261 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002262 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002263 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002264 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002265 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002266 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002267 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002268 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002269 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002270 } else {
2271 printed += scnprintf(bf + printed, size - printed,
2272 ", Thread: %s",
2273 (thread->comm_set ? thread__comm_str(thread) : ""));
2274 }
2275 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002276 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002277 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002278 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002279 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002280 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002281 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002282 if (!is_report_browser(hbt)) {
2283 struct perf_top *top = hbt->arg;
2284
2285 if (top->zero)
2286 printed += scnprintf(bf + printed, size - printed, " [z]");
2287 }
2288
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002289 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002290}
2291
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002292static inline void free_popup_options(char **options, int n)
2293{
2294 int i;
2295
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002296 for (i = 0; i < n; ++i)
2297 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002298}
2299
Feng Tang341487ab2013-02-03 14:38:20 +08002300/*
2301 * Only runtime switching of perf data file will make "input_name" point
2302 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2303 * whether we need to call free() for current "input_name" during the switch.
2304 */
2305static bool is_input_name_malloced = false;
2306
2307static int switch_data_file(void)
2308{
2309 char *pwd, *options[32], *abs_path[32], *tmp;
2310 DIR *pwd_dir;
2311 int nr_options = 0, choice = -1, ret = -1;
2312 struct dirent *dent;
2313
2314 pwd = getenv("PWD");
2315 if (!pwd)
2316 return ret;
2317
2318 pwd_dir = opendir(pwd);
2319 if (!pwd_dir)
2320 return ret;
2321
2322 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002323 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002324
2325 while ((dent = readdir(pwd_dir))) {
2326 char path[PATH_MAX];
2327 u64 magic;
2328 char *name = dent->d_name;
2329 FILE *file;
2330
2331 if (!(dent->d_type == DT_REG))
2332 continue;
2333
2334 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2335
2336 file = fopen(path, "r");
2337 if (!file)
2338 continue;
2339
2340 if (fread(&magic, 1, 8, file) < 8)
2341 goto close_file_and_continue;
2342
2343 if (is_perf_magic(magic)) {
2344 options[nr_options] = strdup(name);
2345 if (!options[nr_options])
2346 goto close_file_and_continue;
2347
2348 abs_path[nr_options] = strdup(path);
2349 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002350 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002351 ui__warning("Can't search all data files due to memory shortage.\n");
2352 fclose(file);
2353 break;
2354 }
2355
2356 nr_options++;
2357 }
2358
2359close_file_and_continue:
2360 fclose(file);
2361 if (nr_options >= 32) {
2362 ui__warning("Too many perf data files in PWD!\n"
2363 "Only the first 32 files will be listed.\n");
2364 break;
2365 }
2366 }
2367 closedir(pwd_dir);
2368
2369 if (nr_options) {
2370 choice = ui__popup_menu(nr_options, options);
2371 if (choice < nr_options && choice >= 0) {
2372 tmp = strdup(abs_path[choice]);
2373 if (tmp) {
2374 if (is_input_name_malloced)
2375 free((void *)input_name);
2376 input_name = tmp;
2377 is_input_name_malloced = true;
2378 ret = 0;
2379 } else
2380 ui__warning("Data switch failed due to memory shortage!\n");
2381 }
2382 }
2383
2384 free_popup_options(options, nr_options);
2385 free_popup_options(abs_path, nr_options);
2386 return ret;
2387}
2388
Namhyung Kimea7cd592015-04-22 16:18:19 +09002389struct popup_action {
2390 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002391 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002392 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002393
2394 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2395};
2396
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002397static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002398do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002399{
2400 struct perf_evsel *evsel;
2401 struct annotation *notes;
2402 struct hist_entry *he;
2403 int err;
2404
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002405 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002406 return 0;
2407
Namhyung Kimea7cd592015-04-22 16:18:19 +09002408 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002409 if (!notes->src)
2410 return 0;
2411
2412 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002413 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002414 he = hist_browser__selected_entry(browser);
2415 /*
2416 * offer option to annotate the other branch source or target
2417 * (if they exists) when returning from annotate
2418 */
2419 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2420 return 1;
2421
2422 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2423 if (err)
2424 ui_browser__handle_resize(&browser->b);
2425 return 0;
2426}
2427
2428static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002429add_annotate_opt(struct hist_browser *browser __maybe_unused,
2430 struct popup_action *act, char **optstr,
2431 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002432{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002433 if (sym == NULL || map->dso->annotate_warned)
2434 return 0;
2435
2436 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2437 return 0;
2438
2439 act->ms.map = map;
2440 act->ms.sym = sym;
2441 act->fn = do_annotate;
2442 return 1;
2443}
2444
2445static int
2446do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2447{
2448 struct thread *thread = act->thread;
2449
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002450 if ((!hists__has(browser->hists, thread) &&
2451 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002452 return 0;
2453
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002454 if (browser->hists->thread_filter) {
2455 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2456 perf_hpp__set_elide(HISTC_THREAD, false);
2457 thread__zput(browser->hists->thread_filter);
2458 ui_helpline__pop();
2459 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002460 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002461 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2462 thread->comm_set ? thread__comm_str(thread) : "",
2463 thread->tid);
2464 } else {
2465 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2466 thread->comm_set ? thread__comm_str(thread) : "");
2467 }
2468
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002469 browser->hists->thread_filter = thread__get(thread);
2470 perf_hpp__set_elide(HISTC_THREAD, false);
2471 pstack__push(browser->pstack, &browser->hists->thread_filter);
2472 }
2473
2474 hists__filter_by_thread(browser->hists);
2475 hist_browser__reset(browser);
2476 return 0;
2477}
2478
2479static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002480add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2481 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002482{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002483 int ret;
2484
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002485 if ((!hists__has(browser->hists, thread) &&
2486 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002487 return 0;
2488
Jiri Olsafa829112016-05-03 13:54:47 +02002489 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002490 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2491 browser->hists->thread_filter ? "out of" : "into",
2492 thread->comm_set ? thread__comm_str(thread) : "",
2493 thread->tid);
2494 } else {
2495 ret = asprintf(optstr, "Zoom %s %s thread",
2496 browser->hists->thread_filter ? "out of" : "into",
2497 thread->comm_set ? thread__comm_str(thread) : "");
2498 }
2499 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002500 return 0;
2501
2502 act->thread = thread;
2503 act->fn = do_zoom_thread;
2504 return 1;
2505}
2506
2507static int
2508do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2509{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002510 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002511
Jiri Olsa69849fc2016-05-03 13:54:45 +02002512 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002513 return 0;
2514
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002515 if (browser->hists->dso_filter) {
2516 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2517 perf_hpp__set_elide(HISTC_DSO, false);
2518 browser->hists->dso_filter = NULL;
2519 ui_helpline__pop();
2520 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002521 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002522 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2523 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002524 perf_hpp__set_elide(HISTC_DSO, true);
2525 pstack__push(browser->pstack, &browser->hists->dso_filter);
2526 }
2527
2528 hists__filter_by_dso(browser->hists);
2529 hist_browser__reset(browser);
2530 return 0;
2531}
2532
2533static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002534add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002535 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002536{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002537 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002538 return 0;
2539
2540 if (asprintf(optstr, "Zoom %s %s DSO",
2541 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002542 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002543 return 0;
2544
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002545 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002546 act->fn = do_zoom_dso;
2547 return 1;
2548}
2549
2550static int
2551do_browse_map(struct hist_browser *browser __maybe_unused,
2552 struct popup_action *act)
2553{
2554 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002555 return 0;
2556}
2557
2558static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002559add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002560 struct popup_action *act, char **optstr, struct map *map)
2561{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002562 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002563 return 0;
2564
2565 if (asprintf(optstr, "Browse map details") < 0)
2566 return 0;
2567
2568 act->ms.map = map;
2569 act->fn = do_browse_map;
2570 return 1;
2571}
2572
2573static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002574do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002575 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002576{
2577 char script_opt[64];
2578 memset(script_opt, 0, sizeof(script_opt));
2579
Namhyung Kimea7cd592015-04-22 16:18:19 +09002580 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002581 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002582 thread__comm_str(act->thread));
2583 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002584 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002585 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002586 }
2587
2588 script_browse(script_opt);
2589 return 0;
2590}
2591
2592static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002593add_script_opt(struct hist_browser *browser __maybe_unused,
2594 struct popup_action *act, char **optstr,
2595 struct thread *thread, struct symbol *sym)
2596{
2597 if (thread) {
2598 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2599 thread__comm_str(thread)) < 0)
2600 return 0;
2601 } else if (sym) {
2602 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2603 sym->name) < 0)
2604 return 0;
2605 } else {
2606 if (asprintf(optstr, "Run scripts for all samples") < 0)
2607 return 0;
2608 }
2609
2610 act->thread = thread;
2611 act->ms.sym = sym;
2612 act->fn = do_run_script;
2613 return 1;
2614}
2615
2616static int
2617do_switch_data(struct hist_browser *browser __maybe_unused,
2618 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002619{
2620 if (switch_data_file()) {
2621 ui__warning("Won't switch the data files due to\n"
2622 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002623 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002624 }
2625
2626 return K_SWITCH_INPUT_DATA;
2627}
2628
Namhyung Kimea7cd592015-04-22 16:18:19 +09002629static int
2630add_switch_opt(struct hist_browser *browser,
2631 struct popup_action *act, char **optstr)
2632{
2633 if (!is_report_browser(browser->hbt))
2634 return 0;
2635
2636 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2637 return 0;
2638
2639 act->fn = do_switch_data;
2640 return 1;
2641}
2642
2643static int
2644do_exit_browser(struct hist_browser *browser __maybe_unused,
2645 struct popup_action *act __maybe_unused)
2646{
2647 return 0;
2648}
2649
2650static int
2651add_exit_opt(struct hist_browser *browser __maybe_unused,
2652 struct popup_action *act, char **optstr)
2653{
2654 if (asprintf(optstr, "Exit") < 0)
2655 return 0;
2656
2657 act->fn = do_exit_browser;
2658 return 1;
2659}
2660
Kan Liang84734b02015-09-04 10:45:45 -04002661static int
2662do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2663{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002664 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002665 return 0;
2666
Kan Liang84734b02015-09-04 10:45:45 -04002667 if (browser->hists->socket_filter > -1) {
2668 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2669 browser->hists->socket_filter = -1;
2670 perf_hpp__set_elide(HISTC_SOCKET, false);
2671 } else {
2672 browser->hists->socket_filter = act->socket;
2673 perf_hpp__set_elide(HISTC_SOCKET, true);
2674 pstack__push(browser->pstack, &browser->hists->socket_filter);
2675 }
2676
2677 hists__filter_by_socket(browser->hists);
2678 hist_browser__reset(browser);
2679 return 0;
2680}
2681
2682static int
2683add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2684 char **optstr, int socket_id)
2685{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002686 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002687 return 0;
2688
2689 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2690 (browser->hists->socket_filter > -1) ? "out of" : "into",
2691 socket_id) < 0)
2692 return 0;
2693
2694 act->socket = socket_id;
2695 act->fn = do_zoom_socket;
2696 return 1;
2697}
2698
Namhyung Kim112f7612014-04-22 14:05:35 +09002699static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002700{
2701 u64 nr_entries = 0;
2702 struct rb_node *nd = rb_first(&hb->hists->entries);
2703
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002704 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002705 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2706 return;
2707 }
2708
Namhyung Kim14135662013-10-31 10:17:39 +09002709 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002710 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002711 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002712 }
2713
Namhyung Kim112f7612014-04-22 14:05:35 +09002714 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002715 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002716}
Feng Tang341487ab2013-02-03 14:38:20 +08002717
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002718static void hist_browser__update_percent_limit(struct hist_browser *hb,
2719 double percent)
2720{
2721 struct hist_entry *he;
2722 struct rb_node *nd = rb_first(&hb->hists->entries);
2723 u64 total = hists__total_period(hb->hists);
2724 u64 min_callchain_hits = total * (percent / 100);
2725
2726 hb->min_pcnt = callchain_param.min_percent = percent;
2727
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002728 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2729 he = rb_entry(nd, struct hist_entry, rb_node);
2730
Namhyung Kim79dded82016-02-26 21:13:19 +09002731 if (he->has_no_entry) {
2732 he->has_no_entry = false;
2733 he->nr_rows = 0;
2734 }
2735
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002736 if (!he->leaf || !symbol_conf.use_callchain)
2737 goto next;
2738
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002739 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2740 total = he->stat.period;
2741
2742 if (symbol_conf.cumulate_callchain)
2743 total = he->stat_acc->period;
2744
2745 min_callchain_hits = total * (percent / 100);
2746 }
2747
2748 callchain_param.sort(&he->sorted_chain, he->callchain,
2749 min_callchain_hits, &callchain_param);
2750
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002751next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002752 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002753
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002754 /* force to re-evaluate folding state of callchains */
2755 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002756 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002757 }
2758}
2759
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002760static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002761 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002762 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002763 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002764 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002765 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002766{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002767 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002768 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002769 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002770#define MAX_OPTIONS 16
2771 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002772 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002773 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002774 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002775 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002776 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002777
Namhyung Kime8e684a2013-12-26 14:37:58 +09002778#define HIST_BROWSER_HELP_COMMON \
2779 "h/?/F1 Show this window\n" \
2780 "UP/DOWN/PGUP\n" \
2781 "PGDN/SPACE Navigate\n" \
2782 "q/ESC/CTRL+C Exit browser\n\n" \
2783 "For multiple event sessions:\n\n" \
2784 "TAB/UNTAB Switch events\n\n" \
2785 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002786 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2787 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002788 "a Annotate current symbol\n" \
2789 "C Collapse all callchains\n" \
2790 "d Zoom into current DSO\n" \
2791 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002792 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002793 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002794 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002795 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002796 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002797
2798 /* help messages are sorted by lexical order of the hotkey */
2799 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002800 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002801 "P Print histograms to perf.hist.N\n"
2802 "r Run available scripts\n"
2803 "s Switch to another data file in PWD\n"
2804 "t Zoom into current Thread\n"
2805 "V Verbose (DSO names in callchains, etc)\n"
2806 "/ Filter symbol by name";
2807 const char top_help[] = HIST_BROWSER_HELP_COMMON
2808 "P Print histograms to perf.hist.N\n"
2809 "t Zoom into current Thread\n"
2810 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002811 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002812 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002813 "/ Filter symbol by name";
2814
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002815 if (browser == NULL)
2816 return -1;
2817
Namhyung Kimed426912015-05-29 21:53:44 +09002818 /* reset abort key so that it can get Ctrl-C as a key */
2819 SLang_reset_tty();
2820 SLang_init_tty(0, 0, 0);
2821
Namhyung Kim03905042015-11-28 02:32:39 +09002822 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002823 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002824 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002825
Kan Liang84734b02015-09-04 10:45:45 -04002826 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002827 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002828 goto out;
2829
2830 ui_helpline__push(helpline);
2831
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002832 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002833 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002834
Namhyung Kim5b591662014-07-31 14:47:38 +09002835 if (symbol_conf.col_width_list_str)
2836 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2837
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002838 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002839 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002840 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002841 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002842 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002843
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002844 nr_options = 0;
2845
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002846 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002847
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002848 if (browser->he_selection != NULL) {
2849 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002850 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002851 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002852 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002853 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002854 case K_TAB:
2855 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002856 if (nr_events == 1)
2857 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002858 /*
2859 * Exit the browser, let hists__browser_tree
2860 * go to the next or previous
2861 */
2862 goto out_free_stack;
2863 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002864 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002865 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002866 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002867 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002868 continue;
2869 }
2870
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002871 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002872 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002873 browser->selection->map->dso->annotate_warned)
2874 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002875
Namhyung Kimea7cd592015-04-22 16:18:19 +09002876 actions->ms.map = browser->selection->map;
2877 actions->ms.sym = browser->selection->sym;
2878 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002879 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002880 case 'P':
2881 hist_browser__dump(browser);
2882 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002883 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002884 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002885 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002886 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002887 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02002888 verbose = (verbose + 1) % 4;
2889 browser->show_dso = verbose > 0;
2890 ui_helpline__fpush("Verbosity level set to %d\n",
2891 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002892 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002893 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002894 actions->thread = thread;
2895 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002896 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002897 case 'S':
2898 actions->socket = socked_id;
2899 do_zoom_socket(browser, actions);
2900 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002901 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002902 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03002903 "Please enter the name of symbol you want to see.\n"
2904 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002905 buf, "ENTER: OK, ESC: Cancel",
2906 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002907 hists->symbol_filter_str = *buf ? buf : NULL;
2908 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002909 hist_browser__reset(browser);
2910 }
2911 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002912 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002913 if (is_report_browser(hbt)) {
2914 actions->thread = NULL;
2915 actions->ms.sym = NULL;
2916 do_run_script(browser, actions);
2917 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002918 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002919 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002920 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002921 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002922 if (key == K_SWITCH_INPUT_DATA)
2923 goto out_free_stack;
2924 }
Feng Tang341487ab2013-02-03 14:38:20 +08002925 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002926 case 'i':
2927 /* env->arch is NULL for live-mode (i.e. perf top) */
2928 if (env->arch)
2929 tui__header_window(env);
2930 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002931 case 'F':
2932 symbol_conf.filter_relative ^= 1;
2933 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002934 case 'z':
2935 if (!is_report_browser(hbt)) {
2936 struct perf_top *top = hbt->arg;
2937
2938 top->zero = !top->zero;
2939 }
2940 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002941 case 'L':
2942 if (ui_browser__input_window("Percent Limit",
2943 "Please enter the value you want to hide entries under that percent.",
2944 buf, "ENTER: OK, ESC: Cancel",
2945 delay_secs * 2) == K_ENTER) {
2946 char *end;
2947 double new_percent = strtod(buf, &end);
2948
2949 if (new_percent < 0 || new_percent > 100) {
2950 ui_browser__warning(&browser->b, delay_secs * 2,
2951 "Invalid percent: %.2f", new_percent);
2952 continue;
2953 }
2954
2955 hist_browser__update_percent_limit(browser, new_percent);
2956 hist_browser__reset(browser);
2957 }
2958 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002959 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002960 case 'h':
2961 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002962 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002963 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002964 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002965 case K_ENTER:
2966 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002967 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002968 /* menu */
2969 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002970 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002971 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002972 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002973
Namhyung Kim01f00a12015-04-22 16:18:16 +09002974 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002975 /*
2976 * Go back to the perf_evsel_menu__run or other user
2977 */
2978 if (left_exits)
2979 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002980
2981 if (key == K_ESC &&
2982 ui_browser__dialog_yesno(&browser->b,
2983 "Do you really want to exit?"))
2984 goto out_free_stack;
2985
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002986 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002987 }
Namhyung Kim64221842015-04-24 10:15:33 +09002988 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002989 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002990 /*
2991 * No need to set actions->dso here since
2992 * it's just to remove the current filter.
2993 * Ditto for thread below.
2994 */
2995 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002996 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002997 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002998 } else if (top == &browser->hists->socket_filter) {
2999 do_zoom_socket(browser, actions);
3000 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003001 continue;
3002 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003003 case 'q':
3004 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003005 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003006 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003007 if (!is_report_browser(hbt)) {
3008 struct perf_top *top = hbt->arg;
3009
3010 perf_evlist__toggle_enable(top->evlist);
3011 /*
3012 * No need to refresh, resort/decay histogram
3013 * entries if we are not collecting samples:
3014 */
3015 if (top->evlist->enabled) {
3016 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3017 hbt->refresh = delay_secs;
3018 } else {
3019 helpline = "Press 'f' again to re-enable the events";
3020 hbt->refresh = 0;
3021 }
3022 continue;
3023 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003024 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003025 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003026 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003027 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003028 }
3029
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003030 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003031 goto skip_annotation;
3032
Namhyung Kim55369fc2013-04-01 20:35:20 +09003033 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003034 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003035
3036 if (bi == NULL)
3037 goto skip_annotation;
3038
Namhyung Kimea7cd592015-04-22 16:18:19 +09003039 nr_options += add_annotate_opt(browser,
3040 &actions[nr_options],
3041 &options[nr_options],
3042 bi->from.map,
3043 bi->from.sym);
3044 if (bi->to.sym != bi->from.sym)
3045 nr_options += add_annotate_opt(browser,
3046 &actions[nr_options],
3047 &options[nr_options],
3048 bi->to.map,
3049 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003050 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003051 nr_options += add_annotate_opt(browser,
3052 &actions[nr_options],
3053 &options[nr_options],
3054 browser->selection->map,
3055 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003056 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003057skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003058 nr_options += add_thread_opt(browser, &actions[nr_options],
3059 &options[nr_options], thread);
3060 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003061 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003062 nr_options += add_map_opt(browser, &actions[nr_options],
3063 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003064 browser->selection ?
3065 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003066 nr_options += add_socket_opt(browser, &actions[nr_options],
3067 &options[nr_options],
3068 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003069 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003070 if (!is_report_browser(hbt))
3071 goto skip_scripting;
3072
Feng Tangcdbab7c2012-10-30 11:56:06 +08003073 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003074 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003075 nr_options += add_script_opt(browser,
3076 &actions[nr_options],
3077 &options[nr_options],
3078 thread, NULL);
3079 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003080 /*
3081 * Note that browser->selection != NULL
3082 * when browser->he_selection is not NULL,
3083 * so we don't need to check browser->selection
3084 * before fetching browser->selection->sym like what
3085 * we do before fetching browser->selection->map.
3086 *
3087 * See hist_browser__show_entry.
3088 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003089 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003090 nr_options += add_script_opt(browser,
3091 &actions[nr_options],
3092 &options[nr_options],
3093 NULL, browser->selection->sym);
3094 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003095 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003096 nr_options += add_script_opt(browser, &actions[nr_options],
3097 &options[nr_options], NULL, NULL);
3098 nr_options += add_switch_opt(browser, &actions[nr_options],
3099 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003100skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003101 nr_options += add_exit_opt(browser, &actions[nr_options],
3102 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003103
Namhyung Kimea7cd592015-04-22 16:18:19 +09003104 do {
3105 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003106
Namhyung Kimea7cd592015-04-22 16:18:19 +09003107 choice = ui__popup_menu(nr_options, options);
3108 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003109 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003110
3111 act = &actions[choice];
3112 key = act->fn(browser, act);
3113 } while (key == 1);
3114
3115 if (key == K_SWITCH_INPUT_DATA)
3116 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003117 }
3118out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003119 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003120out:
3121 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003122 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003123 return key;
3124}
3125
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003126struct perf_evsel_menu {
3127 struct ui_browser b;
3128 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003129 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003130 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003131 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003132};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003133
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003134static void perf_evsel_menu__write(struct ui_browser *browser,
3135 void *entry, int row)
3136{
3137 struct perf_evsel_menu *menu = container_of(browser,
3138 struct perf_evsel_menu, b);
3139 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003140 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003141 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003142 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003143 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003144 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003145 const char *warn = " ";
3146 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003147
3148 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3149 HE_COLORSET_NORMAL);
3150
Namhyung Kim759ff492013-03-05 14:53:26 +09003151 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003152 struct perf_evsel *pos;
3153
3154 ev_name = perf_evsel__group_name(evsel);
3155
3156 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003157 struct hists *pos_hists = evsel__hists(pos);
3158 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003159 }
3160 }
3161
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003162 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003163 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003164 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003165 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003166
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003167 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003168 if (nr_events != 0) {
3169 menu->lost_events = true;
3170 if (!current_entry)
3171 ui_browser__set_color(browser, HE_COLORSET_TOP);
3172 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003173 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3174 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003175 warn = bf;
3176 }
3177
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003178 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003179
3180 if (current_entry)
3181 menu->selection = evsel;
3182}
3183
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003184static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3185 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003186 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003187{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003188 struct perf_evlist *evlist = menu->b.priv;
3189 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003190 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003191 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003192 int key;
3193
3194 if (ui_browser__show(&menu->b, title,
3195 "ESC: exit, ENTER|->: Browse histograms") < 0)
3196 return -1;
3197
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003198 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003199 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003200
3201 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003202 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003203 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003204
3205 if (!menu->lost_events_warned && menu->lost_events) {
3206 ui_browser__warn_lost_events(&menu->b);
3207 menu->lost_events_warned = true;
3208 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003209 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003210 case K_RIGHT:
3211 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003212 if (!menu->selection)
3213 continue;
3214 pos = menu->selection;
3215browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003216 perf_evlist__set_selected(evlist, pos);
3217 /*
3218 * Give the calling tool a chance to populate the non
3219 * default evsel resorted hists tree.
3220 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003221 if (hbt)
3222 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003223 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003224 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003225 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003226 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003227 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003228 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003229 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003230 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003231 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003232 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003233 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003234 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003235 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003236 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003237 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003238 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003239 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003240 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003241 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003242 case 'q':
3243 case CTRL('c'):
3244 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003245 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003246 default:
3247 continue;
3248 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003249 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003250 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003251 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003252 if (!ui_browser__dialog_yesno(&menu->b,
3253 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003254 continue;
3255 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003256 case 'q':
3257 case CTRL('c'):
3258 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003259 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003260 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003261 }
3262 }
3263
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003264out:
3265 ui_browser__hide(&menu->b);
3266 return key;
3267}
3268
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003269static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003270 void *entry)
3271{
3272 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3273
3274 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3275 return true;
3276
3277 return false;
3278}
3279
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003280static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003281 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003282 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003283 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003284 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003285{
3286 struct perf_evsel *pos;
3287 struct perf_evsel_menu menu = {
3288 .b = {
3289 .entries = &evlist->entries,
3290 .refresh = ui_browser__list_head_refresh,
3291 .seek = ui_browser__list_head_seek,
3292 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003293 .filter = filter_group_entries,
3294 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003295 .priv = evlist,
3296 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003297 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003298 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003299 };
3300
3301 ui_helpline__push("Press ESC to exit");
3302
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003303 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003304 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003305 size_t line_len = strlen(ev_name) + 7;
3306
3307 if (menu.b.width < line_len)
3308 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003309 }
3310
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003311 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003312}
3313
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003314int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003315 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003316 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003317 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003318{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003319 int nr_entries = evlist->nr_entries;
3320
3321single_entry:
3322 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003323 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003324
3325 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003326 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003327 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003328 }
3329
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003330 if (symbol_conf.event_group) {
3331 struct perf_evsel *pos;
3332
3333 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003334 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003335 if (perf_evsel__is_group_leader(pos))
3336 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003337 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003338
3339 if (nr_entries == 1)
3340 goto single_entry;
3341 }
3342
3343 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003344 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003345}