blob: a81b298b79f98bfe988973bb980ac4d1a2ba9640 [file] [log] [blame]
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002#include <stdlib.h>
3#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <linux/rbtree.h>
5
Namhyung Kimaca7a942012-04-04 00:14:26 -07006#include "../../util/evsel.h"
7#include "../../util/evlist.h"
8#include "../../util/hist.h"
9#include "../../util/pstack.h"
10#include "../../util/sort.h"
11#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090012#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090013#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030014
Jiri Olsaf7589902016-06-20 23:58:13 +020015#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030016#include "../helpline.h"
17#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020018#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030019#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020020#include "annotate.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030021
Namhyung Kimf5951d52012-09-03 11:53:09 +090022extern void hist_browser__init_hpp(void);
23
Jiri Olsa5b91a862016-06-20 23:58:15 +020024static int perf_evsel_browser_title(struct hist_browser *browser,
25 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090026static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030027
Namhyung Kimc3b78952014-04-22 15:56:17 +090028static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090029 float min_pcnt);
30
Namhyung Kim268397c2014-04-22 14:49:31 +090031static bool hist_browser__has_filter(struct hist_browser *hb)
32{
Arnaldo Carvalho de Melo9c0fa8d2015-07-13 08:26:35 -030033 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090034}
35
He Kuang4fabf3d2015-03-12 15:21:49 +080036static int hist_browser__get_folding(struct hist_browser *browser)
37{
38 struct rb_node *nd;
39 struct hists *hists = browser->hists;
40 int unfolded_rows = 0;
41
42 for (nd = rb_first(&hists->entries);
43 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090044 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080045 struct hist_entry *he =
46 rb_entry(nd, struct hist_entry, rb_node);
47
Namhyung Kimf5b763f2016-02-25 00:13:43 +090048 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080049 unfolded_rows += he->nr_rows;
50 }
51 return unfolded_rows;
52}
53
Namhyung Kimc3b78952014-04-22 15:56:17 +090054static u32 hist_browser__nr_entries(struct hist_browser *hb)
55{
56 u32 nr_entries;
57
Namhyung Kimf5b763f2016-02-25 00:13:43 +090058 if (symbol_conf.report_hierarchy)
59 nr_entries = hb->nr_hierarchy_entries;
60 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090061 nr_entries = hb->nr_non_filtered_entries;
62 else
63 nr_entries = hb->hists->nr_entries;
64
He Kuang4fabf3d2015-03-12 15:21:49 +080065 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090066 return nr_entries + hb->nr_callchain_rows;
67}
68
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020069static void hist_browser__update_rows(struct hist_browser *hb)
70{
71 struct ui_browser *browser = &hb->b;
72 u16 header_offset = hb->show_headers ? 1 : 0, index_row;
73
74 browser->rows = browser->height - header_offset;
75 /*
76 * Verify if we were at the last line and that line isn't
77 * visibe because we now show the header line(s).
78 */
79 index_row = browser->index - browser->top_idx;
80 if (index_row >= browser->rows)
81 browser->index -= index_row - browser->rows + 1;
82}
83
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030084static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030085{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030086 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
87
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030088 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030089 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
90 /*
91 * FIXME: Just keeping existing behaviour, but this really should be
92 * before updating browser->width, as it will invalidate the
93 * calculation above. Fix this and the fallout in another
94 * changeset.
95 */
96 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020097 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030098}
99
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300100static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
101{
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200102 u16 header_offset = browser->show_headers ? 1 : 0;
103
104 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300105}
106
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300107static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300108{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900109 /*
110 * The hists__remove_entry_filter() already folds non-filtered
111 * entries so we can assume it has 0 callchain rows.
112 */
113 browser->nr_callchain_rows = 0;
114
Namhyung Kim268397c2014-04-22 14:49:31 +0900115 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900116 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300117 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300118 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300119}
120
121static char tree__folded_sign(bool unfolded)
122{
123 return unfolded ? '-' : '+';
124}
125
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300126static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300127{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900128 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300129}
130
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300131static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300132{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900133 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300134}
135
Namhyung Kim3698dab2015-05-05 23:55:46 +0900136static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300137{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900138 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300139}
140
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300141static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300142{
143 int n = 0;
144 struct rb_node *nd;
145
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300146 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300147 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
148 struct callchain_list *chain;
149 char folded_sign = ' '; /* No children */
150
151 list_for_each_entry(chain, &child->val, list) {
152 ++n;
153 /* We need this because we may not have children */
154 folded_sign = callchain_list__folded(chain);
155 if (folded_sign == '+')
156 break;
157 }
158
159 if (folded_sign == '-') /* Have children and they're unfolded */
160 n += callchain_node__count_rows_rb_tree(child);
161 }
162
163 return n;
164}
165
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900166static int callchain_node__count_flat_rows(struct callchain_node *node)
167{
168 struct callchain_list *chain;
169 char folded_sign = 0;
170 int n = 0;
171
172 list_for_each_entry(chain, &node->parent_val, list) {
173 if (!folded_sign) {
174 /* only check first chain list entry */
175 folded_sign = callchain_list__folded(chain);
176 if (folded_sign == '+')
177 return 1;
178 }
179 n++;
180 }
181
182 list_for_each_entry(chain, &node->val, list) {
183 if (!folded_sign) {
184 /* node->parent_val list might be empty */
185 folded_sign = callchain_list__folded(chain);
186 if (folded_sign == '+')
187 return 1;
188 }
189 n++;
190 }
191
192 return n;
193}
194
Namhyung Kim8c430a32015-11-09 14:45:44 +0900195static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
196{
197 return 1;
198}
199
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300200static int callchain_node__count_rows(struct callchain_node *node)
201{
202 struct callchain_list *chain;
203 bool unfolded = false;
204 int n = 0;
205
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900206 if (callchain_param.mode == CHAIN_FLAT)
207 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900208 else if (callchain_param.mode == CHAIN_FOLDED)
209 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900210
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300211 list_for_each_entry(chain, &node->val, list) {
212 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900213 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300214 }
215
216 if (unfolded)
217 n += callchain_node__count_rows_rb_tree(node);
218
219 return n;
220}
221
222static int callchain__count_rows(struct rb_root *chain)
223{
224 struct rb_node *nd;
225 int n = 0;
226
227 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
228 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
229 n += callchain_node__count_rows(node);
230 }
231
232 return n;
233}
234
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900235static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
236 bool include_children)
237{
238 int count = 0;
239 struct rb_node *node;
240 struct hist_entry *child;
241
242 if (he->leaf)
243 return callchain__count_rows(&he->sorted_chain);
244
Namhyung Kim79dded82016-02-26 21:13:19 +0900245 if (he->has_no_entry)
246 return 1;
247
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900248 node = rb_first(&he->hroot_out);
249 while (node) {
250 float percent;
251
252 child = rb_entry(node, struct hist_entry, rb_node);
253 percent = hist_entry__get_percent_limit(child);
254
255 if (!child->filtered && percent >= hb->min_pcnt) {
256 count++;
257
258 if (include_children && child->unfolded)
259 count += hierarchy_count_rows(hb, child, true);
260 }
261
262 node = rb_next(node);
263 }
264 return count;
265}
266
Namhyung Kim3698dab2015-05-05 23:55:46 +0900267static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300268{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900269 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200270 return false;
271
Namhyung Kim3698dab2015-05-05 23:55:46 +0900272 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300273 return false;
274
Namhyung Kim3698dab2015-05-05 23:55:46 +0900275 he->unfolded = !he->unfolded;
276 return true;
277}
278
279static bool callchain_list__toggle_fold(struct callchain_list *cl)
280{
281 if (!cl)
282 return false;
283
284 if (!cl->has_children)
285 return false;
286
287 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300288 return true;
289}
290
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300291static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300292{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300293 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300294
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300295 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300296 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
297 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300298 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300299
300 list_for_each_entry(chain, &child->val, list) {
301 if (first) {
302 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900303 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300304 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300305 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900306 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300307 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300308 }
309
310 callchain_node__init_have_children_rb_tree(child);
311 }
312}
313
Namhyung Kima7444af2014-11-24 17:13:27 +0900314static void callchain_node__init_have_children(struct callchain_node *node,
315 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300316{
317 struct callchain_list *chain;
318
Namhyung Kima7444af2014-11-24 17:13:27 +0900319 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900320 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900321
Andres Freund90989032016-03-30 21:02:45 +0200322 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900323 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900324 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900325 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300326
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300327 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300328}
329
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300330static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300331{
Namhyung Kima7444af2014-11-24 17:13:27 +0900332 struct rb_node *nd = rb_first(root);
333 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300334
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300335 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300336 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900337 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900338 if (callchain_param.mode == CHAIN_FLAT ||
339 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900340 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300341 }
342}
343
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300344static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300345{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900346 if (he->init_have_children)
347 return;
348
349 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900350 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300351 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900352 } else {
353 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300354 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900355
356 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300357}
358
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300359static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300360{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900361 struct hist_entry *he = browser->he_selection;
362 struct map_symbol *ms = browser->selection;
363 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
364 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300365
Wang Nan4938cf02015-12-07 02:35:44 +0000366 if (!he || !ms)
367 return false;
368
Namhyung Kim3698dab2015-05-05 23:55:46 +0900369 if (ms == &he->ms)
370 has_children = hist_entry__toggle_fold(he);
371 else
372 has_children = callchain_list__toggle_fold(cl);
373
374 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900375 int child_rows = 0;
376
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300377 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900378 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300379
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900380 if (he->leaf)
381 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300382 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900383 browser->nr_hierarchy_entries -= he->nr_rows;
384
385 if (symbol_conf.report_hierarchy)
386 child_rows = hierarchy_count_rows(browser, he, true);
387
388 if (he->unfolded) {
389 if (he->leaf)
390 he->nr_rows = callchain__count_rows(&he->sorted_chain);
391 else
392 he->nr_rows = hierarchy_count_rows(browser, he, false);
393
394 /* account grand children */
395 if (symbol_conf.report_hierarchy)
396 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900397
398 if (!he->leaf && he->nr_rows == 0) {
399 he->has_no_entry = true;
400 he->nr_rows = 1;
401 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900402 } else {
403 if (symbol_conf.report_hierarchy)
404 browser->b.nr_entries -= child_rows - he->nr_rows;
405
Namhyung Kim79dded82016-02-26 21:13:19 +0900406 if (he->has_no_entry)
407 he->has_no_entry = false;
408
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300409 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900410 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900411
412 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900413
414 if (he->leaf)
415 browser->nr_callchain_rows += he->nr_rows;
416 else
417 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300418
419 return true;
420 }
421
422 /* If it doesn't have children, no toggling performed */
423 return false;
424}
425
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300426static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300427{
428 int n = 0;
429 struct rb_node *nd;
430
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300431 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300432 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
433 struct callchain_list *chain;
434 bool has_children = false;
435
436 list_for_each_entry(chain, &child->val, list) {
437 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900438 callchain_list__set_folding(chain, unfold);
439 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300440 }
441
442 if (has_children)
443 n += callchain_node__set_folding_rb_tree(child, unfold);
444 }
445
446 return n;
447}
448
449static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
450{
451 struct callchain_list *chain;
452 bool has_children = false;
453 int n = 0;
454
455 list_for_each_entry(chain, &node->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(node, unfold);
463
464 return n;
465}
466
467static int callchain__set_folding(struct rb_root *chain, bool unfold)
468{
469 struct rb_node *nd;
470 int n = 0;
471
472 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
473 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
474 n += callchain_node__set_folding(node, unfold);
475 }
476
477 return n;
478}
479
Namhyung Kim492b1012016-02-25 00:13:44 +0900480static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
481 bool unfold __maybe_unused)
482{
483 float percent;
484 struct rb_node *nd;
485 struct hist_entry *child;
486 int n = 0;
487
488 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
489 child = rb_entry(nd, struct hist_entry, rb_node);
490 percent = hist_entry__get_percent_limit(child);
491 if (!child->filtered && percent >= hb->min_pcnt)
492 n++;
493 }
494
495 return n;
496}
497
498static void hist_entry__set_folding(struct hist_entry *he,
499 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300500{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300501 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900502 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300503
Namhyung Kim3698dab2015-05-05 23:55:46 +0900504 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900505 int n;
506
507 if (he->leaf)
508 n = callchain__set_folding(&he->sorted_chain, unfold);
509 else
510 n = hierarchy_set_folding(hb, he, unfold);
511
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300512 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300513 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300514 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300515}
516
Namhyung Kimc3b78952014-04-22 15:56:17 +0900517static void
518__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300519{
520 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900521 struct hist_entry *he;
522 double percent;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300523
Namhyung Kim492b1012016-02-25 00:13:44 +0900524 nd = rb_first(&browser->hists->entries);
525 while (nd) {
526 he = rb_entry(nd, struct hist_entry, rb_node);
527
528 /* set folding state even if it's currently folded */
529 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
530
531 hist_entry__set_folding(he, browser, unfold);
532
533 percent = hist_entry__get_percent_limit(he);
534 if (he->filtered || percent < browser->min_pcnt)
535 continue;
536
537 if (!he->depth || unfold)
538 browser->nr_hierarchy_entries++;
539 if (he->leaf)
540 browser->nr_callchain_rows += he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900541 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
542 browser->nr_hierarchy_entries++;
543 he->has_no_entry = true;
544 he->nr_rows = 1;
545 } else
546 he->has_no_entry = false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300547 }
548}
549
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300550static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300551{
Namhyung Kim492b1012016-02-25 00:13:44 +0900552 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900553 browser->nr_callchain_rows = 0;
554 __hist_browser__set_folding(browser, unfold);
555
556 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300557 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300558 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300559}
560
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200561static void ui_browser__warn_lost_events(struct ui_browser *browser)
562{
563 ui_browser__warning(browser, 4,
564 "Events are being lost, check IO/CPU overload!\n\n"
565 "You may want to run 'perf' using a RT scheduler policy:\n\n"
566 " perf top -r 80\n\n"
567 "Or reduce the sampling frequency.");
568}
569
Jiri Olsa5b91a862016-06-20 23:58:15 +0200570static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
571{
572 return browser->title ? browser->title(browser, bf, size) : 0;
573}
574
Jiri Olsadabd2012016-06-20 23:58:14 +0200575int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300576{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300577 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300578 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900579 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900580 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300581
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300582 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900583 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300584
Jiri Olsa5b91a862016-06-20 23:58:15 +0200585 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300586
Namhyung Kim090cff32016-01-11 19:53:14 +0900587 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300588 return -1;
589
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300590 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300591 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300592
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300593 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900594 case K_TIMER: {
595 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900596 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900597
Namhyung Kimc3b78952014-04-22 15:56:17 +0900598 if (hist_browser__has_filter(browser))
Namhyung Kim112f7612014-04-22 14:05:35 +0900599 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900600
Namhyung Kimc3b78952014-04-22 15:56:17 +0900601 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900602 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200603
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300604 if (browser->hists->stats.nr_lost_warned !=
605 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
606 browser->hists->stats.nr_lost_warned =
607 browser->hists->stats.nr_events[PERF_RECORD_LOST];
608 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200609 }
610
Jiri Olsa5b91a862016-06-20 23:58:15 +0200611 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300612 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300613 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900614 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300615 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300616 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300617 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300618 struct hist_entry, rb_node);
619 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300620 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 -0300621 seq++, browser->b.nr_entries,
622 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300623 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300624 browser->b.index,
625 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300626 h->row_offset, h->nr_rows);
627 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300628 break;
629 case 'C':
630 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300631 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300632 break;
633 case 'E':
634 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300635 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300636 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200637 case 'H':
638 browser->show_headers = !browser->show_headers;
639 hist_browser__update_rows(browser);
640 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200641 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300642 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300643 break;
644 /* fall thru */
645 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300646 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300647 }
648 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300649out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300650 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300651 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300652}
653
Namhyung Kim39ee5332014-08-22 09:13:21 +0900654struct callchain_print_arg {
655 /* for hists browser */
656 off_t row_offset;
657 bool is_current_entry;
658
659 /* for file dump */
660 FILE *fp;
661 int printed;
662};
663
664typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
665 struct callchain_list *chain,
666 const char *str, int offset,
667 unsigned short row,
668 struct callchain_print_arg *arg);
669
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900670static void hist_browser__show_callchain_entry(struct hist_browser *browser,
671 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900672 const char *str, int offset,
673 unsigned short row,
674 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900675{
676 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900677 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300678 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900679
680 color = HE_COLORSET_NORMAL;
681 width = browser->b.width - (offset + 2);
682 if (ui_browser__is_current_entry(&browser->b, row)) {
683 browser->selection = &chain->ms;
684 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900685 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900686 }
687
688 ui_browser__set_color(&browser->b, color);
689 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300690 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300691 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300692 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300693 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900694}
695
Namhyung Kim39ee5332014-08-22 09:13:21 +0900696static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
697 struct callchain_list *chain,
698 const char *str, int offset,
699 unsigned short row __maybe_unused,
700 struct callchain_print_arg *arg)
701{
702 char folded_sign = callchain_list__folded(chain);
703
704 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
705 folded_sign, str);
706}
707
708typedef bool (*check_output_full_fn)(struct hist_browser *browser,
709 unsigned short row);
710
711static bool hist_browser__check_output_full(struct hist_browser *browser,
712 unsigned short row)
713{
714 return browser->b.rows == row;
715}
716
717static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
718 unsigned short row __maybe_unused)
719{
720 return false;
721}
722
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300723#define LEVEL_OFFSET_STEP 3
724
Namhyung Kim18bb8382015-11-09 14:45:42 +0900725static int hist_browser__show_callchain_list(struct hist_browser *browser,
726 struct callchain_node *node,
727 struct callchain_list *chain,
728 unsigned short row, u64 total,
729 bool need_percent, int offset,
730 print_callchain_entry_fn print,
731 struct callchain_print_arg *arg)
732{
733 char bf[1024], *alloc_str;
734 const char *str;
735
736 if (arg->row_offset != 0) {
737 arg->row_offset--;
738 return 0;
739 }
740
741 alloc_str = NULL;
742 str = callchain_list__sym_name(chain, bf, sizeof(bf),
743 browser->show_dso);
744
745 if (need_percent) {
746 char buf[64];
747
748 callchain_node__scnprintf_value(node, buf, sizeof(buf),
749 total);
750
751 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
752 str = "Not enough memory!";
753 else
754 str = alloc_str;
755 }
756
757 print(browser, chain, str, offset, row, arg);
758
759 free(alloc_str);
760 return 1;
761}
762
Namhyung Kim59c624e2016-01-28 00:40:56 +0900763static bool check_percent_display(struct rb_node *node, u64 parent_total)
764{
765 struct callchain_node *child;
766
767 if (node == NULL)
768 return false;
769
770 if (rb_next(node))
771 return true;
772
773 child = rb_entry(node, struct callchain_node, rb_node);
774 return callchain_cumul_hits(child) != parent_total;
775}
776
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900777static int hist_browser__show_callchain_flat(struct hist_browser *browser,
778 struct rb_root *root,
779 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900780 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900781 print_callchain_entry_fn print,
782 struct callchain_print_arg *arg,
783 check_output_full_fn is_output_full)
784{
785 struct rb_node *node;
786 int first_row = row, offset = LEVEL_OFFSET_STEP;
787 bool need_percent;
788
789 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900790 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900791
792 while (node) {
793 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
794 struct rb_node *next = rb_next(node);
795 struct callchain_list *chain;
796 char folded_sign = ' ';
797 int first = true;
798 int extra_offset = 0;
799
800 list_for_each_entry(chain, &child->parent_val, list) {
801 bool was_first = first;
802
803 if (first)
804 first = false;
805 else if (need_percent)
806 extra_offset = LEVEL_OFFSET_STEP;
807
808 folded_sign = callchain_list__folded(chain);
809
810 row += hist_browser__show_callchain_list(browser, child,
811 chain, row, total,
812 was_first && need_percent,
813 offset + extra_offset,
814 print, arg);
815
816 if (is_output_full(browser, row))
817 goto out;
818
819 if (folded_sign == '+')
820 goto next;
821 }
822
823 list_for_each_entry(chain, &child->val, list) {
824 bool was_first = first;
825
826 if (first)
827 first = false;
828 else if (need_percent)
829 extra_offset = LEVEL_OFFSET_STEP;
830
831 folded_sign = callchain_list__folded(chain);
832
833 row += hist_browser__show_callchain_list(browser, child,
834 chain, row, total,
835 was_first && need_percent,
836 offset + extra_offset,
837 print, arg);
838
839 if (is_output_full(browser, row))
840 goto out;
841
842 if (folded_sign == '+')
843 break;
844 }
845
846next:
847 if (is_output_full(browser, row))
848 break;
849 node = next;
850 }
851out:
852 return row - first_row;
853}
854
Namhyung Kim8c430a32015-11-09 14:45:44 +0900855static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
856 struct callchain_list *chain,
857 char *value_str, char *old_str)
858{
859 char bf[1024];
860 const char *str;
861 char *new;
862
863 str = callchain_list__sym_name(chain, bf, sizeof(bf),
864 browser->show_dso);
865 if (old_str) {
866 if (asprintf(&new, "%s%s%s", old_str,
867 symbol_conf.field_sep ?: ";", str) < 0)
868 new = NULL;
869 } else {
870 if (value_str) {
871 if (asprintf(&new, "%s %s", value_str, str) < 0)
872 new = NULL;
873 } else {
874 if (asprintf(&new, "%s", str) < 0)
875 new = NULL;
876 }
877 }
878 return new;
879}
880
881static int hist_browser__show_callchain_folded(struct hist_browser *browser,
882 struct rb_root *root,
883 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900884 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +0900885 print_callchain_entry_fn print,
886 struct callchain_print_arg *arg,
887 check_output_full_fn is_output_full)
888{
889 struct rb_node *node;
890 int first_row = row, offset = LEVEL_OFFSET_STEP;
891 bool need_percent;
892
893 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900894 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900895
896 while (node) {
897 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
898 struct rb_node *next = rb_next(node);
899 struct callchain_list *chain, *first_chain = NULL;
900 int first = true;
901 char *value_str = NULL, *value_str_alloc = NULL;
902 char *chain_str = NULL, *chain_str_alloc = NULL;
903
904 if (arg->row_offset != 0) {
905 arg->row_offset--;
906 goto next;
907 }
908
909 if (need_percent) {
910 char buf[64];
911
912 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
913 if (asprintf(&value_str, "%s", buf) < 0) {
914 value_str = (char *)"<...>";
915 goto do_print;
916 }
917 value_str_alloc = value_str;
918 }
919
920 list_for_each_entry(chain, &child->parent_val, list) {
921 chain_str = hist_browser__folded_callchain_str(browser,
922 chain, value_str, chain_str);
923 if (first) {
924 first = false;
925 first_chain = chain;
926 }
927
928 if (chain_str == NULL) {
929 chain_str = (char *)"Not enough memory!";
930 goto do_print;
931 }
932
933 chain_str_alloc = chain_str;
934 }
935
936 list_for_each_entry(chain, &child->val, list) {
937 chain_str = hist_browser__folded_callchain_str(browser,
938 chain, value_str, chain_str);
939 if (first) {
940 first = false;
941 first_chain = chain;
942 }
943
944 if (chain_str == NULL) {
945 chain_str = (char *)"Not enough memory!";
946 goto do_print;
947 }
948
949 chain_str_alloc = chain_str;
950 }
951
952do_print:
953 print(browser, first_chain, chain_str, offset, row++, arg);
954 free(value_str_alloc);
955 free(chain_str_alloc);
956
957next:
958 if (is_output_full(browser, row))
959 break;
960 node = next;
961 }
962
963 return row - first_row;
964}
965
Namhyung Kim0c841c62016-01-28 00:40:54 +0900966static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900967 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900968 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +0900969 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900970 print_callchain_entry_fn print,
971 struct callchain_print_arg *arg,
972 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300973{
974 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900975 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +0900976 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +0900977 u64 percent_total = total;
978
979 if (callchain_param.mode == CHAIN_GRAPH_REL)
980 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300981
Namhyung Kimc09a7e72014-08-21 10:15:45 +0900982 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900983 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +0900984
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300985 while (node) {
986 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
987 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300988 struct callchain_list *chain;
989 char folded_sign = ' ';
990 int first = true;
991 int extra_offset = 0;
992
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300993 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300994 bool was_first = first;
995
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -0300996 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300997 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +0900998 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300999 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001000
1001 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001002
Namhyung Kim18bb8382015-11-09 14:45:42 +09001003 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001004 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001005 was_first && need_percent,
1006 offset + extra_offset,
1007 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001008
Namhyung Kim18bb8382015-11-09 14:45:42 +09001009 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001010 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001011
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001012 if (folded_sign == '+')
1013 break;
1014 }
1015
1016 if (folded_sign == '-') {
1017 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001018
Namhyung Kim0c841c62016-01-28 00:40:54 +09001019 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001020 new_level, row, total,
1021 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001022 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001023 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001024 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001025 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001026 node = next;
1027 }
1028out:
1029 return row - first_row;
1030}
1031
Namhyung Kim0c841c62016-01-28 00:40:54 +09001032static int hist_browser__show_callchain(struct hist_browser *browser,
1033 struct hist_entry *entry, int level,
1034 unsigned short row,
1035 print_callchain_entry_fn print,
1036 struct callchain_print_arg *arg,
1037 check_output_full_fn is_output_full)
1038{
1039 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001040 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001041 int printed;
1042
Namhyung Kim5eca1042016-01-28 00:40:55 +09001043 if (symbol_conf.cumulate_callchain)
1044 parent_total = entry->stat_acc->period;
1045 else
1046 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001047
1048 if (callchain_param.mode == CHAIN_FLAT) {
1049 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001050 &entry->sorted_chain, row,
1051 total, parent_total, print, arg,
1052 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001053 } else if (callchain_param.mode == CHAIN_FOLDED) {
1054 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001055 &entry->sorted_chain, row,
1056 total, parent_total, print, arg,
1057 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001058 } else {
1059 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001060 &entry->sorted_chain, level, row,
1061 total, parent_total, print, arg,
1062 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001063 }
1064
1065 if (arg->is_current_entry)
1066 browser->he_selection = entry;
1067
1068 return printed;
1069}
1070
Namhyung Kim89701462013-01-22 18:09:38 +09001071struct hpp_arg {
1072 struct ui_browser *b;
1073 char folded_sign;
1074 bool current_entry;
1075};
1076
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001077static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
1078{
1079 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001080 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001081 va_list args;
1082 double percent;
1083
1084 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001085 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001086 percent = va_arg(args, double);
1087 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001088
Namhyung Kim89701462013-01-22 18:09:38 +09001089 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001090
Namhyung Kimd6751072014-07-31 14:47:36 +09001091 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001092 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001093
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001094 advance_hpp(hpp, ret);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001095 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001096}
1097
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001098#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001099static u64 __hpp_get_##_field(struct hist_entry *he) \
1100{ \
1101 return he->stat._field; \
1102} \
1103 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001104static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001105hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001106 struct perf_hpp *hpp, \
1107 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001108{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001109 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1110 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001111}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001112
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001113#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1114static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1115{ \
1116 return he->stat_acc->_field; \
1117} \
1118 \
1119static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001120hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001121 struct perf_hpp *hpp, \
1122 struct hist_entry *he) \
1123{ \
1124 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001125 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001126 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001127 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001128 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001129 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001130 \
1131 return ret; \
1132 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001133 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1134 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001135}
1136
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001137__HPP_COLOR_PERCENT_FN(overhead, period)
1138__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1139__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1140__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1141__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001142__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001143
1144#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001145#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001146
1147void hist_browser__init_hpp(void)
1148{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001149 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1150 hist_browser__hpp_color_overhead;
1151 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1152 hist_browser__hpp_color_overhead_sys;
1153 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1154 hist_browser__hpp_color_overhead_us;
1155 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1156 hist_browser__hpp_color_overhead_guest_sys;
1157 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1158 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001159 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1160 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001161}
1162
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001163static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001164 struct hist_entry *entry,
1165 unsigned short row)
1166{
Jiri Olsa12400052012-10-13 00:06:16 +02001167 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001168 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001169 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001170 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001171 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001172 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001173 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001174
1175 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001176 browser->he_selection = entry;
1177 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001178 }
1179
1180 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001181 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001182 folded_sign = hist_entry__folded(entry);
1183 }
1184
1185 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001186 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001187 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001188 .folded_sign = folded_sign,
1189 .current_entry = current_entry,
1190 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001191 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001192
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001193 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001194
Jiri Olsaf0786af2016-01-18 10:24:23 +01001195 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001196 char s[2048];
1197 struct perf_hpp hpp = {
1198 .buf = s,
1199 .size = sizeof(s),
1200 .ptr = &arg,
1201 };
1202
Namhyung Kim361459f2015-12-23 02:07:08 +09001203 if (perf_hpp__should_skip(fmt, entry->hists) ||
1204 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001205 continue;
1206
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001207 if (current_entry && browser->b.navkeypressed) {
1208 ui_browser__set_color(&browser->b,
1209 HE_COLORSET_SELECTED);
1210 } else {
1211 ui_browser__set_color(&browser->b,
1212 HE_COLORSET_NORMAL);
1213 }
1214
1215 if (first) {
1216 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001217 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001218 width -= 2;
1219 }
1220 first = false;
1221 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001222 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001223 width -= 2;
1224 }
1225
Jiri Olsa12400052012-10-13 00:06:16 +02001226 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001227 int ret = fmt->color(fmt, &hpp, entry);
1228 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1229 /*
1230 * fmt->color() already used ui_browser to
1231 * print the non alignment bits, skip it (+ret):
1232 */
1233 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001234 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001235 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001236 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001237 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001238 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001239 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001240
1241 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001242 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001243 width += 1;
1244
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001245 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001246
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001247 ++row;
1248 ++printed;
1249 } else
1250 --row_offset;
1251
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001252 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001253 struct callchain_print_arg arg = {
1254 .row_offset = row_offset,
1255 .is_current_entry = current_entry,
1256 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001257
Namhyung Kim0c841c62016-01-28 00:40:54 +09001258 printed += hist_browser__show_callchain(browser, entry, 1, row,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001259 hist_browser__show_callchain_entry, &arg,
1260 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001261 }
1262
1263 return printed;
1264}
1265
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001266static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1267 struct hist_entry *entry,
1268 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001269 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001270{
1271 int printed = 0;
1272 int width = browser->b.width;
1273 char folded_sign = ' ';
1274 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1275 off_t row_offset = entry->row_offset;
1276 bool first = true;
1277 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001278 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001279 struct hpp_arg arg = {
1280 .b = &browser->b,
1281 .current_entry = current_entry,
1282 };
1283 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001284 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001285
1286 if (current_entry) {
1287 browser->he_selection = entry;
1288 browser->selection = &entry->ms;
1289 }
1290
1291 hist_entry__init_have_children(entry);
1292 folded_sign = hist_entry__folded(entry);
1293 arg.folded_sign = folded_sign;
1294
1295 if (entry->leaf && row_offset) {
1296 row_offset--;
1297 goto show_callchain;
1298 }
1299
1300 hist_browser__gotorc(browser, row, 0);
1301
1302 if (current_entry && browser->b.navkeypressed)
1303 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1304 else
1305 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1306
1307 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1308 width -= level * HIERARCHY_INDENT;
1309
Namhyung Kima61a22f2016-03-07 16:44:50 -03001310 /* the first hpp_list_node is for overhead columns */
1311 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1312 struct perf_hpp_list_node, list);
1313 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001314 char s[2048];
1315 struct perf_hpp hpp = {
1316 .buf = s,
1317 .size = sizeof(s),
1318 .ptr = &arg,
1319 };
1320
1321 if (perf_hpp__should_skip(fmt, entry->hists) ||
1322 column++ < browser->b.horiz_scroll)
1323 continue;
1324
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001325 if (current_entry && browser->b.navkeypressed) {
1326 ui_browser__set_color(&browser->b,
1327 HE_COLORSET_SELECTED);
1328 } else {
1329 ui_browser__set_color(&browser->b,
1330 HE_COLORSET_NORMAL);
1331 }
1332
1333 if (first) {
1334 ui_browser__printf(&browser->b, "%c", folded_sign);
1335 width--;
1336 first = false;
1337 } else {
1338 ui_browser__printf(&browser->b, " ");
1339 width -= 2;
1340 }
1341
1342 if (fmt->color) {
1343 int ret = fmt->color(fmt, &hpp, entry);
1344 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1345 /*
1346 * fmt->color() already used ui_browser to
1347 * print the non alignment bits, skip it (+ret):
1348 */
1349 ui_browser__printf(&browser->b, "%s", s + ret);
1350 } else {
1351 int ret = fmt->entry(fmt, &hpp, entry);
1352 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1353 ui_browser__printf(&browser->b, "%s", s);
1354 }
1355 width -= hpp.buf - s;
1356 }
1357
1358 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1359 width -= hierarchy_indent;
1360
1361 if (column >= browser->b.horiz_scroll) {
1362 char s[2048];
1363 struct perf_hpp hpp = {
1364 .buf = s,
1365 .size = sizeof(s),
1366 .ptr = &arg,
1367 };
1368
1369 if (current_entry && browser->b.navkeypressed) {
1370 ui_browser__set_color(&browser->b,
1371 HE_COLORSET_SELECTED);
1372 } else {
1373 ui_browser__set_color(&browser->b,
1374 HE_COLORSET_NORMAL);
1375 }
1376
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001377 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1378 ui_browser__write_nstring(&browser->b, "", 2);
1379 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001380
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001381 /*
1382 * No need to call hist_entry__snprintf_alignment()
1383 * since this fmt is always the last column in the
1384 * hierarchy mode.
1385 */
1386 if (fmt->color) {
1387 width -= fmt->color(fmt, &hpp, entry);
1388 } else {
1389 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001390
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001391 width -= fmt->entry(fmt, &hpp, entry);
1392 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001393
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001394 while (isspace(s[i++]))
1395 width++;
1396 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001397 }
1398 }
1399
1400 /* The scroll bar isn't being used */
1401 if (!browser->b.navkeypressed)
1402 width += 1;
1403
1404 ui_browser__write_nstring(&browser->b, "", width);
1405
1406 ++row;
1407 ++printed;
1408
1409show_callchain:
1410 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1411 struct callchain_print_arg carg = {
1412 .row_offset = row_offset,
1413 };
1414
1415 printed += hist_browser__show_callchain(browser, entry,
1416 level + 1, row,
1417 hist_browser__show_callchain_entry, &carg,
1418 hist_browser__check_output_full);
1419 }
1420
1421 return printed;
1422}
1423
Namhyung Kim79dded82016-02-26 21:13:19 +09001424static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001425 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001426{
1427 int width = browser->b.width;
1428 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1429 bool first = true;
1430 int column = 0;
1431 int ret;
1432 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001433 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001434 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001435
1436 if (current_entry) {
1437 browser->he_selection = NULL;
1438 browser->selection = NULL;
1439 }
1440
1441 hist_browser__gotorc(browser, row, 0);
1442
1443 if (current_entry && browser->b.navkeypressed)
1444 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1445 else
1446 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1447
1448 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1449 width -= level * HIERARCHY_INDENT;
1450
Namhyung Kima61a22f2016-03-07 16:44:50 -03001451 /* the first hpp_list_node is for overhead columns */
1452 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1453 struct perf_hpp_list_node, list);
1454 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001455 if (perf_hpp__should_skip(fmt, browser->hists) ||
1456 column++ < browser->b.horiz_scroll)
1457 continue;
1458
Jiri Olsada1b0402016-06-14 20:19:20 +02001459 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001460
1461 if (first) {
1462 /* for folded sign */
1463 first = false;
1464 ret++;
1465 } else {
1466 /* space between columns */
1467 ret += 2;
1468 }
1469
1470 ui_browser__write_nstring(&browser->b, "", ret);
1471 width -= ret;
1472 }
1473
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001474 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1475 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001476
1477 if (column >= browser->b.horiz_scroll) {
1478 char buf[32];
1479
1480 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1481 ui_browser__printf(&browser->b, " %s", buf);
1482 width -= ret + 2;
1483 }
1484
1485 /* The scroll bar isn't being used */
1486 if (!browser->b.navkeypressed)
1487 width += 1;
1488
1489 ui_browser__write_nstring(&browser->b, "", width);
1490 return 1;
1491}
1492
Jiri Olsa81a888f2014-06-14 15:44:52 +02001493static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1494{
1495 advance_hpp(hpp, inc);
1496 return hpp->size <= 0;
1497}
1498
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001499static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001500{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001501 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001502 struct perf_hpp dummy_hpp = {
1503 .buf = buf,
1504 .size = size,
1505 };
1506 struct perf_hpp_fmt *fmt;
1507 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001508 int column = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001509
1510 if (symbol_conf.use_callchain) {
1511 ret = scnprintf(buf, size, " ");
1512 if (advance_hpp_check(&dummy_hpp, ret))
1513 return ret;
1514 }
1515
Jiri Olsaf0786af2016-01-18 10:24:23 +01001516 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001517 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001518 continue;
1519
Jiri Olsa05372172016-06-14 20:19:19 +02001520 ret = fmt->header(fmt, &dummy_hpp, hists);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001521 if (advance_hpp_check(&dummy_hpp, ret))
1522 break;
1523
1524 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1525 if (advance_hpp_check(&dummy_hpp, ret))
1526 break;
1527 }
1528
1529 return ret;
1530}
1531
Namhyung Kimd8b92402016-02-25 00:13:46 +09001532static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1533{
1534 struct hists *hists = browser->hists;
1535 struct perf_hpp dummy_hpp = {
1536 .buf = buf,
1537 .size = size,
1538 };
1539 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001540 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001541 size_t ret = 0;
1542 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001543 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001544 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001545
1546 ret = scnprintf(buf, size, " ");
1547 if (advance_hpp_check(&dummy_hpp, ret))
1548 return ret;
1549
Namhyung Kima61a22f2016-03-07 16:44:50 -03001550 /* the first hpp_list_node is for overhead columns */
1551 fmt_node = list_first_entry(&hists->hpp_formats,
1552 struct perf_hpp_list_node, list);
1553 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001554 if (column++ < browser->b.horiz_scroll)
1555 continue;
1556
Jiri Olsa05372172016-06-14 20:19:19 +02001557 ret = fmt->header(fmt, &dummy_hpp, hists);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001558 if (advance_hpp_check(&dummy_hpp, ret))
1559 break;
1560
1561 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1562 if (advance_hpp_check(&dummy_hpp, ret))
1563 break;
1564 }
1565
1566 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001567 indent * HIERARCHY_INDENT, "");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001568 if (advance_hpp_check(&dummy_hpp, ret))
1569 return ret;
1570
Namhyung Kima61a22f2016-03-07 16:44:50 -03001571 first_node = true;
1572 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1573 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001574 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1575 if (advance_hpp_check(&dummy_hpp, ret))
1576 break;
1577 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001578 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001579
Namhyung Kima61a22f2016-03-07 16:44:50 -03001580 first_col = true;
1581 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1582 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001583
Namhyung Kima61a22f2016-03-07 16:44:50 -03001584 if (perf_hpp__should_skip(fmt, hists))
1585 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001586
Namhyung Kima61a22f2016-03-07 16:44:50 -03001587 if (!first_col) {
1588 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1589 if (advance_hpp_check(&dummy_hpp, ret))
1590 break;
1591 }
1592 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001593
Jiri Olsa05372172016-06-14 20:19:19 +02001594 ret = fmt->header(fmt, &dummy_hpp, hists);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001595 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001596
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001597 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001598 ret = strlen(start);
1599
1600 if (start != dummy_hpp.buf)
1601 memmove(dummy_hpp.buf, start, ret + 1);
1602
1603 if (advance_hpp_check(&dummy_hpp, ret))
1604 break;
1605 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001606 }
1607
1608 return ret;
1609}
1610
Jiri Olsa01b47702016-06-14 20:19:13 +02001611static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001612{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001613 char headers[1024];
1614
Jiri Olsa01b47702016-06-14 20:19:13 +02001615 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1616 sizeof(headers));
1617
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001618 ui_browser__gotorc(&browser->b, 0, 0);
1619 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001620 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001621}
1622
Jiri Olsa01b47702016-06-14 20:19:13 +02001623static void hists_browser__headers(struct hist_browser *browser)
1624{
1625 char headers[1024];
1626
1627 hists_browser__scnprintf_headers(browser, headers,
1628 sizeof(headers));
1629
1630 ui_browser__gotorc(&browser->b, 0, 0);
1631 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1632 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1633}
1634
1635static void hist_browser__show_headers(struct hist_browser *browser)
1636{
1637 if (symbol_conf.report_hierarchy)
1638 hists_browser__hierarchy_headers(browser);
1639 else
1640 hists_browser__headers(browser);
1641}
1642
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001643static void ui_browser__hists_init_top(struct ui_browser *browser)
1644{
1645 if (browser->top == NULL) {
1646 struct hist_browser *hb;
1647
1648 hb = container_of(browser, struct hist_browser, b);
1649 browser->top = rb_first(&hb->hists->entries);
1650 }
1651}
1652
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001653static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001654{
1655 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001656 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001657 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001658 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001659
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001660 if (hb->show_headers) {
1661 hist_browser__show_headers(hb);
1662 header_offset = 1;
1663 }
1664
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001665 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001666 hb->he_selection = NULL;
1667 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001668
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001669 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001670 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001671 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001672
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001673 if (h->filtered) {
1674 /* let it move to sibling */
1675 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001676 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001677 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001678
Namhyung Kim14135662013-10-31 10:17:39 +09001679 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001680 if (percent < hb->min_pcnt)
1681 continue;
1682
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001683 if (symbol_conf.report_hierarchy) {
1684 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001685 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001686 if (row == browser->rows)
1687 break;
1688
1689 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001690 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001691 row++;
1692 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001693 } else {
1694 row += hist_browser__show_entry(hb, h, row);
1695 }
1696
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001697 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001698 break;
1699 }
1700
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001701 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001702}
1703
Namhyung Kim064f1982013-05-14 11:09:04 +09001704static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001705 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001706{
1707 while (nd != NULL) {
1708 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001709 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001710
Namhyung Kimc0f15272014-04-16 11:16:33 +09001711 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001712 return nd;
1713
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001714 /*
1715 * If it's filtered, its all children also were filtered.
1716 * So move to sibling node.
1717 */
1718 if (rb_next(nd))
1719 nd = rb_next(nd);
1720 else
1721 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001722 }
1723
1724 return NULL;
1725}
1726
Namhyung Kim064f1982013-05-14 11:09:04 +09001727static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001728 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001729{
1730 while (nd != NULL) {
1731 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001732 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001733
1734 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001735 return nd;
1736
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001737 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001738 }
1739
1740 return NULL;
1741}
1742
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001743static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001744 off_t offset, int whence)
1745{
1746 struct hist_entry *h;
1747 struct rb_node *nd;
1748 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001749 struct hist_browser *hb;
1750
1751 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001752
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001753 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03001754 return;
1755
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001756 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001757
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001758 switch (whence) {
1759 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09001760 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09001761 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001762 break;
1763 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001764 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001765 goto do_offset;
1766 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001767 nd = rb_hierarchy_last(rb_last(browser->entries));
1768 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001769 first = false;
1770 break;
1771 default:
1772 return;
1773 }
1774
1775 /*
1776 * Moves not relative to the first visible entry invalidates its
1777 * row_offset:
1778 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001779 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001780 h->row_offset = 0;
1781
1782 /*
1783 * Here we have to check if nd is expanded (+), if it is we can't go
1784 * the next top level hist_entry, instead we must compute an offset of
1785 * what _not_ to show and not change the first visible entry.
1786 *
1787 * This offset increments when we are going from top to bottom and
1788 * decreases when we're going from bottom to top.
1789 *
1790 * As we don't have backpointers to the top level in the callchains
1791 * structure, we need to always print the whole hist_entry callchain,
1792 * skipping the first ones that are before the first visible entry
1793 * and stop when we printed enough lines to fill the screen.
1794 */
1795do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00001796 if (!nd)
1797 return;
1798
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001799 if (offset > 0) {
1800 do {
1801 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001802 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001803 u16 remaining = h->nr_rows - h->row_offset;
1804 if (offset > remaining) {
1805 offset -= remaining;
1806 h->row_offset = 0;
1807 } else {
1808 h->row_offset += offset;
1809 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001810 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001811 break;
1812 }
1813 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001814 nd = hists__filter_entries(rb_hierarchy_next(nd),
1815 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001816 if (nd == NULL)
1817 break;
1818 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001819 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001820 } while (offset != 0);
1821 } else if (offset < 0) {
1822 while (1) {
1823 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001824 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001825 if (first) {
1826 if (-offset > h->row_offset) {
1827 offset += h->row_offset;
1828 h->row_offset = 0;
1829 } else {
1830 h->row_offset += offset;
1831 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001832 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001833 break;
1834 }
1835 } else {
1836 if (-offset > h->nr_rows) {
1837 offset += h->nr_rows;
1838 h->row_offset = 0;
1839 } else {
1840 h->row_offset = h->nr_rows + offset;
1841 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001842 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001843 break;
1844 }
1845 }
1846 }
1847
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001848 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09001849 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001850 if (nd == NULL)
1851 break;
1852 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001853 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001854 if (offset == 0) {
1855 /*
1856 * Last unfiltered hist_entry, check if it is
1857 * unfolded, if it is then we should have
1858 * row_offset at its last entry.
1859 */
1860 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001861 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001862 h->row_offset = h->nr_rows;
1863 break;
1864 }
1865 first = false;
1866 }
1867 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001868 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001869 h = rb_entry(nd, struct hist_entry, rb_node);
1870 h->row_offset = 0;
1871 }
1872}
1873
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001874static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001875 struct hist_entry *he, FILE *fp,
1876 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001877{
Namhyung Kim39ee5332014-08-22 09:13:21 +09001878 struct callchain_print_arg arg = {
1879 .fp = fp,
1880 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001881
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001882 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001883 hist_browser__fprintf_callchain_entry, &arg,
1884 hist_browser__check_dump_full);
1885 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001886}
1887
1888static int hist_browser__fprintf_entry(struct hist_browser *browser,
1889 struct hist_entry *he, FILE *fp)
1890{
1891 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001892 int printed = 0;
1893 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09001894 struct perf_hpp hpp = {
1895 .buf = s,
1896 .size = sizeof(s),
1897 };
1898 struct perf_hpp_fmt *fmt;
1899 bool first = true;
1900 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001901
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001902 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001903 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001904 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03001905 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001906
Jiri Olsaf0786af2016-01-18 10:24:23 +01001907 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001908 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09001909 continue;
1910
Namhyung Kim26d8b332014-03-03 16:16:20 +09001911 if (!first) {
1912 ret = scnprintf(hpp.buf, hpp.size, " ");
1913 advance_hpp(&hpp, ret);
1914 } else
1915 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001916
Namhyung Kim26d8b332014-03-03 16:16:20 +09001917 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001918 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001919 advance_hpp(&hpp, ret);
1920 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001921 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001922
1923 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001924 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1925
1926 return printed;
1927}
1928
1929
1930static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1931 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09001932 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001933{
1934 char s[8192];
1935 int printed = 0;
1936 char folded_sign = ' ';
1937 struct perf_hpp hpp = {
1938 .buf = s,
1939 .size = sizeof(s),
1940 };
1941 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09001942 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001943 bool first = true;
1944 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09001945 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001946
1947 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1948
1949 folded_sign = hist_entry__folded(he);
1950 printed += fprintf(fp, "%c", folded_sign);
1951
Namhyung Kim325a6282016-03-09 22:47:00 +09001952 /* the first hpp_list_node is for overhead columns */
1953 fmt_node = list_first_entry(&he->hists->hpp_formats,
1954 struct perf_hpp_list_node, list);
1955 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001956 if (!first) {
1957 ret = scnprintf(hpp.buf, hpp.size, " ");
1958 advance_hpp(&hpp, ret);
1959 } else
1960 first = false;
1961
1962 ret = fmt->entry(fmt, &hpp, he);
1963 advance_hpp(&hpp, ret);
1964 }
1965
1966 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1967 advance_hpp(&hpp, ret);
1968
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001969 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1970 ret = scnprintf(hpp.buf, hpp.size, " ");
1971 advance_hpp(&hpp, ret);
1972
1973 ret = fmt->entry(fmt, &hpp, he);
1974 advance_hpp(&hpp, ret);
1975 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001976
1977 printed += fprintf(fp, "%s\n", rtrim(s));
1978
1979 if (he->leaf && folded_sign == '-') {
1980 printed += hist_browser__fprintf_callchain(browser, he, fp,
1981 he->depth + 1);
1982 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001983
1984 return printed;
1985}
1986
1987static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1988{
Namhyung Kim064f1982013-05-14 11:09:04 +09001989 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09001990 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03001991 int printed = 0;
1992
1993 while (nd) {
1994 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1995
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001996 if (symbol_conf.report_hierarchy) {
1997 printed += hist_browser__fprintf_hierarchy_entry(browser,
1998 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09001999 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002000 } else {
2001 printed += hist_browser__fprintf_entry(browser, h, fp);
2002 }
2003
2004 nd = hists__filter_entries(rb_hierarchy_next(nd),
2005 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002006 }
2007
2008 return printed;
2009}
2010
2011static int hist_browser__dump(struct hist_browser *browser)
2012{
2013 char filename[64];
2014 FILE *fp;
2015
2016 while (1) {
2017 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2018 if (access(filename, F_OK))
2019 break;
2020 /*
2021 * XXX: Just an arbitrary lazy upper limit
2022 */
2023 if (++browser->print_seq == 8192) {
2024 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2025 return -1;
2026 }
2027 }
2028
2029 fp = fopen(filename, "w");
2030 if (fp == NULL) {
2031 char bf[64];
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002032 const char *err = strerror_r(errno, bf, sizeof(bf));
2033 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002034 return -1;
2035 }
2036
2037 ++browser->print_seq;
2038 hist_browser__fprintf(browser, fp);
2039 fclose(fp);
2040 ui_helpline__fpush("%s written!", filename);
2041
2042 return 0;
2043}
2044
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002045struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002046{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002047 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002048
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002049 if (browser) {
Jiri Olsab1c7a8f2016-06-20 23:58:16 +02002050 struct perf_hpp_fmt *fmt;
2051
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002052 browser->hists = hists;
2053 browser->b.refresh = hist_browser__refresh;
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -03002054 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002055 browser->b.seek = ui_browser__hists_seek;
2056 browser->b.use_navkeypressed = true;
Jiri Olsac8302362014-06-27 18:26:58 +02002057 browser->show_headers = symbol_conf.show_hist_headers;
Jiri Olsab1c7a8f2016-06-20 23:58:16 +02002058
2059 hists__for_each_format(hists, fmt) {
2060 perf_hpp__reset_width(fmt, hists);
2061 ++browser->b.columns;
2062 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002063 }
2064
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002065 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002066}
2067
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002068static struct hist_browser *
2069perf_evsel_browser__new(struct perf_evsel *evsel,
2070 struct hist_browser_timer *hbt,
2071 struct perf_env *env)
2072{
2073 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2074
2075 if (browser) {
2076 browser->hbt = hbt;
2077 browser->env = env;
2078 browser->title = perf_evsel_browser_title;
2079 }
2080 return browser;
2081}
2082
Jiri Olsadabd2012016-06-20 23:58:14 +02002083void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002084{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002085 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002086}
2087
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002088static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002089{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002090 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002091}
2092
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002093static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002094{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002095 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002096}
2097
Taeung Song1e378eb2014-10-07 16:13:15 +09002098/* Check whether the browser is for 'top' or 'report' */
2099static inline bool is_report_browser(void *timer)
2100{
2101 return timer == NULL;
2102}
2103
Jiri Olsa5b91a862016-06-20 23:58:15 +02002104static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002105 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002106{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002107 struct hist_browser_timer *hbt = browser->hbt;
2108 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002109 char unit;
2110 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002111 const struct dso *dso = hists->dso_filter;
2112 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002113 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002114 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2115 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002116 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002117 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002118 char buf[512];
2119 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002120 char ref[30] = " show reference callgraph, ";
2121 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002122
Namhyung Kimf2148332014-01-14 11:52:48 +09002123 if (symbol_conf.filter_relative) {
2124 nr_samples = hists->stats.nr_non_filtered_samples;
2125 nr_events = hists->stats.total_non_filtered_period;
2126 }
2127
Namhyung Kim759ff492013-03-05 14:53:26 +09002128 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002129 struct perf_evsel *pos;
2130
2131 perf_evsel__group_desc(evsel, buf, buflen);
2132 ev_name = buf;
2133
2134 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002135 struct hists *pos_hists = evsel__hists(pos);
2136
Namhyung Kimf2148332014-01-14 11:52:48 +09002137 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002138 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2139 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002140 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002141 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2142 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002143 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002144 }
2145 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002146
Kan Liang9e207dd2015-08-11 06:30:49 -04002147 if (symbol_conf.show_ref_callgraph &&
2148 strstr(ev_name, "call-graph=no"))
2149 enable_ref = true;
Ashay Ranecc686282012-04-05 21:01:01 -05002150 nr_samples = convert_unit(nr_samples, &unit);
2151 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002152 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2153 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc686282012-04-05 21:01:01 -05002154
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002155
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002156 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002157 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002158 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002159 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002160 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002161 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002162 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002163 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002164 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002165 } else {
2166 printed += scnprintf(bf + printed, size - printed,
2167 ", Thread: %s",
2168 (thread->comm_set ? thread__comm_str(thread) : ""));
2169 }
2170 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002171 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002172 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002173 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002174 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002175 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002176 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002177 if (!is_report_browser(hbt)) {
2178 struct perf_top *top = hbt->arg;
2179
2180 if (top->zero)
2181 printed += scnprintf(bf + printed, size - printed, " [z]");
2182 }
2183
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002184 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002185}
2186
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002187static inline void free_popup_options(char **options, int n)
2188{
2189 int i;
2190
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002191 for (i = 0; i < n; ++i)
2192 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002193}
2194
Feng Tang341487ab2013-02-03 14:38:20 +08002195/*
2196 * Only runtime switching of perf data file will make "input_name" point
2197 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2198 * whether we need to call free() for current "input_name" during the switch.
2199 */
2200static bool is_input_name_malloced = false;
2201
2202static int switch_data_file(void)
2203{
2204 char *pwd, *options[32], *abs_path[32], *tmp;
2205 DIR *pwd_dir;
2206 int nr_options = 0, choice = -1, ret = -1;
2207 struct dirent *dent;
2208
2209 pwd = getenv("PWD");
2210 if (!pwd)
2211 return ret;
2212
2213 pwd_dir = opendir(pwd);
2214 if (!pwd_dir)
2215 return ret;
2216
2217 memset(options, 0, sizeof(options));
2218 memset(options, 0, sizeof(abs_path));
2219
2220 while ((dent = readdir(pwd_dir))) {
2221 char path[PATH_MAX];
2222 u64 magic;
2223 char *name = dent->d_name;
2224 FILE *file;
2225
2226 if (!(dent->d_type == DT_REG))
2227 continue;
2228
2229 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2230
2231 file = fopen(path, "r");
2232 if (!file)
2233 continue;
2234
2235 if (fread(&magic, 1, 8, file) < 8)
2236 goto close_file_and_continue;
2237
2238 if (is_perf_magic(magic)) {
2239 options[nr_options] = strdup(name);
2240 if (!options[nr_options])
2241 goto close_file_and_continue;
2242
2243 abs_path[nr_options] = strdup(path);
2244 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002245 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002246 ui__warning("Can't search all data files due to memory shortage.\n");
2247 fclose(file);
2248 break;
2249 }
2250
2251 nr_options++;
2252 }
2253
2254close_file_and_continue:
2255 fclose(file);
2256 if (nr_options >= 32) {
2257 ui__warning("Too many perf data files in PWD!\n"
2258 "Only the first 32 files will be listed.\n");
2259 break;
2260 }
2261 }
2262 closedir(pwd_dir);
2263
2264 if (nr_options) {
2265 choice = ui__popup_menu(nr_options, options);
2266 if (choice < nr_options && choice >= 0) {
2267 tmp = strdup(abs_path[choice]);
2268 if (tmp) {
2269 if (is_input_name_malloced)
2270 free((void *)input_name);
2271 input_name = tmp;
2272 is_input_name_malloced = true;
2273 ret = 0;
2274 } else
2275 ui__warning("Data switch failed due to memory shortage!\n");
2276 }
2277 }
2278
2279 free_popup_options(options, nr_options);
2280 free_popup_options(abs_path, nr_options);
2281 return ret;
2282}
2283
Namhyung Kimea7cd592015-04-22 16:18:19 +09002284struct popup_action {
2285 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002286 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002287 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002288
2289 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2290};
2291
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002292static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002293do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002294{
2295 struct perf_evsel *evsel;
2296 struct annotation *notes;
2297 struct hist_entry *he;
2298 int err;
2299
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002300 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002301 return 0;
2302
Namhyung Kimea7cd592015-04-22 16:18:19 +09002303 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002304 if (!notes->src)
2305 return 0;
2306
2307 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002308 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002309 he = hist_browser__selected_entry(browser);
2310 /*
2311 * offer option to annotate the other branch source or target
2312 * (if they exists) when returning from annotate
2313 */
2314 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2315 return 1;
2316
2317 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2318 if (err)
2319 ui_browser__handle_resize(&browser->b);
2320 return 0;
2321}
2322
2323static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002324add_annotate_opt(struct hist_browser *browser __maybe_unused,
2325 struct popup_action *act, char **optstr,
2326 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002327{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002328 if (sym == NULL || map->dso->annotate_warned)
2329 return 0;
2330
2331 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2332 return 0;
2333
2334 act->ms.map = map;
2335 act->ms.sym = sym;
2336 act->fn = do_annotate;
2337 return 1;
2338}
2339
2340static int
2341do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2342{
2343 struct thread *thread = act->thread;
2344
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002345 if ((!hists__has(browser->hists, thread) &&
2346 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002347 return 0;
2348
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002349 if (browser->hists->thread_filter) {
2350 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2351 perf_hpp__set_elide(HISTC_THREAD, false);
2352 thread__zput(browser->hists->thread_filter);
2353 ui_helpline__pop();
2354 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002355 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002356 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2357 thread->comm_set ? thread__comm_str(thread) : "",
2358 thread->tid);
2359 } else {
2360 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2361 thread->comm_set ? thread__comm_str(thread) : "");
2362 }
2363
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002364 browser->hists->thread_filter = thread__get(thread);
2365 perf_hpp__set_elide(HISTC_THREAD, false);
2366 pstack__push(browser->pstack, &browser->hists->thread_filter);
2367 }
2368
2369 hists__filter_by_thread(browser->hists);
2370 hist_browser__reset(browser);
2371 return 0;
2372}
2373
2374static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002375add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2376 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002377{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002378 int ret;
2379
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002380 if ((!hists__has(browser->hists, thread) &&
2381 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002382 return 0;
2383
Jiri Olsafa829112016-05-03 13:54:47 +02002384 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002385 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2386 browser->hists->thread_filter ? "out of" : "into",
2387 thread->comm_set ? thread__comm_str(thread) : "",
2388 thread->tid);
2389 } else {
2390 ret = asprintf(optstr, "Zoom %s %s thread",
2391 browser->hists->thread_filter ? "out of" : "into",
2392 thread->comm_set ? thread__comm_str(thread) : "");
2393 }
2394 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002395 return 0;
2396
2397 act->thread = thread;
2398 act->fn = do_zoom_thread;
2399 return 1;
2400}
2401
2402static int
2403do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2404{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002405 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002406
Jiri Olsa69849fc2016-05-03 13:54:45 +02002407 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002408 return 0;
2409
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002410 if (browser->hists->dso_filter) {
2411 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2412 perf_hpp__set_elide(HISTC_DSO, false);
2413 browser->hists->dso_filter = NULL;
2414 ui_helpline__pop();
2415 } else {
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002416 if (map == NULL)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002417 return 0;
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002418 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002419 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2420 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002421 perf_hpp__set_elide(HISTC_DSO, true);
2422 pstack__push(browser->pstack, &browser->hists->dso_filter);
2423 }
2424
2425 hists__filter_by_dso(browser->hists);
2426 hist_browser__reset(browser);
2427 return 0;
2428}
2429
2430static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002431add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002432 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002433{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002434 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002435 return 0;
2436
2437 if (asprintf(optstr, "Zoom %s %s DSO",
2438 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002439 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002440 return 0;
2441
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002442 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002443 act->fn = do_zoom_dso;
2444 return 1;
2445}
2446
2447static int
2448do_browse_map(struct hist_browser *browser __maybe_unused,
2449 struct popup_action *act)
2450{
2451 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002452 return 0;
2453}
2454
2455static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002456add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002457 struct popup_action *act, char **optstr, struct map *map)
2458{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002459 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002460 return 0;
2461
2462 if (asprintf(optstr, "Browse map details") < 0)
2463 return 0;
2464
2465 act->ms.map = map;
2466 act->fn = do_browse_map;
2467 return 1;
2468}
2469
2470static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002471do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002472 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002473{
2474 char script_opt[64];
2475 memset(script_opt, 0, sizeof(script_opt));
2476
Namhyung Kimea7cd592015-04-22 16:18:19 +09002477 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002478 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002479 thread__comm_str(act->thread));
2480 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002481 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002482 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002483 }
2484
2485 script_browse(script_opt);
2486 return 0;
2487}
2488
2489static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002490add_script_opt(struct hist_browser *browser __maybe_unused,
2491 struct popup_action *act, char **optstr,
2492 struct thread *thread, struct symbol *sym)
2493{
2494 if (thread) {
2495 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2496 thread__comm_str(thread)) < 0)
2497 return 0;
2498 } else if (sym) {
2499 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2500 sym->name) < 0)
2501 return 0;
2502 } else {
2503 if (asprintf(optstr, "Run scripts for all samples") < 0)
2504 return 0;
2505 }
2506
2507 act->thread = thread;
2508 act->ms.sym = sym;
2509 act->fn = do_run_script;
2510 return 1;
2511}
2512
2513static int
2514do_switch_data(struct hist_browser *browser __maybe_unused,
2515 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002516{
2517 if (switch_data_file()) {
2518 ui__warning("Won't switch the data files due to\n"
2519 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002520 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002521 }
2522
2523 return K_SWITCH_INPUT_DATA;
2524}
2525
Namhyung Kimea7cd592015-04-22 16:18:19 +09002526static int
2527add_switch_opt(struct hist_browser *browser,
2528 struct popup_action *act, char **optstr)
2529{
2530 if (!is_report_browser(browser->hbt))
2531 return 0;
2532
2533 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2534 return 0;
2535
2536 act->fn = do_switch_data;
2537 return 1;
2538}
2539
2540static int
2541do_exit_browser(struct hist_browser *browser __maybe_unused,
2542 struct popup_action *act __maybe_unused)
2543{
2544 return 0;
2545}
2546
2547static int
2548add_exit_opt(struct hist_browser *browser __maybe_unused,
2549 struct popup_action *act, char **optstr)
2550{
2551 if (asprintf(optstr, "Exit") < 0)
2552 return 0;
2553
2554 act->fn = do_exit_browser;
2555 return 1;
2556}
2557
Kan Liang84734b02015-09-04 10:45:45 -04002558static int
2559do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2560{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002561 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002562 return 0;
2563
Kan Liang84734b02015-09-04 10:45:45 -04002564 if (browser->hists->socket_filter > -1) {
2565 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2566 browser->hists->socket_filter = -1;
2567 perf_hpp__set_elide(HISTC_SOCKET, false);
2568 } else {
2569 browser->hists->socket_filter = act->socket;
2570 perf_hpp__set_elide(HISTC_SOCKET, true);
2571 pstack__push(browser->pstack, &browser->hists->socket_filter);
2572 }
2573
2574 hists__filter_by_socket(browser->hists);
2575 hist_browser__reset(browser);
2576 return 0;
2577}
2578
2579static int
2580add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2581 char **optstr, int socket_id)
2582{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002583 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002584 return 0;
2585
2586 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2587 (browser->hists->socket_filter > -1) ? "out of" : "into",
2588 socket_id) < 0)
2589 return 0;
2590
2591 act->socket = socket_id;
2592 act->fn = do_zoom_socket;
2593 return 1;
2594}
2595
Namhyung Kim112f7612014-04-22 14:05:35 +09002596static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002597{
2598 u64 nr_entries = 0;
2599 struct rb_node *nd = rb_first(&hb->hists->entries);
2600
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002601 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002602 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2603 return;
2604 }
2605
Namhyung Kim14135662013-10-31 10:17:39 +09002606 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002607 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002608 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002609 }
2610
Namhyung Kim112f7612014-04-22 14:05:35 +09002611 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002612 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002613}
Feng Tang341487ab2013-02-03 14:38:20 +08002614
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002615static void hist_browser__update_percent_limit(struct hist_browser *hb,
2616 double percent)
2617{
2618 struct hist_entry *he;
2619 struct rb_node *nd = rb_first(&hb->hists->entries);
2620 u64 total = hists__total_period(hb->hists);
2621 u64 min_callchain_hits = total * (percent / 100);
2622
2623 hb->min_pcnt = callchain_param.min_percent = percent;
2624
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002625 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2626 he = rb_entry(nd, struct hist_entry, rb_node);
2627
Namhyung Kim79dded82016-02-26 21:13:19 +09002628 if (he->has_no_entry) {
2629 he->has_no_entry = false;
2630 he->nr_rows = 0;
2631 }
2632
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002633 if (!he->leaf || !symbol_conf.use_callchain)
2634 goto next;
2635
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002636 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2637 total = he->stat.period;
2638
2639 if (symbol_conf.cumulate_callchain)
2640 total = he->stat_acc->period;
2641
2642 min_callchain_hits = total * (percent / 100);
2643 }
2644
2645 callchain_param.sort(&he->sorted_chain, he->callchain,
2646 min_callchain_hits, &callchain_param);
2647
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002648next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002649 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002650
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002651 /* force to re-evaluate folding state of callchains */
2652 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002653 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002654 }
2655}
2656
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002657static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002658 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002659 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002660 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002661 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002662 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002663{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002664 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002665 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002666 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002667#define MAX_OPTIONS 16
2668 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002669 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002670 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002671 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002672 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002673 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002674
Namhyung Kime8e684a2013-12-26 14:37:58 +09002675#define HIST_BROWSER_HELP_COMMON \
2676 "h/?/F1 Show this window\n" \
2677 "UP/DOWN/PGUP\n" \
2678 "PGDN/SPACE Navigate\n" \
2679 "q/ESC/CTRL+C Exit browser\n\n" \
2680 "For multiple event sessions:\n\n" \
2681 "TAB/UNTAB Switch events\n\n" \
2682 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002683 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2684 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002685 "a Annotate current symbol\n" \
2686 "C Collapse all callchains\n" \
2687 "d Zoom into current DSO\n" \
2688 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002689 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002690 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002691 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002692 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002693 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002694
2695 /* help messages are sorted by lexical order of the hotkey */
2696 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002697 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002698 "P Print histograms to perf.hist.N\n"
2699 "r Run available scripts\n"
2700 "s Switch to another data file in PWD\n"
2701 "t Zoom into current Thread\n"
2702 "V Verbose (DSO names in callchains, etc)\n"
2703 "/ Filter symbol by name";
2704 const char top_help[] = HIST_BROWSER_HELP_COMMON
2705 "P Print histograms to perf.hist.N\n"
2706 "t Zoom into current Thread\n"
2707 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002708 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002709 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002710 "/ Filter symbol by name";
2711
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002712 if (browser == NULL)
2713 return -1;
2714
Namhyung Kimed426912015-05-29 21:53:44 +09002715 /* reset abort key so that it can get Ctrl-C as a key */
2716 SLang_reset_tty();
2717 SLang_init_tty(0, 0, 0);
2718
Namhyung Kim03905042015-11-28 02:32:39 +09002719 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002720 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002721 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002722
Kan Liang84734b02015-09-04 10:45:45 -04002723 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002724 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002725 goto out;
2726
2727 ui_helpline__push(helpline);
2728
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002729 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002730 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002731
Namhyung Kim5b591662014-07-31 14:47:38 +09002732 if (symbol_conf.col_width_list_str)
2733 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2734
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002735 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002736 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002737 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002738 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04002739 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002740
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002741 nr_options = 0;
2742
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03002743 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002744
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002745 if (browser->he_selection != NULL) {
2746 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002747 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04002748 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002749 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002750 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002751 case K_TAB:
2752 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06002753 if (nr_events == 1)
2754 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002755 /*
2756 * Exit the browser, let hists__browser_tree
2757 * go to the next or previous
2758 */
2759 goto out_free_stack;
2760 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002761 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02002762 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002763 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002764 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02002765 continue;
2766 }
2767
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002768 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08002769 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002770 browser->selection->map->dso->annotate_warned)
2771 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002772
Namhyung Kimea7cd592015-04-22 16:18:19 +09002773 actions->ms.map = browser->selection->map;
2774 actions->ms.sym = browser->selection->sym;
2775 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002776 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002777 case 'P':
2778 hist_browser__dump(browser);
2779 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002780 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03002781 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002782 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002783 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03002784 case 'V':
2785 browser->show_dso = !browser->show_dso;
2786 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002787 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002788 actions->thread = thread;
2789 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002790 continue;
Kan Liang84734b02015-09-04 10:45:45 -04002791 case 'S':
2792 actions->socket = socked_id;
2793 do_zoom_socket(browser, actions);
2794 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03002795 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09002796 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e452015-10-12 14:02:29 -03002797 "Please enter the name of symbol you want to see.\n"
2798 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09002799 buf, "ENTER: OK, ESC: Cancel",
2800 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002801 hists->symbol_filter_str = *buf ? buf : NULL;
2802 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09002803 hist_browser__reset(browser);
2804 }
2805 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08002806 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09002807 if (is_report_browser(hbt)) {
2808 actions->thread = NULL;
2809 actions->ms.sym = NULL;
2810 do_run_script(browser, actions);
2811 }
Feng Tangc77d8d72012-11-01 00:00:55 +08002812 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08002813 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002814 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002815 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002816 if (key == K_SWITCH_INPUT_DATA)
2817 goto out_free_stack;
2818 }
Feng Tang341487ab2013-02-03 14:38:20 +08002819 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09002820 case 'i':
2821 /* env->arch is NULL for live-mode (i.e. perf top) */
2822 if (env->arch)
2823 tui__header_window(env);
2824 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09002825 case 'F':
2826 symbol_conf.filter_relative ^= 1;
2827 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09002828 case 'z':
2829 if (!is_report_browser(hbt)) {
2830 struct perf_top *top = hbt->arg;
2831
2832 top->zero = !top->zero;
2833 }
2834 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002835 case 'L':
2836 if (ui_browser__input_window("Percent Limit",
2837 "Please enter the value you want to hide entries under that percent.",
2838 buf, "ENTER: OK, ESC: Cancel",
2839 delay_secs * 2) == K_ENTER) {
2840 char *end;
2841 double new_percent = strtod(buf, &end);
2842
2843 if (new_percent < 0 || new_percent > 100) {
2844 ui_browser__warning(&browser->b, delay_secs * 2,
2845 "Invalid percent: %.2f", new_percent);
2846 continue;
2847 }
2848
2849 hist_browser__update_percent_limit(browser, new_percent);
2850 hist_browser__reset(browser);
2851 }
2852 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002853 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002854 case 'h':
2855 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02002856 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09002857 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002858 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002859 case K_ENTER:
2860 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09002861 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002862 /* menu */
2863 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002864 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02002865 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002866 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002867
Namhyung Kim01f00a12015-04-22 16:18:16 +09002868 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002869 /*
2870 * Go back to the perf_evsel_menu__run or other user
2871 */
2872 if (left_exits)
2873 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03002874
2875 if (key == K_ESC &&
2876 ui_browser__dialog_yesno(&browser->b,
2877 "Do you really want to exit?"))
2878 goto out_free_stack;
2879
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002880 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03002881 }
Namhyung Kim64221842015-04-24 10:15:33 +09002882 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002883 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002884 /*
2885 * No need to set actions->dso here since
2886 * it's just to remove the current filter.
2887 * Ditto for thread below.
2888 */
2889 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002890 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09002891 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04002892 } else if (top == &browser->hists->socket_filter) {
2893 do_zoom_socket(browser, actions);
2894 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03002895 continue;
2896 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002897 case 'q':
2898 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03002899 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002900 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09002901 if (!is_report_browser(hbt)) {
2902 struct perf_top *top = hbt->arg;
2903
2904 perf_evlist__toggle_enable(top->evlist);
2905 /*
2906 * No need to refresh, resort/decay histogram
2907 * entries if we are not collecting samples:
2908 */
2909 if (top->evlist->enabled) {
2910 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
2911 hbt->refresh = delay_secs;
2912 } else {
2913 helpline = "Press 'f' again to re-enable the events";
2914 hbt->refresh = 0;
2915 }
2916 continue;
2917 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002918 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002919 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03002920 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03002921 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002922 }
2923
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002924 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002925 goto skip_annotation;
2926
Namhyung Kim55369fc2013-04-01 20:35:20 +09002927 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002928 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002929
2930 if (bi == NULL)
2931 goto skip_annotation;
2932
Namhyung Kimea7cd592015-04-22 16:18:19 +09002933 nr_options += add_annotate_opt(browser,
2934 &actions[nr_options],
2935 &options[nr_options],
2936 bi->from.map,
2937 bi->from.sym);
2938 if (bi->to.sym != bi->from.sym)
2939 nr_options += add_annotate_opt(browser,
2940 &actions[nr_options],
2941 &options[nr_options],
2942 bi->to.map,
2943 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002944 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09002945 nr_options += add_annotate_opt(browser,
2946 &actions[nr_options],
2947 &options[nr_options],
2948 browser->selection->map,
2949 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002950 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03002951skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002952 nr_options += add_thread_opt(browser, &actions[nr_options],
2953 &options[nr_options], thread);
2954 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002955 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002956 nr_options += add_map_opt(browser, &actions[nr_options],
2957 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00002958 browser->selection ?
2959 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04002960 nr_options += add_socket_opt(browser, &actions[nr_options],
2961 &options[nr_options],
2962 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08002963 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03002964 if (!is_report_browser(hbt))
2965 goto skip_scripting;
2966
Feng Tangcdbab7c2012-10-30 11:56:06 +08002967 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02002968 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03002969 nr_options += add_script_opt(browser,
2970 &actions[nr_options],
2971 &options[nr_options],
2972 thread, NULL);
2973 }
Wang Nanbd315aa2015-09-14 10:23:55 +00002974 /*
2975 * Note that browser->selection != NULL
2976 * when browser->he_selection is not NULL,
2977 * so we don't need to check browser->selection
2978 * before fetching browser->selection->sym like what
2979 * we do before fetching browser->selection->map.
2980 *
2981 * See hist_browser__show_entry.
2982 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002983 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03002984 nr_options += add_script_opt(browser,
2985 &actions[nr_options],
2986 &options[nr_options],
2987 NULL, browser->selection->sym);
2988 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08002989 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09002990 nr_options += add_script_opt(browser, &actions[nr_options],
2991 &options[nr_options], NULL, NULL);
2992 nr_options += add_switch_opt(browser, &actions[nr_options],
2993 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03002994skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09002995 nr_options += add_exit_opt(browser, &actions[nr_options],
2996 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002997
Namhyung Kimea7cd592015-04-22 16:18:19 +09002998 do {
2999 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003000
Namhyung Kimea7cd592015-04-22 16:18:19 +09003001 choice = ui__popup_menu(nr_options, options);
3002 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003003 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003004
3005 act = &actions[choice];
3006 key = act->fn(browser, act);
3007 } while (key == 1);
3008
3009 if (key == K_SWITCH_INPUT_DATA)
3010 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003011 }
3012out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003013 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003014out:
3015 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003016 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003017 return key;
3018}
3019
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003020struct perf_evsel_menu {
3021 struct ui_browser b;
3022 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003023 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003024 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003025 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003026};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003027
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003028static void perf_evsel_menu__write(struct ui_browser *browser,
3029 void *entry, int row)
3030{
3031 struct perf_evsel_menu *menu = container_of(browser,
3032 struct perf_evsel_menu, b);
3033 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003034 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003035 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003036 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003037 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003038 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003039 const char *warn = " ";
3040 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003041
3042 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3043 HE_COLORSET_NORMAL);
3044
Namhyung Kim759ff492013-03-05 14:53:26 +09003045 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003046 struct perf_evsel *pos;
3047
3048 ev_name = perf_evsel__group_name(evsel);
3049
3050 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003051 struct hists *pos_hists = evsel__hists(pos);
3052 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003053 }
3054 }
3055
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003056 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003057 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003058 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003059 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003060
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003061 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003062 if (nr_events != 0) {
3063 menu->lost_events = true;
3064 if (!current_entry)
3065 ui_browser__set_color(browser, HE_COLORSET_TOP);
3066 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003067 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3068 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003069 warn = bf;
3070 }
3071
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003072 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003073
3074 if (current_entry)
3075 menu->selection = evsel;
3076}
3077
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003078static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3079 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003080 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003081{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003082 struct perf_evlist *evlist = menu->b.priv;
3083 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003084 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003085 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003086 int key;
3087
3088 if (ui_browser__show(&menu->b, title,
3089 "ESC: exit, ENTER|->: Browse histograms") < 0)
3090 return -1;
3091
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003092 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003093 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003094
3095 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003096 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003097 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003098
3099 if (!menu->lost_events_warned && menu->lost_events) {
3100 ui_browser__warn_lost_events(&menu->b);
3101 menu->lost_events_warned = true;
3102 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003103 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003104 case K_RIGHT:
3105 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003106 if (!menu->selection)
3107 continue;
3108 pos = menu->selection;
3109browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003110 perf_evlist__set_selected(evlist, pos);
3111 /*
3112 * Give the calling tool a chance to populate the non
3113 * default evsel resorted hists tree.
3114 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003115 if (hbt)
3116 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003117 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003118 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003119 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003120 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003121 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003122 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003123 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003124 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003125 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003126 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003127 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003128 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003129 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003130 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003131 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003132 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003133 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003134 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003135 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003136 case 'q':
3137 case CTRL('c'):
3138 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003139 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003140 default:
3141 continue;
3142 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003143 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003144 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003145 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003146 if (!ui_browser__dialog_yesno(&menu->b,
3147 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003148 continue;
3149 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003150 case 'q':
3151 case CTRL('c'):
3152 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003153 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003154 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003155 }
3156 }
3157
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003158out:
3159 ui_browser__hide(&menu->b);
3160 return key;
3161}
3162
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003163static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003164 void *entry)
3165{
3166 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3167
3168 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3169 return true;
3170
3171 return false;
3172}
3173
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003174static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003175 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003176 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003177 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003178 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003179{
3180 struct perf_evsel *pos;
3181 struct perf_evsel_menu menu = {
3182 .b = {
3183 .entries = &evlist->entries,
3184 .refresh = ui_browser__list_head_refresh,
3185 .seek = ui_browser__list_head_seek,
3186 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003187 .filter = filter_group_entries,
3188 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003189 .priv = evlist,
3190 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003191 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003192 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003193 };
3194
3195 ui_helpline__push("Press ESC to exit");
3196
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003197 evlist__for_each(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003198 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003199 size_t line_len = strlen(ev_name) + 7;
3200
3201 if (menu.b.width < line_len)
3202 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003203 }
3204
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003205 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003206}
3207
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003208int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003209 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003210 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003211 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003212{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003213 int nr_entries = evlist->nr_entries;
3214
3215single_entry:
3216 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003217 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003218
3219 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003220 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003221 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003222 }
3223
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003224 if (symbol_conf.event_group) {
3225 struct perf_evsel *pos;
3226
3227 nr_entries = 0;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003228 evlist__for_each(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003229 if (perf_evsel__is_group_leader(pos))
3230 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003231 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003232
3233 if (nr_entries == 1)
3234 goto single_entry;
3235 }
3236
3237 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003238 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003239}