blob: f0b5b2b0e521771e599486b5b0803416a9f5d16c [file] [log] [blame]
Arnaldo Carvalho de Melo76b31a22017-04-18 12:26:44 -03001#include <dirent.h>
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03002#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03003#include <inttypes.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03004#include <stdio.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03005#include <stdlib.h>
6#include <string.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03007#include <linux/rbtree.h>
Arnaldo Carvalho de Melob0742e92017-04-18 11:08:10 -03008#include <sys/ttydefaults.h>
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03009
Namhyung Kimaca7a942012-04-04 00:14:26 -070010#include "../../util/evsel.h"
11#include "../../util/evlist.h"
12#include "../../util/hist.h"
13#include "../../util/pstack.h"
14#include "../../util/sort.h"
15#include "../../util/util.h"
Namhyung Kim42337a22014-08-12 17:16:06 +090016#include "../../util/top.h"
Namhyung Kim68d80752012-11-02 14:50:06 +090017#include "../../arch/common.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030018
Jiri Olsaf7589902016-06-20 23:58:13 +020019#include "../browsers/hists.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030020#include "../helpline.h"
21#include "../util.h"
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -020022#include "../ui.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030023#include "map.h"
Jiri Olsad7553302014-06-15 10:22:15 +020024#include "annotate.h"
Arnaldo Carvalho de Melo632a5ca2017-04-17 16:30:49 -030025#include "srcline.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030026#include "string2.h"
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030027
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030028#include "sane_ctype.h"
29
Namhyung Kimf5951d52012-09-03 11:53:09 +090030extern void hist_browser__init_hpp(void);
31
Jiri Olsa5b91a862016-06-20 23:58:15 +020032static int perf_evsel_browser_title(struct hist_browser *browser,
33 char *bf, size_t size);
Namhyung Kim112f7612014-04-22 14:05:35 +090034static void hist_browser__update_nr_entries(struct hist_browser *hb);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -030035
Namhyung Kimc3b78952014-04-22 15:56:17 +090036static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kimc3b78952014-04-22 15:56:17 +090037 float min_pcnt);
38
Namhyung Kim268397c2014-04-22 14:49:31 +090039static bool hist_browser__has_filter(struct hist_browser *hb)
40{
Jiri Olsa5a1a99c2016-01-06 16:59:02 +010041 return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter;
Namhyung Kim268397c2014-04-22 14:49:31 +090042}
43
He Kuang4fabf3d2015-03-12 15:21:49 +080044static int hist_browser__get_folding(struct hist_browser *browser)
45{
46 struct rb_node *nd;
47 struct hists *hists = browser->hists;
48 int unfolded_rows = 0;
49
50 for (nd = rb_first(&hists->entries);
51 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
Namhyung Kimf5b763f2016-02-25 00:13:43 +090052 nd = rb_hierarchy_next(nd)) {
He Kuang4fabf3d2015-03-12 15:21:49 +080053 struct hist_entry *he =
54 rb_entry(nd, struct hist_entry, rb_node);
55
Namhyung Kimf5b763f2016-02-25 00:13:43 +090056 if (he->leaf && he->unfolded)
He Kuang4fabf3d2015-03-12 15:21:49 +080057 unfolded_rows += he->nr_rows;
58 }
59 return unfolded_rows;
60}
61
Namhyung Kimc3b78952014-04-22 15:56:17 +090062static u32 hist_browser__nr_entries(struct hist_browser *hb)
63{
64 u32 nr_entries;
65
Namhyung Kimf5b763f2016-02-25 00:13:43 +090066 if (symbol_conf.report_hierarchy)
67 nr_entries = hb->nr_hierarchy_entries;
68 else if (hist_browser__has_filter(hb))
Namhyung Kimc3b78952014-04-22 15:56:17 +090069 nr_entries = hb->nr_non_filtered_entries;
70 else
71 nr_entries = hb->hists->nr_entries;
72
He Kuang4fabf3d2015-03-12 15:21:49 +080073 hb->nr_callchain_rows = hist_browser__get_folding(hb);
Namhyung Kimc3b78952014-04-22 15:56:17 +090074 return nr_entries + hb->nr_callchain_rows;
75}
76
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020077static void hist_browser__update_rows(struct hist_browser *hb)
78{
79 struct ui_browser *browser = &hb->b;
Jiri Olsaf8e67102016-08-07 17:28:26 +020080 struct hists *hists = hb->hists;
81 struct perf_hpp_list *hpp_list = hists->hpp_list;
82 u16 header_offset, index_row;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020083
Jiri Olsaf8e67102016-08-07 17:28:26 +020084 header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +020085 browser->rows = browser->height - header_offset;
86 /*
87 * Verify if we were at the last line and that line isn't
88 * visibe because we now show the header line(s).
89 */
90 index_row = browser->index - browser->top_idx;
91 if (index_row >= browser->rows)
92 browser->index -= index_row - browser->rows + 1;
93}
94
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030095static void hist_browser__refresh_dimensions(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030096{
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -030097 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
98
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -030099 /* 3 == +/- toggle symbol before actual hist_entry rendering */
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300100 browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]"));
101 /*
102 * FIXME: Just keeping existing behaviour, but this really should be
103 * before updating browser->width, as it will invalidate the
104 * calculation above. Fix this and the fallout in another
105 * changeset.
106 */
107 ui_browser__refresh_dimensions(browser);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200108 hist_browser__update_rows(hb);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300109}
110
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300111static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
112{
Jiri Olsaf8e67102016-08-07 17:28:26 +0200113 struct hists *hists = browser->hists;
114 struct perf_hpp_list *hpp_list = hists->hpp_list;
115 u16 header_offset;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200116
Jiri Olsaf8e67102016-08-07 17:28:26 +0200117 header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200118 ui_browser__gotorc(&browser->b, row + header_offset, column);
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -0300119}
120
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300121static void hist_browser__reset(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300122{
Namhyung Kimc3b78952014-04-22 15:56:17 +0900123 /*
124 * The hists__remove_entry_filter() already folds non-filtered
125 * entries so we can assume it has 0 callchain rows.
126 */
127 browser->nr_callchain_rows = 0;
128
Namhyung Kim268397c2014-04-22 14:49:31 +0900129 hist_browser__update_nr_entries(browser);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900130 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo357cfff2014-07-01 17:01:01 -0300131 hist_browser__refresh_dimensions(&browser->b);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300132 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300133}
134
135static char tree__folded_sign(bool unfolded)
136{
137 return unfolded ? '-' : '+';
138}
139
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300140static char hist_entry__folded(const struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300141{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900142 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300143}
144
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300145static char callchain_list__folded(const struct callchain_list *cl)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300146{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900147 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300148}
149
Namhyung Kim3698dab2015-05-05 23:55:46 +0900150static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300151{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900152 cl->unfolded = unfold ? cl->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300153}
154
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800155static struct inline_node *inline_node__create(struct map *map, u64 ip)
156{
157 struct dso *dso;
158 struct inline_node *node;
159
160 if (map == NULL)
161 return NULL;
162
163 dso = map->dso;
164 if (dso == NULL)
165 return NULL;
166
167 if (dso->kernel != DSO_TYPE_USER)
168 return NULL;
169
170 node = dso__parse_addr_inlines(dso,
171 map__rip_2objdump(map, ip));
172
173 return node;
174}
175
176static int inline__count_rows(struct inline_node *node)
177{
178 struct inline_list *ilist;
179 int i = 0;
180
181 if (node == NULL)
182 return 0;
183
184 list_for_each_entry(ilist, &node->val, list) {
185 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
186 i++;
187 }
188
189 return i;
190}
191
192static int callchain_list__inline_rows(struct callchain_list *chain)
193{
194 struct inline_node *node;
195 int rows;
196
197 node = inline_node__create(chain->ms.map, chain->ip);
198 if (node == NULL)
199 return 0;
200
201 rows = inline__count_rows(node);
202 inline_node__delete(node);
203 return rows;
204}
205
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300206static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300207{
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800208 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300209 struct rb_node *nd;
210
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300211 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300212 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
213 struct callchain_list *chain;
214 char folded_sign = ' '; /* No children */
215
216 list_for_each_entry(chain, &child->val, list) {
217 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800218
219 if (symbol_conf.inline_name) {
220 inline_rows =
221 callchain_list__inline_rows(chain);
222 n += inline_rows;
223 }
224
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300225 /* We need this because we may not have children */
226 folded_sign = callchain_list__folded(chain);
227 if (folded_sign == '+')
228 break;
229 }
230
231 if (folded_sign == '-') /* Have children and they're unfolded */
232 n += callchain_node__count_rows_rb_tree(child);
233 }
234
235 return n;
236}
237
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900238static int callchain_node__count_flat_rows(struct callchain_node *node)
239{
240 struct callchain_list *chain;
241 char folded_sign = 0;
242 int n = 0;
243
244 list_for_each_entry(chain, &node->parent_val, list) {
245 if (!folded_sign) {
246 /* only check first chain list entry */
247 folded_sign = callchain_list__folded(chain);
248 if (folded_sign == '+')
249 return 1;
250 }
251 n++;
252 }
253
254 list_for_each_entry(chain, &node->val, list) {
255 if (!folded_sign) {
256 /* node->parent_val list might be empty */
257 folded_sign = callchain_list__folded(chain);
258 if (folded_sign == '+')
259 return 1;
260 }
261 n++;
262 }
263
264 return n;
265}
266
Namhyung Kim8c430a32015-11-09 14:45:44 +0900267static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
268{
269 return 1;
270}
271
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300272static int callchain_node__count_rows(struct callchain_node *node)
273{
274 struct callchain_list *chain;
275 bool unfolded = false;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800276 int n = 0, inline_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300277
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900278 if (callchain_param.mode == CHAIN_FLAT)
279 return callchain_node__count_flat_rows(node);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900280 else if (callchain_param.mode == CHAIN_FOLDED)
281 return callchain_node__count_folded_rows(node);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900282
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300283 list_for_each_entry(chain, &node->val, list) {
284 ++n;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800285 if (symbol_conf.inline_name) {
286 inline_rows = callchain_list__inline_rows(chain);
287 n += inline_rows;
288 }
289
Namhyung Kim3698dab2015-05-05 23:55:46 +0900290 unfolded = chain->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300291 }
292
293 if (unfolded)
294 n += callchain_node__count_rows_rb_tree(node);
295
296 return n;
297}
298
299static int callchain__count_rows(struct rb_root *chain)
300{
301 struct rb_node *nd;
302 int n = 0;
303
304 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
305 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
306 n += callchain_node__count_rows(node);
307 }
308
309 return n;
310}
311
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900312static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
313 bool include_children)
314{
315 int count = 0;
316 struct rb_node *node;
317 struct hist_entry *child;
318
319 if (he->leaf)
320 return callchain__count_rows(&he->sorted_chain);
321
Namhyung Kim79dded82016-02-26 21:13:19 +0900322 if (he->has_no_entry)
323 return 1;
324
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900325 node = rb_first(&he->hroot_out);
326 while (node) {
327 float percent;
328
329 child = rb_entry(node, struct hist_entry, rb_node);
330 percent = hist_entry__get_percent_limit(child);
331
332 if (!child->filtered && percent >= hb->min_pcnt) {
333 count++;
334
335 if (include_children && child->unfolded)
336 count += hierarchy_count_rows(hb, child, true);
337 }
338
339 node = rb_next(node);
340 }
341 return count;
342}
343
Namhyung Kim3698dab2015-05-05 23:55:46 +0900344static bool hist_entry__toggle_fold(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300345{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900346 if (!he)
Jiri Olsa8493fe12012-04-04 22:21:31 +0200347 return false;
348
Namhyung Kim3698dab2015-05-05 23:55:46 +0900349 if (!he->has_children)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300350 return false;
351
Namhyung Kim3698dab2015-05-05 23:55:46 +0900352 he->unfolded = !he->unfolded;
353 return true;
354}
355
356static bool callchain_list__toggle_fold(struct callchain_list *cl)
357{
358 if (!cl)
359 return false;
360
361 if (!cl->has_children)
362 return false;
363
364 cl->unfolded = !cl->unfolded;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300365 return true;
366}
367
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300368static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300369{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300370 struct rb_node *nd = rb_first(&node->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300371
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300372 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300373 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
374 struct callchain_list *chain;
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300375 bool first = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300376
377 list_for_each_entry(chain, &child->val, list) {
378 if (first) {
379 first = false;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900380 chain->has_children = chain->list.next != &child->val ||
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300381 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300382 } else
Namhyung Kim3698dab2015-05-05 23:55:46 +0900383 chain->has_children = chain->list.next == &child->val &&
Arnaldo Carvalho de Melo293db472010-08-25 16:05:36 -0300384 !RB_EMPTY_ROOT(&child->rb_root);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300385 }
386
387 callchain_node__init_have_children_rb_tree(child);
388 }
389}
390
Namhyung Kima7444af2014-11-24 17:13:27 +0900391static void callchain_node__init_have_children(struct callchain_node *node,
392 bool has_sibling)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300393{
394 struct callchain_list *chain;
395
Namhyung Kima7444af2014-11-24 17:13:27 +0900396 chain = list_entry(node->val.next, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900397 chain->has_children = has_sibling;
Namhyung Kima7444af2014-11-24 17:13:27 +0900398
Andres Freund90989032016-03-30 21:02:45 +0200399 if (!list_empty(&node->val)) {
Namhyung Kim82162b52014-08-13 15:02:41 +0900400 chain = list_entry(node->val.prev, struct callchain_list, list);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900401 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
Namhyung Kim82162b52014-08-13 15:02:41 +0900402 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300403
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300404 callchain_node__init_have_children_rb_tree(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300405}
406
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300407static void callchain__init_have_children(struct rb_root *root)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300408{
Namhyung Kima7444af2014-11-24 17:13:27 +0900409 struct rb_node *nd = rb_first(root);
410 bool has_sibling = nd && rb_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300411
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300412 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300413 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
Namhyung Kima7444af2014-11-24 17:13:27 +0900414 callchain_node__init_have_children(node, has_sibling);
Namhyung Kim8c430a32015-11-09 14:45:44 +0900415 if (callchain_param.mode == CHAIN_FLAT ||
416 callchain_param.mode == CHAIN_FOLDED)
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900417 callchain_node__make_parent_list(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300418 }
419}
420
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300421static void hist_entry__init_have_children(struct hist_entry *he)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300422{
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900423 if (he->init_have_children)
424 return;
425
426 if (he->leaf) {
Namhyung Kim3698dab2015-05-05 23:55:46 +0900427 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300428 callchain__init_have_children(&he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900429 } else {
430 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300431 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900432
433 he->init_have_children = true;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300434}
435
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800436static void hist_entry_init_inline_node(struct hist_entry *he)
437{
438 if (he->inline_node)
439 return;
440
441 he->inline_node = inline_node__create(he->ms.map, he->ip);
442
443 if (he->inline_node == NULL)
444 return;
445
446 he->has_children = true;
447}
448
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300449static bool hist_browser__toggle_fold(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300450{
Namhyung Kim3698dab2015-05-05 23:55:46 +0900451 struct hist_entry *he = browser->he_selection;
452 struct map_symbol *ms = browser->selection;
453 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
454 bool has_children;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300455
Wang Nan4938cf02015-12-07 02:35:44 +0000456 if (!he || !ms)
457 return false;
458
Namhyung Kim3698dab2015-05-05 23:55:46 +0900459 if (ms == &he->ms)
460 has_children = hist_entry__toggle_fold(he);
461 else
462 has_children = callchain_list__toggle_fold(cl);
463
464 if (has_children) {
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900465 int child_rows = 0;
466
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300467 hist_entry__init_have_children(he);
Namhyung Kimc3b78952014-04-22 15:56:17 +0900468 browser->b.nr_entries -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300469
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900470 if (he->leaf)
471 browser->nr_callchain_rows -= he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300472 else
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900473 browser->nr_hierarchy_entries -= he->nr_rows;
474
475 if (symbol_conf.report_hierarchy)
476 child_rows = hierarchy_count_rows(browser, he, true);
477
478 if (he->unfolded) {
479 if (he->leaf)
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800480 if (he->inline_node)
481 he->nr_rows = inline__count_rows(
482 he->inline_node);
483 else
484 he->nr_rows = callchain__count_rows(
485 &he->sorted_chain);
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900486 else
487 he->nr_rows = hierarchy_count_rows(browser, he, false);
488
489 /* account grand children */
490 if (symbol_conf.report_hierarchy)
491 browser->b.nr_entries += child_rows - he->nr_rows;
Namhyung Kim79dded82016-02-26 21:13:19 +0900492
493 if (!he->leaf && he->nr_rows == 0) {
494 he->has_no_entry = true;
495 he->nr_rows = 1;
496 }
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900497 } else {
498 if (symbol_conf.report_hierarchy)
499 browser->b.nr_entries -= child_rows - he->nr_rows;
500
Namhyung Kim79dded82016-02-26 21:13:19 +0900501 if (he->has_no_entry)
502 he->has_no_entry = false;
503
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300504 he->nr_rows = 0;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900505 }
Namhyung Kimc3b78952014-04-22 15:56:17 +0900506
507 browser->b.nr_entries += he->nr_rows;
Namhyung Kimf5b763f2016-02-25 00:13:43 +0900508
509 if (he->leaf)
510 browser->nr_callchain_rows += he->nr_rows;
511 else
512 browser->nr_hierarchy_entries += he->nr_rows;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300513
514 return true;
515 }
516
517 /* If it doesn't have children, no toggling performed */
518 return false;
519}
520
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300521static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300522{
523 int n = 0;
524 struct rb_node *nd;
525
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300526 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300527 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
528 struct callchain_list *chain;
529 bool has_children = false;
530
531 list_for_each_entry(chain, &child->val, list) {
532 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900533 callchain_list__set_folding(chain, unfold);
534 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300535 }
536
537 if (has_children)
538 n += callchain_node__set_folding_rb_tree(child, unfold);
539 }
540
541 return n;
542}
543
544static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
545{
546 struct callchain_list *chain;
547 bool has_children = false;
548 int n = 0;
549
550 list_for_each_entry(chain, &node->val, list) {
551 ++n;
Namhyung Kim3698dab2015-05-05 23:55:46 +0900552 callchain_list__set_folding(chain, unfold);
553 has_children = chain->has_children;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300554 }
555
556 if (has_children)
557 n += callchain_node__set_folding_rb_tree(node, unfold);
558
559 return n;
560}
561
562static int callchain__set_folding(struct rb_root *chain, bool unfold)
563{
564 struct rb_node *nd;
565 int n = 0;
566
567 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
568 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
569 n += callchain_node__set_folding(node, unfold);
570 }
571
572 return n;
573}
574
Namhyung Kim492b1012016-02-25 00:13:44 +0900575static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
576 bool unfold __maybe_unused)
577{
578 float percent;
579 struct rb_node *nd;
580 struct hist_entry *child;
581 int n = 0;
582
583 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
584 child = rb_entry(nd, struct hist_entry, rb_node);
585 percent = hist_entry__get_percent_limit(child);
586 if (!child->filtered && percent >= hb->min_pcnt)
587 n++;
588 }
589
590 return n;
591}
592
Jiri Olsab33f9222017-01-20 10:20:29 +0100593static void __hist_entry__set_folding(struct hist_entry *he,
594 struct hist_browser *hb, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300595{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300596 hist_entry__init_have_children(he);
Namhyung Kim3698dab2015-05-05 23:55:46 +0900597 he->unfolded = unfold ? he->has_children : false;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300598
Namhyung Kim3698dab2015-05-05 23:55:46 +0900599 if (he->has_children) {
Namhyung Kim492b1012016-02-25 00:13:44 +0900600 int n;
601
602 if (he->leaf)
603 n = callchain__set_folding(&he->sorted_chain, unfold);
604 else
605 n = hierarchy_set_folding(hb, he, unfold);
606
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300607 he->nr_rows = unfold ? n : 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300608 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300609 he->nr_rows = 0;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300610}
611
Jiri Olsab33f9222017-01-20 10:20:29 +0100612static void hist_entry__set_folding(struct hist_entry *he,
613 struct hist_browser *browser, bool unfold)
614{
615 double percent;
616
617 percent = hist_entry__get_percent_limit(he);
618 if (he->filtered || percent < browser->min_pcnt)
619 return;
620
621 __hist_entry__set_folding(he, browser, unfold);
622
623 if (!he->depth || unfold)
624 browser->nr_hierarchy_entries++;
625 if (he->leaf)
626 browser->nr_callchain_rows += he->nr_rows;
627 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
628 browser->nr_hierarchy_entries++;
629 he->has_no_entry = true;
630 he->nr_rows = 1;
631 } else
632 he->has_no_entry = false;
633}
634
Namhyung Kimc3b78952014-04-22 15:56:17 +0900635static void
636__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300637{
638 struct rb_node *nd;
Namhyung Kim492b1012016-02-25 00:13:44 +0900639 struct hist_entry *he;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300640
Namhyung Kim492b1012016-02-25 00:13:44 +0900641 nd = rb_first(&browser->hists->entries);
642 while (nd) {
643 he = rb_entry(nd, struct hist_entry, rb_node);
644
645 /* set folding state even if it's currently folded */
646 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
647
648 hist_entry__set_folding(he, browser, unfold);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300649 }
650}
651
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300652static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300653{
Namhyung Kim492b1012016-02-25 00:13:44 +0900654 browser->nr_hierarchy_entries = 0;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900655 browser->nr_callchain_rows = 0;
656 __hist_browser__set_folding(browser, unfold);
657
658 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300659 /* Go to the start, we may be way after valid entries after a collapse */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300660 ui_browser__reset_index(&browser->b);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300661}
662
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100663static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
664{
665 if (!browser->he_selection)
666 return;
667
668 hist_entry__set_folding(browser->he_selection, browser, unfold);
669 browser->b.nr_entries = hist_browser__nr_entries(browser);
670}
671
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200672static void ui_browser__warn_lost_events(struct ui_browser *browser)
673{
674 ui_browser__warning(browser, 4,
675 "Events are being lost, check IO/CPU overload!\n\n"
676 "You may want to run 'perf' using a RT scheduler policy:\n\n"
677 " perf top -r 80\n\n"
678 "Or reduce the sampling frequency.");
679}
680
Jiri Olsa5b91a862016-06-20 23:58:15 +0200681static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
682{
683 return browser->title ? browser->title(browser, bf, size) : 0;
684}
685
Jiri Olsadabd2012016-06-20 23:58:14 +0200686int hist_browser__run(struct hist_browser *browser, const char *help)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300687{
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300688 int key;
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300689 char title[160];
Namhyung Kimc2a51ab2015-04-22 16:18:15 +0900690 struct hist_browser_timer *hbt = browser->hbt;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900691 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300692
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300693 browser->b.entries = &browser->hists->entries;
Namhyung Kimc3b78952014-04-22 15:56:17 +0900694 browser->b.nr_entries = hist_browser__nr_entries(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300695
Jiri Olsa5b91a862016-06-20 23:58:15 +0200696 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300697
Namhyung Kim090cff32016-01-11 19:53:14 +0900698 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300699 return -1;
700
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300701 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300702 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300703
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300704 switch (key) {
Namhyung Kimfa5df942013-05-14 11:09:05 +0900705 case K_TIMER: {
706 u64 nr_entries;
Namhyung Kim9783adf2012-11-02 14:50:05 +0900707 hbt->timer(hbt->arg);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900708
Namhyung Kimc6111522016-10-07 14:04:12 +0900709 if (hist_browser__has_filter(browser) ||
710 symbol_conf.report_hierarchy)
Namhyung Kim112f7612014-04-22 14:05:35 +0900711 hist_browser__update_nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900712
Namhyung Kimc3b78952014-04-22 15:56:17 +0900713 nr_entries = hist_browser__nr_entries(browser);
Namhyung Kimfa5df942013-05-14 11:09:05 +0900714 ui_browser__update_nr_entries(&browser->b, nr_entries);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200715
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300716 if (browser->hists->stats.nr_lost_warned !=
717 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
718 browser->hists->stats.nr_lost_warned =
719 browser->hists->stats.nr_events[PERF_RECORD_LOST];
720 ui_browser__warn_lost_events(&browser->b);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -0200721 }
722
Jiri Olsa5b91a862016-06-20 23:58:15 +0200723 hist_browser__title(browser, title, sizeof(title));
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300724 ui_browser__show_title(&browser->b, title);
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300725 continue;
Namhyung Kimfa5df942013-05-14 11:09:05 +0900726 }
Arnaldo Carvalho de Melo46941532010-08-10 15:50:07 -0300727 case 'D': { /* Debug */
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300728 static int seq;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300729 struct hist_entry *h = rb_entry(browser->b.top,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300730 struct hist_entry, rb_node);
731 ui_helpline__pop();
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300732 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 -0300733 seq++, browser->b.nr_entries,
734 browser->hists->nr_entries,
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -0300735 browser->b.rows,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300736 browser->b.index,
737 browser->b.top_idx,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300738 h->row_offset, h->nr_rows);
739 }
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300740 break;
741 case 'C':
742 /* Collapse the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300743 hist_browser__set_folding(browser, false);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300744 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100745 case 'c':
746 /* Collapse the selected entry. */
747 hist_browser__set_folding_selected(browser, false);
748 break;
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300749 case 'E':
750 /* Expand the whole world. */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300751 hist_browser__set_folding(browser, true);
Arnaldo Carvalho de Melo3c916cc2010-08-25 17:18:35 -0300752 break;
Jiri Olsa0e3fa7a2017-01-20 10:20:30 +0100753 case 'e':
754 /* Expand the selected entry. */
755 hist_browser__set_folding_selected(browser, true);
756 break;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +0200757 case 'H':
758 browser->show_headers = !browser->show_headers;
759 hist_browser__update_rows(browser);
760 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200761 case K_ENTER:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300762 if (hist_browser__toggle_fold(browser))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300763 break;
764 /* fall thru */
765 default:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300766 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300767 }
768 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300769out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300770 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300771 return key;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300772}
773
Namhyung Kim39ee5332014-08-22 09:13:21 +0900774struct callchain_print_arg {
775 /* for hists browser */
776 off_t row_offset;
777 bool is_current_entry;
778
779 /* for file dump */
780 FILE *fp;
781 int printed;
782};
783
784typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
785 struct callchain_list *chain,
786 const char *str, int offset,
787 unsigned short row,
788 struct callchain_print_arg *arg);
789
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900790static void hist_browser__show_callchain_entry(struct hist_browser *browser,
791 struct callchain_list *chain,
Namhyung Kim39ee5332014-08-22 09:13:21 +0900792 const char *str, int offset,
793 unsigned short row,
794 struct callchain_print_arg *arg)
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900795{
796 int color, width;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900797 char folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300798 bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900799
800 color = HE_COLORSET_NORMAL;
801 width = browser->b.width - (offset + 2);
802 if (ui_browser__is_current_entry(&browser->b, row)) {
803 browser->selection = &chain->ms;
804 color = HE_COLORSET_SELECTED;
Namhyung Kim39ee5332014-08-22 09:13:21 +0900805 arg->is_current_entry = true;
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900806 }
807
808 ui_browser__set_color(&browser->b, color);
809 hist_browser__gotorc(browser, row, 0);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300810 ui_browser__write_nstring(&browser->b, " ", offset);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -0300811 ui_browser__printf(&browser->b, "%c", folded_sign);
Arnaldo Carvalho de Melo70e97272015-03-19 16:07:21 -0300812 ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -0300813 ui_browser__write_nstring(&browser->b, str, width);
Namhyung Kimf4536dd2014-08-20 17:07:57 +0900814}
815
Namhyung Kim39ee5332014-08-22 09:13:21 +0900816static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
817 struct callchain_list *chain,
818 const char *str, int offset,
819 unsigned short row __maybe_unused,
820 struct callchain_print_arg *arg)
821{
822 char folded_sign = callchain_list__folded(chain);
823
824 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
825 folded_sign, str);
826}
827
828typedef bool (*check_output_full_fn)(struct hist_browser *browser,
829 unsigned short row);
830
831static bool hist_browser__check_output_full(struct hist_browser *browser,
832 unsigned short row)
833{
834 return browser->b.rows == row;
835}
836
837static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
838 unsigned short row __maybe_unused)
839{
840 return false;
841}
842
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -0300843#define LEVEL_OFFSET_STEP 3
844
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800845static int hist_browser__show_inline(struct hist_browser *browser,
846 struct inline_node *node,
847 unsigned short row,
848 int offset)
849{
850 struct inline_list *ilist;
851 char buf[1024];
852 int color, width, first_row;
853
854 first_row = row;
855 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
856 list_for_each_entry(ilist, &node->val, list) {
857 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
858 color = HE_COLORSET_NORMAL;
859 if (ui_browser__is_current_entry(&browser->b, row))
860 color = HE_COLORSET_SELECTED;
861
Milian Wolff5dfa2102017-03-18 22:49:28 +0100862 if (callchain_param.key == CCKEY_ADDRESS ||
863 callchain_param.key == CCKEY_SRCLINE) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800864 if (ilist->filename != NULL)
865 scnprintf(buf, sizeof(buf),
866 "%s:%d (inline)",
867 ilist->filename,
868 ilist->line_nr);
869 else
870 scnprintf(buf, sizeof(buf), "??");
871 } else if (ilist->funcname != NULL)
872 scnprintf(buf, sizeof(buf), "%s (inline)",
873 ilist->funcname);
874 else if (ilist->filename != NULL)
875 scnprintf(buf, sizeof(buf),
876 "%s:%d (inline)",
877 ilist->filename,
878 ilist->line_nr);
879 else
880 scnprintf(buf, sizeof(buf), "??");
881
882 ui_browser__set_color(&browser->b, color);
883 hist_browser__gotorc(browser, row, 0);
884 ui_browser__write_nstring(&browser->b, " ",
885 LEVEL_OFFSET_STEP + offset);
886 ui_browser__write_nstring(&browser->b, buf, width);
887 row++;
888 }
889 }
890
891 return row - first_row;
892}
893
894static size_t show_inline_list(struct hist_browser *browser, struct map *map,
895 u64 ip, int row, int offset)
896{
897 struct inline_node *node;
898 int ret;
899
900 node = inline_node__create(map, ip);
901 if (node == NULL)
902 return 0;
903
904 ret = hist_browser__show_inline(browser, node, row, offset);
905
906 inline_node__delete(node);
907 return ret;
908}
909
Namhyung Kim18bb8382015-11-09 14:45:42 +0900910static int hist_browser__show_callchain_list(struct hist_browser *browser,
911 struct callchain_node *node,
912 struct callchain_list *chain,
913 unsigned short row, u64 total,
914 bool need_percent, int offset,
915 print_callchain_entry_fn print,
916 struct callchain_print_arg *arg)
917{
918 char bf[1024], *alloc_str;
Jin Yaofef51ec2016-10-31 09:19:53 +0800919 char buf[64], *alloc_str2;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900920 const char *str;
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800921 int inline_rows = 0, ret = 1;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900922
923 if (arg->row_offset != 0) {
924 arg->row_offset--;
925 return 0;
926 }
927
928 alloc_str = NULL;
Jin Yaofef51ec2016-10-31 09:19:53 +0800929 alloc_str2 = NULL;
930
Namhyung Kim18bb8382015-11-09 14:45:42 +0900931 str = callchain_list__sym_name(chain, bf, sizeof(bf),
932 browser->show_dso);
933
Jin Yaofef51ec2016-10-31 09:19:53 +0800934 if (symbol_conf.show_branchflag_count) {
935 if (need_percent)
936 callchain_list_counts__printf_value(node, chain, NULL,
937 buf, sizeof(buf));
938 else
939 callchain_list_counts__printf_value(NULL, chain, NULL,
940 buf, sizeof(buf));
Namhyung Kim18bb8382015-11-09 14:45:42 +0900941
Jin Yaofef51ec2016-10-31 09:19:53 +0800942 if (asprintf(&alloc_str2, "%s%s", str, buf) < 0)
943 str = "Not enough memory!";
944 else
945 str = alloc_str2;
946 }
947
948 if (need_percent) {
Namhyung Kim18bb8382015-11-09 14:45:42 +0900949 callchain_node__scnprintf_value(node, buf, sizeof(buf),
950 total);
951
952 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
953 str = "Not enough memory!";
954 else
955 str = alloc_str;
956 }
957
958 print(browser, chain, str, offset, row, arg);
Namhyung Kim18bb8382015-11-09 14:45:42 +0900959 free(alloc_str);
Jin Yaofef51ec2016-10-31 09:19:53 +0800960 free(alloc_str2);
Jin Yao0d3eb0b2017-03-26 04:34:29 +0800961
962 if (symbol_conf.inline_name) {
963 inline_rows = show_inline_list(browser, chain->ms.map,
964 chain->ip, row + 1, offset);
965 }
966
967 return ret + inline_rows;
Namhyung Kim18bb8382015-11-09 14:45:42 +0900968}
969
Namhyung Kim59c624e2016-01-28 00:40:56 +0900970static bool check_percent_display(struct rb_node *node, u64 parent_total)
971{
972 struct callchain_node *child;
973
974 if (node == NULL)
975 return false;
976
977 if (rb_next(node))
978 return true;
979
980 child = rb_entry(node, struct callchain_node, rb_node);
981 return callchain_cumul_hits(child) != parent_total;
982}
983
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900984static int hist_browser__show_callchain_flat(struct hist_browser *browser,
985 struct rb_root *root,
986 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +0900987 u64 parent_total,
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900988 print_callchain_entry_fn print,
989 struct callchain_print_arg *arg,
990 check_output_full_fn is_output_full)
991{
992 struct rb_node *node;
993 int first_row = row, offset = LEVEL_OFFSET_STEP;
994 bool need_percent;
995
996 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +0900997 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4b3a3212015-11-09 14:45:43 +0900998
999 while (node) {
1000 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1001 struct rb_node *next = rb_next(node);
1002 struct callchain_list *chain;
1003 char folded_sign = ' ';
1004 int first = true;
1005 int extra_offset = 0;
1006
1007 list_for_each_entry(chain, &child->parent_val, list) {
1008 bool was_first = first;
1009
1010 if (first)
1011 first = false;
1012 else if (need_percent)
1013 extra_offset = LEVEL_OFFSET_STEP;
1014
1015 folded_sign = callchain_list__folded(chain);
1016
1017 row += hist_browser__show_callchain_list(browser, child,
1018 chain, row, total,
1019 was_first && need_percent,
1020 offset + extra_offset,
1021 print, arg);
1022
1023 if (is_output_full(browser, row))
1024 goto out;
1025
1026 if (folded_sign == '+')
1027 goto next;
1028 }
1029
1030 list_for_each_entry(chain, &child->val, list) {
1031 bool was_first = first;
1032
1033 if (first)
1034 first = false;
1035 else if (need_percent)
1036 extra_offset = LEVEL_OFFSET_STEP;
1037
1038 folded_sign = callchain_list__folded(chain);
1039
1040 row += hist_browser__show_callchain_list(browser, child,
1041 chain, row, total,
1042 was_first && need_percent,
1043 offset + extra_offset,
1044 print, arg);
1045
1046 if (is_output_full(browser, row))
1047 goto out;
1048
1049 if (folded_sign == '+')
1050 break;
1051 }
1052
1053next:
1054 if (is_output_full(browser, row))
1055 break;
1056 node = next;
1057 }
1058out:
1059 return row - first_row;
1060}
1061
Namhyung Kim8c430a32015-11-09 14:45:44 +09001062static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
1063 struct callchain_list *chain,
1064 char *value_str, char *old_str)
1065{
1066 char bf[1024];
1067 const char *str;
1068 char *new;
1069
1070 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1071 browser->show_dso);
1072 if (old_str) {
1073 if (asprintf(&new, "%s%s%s", old_str,
1074 symbol_conf.field_sep ?: ";", str) < 0)
1075 new = NULL;
1076 } else {
1077 if (value_str) {
1078 if (asprintf(&new, "%s %s", value_str, str) < 0)
1079 new = NULL;
1080 } else {
1081 if (asprintf(&new, "%s", str) < 0)
1082 new = NULL;
1083 }
1084 }
1085 return new;
1086}
1087
1088static int hist_browser__show_callchain_folded(struct hist_browser *browser,
1089 struct rb_root *root,
1090 unsigned short row, u64 total,
Namhyung Kim59c624e2016-01-28 00:40:56 +09001091 u64 parent_total,
Namhyung Kim8c430a32015-11-09 14:45:44 +09001092 print_callchain_entry_fn print,
1093 struct callchain_print_arg *arg,
1094 check_output_full_fn is_output_full)
1095{
1096 struct rb_node *node;
1097 int first_row = row, offset = LEVEL_OFFSET_STEP;
1098 bool need_percent;
1099
1100 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001101 need_percent = check_percent_display(node, parent_total);
Namhyung Kim8c430a32015-11-09 14:45:44 +09001102
1103 while (node) {
1104 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1105 struct rb_node *next = rb_next(node);
1106 struct callchain_list *chain, *first_chain = NULL;
1107 int first = true;
1108 char *value_str = NULL, *value_str_alloc = NULL;
1109 char *chain_str = NULL, *chain_str_alloc = NULL;
1110
1111 if (arg->row_offset != 0) {
1112 arg->row_offset--;
1113 goto next;
1114 }
1115
1116 if (need_percent) {
1117 char buf[64];
1118
1119 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
1120 if (asprintf(&value_str, "%s", buf) < 0) {
1121 value_str = (char *)"<...>";
1122 goto do_print;
1123 }
1124 value_str_alloc = value_str;
1125 }
1126
1127 list_for_each_entry(chain, &child->parent_val, list) {
1128 chain_str = hist_browser__folded_callchain_str(browser,
1129 chain, value_str, chain_str);
1130 if (first) {
1131 first = false;
1132 first_chain = chain;
1133 }
1134
1135 if (chain_str == NULL) {
1136 chain_str = (char *)"Not enough memory!";
1137 goto do_print;
1138 }
1139
1140 chain_str_alloc = chain_str;
1141 }
1142
1143 list_for_each_entry(chain, &child->val, list) {
1144 chain_str = hist_browser__folded_callchain_str(browser,
1145 chain, value_str, chain_str);
1146 if (first) {
1147 first = false;
1148 first_chain = chain;
1149 }
1150
1151 if (chain_str == NULL) {
1152 chain_str = (char *)"Not enough memory!";
1153 goto do_print;
1154 }
1155
1156 chain_str_alloc = chain_str;
1157 }
1158
1159do_print:
1160 print(browser, first_chain, chain_str, offset, row++, arg);
1161 free(value_str_alloc);
1162 free(chain_str_alloc);
1163
1164next:
1165 if (is_output_full(browser, row))
1166 break;
1167 node = next;
1168 }
1169
1170 return row - first_row;
1171}
1172
Namhyung Kim0c841c62016-01-28 00:40:54 +09001173static int hist_browser__show_callchain_graph(struct hist_browser *browser,
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001174 struct rb_root *root, int level,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001175 unsigned short row, u64 total,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001176 u64 parent_total,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001177 print_callchain_entry_fn print,
1178 struct callchain_print_arg *arg,
1179 check_output_full_fn is_output_full)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001180{
1181 struct rb_node *node;
Namhyung Kimf4536dd2014-08-20 17:07:57 +09001182 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
Namhyung Kim4087d112014-11-24 17:13:26 +09001183 bool need_percent;
Namhyung Kim5eca1042016-01-28 00:40:55 +09001184 u64 percent_total = total;
1185
1186 if (callchain_param.mode == CHAIN_GRAPH_REL)
1187 percent_total = parent_total;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001188
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001189 node = rb_first(root);
Namhyung Kim59c624e2016-01-28 00:40:56 +09001190 need_percent = check_percent_display(node, parent_total);
Namhyung Kim4087d112014-11-24 17:13:26 +09001191
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001192 while (node) {
1193 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1194 struct rb_node *next = rb_next(node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001195 struct callchain_list *chain;
1196 char folded_sign = ' ';
1197 int first = true;
1198 int extra_offset = 0;
1199
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001200 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001201 bool was_first = first;
1202
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001203 if (first)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001204 first = false;
Namhyung Kim4087d112014-11-24 17:13:26 +09001205 else if (need_percent)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001206 extra_offset = LEVEL_OFFSET_STEP;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001207
1208 folded_sign = callchain_list__folded(chain);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001209
Namhyung Kim18bb8382015-11-09 14:45:42 +09001210 row += hist_browser__show_callchain_list(browser, child,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001211 chain, row, percent_total,
Namhyung Kim18bb8382015-11-09 14:45:42 +09001212 was_first && need_percent,
1213 offset + extra_offset,
1214 print, arg);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001215
Namhyung Kim18bb8382015-11-09 14:45:42 +09001216 if (is_output_full(browser, row))
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001217 goto out;
Namhyung Kim18bb8382015-11-09 14:45:42 +09001218
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001219 if (folded_sign == '+')
1220 break;
1221 }
1222
1223 if (folded_sign == '-') {
1224 const int new_level = level + (extra_offset ? 2 : 1);
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001225
Namhyung Kim0c841c62016-01-28 00:40:54 +09001226 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001227 new_level, row, total,
1228 child->children_hit,
Namhyung Kim39ee5332014-08-22 09:13:21 +09001229 print, arg, is_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001230 }
Namhyung Kim39ee5332014-08-22 09:13:21 +09001231 if (is_output_full(browser, row))
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001232 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001233 node = next;
1234 }
1235out:
1236 return row - first_row;
1237}
1238
Namhyung Kim0c841c62016-01-28 00:40:54 +09001239static int hist_browser__show_callchain(struct hist_browser *browser,
1240 struct hist_entry *entry, int level,
1241 unsigned short row,
1242 print_callchain_entry_fn print,
1243 struct callchain_print_arg *arg,
1244 check_output_full_fn is_output_full)
1245{
1246 u64 total = hists__total_period(entry->hists);
Namhyung Kim5eca1042016-01-28 00:40:55 +09001247 u64 parent_total;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001248 int printed;
1249
Namhyung Kim5eca1042016-01-28 00:40:55 +09001250 if (symbol_conf.cumulate_callchain)
1251 parent_total = entry->stat_acc->period;
1252 else
1253 parent_total = entry->stat.period;
Namhyung Kim0c841c62016-01-28 00:40:54 +09001254
1255 if (callchain_param.mode == CHAIN_FLAT) {
1256 printed = hist_browser__show_callchain_flat(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001257 &entry->sorted_chain, row,
1258 total, parent_total, print, arg,
1259 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001260 } else if (callchain_param.mode == CHAIN_FOLDED) {
1261 printed = hist_browser__show_callchain_folded(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001262 &entry->sorted_chain, row,
1263 total, parent_total, print, arg,
1264 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001265 } else {
1266 printed = hist_browser__show_callchain_graph(browser,
Namhyung Kim5eca1042016-01-28 00:40:55 +09001267 &entry->sorted_chain, level, row,
1268 total, parent_total, print, arg,
1269 is_output_full);
Namhyung Kim0c841c62016-01-28 00:40:54 +09001270 }
1271
1272 if (arg->is_current_entry)
1273 browser->he_selection = entry;
1274
1275 return printed;
1276}
1277
Namhyung Kim89701462013-01-22 18:09:38 +09001278struct hpp_arg {
1279 struct ui_browser *b;
1280 char folded_sign;
1281 bool current_entry;
1282};
1283
Jiri Olsa98ba1602016-09-22 17:36:35 +02001284int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001285{
1286 struct hpp_arg *arg = hpp->ptr;
Namhyung Kimd6751072014-07-31 14:47:36 +09001287 int ret, len;
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001288 va_list args;
1289 double percent;
1290
1291 va_start(args, fmt);
Namhyung Kimd6751072014-07-31 14:47:36 +09001292 len = va_arg(args, int);
Namhyung Kim2f6d9002014-03-03 10:14:05 +09001293 percent = va_arg(args, double);
1294 va_end(args);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001295
Namhyung Kim89701462013-01-22 18:09:38 +09001296 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001297
Namhyung Kimd6751072014-07-31 14:47:36 +09001298 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001299 ui_browser__printf(arg->b, "%s", hpp->buf);
Namhyung Kim89701462013-01-22 18:09:38 +09001300
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001301 return ret;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001302}
1303
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001304#define __HPP_COLOR_PERCENT_FN(_type, _field) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001305static u64 __hpp_get_##_field(struct hist_entry *he) \
1306{ \
1307 return he->stat._field; \
1308} \
1309 \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001310static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001311hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Jiri Olsa2c5d4b42013-01-31 23:31:11 +01001312 struct perf_hpp *hpp, \
1313 struct hist_entry *he) \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001314{ \
Namhyung Kim5b591662014-07-31 14:47:38 +09001315 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
1316 __hpp__slsmg_color_printf, true); \
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001317}
Namhyung Kimf5951d52012-09-03 11:53:09 +09001318
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001319#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
1320static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
1321{ \
1322 return he->stat_acc->_field; \
1323} \
1324 \
1325static int \
Namhyung Kim5b591662014-07-31 14:47:38 +09001326hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001327 struct perf_hpp *hpp, \
1328 struct hist_entry *he) \
1329{ \
1330 if (!symbol_conf.cumulate_callchain) { \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001331 struct hpp_arg *arg = hpp->ptr; \
Namhyung Kim5b591662014-07-31 14:47:38 +09001332 int len = fmt->user_len ?: fmt->len; \
Namhyung Kimd6751072014-07-31 14:47:36 +09001333 int ret = scnprintf(hpp->buf, hpp->size, \
Namhyung Kim5b591662014-07-31 14:47:38 +09001334 "%*s", len, "N/A"); \
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001335 ui_browser__printf(arg->b, "%s", hpp->buf); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001336 \
1337 return ret; \
1338 } \
Namhyung Kim5b591662014-07-31 14:47:38 +09001339 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
1340 " %*.2f%%", __hpp__slsmg_color_printf, true); \
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001341}
1342
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001343__HPP_COLOR_PERCENT_FN(overhead, period)
1344__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
1345__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
1346__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
1347__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001348__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
Namhyung Kim5aed9d22013-01-22 18:09:35 +09001349
1350#undef __HPP_COLOR_PERCENT_FN
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001351#undef __HPP_COLOR_ACC_PERCENT_FN
Namhyung Kimf5951d52012-09-03 11:53:09 +09001352
1353void hist_browser__init_hpp(void)
1354{
Namhyung Kimf5951d52012-09-03 11:53:09 +09001355 perf_hpp__format[PERF_HPP__OVERHEAD].color =
1356 hist_browser__hpp_color_overhead;
1357 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
1358 hist_browser__hpp_color_overhead_sys;
1359 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
1360 hist_browser__hpp_color_overhead_us;
1361 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
1362 hist_browser__hpp_color_overhead_guest_sys;
1363 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
1364 hist_browser__hpp_color_overhead_guest_us;
Namhyung Kim0434ddd2013-10-30 16:12:59 +09001365 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
1366 hist_browser__hpp_color_overhead_acc;
Namhyung Kimf5951d52012-09-03 11:53:09 +09001367}
1368
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001369static int hist_browser__show_entry(struct hist_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001370 struct hist_entry *entry,
1371 unsigned short row)
1372{
Jiri Olsa12400052012-10-13 00:06:16 +02001373 int printed = 0;
Namhyung Kim67d25912012-09-12 15:35:06 +09001374 int width = browser->b.width;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001375 char folded_sign = ' ';
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001376 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001377 off_t row_offset = entry->row_offset;
Namhyung Kim63a1a3d2012-10-15 18:14:35 -03001378 bool first = true;
Jiri Olsa12400052012-10-13 00:06:16 +02001379 struct perf_hpp_fmt *fmt;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001380
1381 if (current_entry) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001382 browser->he_selection = entry;
1383 browser->selection = &entry->ms;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001384 }
1385
1386 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo163caed2010-08-25 16:30:03 -03001387 hist_entry__init_have_children(entry);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001388 folded_sign = hist_entry__folded(entry);
1389 }
1390
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001391 if (symbol_conf.inline_name &&
1392 (!entry->has_children)) {
1393 hist_entry_init_inline_node(entry);
1394 folded_sign = hist_entry__folded(entry);
1395 }
1396
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001397 if (row_offset == 0) {
Namhyung Kim89701462013-01-22 18:09:38 +09001398 struct hpp_arg arg = {
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001399 .b = &browser->b,
Namhyung Kim89701462013-01-22 18:09:38 +09001400 .folded_sign = folded_sign,
1401 .current_entry = current_entry,
1402 };
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001403 int column = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001404
Arnaldo Carvalho de Meloca3ff332014-07-01 16:42:24 -03001405 hist_browser__gotorc(browser, row, 0);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001406
Jiri Olsaf0786af2016-01-18 10:24:23 +01001407 hists__for_each_format(browser->hists, fmt) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001408 char s[2048];
1409 struct perf_hpp hpp = {
1410 .buf = s,
1411 .size = sizeof(s),
1412 .ptr = &arg,
1413 };
1414
Namhyung Kim361459f2015-12-23 02:07:08 +09001415 if (perf_hpp__should_skip(fmt, entry->hists) ||
1416 column++ < browser->b.horiz_scroll)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001417 continue;
1418
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001419 if (current_entry && browser->b.navkeypressed) {
1420 ui_browser__set_color(&browser->b,
1421 HE_COLORSET_SELECTED);
1422 } else {
1423 ui_browser__set_color(&browser->b,
1424 HE_COLORSET_NORMAL);
1425 }
1426
1427 if (first) {
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001428 if (symbol_conf.use_callchain ||
1429 symbol_conf.inline_name) {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001430 ui_browser__printf(&browser->b, "%c ", folded_sign);
Namhyung Kimfb821c9e2014-03-03 17:05:19 +09001431 width -= 2;
1432 }
1433 first = false;
1434 } else {
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001435 ui_browser__printf(&browser->b, " ");
Namhyung Kimf5951d52012-09-03 11:53:09 +09001436 width -= 2;
1437 }
1438
Jiri Olsa12400052012-10-13 00:06:16 +02001439 if (fmt->color) {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001440 int ret = fmt->color(fmt, &hpp, entry);
1441 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1442 /*
1443 * fmt->color() already used ui_browser to
1444 * print the non alignment bits, skip it (+ret):
1445 */
1446 ui_browser__printf(&browser->b, "%s", s + ret);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001447 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001448 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03001449 ui_browser__printf(&browser->b, "%s", s);
Namhyung Kimf5951d52012-09-03 11:53:09 +09001450 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03001451 width -= hpp.buf - s;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001452 }
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001453
1454 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001455 if (!browser->b.navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -02001456 width += 1;
1457
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001458 ui_browser__write_nstring(&browser->b, "", width);
Namhyung Kim26d8b332014-03-03 16:16:20 +09001459
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001460 ++row;
1461 ++printed;
1462 } else
1463 --row_offset;
1464
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001465 if (folded_sign == '-' && row != browser->b.rows) {
Namhyung Kim39ee5332014-08-22 09:13:21 +09001466 struct callchain_print_arg arg = {
1467 .row_offset = row_offset,
1468 .is_current_entry = current_entry,
1469 };
Namhyung Kimc09a7e72014-08-21 10:15:45 +09001470
Jin Yao0d3eb0b2017-03-26 04:34:29 +08001471 if (entry->inline_node)
1472 printed += hist_browser__show_inline(browser,
1473 entry->inline_node, row, 0);
1474 else
1475 printed += hist_browser__show_callchain(browser,
1476 entry, 1, row,
1477 hist_browser__show_callchain_entry,
1478 &arg,
Namhyung Kim4b3a3212015-11-09 14:45:43 +09001479 hist_browser__check_output_full);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001480 }
1481
1482 return printed;
1483}
1484
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001485static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1486 struct hist_entry *entry,
1487 unsigned short row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001488 int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001489{
1490 int printed = 0;
1491 int width = browser->b.width;
1492 char folded_sign = ' ';
1493 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1494 off_t row_offset = entry->row_offset;
1495 bool first = true;
1496 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001497 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001498 struct hpp_arg arg = {
1499 .b = &browser->b,
1500 .current_entry = current_entry,
1501 };
1502 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001503 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001504
1505 if (current_entry) {
1506 browser->he_selection = entry;
1507 browser->selection = &entry->ms;
1508 }
1509
1510 hist_entry__init_have_children(entry);
1511 folded_sign = hist_entry__folded(entry);
1512 arg.folded_sign = folded_sign;
1513
1514 if (entry->leaf && row_offset) {
1515 row_offset--;
1516 goto show_callchain;
1517 }
1518
1519 hist_browser__gotorc(browser, row, 0);
1520
1521 if (current_entry && browser->b.navkeypressed)
1522 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1523 else
1524 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1525
1526 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1527 width -= level * HIERARCHY_INDENT;
1528
Namhyung Kima61a22f2016-03-07 16:44:50 -03001529 /* the first hpp_list_node is for overhead columns */
1530 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1531 struct perf_hpp_list_node, list);
1532 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001533 char s[2048];
1534 struct perf_hpp hpp = {
1535 .buf = s,
1536 .size = sizeof(s),
1537 .ptr = &arg,
1538 };
1539
1540 if (perf_hpp__should_skip(fmt, entry->hists) ||
1541 column++ < browser->b.horiz_scroll)
1542 continue;
1543
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001544 if (current_entry && browser->b.navkeypressed) {
1545 ui_browser__set_color(&browser->b,
1546 HE_COLORSET_SELECTED);
1547 } else {
1548 ui_browser__set_color(&browser->b,
1549 HE_COLORSET_NORMAL);
1550 }
1551
1552 if (first) {
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001553 ui_browser__printf(&browser->b, "%c ", folded_sign);
1554 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001555 first = false;
1556 } else {
1557 ui_browser__printf(&browser->b, " ");
1558 width -= 2;
1559 }
1560
1561 if (fmt->color) {
1562 int ret = fmt->color(fmt, &hpp, entry);
1563 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1564 /*
1565 * fmt->color() already used ui_browser to
1566 * print the non alignment bits, skip it (+ret):
1567 */
1568 ui_browser__printf(&browser->b, "%s", s + ret);
1569 } else {
1570 int ret = fmt->entry(fmt, &hpp, entry);
1571 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1572 ui_browser__printf(&browser->b, "%s", s);
1573 }
1574 width -= hpp.buf - s;
1575 }
1576
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001577 if (!first) {
1578 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1579 width -= hierarchy_indent;
1580 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001581
1582 if (column >= browser->b.horiz_scroll) {
1583 char s[2048];
1584 struct perf_hpp hpp = {
1585 .buf = s,
1586 .size = sizeof(s),
1587 .ptr = &arg,
1588 };
1589
1590 if (current_entry && browser->b.navkeypressed) {
1591 ui_browser__set_color(&browser->b,
1592 HE_COLORSET_SELECTED);
1593 } else {
1594 ui_browser__set_color(&browser->b,
1595 HE_COLORSET_NORMAL);
1596 }
1597
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001598 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
Namhyung Kim131d51e2016-11-08 22:08:31 +09001599 if (first) {
1600 ui_browser__printf(&browser->b, "%c ", folded_sign);
1601 first = false;
1602 } else {
1603 ui_browser__write_nstring(&browser->b, "", 2);
1604 }
1605
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001606 width -= 2;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001607
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001608 /*
1609 * No need to call hist_entry__snprintf_alignment()
1610 * since this fmt is always the last column in the
1611 * hierarchy mode.
1612 */
1613 if (fmt->color) {
1614 width -= fmt->color(fmt, &hpp, entry);
1615 } else {
1616 int i = 0;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001617
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001618 width -= fmt->entry(fmt, &hpp, entry);
1619 ui_browser__printf(&browser->b, "%s", ltrim(s));
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001620
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03001621 while (isspace(s[i++]))
1622 width++;
1623 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001624 }
1625 }
1626
1627 /* The scroll bar isn't being used */
1628 if (!browser->b.navkeypressed)
1629 width += 1;
1630
1631 ui_browser__write_nstring(&browser->b, "", width);
1632
1633 ++row;
1634 ++printed;
1635
1636show_callchain:
1637 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1638 struct callchain_print_arg carg = {
1639 .row_offset = row_offset,
1640 };
1641
1642 printed += hist_browser__show_callchain(browser, entry,
1643 level + 1, row,
1644 hist_browser__show_callchain_entry, &carg,
1645 hist_browser__check_output_full);
1646 }
1647
1648 return printed;
1649}
1650
Namhyung Kim79dded82016-02-26 21:13:19 +09001651static int hist_browser__show_no_entry(struct hist_browser *browser,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001652 unsigned short row, int level)
Namhyung Kim79dded82016-02-26 21:13:19 +09001653{
1654 int width = browser->b.width;
1655 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1656 bool first = true;
1657 int column = 0;
1658 int ret;
1659 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001660 struct perf_hpp_list_node *fmt_node;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001661 int indent = browser->hists->nr_hpp_node - 2;
Namhyung Kim79dded82016-02-26 21:13:19 +09001662
1663 if (current_entry) {
1664 browser->he_selection = NULL;
1665 browser->selection = NULL;
1666 }
1667
1668 hist_browser__gotorc(browser, row, 0);
1669
1670 if (current_entry && browser->b.navkeypressed)
1671 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1672 else
1673 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1674
1675 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1676 width -= level * HIERARCHY_INDENT;
1677
Namhyung Kima61a22f2016-03-07 16:44:50 -03001678 /* the first hpp_list_node is for overhead columns */
1679 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1680 struct perf_hpp_list_node, list);
1681 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kim79dded82016-02-26 21:13:19 +09001682 if (perf_hpp__should_skip(fmt, browser->hists) ||
1683 column++ < browser->b.horiz_scroll)
1684 continue;
1685
Jiri Olsada1b0402016-06-14 20:19:20 +02001686 ret = fmt->width(fmt, NULL, browser->hists);
Namhyung Kim79dded82016-02-26 21:13:19 +09001687
1688 if (first) {
1689 /* for folded sign */
1690 first = false;
1691 ret++;
1692 } else {
1693 /* space between columns */
1694 ret += 2;
1695 }
1696
1697 ui_browser__write_nstring(&browser->b, "", ret);
1698 width -= ret;
1699 }
1700
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001701 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1702 width -= indent * HIERARCHY_INDENT;
Namhyung Kim79dded82016-02-26 21:13:19 +09001703
1704 if (column >= browser->b.horiz_scroll) {
1705 char buf[32];
1706
1707 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1708 ui_browser__printf(&browser->b, " %s", buf);
1709 width -= ret + 2;
1710 }
1711
1712 /* The scroll bar isn't being used */
1713 if (!browser->b.navkeypressed)
1714 width += 1;
1715
1716 ui_browser__write_nstring(&browser->b, "", width);
1717 return 1;
1718}
1719
Jiri Olsa81a888f2014-06-14 15:44:52 +02001720static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1721{
1722 advance_hpp(hpp, inc);
1723 return hpp->size <= 0;
1724}
1725
Jiri Olsa69705b32016-08-07 17:28:28 +02001726static int
1727hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
1728 size_t size, int line)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001729{
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001730 struct hists *hists = browser->hists;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001731 struct perf_hpp dummy_hpp = {
1732 .buf = buf,
1733 .size = size,
1734 };
1735 struct perf_hpp_fmt *fmt;
1736 size_t ret = 0;
Arnaldo Carvalho de Meloc6c3c022015-08-11 17:22:43 -03001737 int column = 0;
Jiri Olsa29659ab2016-08-07 17:28:30 +02001738 int span = 0;
Jiri Olsa81a888f2014-06-14 15:44:52 +02001739
1740 if (symbol_conf.use_callchain) {
1741 ret = scnprintf(buf, size, " ");
1742 if (advance_hpp_check(&dummy_hpp, ret))
1743 return ret;
1744 }
1745
Jiri Olsaf0786af2016-01-18 10:24:23 +01001746 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09001747 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
Jiri Olsa81a888f2014-06-14 15:44:52 +02001748 continue;
1749
Jiri Olsa29659ab2016-08-07 17:28:30 +02001750 ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
Jiri Olsa81a888f2014-06-14 15:44:52 +02001751 if (advance_hpp_check(&dummy_hpp, ret))
1752 break;
1753
Jiri Olsa29659ab2016-08-07 17:28:30 +02001754 if (span)
1755 continue;
1756
Jiri Olsa81a888f2014-06-14 15:44:52 +02001757 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1758 if (advance_hpp_check(&dummy_hpp, ret))
1759 break;
1760 }
1761
1762 return ret;
1763}
1764
Namhyung Kimd8b92402016-02-25 00:13:46 +09001765static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1766{
1767 struct hists *hists = browser->hists;
1768 struct perf_hpp dummy_hpp = {
1769 .buf = buf,
1770 .size = size,
1771 };
1772 struct perf_hpp_fmt *fmt;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001773 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001774 size_t ret = 0;
1775 int column = 0;
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001776 int indent = hists->nr_hpp_node - 2;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001777 bool first_node, first_col;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001778
Namhyung Kim3d9f4682016-11-08 22:08:30 +09001779 ret = scnprintf(buf, size, " ");
Namhyung Kimd8b92402016-02-25 00:13:46 +09001780 if (advance_hpp_check(&dummy_hpp, ret))
1781 return ret;
1782
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001783 first_node = true;
Namhyung Kima61a22f2016-03-07 16:44:50 -03001784 /* the first hpp_list_node is for overhead columns */
1785 fmt_node = list_first_entry(&hists->hpp_formats,
1786 struct perf_hpp_list_node, list);
1787 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001788 if (column++ < browser->b.horiz_scroll)
1789 continue;
1790
Jiri Olsa29659ab2016-08-07 17:28:30 +02001791 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kimd8b92402016-02-25 00:13:46 +09001792 if (advance_hpp_check(&dummy_hpp, ret))
1793 break;
1794
1795 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1796 if (advance_hpp_check(&dummy_hpp, ret))
1797 break;
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001798
1799 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001800 }
1801
Namhyung Kimb9bf9112016-11-08 22:08:32 +09001802 if (!first_node) {
1803 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1804 indent * HIERARCHY_INDENT, "");
1805 if (advance_hpp_check(&dummy_hpp, ret))
1806 return ret;
1807 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001808
Namhyung Kima61a22f2016-03-07 16:44:50 -03001809 first_node = true;
1810 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1811 if (!first_node) {
Namhyung Kimd8b92402016-02-25 00:13:46 +09001812 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1813 if (advance_hpp_check(&dummy_hpp, ret))
1814 break;
1815 }
Namhyung Kima61a22f2016-03-07 16:44:50 -03001816 first_node = false;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001817
Namhyung Kima61a22f2016-03-07 16:44:50 -03001818 first_col = true;
1819 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1820 char *start;
Namhyung Kimd8b92402016-02-25 00:13:46 +09001821
Namhyung Kima61a22f2016-03-07 16:44:50 -03001822 if (perf_hpp__should_skip(fmt, hists))
1823 continue;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001824
Namhyung Kima61a22f2016-03-07 16:44:50 -03001825 if (!first_col) {
1826 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1827 if (advance_hpp_check(&dummy_hpp, ret))
1828 break;
1829 }
1830 first_col = false;
Namhyung Kimcb1fab92016-02-27 03:52:45 +09001831
Jiri Olsa29659ab2016-08-07 17:28:30 +02001832 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001833 dummy_hpp.buf[ret] = '\0';
Namhyung Kima61a22f2016-03-07 16:44:50 -03001834
Jiri Olsa7d6a7e72016-04-07 09:11:11 +02001835 start = trim(dummy_hpp.buf);
Namhyung Kima61a22f2016-03-07 16:44:50 -03001836 ret = strlen(start);
1837
1838 if (start != dummy_hpp.buf)
1839 memmove(dummy_hpp.buf, start, ret + 1);
1840
1841 if (advance_hpp_check(&dummy_hpp, ret))
1842 break;
1843 }
Namhyung Kimd8b92402016-02-25 00:13:46 +09001844 }
1845
1846 return ret;
1847}
1848
Jiri Olsa01b47702016-06-14 20:19:13 +02001849static void hists_browser__hierarchy_headers(struct hist_browser *browser)
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001850{
Jiri Olsa81a888f2014-06-14 15:44:52 +02001851 char headers[1024];
1852
Jiri Olsa01b47702016-06-14 20:19:13 +02001853 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1854 sizeof(headers));
1855
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001856 ui_browser__gotorc(&browser->b, 0, 0);
1857 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03001858 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001859}
1860
Jiri Olsa01b47702016-06-14 20:19:13 +02001861static void hists_browser__headers(struct hist_browser *browser)
1862{
Jiri Olsa69705b32016-08-07 17:28:28 +02001863 struct hists *hists = browser->hists;
1864 struct perf_hpp_list *hpp_list = hists->hpp_list;
Jiri Olsa01b47702016-06-14 20:19:13 +02001865
Jiri Olsa69705b32016-08-07 17:28:28 +02001866 int line;
Jiri Olsa01b47702016-06-14 20:19:13 +02001867
Jiri Olsa69705b32016-08-07 17:28:28 +02001868 for (line = 0; line < hpp_list->nr_header_lines; line++) {
1869 char headers[1024];
1870
1871 hists_browser__scnprintf_headers(browser, headers,
1872 sizeof(headers), line);
1873
1874 ui_browser__gotorc(&browser->b, line, 0);
1875 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1876 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
1877 }
Jiri Olsa01b47702016-06-14 20:19:13 +02001878}
1879
1880static void hist_browser__show_headers(struct hist_browser *browser)
1881{
1882 if (symbol_conf.report_hierarchy)
1883 hists_browser__hierarchy_headers(browser);
1884 else
1885 hists_browser__headers(browser);
1886}
1887
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03001888static void ui_browser__hists_init_top(struct ui_browser *browser)
1889{
1890 if (browser->top == NULL) {
1891 struct hist_browser *hb;
1892
1893 hb = container_of(browser, struct hist_browser, b);
1894 browser->top = rb_first(&hb->hists->entries);
1895 }
1896}
1897
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001898static unsigned int hist_browser__refresh(struct ui_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001899{
1900 unsigned row = 0;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001901 u16 header_offset = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001902 struct rb_node *nd;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001903 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001904 struct hists *hists = hb->hists;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001905
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001906 if (hb->show_headers) {
Jiri Olsaf8e67102016-08-07 17:28:26 +02001907 struct perf_hpp_list *hpp_list = hists->hpp_list;
1908
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001909 hist_browser__show_headers(hb);
Jiri Olsaf8e67102016-08-07 17:28:26 +02001910 header_offset = hpp_list->nr_header_lines;
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001911 }
1912
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001913 ui_browser__hists_init_top(browser);
Wang Nan979d2ca2015-12-07 02:35:46 +00001914 hb->he_selection = NULL;
1915 hb->selection = NULL;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001916
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001917 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001918 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001919 float percent;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001920
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001921 if (h->filtered) {
1922 /* let it move to sibling */
1923 h->unfolded = false;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001924 continue;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001925 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001926
Namhyung Kim14135662013-10-31 10:17:39 +09001927 percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001928 if (percent < hb->min_pcnt)
1929 continue;
1930
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001931 if (symbol_conf.report_hierarchy) {
1932 row += hist_browser__show_hierarchy_entry(hb, h, row,
Namhyung Kim2dbbe9f2016-03-07 16:44:48 -03001933 h->depth);
Namhyung Kim79dded82016-02-26 21:13:19 +09001934 if (row == browser->rows)
1935 break;
1936
1937 if (h->has_no_entry) {
Namhyung Kima61a22f2016-03-07 16:44:50 -03001938 hist_browser__show_no_entry(hb, row, h->depth + 1);
Namhyung Kim79dded82016-02-26 21:13:19 +09001939 row++;
1940 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001941 } else {
1942 row += hist_browser__show_entry(hb, h, row);
1943 }
1944
Arnaldo Carvalho de Melo62c95ae2014-07-01 11:07:54 -03001945 if (row == browser->rows)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001946 break;
1947 }
1948
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02001949 return row + header_offset;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001950}
1951
Namhyung Kim064f1982013-05-14 11:09:04 +09001952static struct rb_node *hists__filter_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001953 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001954{
1955 while (nd != NULL) {
1956 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001957 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001958
Namhyung Kimc0f15272014-04-16 11:16:33 +09001959 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001960 return nd;
1961
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001962 /*
1963 * If it's filtered, its all children also were filtered.
1964 * So move to sibling node.
1965 */
1966 if (rb_next(nd))
1967 nd = rb_next(nd);
1968 else
1969 nd = rb_hierarchy_next(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001970 }
1971
1972 return NULL;
1973}
1974
Namhyung Kim064f1982013-05-14 11:09:04 +09001975static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
Namhyung Kim064f1982013-05-14 11:09:04 +09001976 float min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001977{
1978 while (nd != NULL) {
1979 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kim14135662013-10-31 10:17:39 +09001980 float percent = hist_entry__get_percent_limit(h);
Namhyung Kim064f1982013-05-14 11:09:04 +09001981
1982 if (!h->filtered && percent >= min_pcnt)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001983 return nd;
1984
Namhyung Kimd0506ed2016-02-25 00:13:45 +09001985 nd = rb_hierarchy_prev(nd);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001986 }
1987
1988 return NULL;
1989}
1990
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03001991static void ui_browser__hists_seek(struct ui_browser *browser,
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03001992 off_t offset, int whence)
1993{
1994 struct hist_entry *h;
1995 struct rb_node *nd;
1996 bool first = true;
Namhyung Kim064f1982013-05-14 11:09:04 +09001997 struct hist_browser *hb;
1998
1999 hb = container_of(browser, struct hist_browser, b);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002000
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002001 if (browser->nr_entries == 0)
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03002002 return;
2003
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002004 ui_browser__hists_init_top(browser);
Arnaldo Carvalho de Melo437cfe72011-10-14 09:31:53 -03002005
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002006 switch (whence) {
2007 case SEEK_SET:
Namhyung Kim064f1982013-05-14 11:09:04 +09002008 nd = hists__filter_entries(rb_first(browser->entries),
Namhyung Kim14135662013-10-31 10:17:39 +09002009 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002010 break;
2011 case SEEK_CUR:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002012 nd = browser->top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002013 goto do_offset;
2014 case SEEK_END:
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002015 nd = rb_hierarchy_last(rb_last(browser->entries));
2016 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002017 first = false;
2018 break;
2019 default:
2020 return;
2021 }
2022
2023 /*
2024 * Moves not relative to the first visible entry invalidates its
2025 * row_offset:
2026 */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002027 h = rb_entry(browser->top, struct hist_entry, rb_node);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002028 h->row_offset = 0;
2029
2030 /*
2031 * Here we have to check if nd is expanded (+), if it is we can't go
2032 * the next top level hist_entry, instead we must compute an offset of
2033 * what _not_ to show and not change the first visible entry.
2034 *
2035 * This offset increments when we are going from top to bottom and
2036 * decreases when we're going from bottom to top.
2037 *
2038 * As we don't have backpointers to the top level in the callchains
2039 * structure, we need to always print the whole hist_entry callchain,
2040 * skipping the first ones that are before the first visible entry
2041 * and stop when we printed enough lines to fill the screen.
2042 */
2043do_offset:
Wang Nan837eeb72015-12-07 02:35:45 +00002044 if (!nd)
2045 return;
2046
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002047 if (offset > 0) {
2048 do {
2049 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002050 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002051 u16 remaining = h->nr_rows - h->row_offset;
2052 if (offset > remaining) {
2053 offset -= remaining;
2054 h->row_offset = 0;
2055 } else {
2056 h->row_offset += offset;
2057 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002058 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002059 break;
2060 }
2061 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002062 nd = hists__filter_entries(rb_hierarchy_next(nd),
2063 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002064 if (nd == NULL)
2065 break;
2066 --offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002067 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002068 } while (offset != 0);
2069 } else if (offset < 0) {
2070 while (1) {
2071 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002072 if (h->unfolded && h->leaf) {
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002073 if (first) {
2074 if (-offset > h->row_offset) {
2075 offset += h->row_offset;
2076 h->row_offset = 0;
2077 } else {
2078 h->row_offset += offset;
2079 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002080 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002081 break;
2082 }
2083 } else {
2084 if (-offset > h->nr_rows) {
2085 offset += h->nr_rows;
2086 h->row_offset = 0;
2087 } else {
2088 h->row_offset = h->nr_rows + offset;
2089 offset = 0;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002090 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002091 break;
2092 }
2093 }
2094 }
2095
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002096 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
Namhyung Kim064f1982013-05-14 11:09:04 +09002097 hb->min_pcnt);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002098 if (nd == NULL)
2099 break;
2100 ++offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002101 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002102 if (offset == 0) {
2103 /*
2104 * Last unfiltered hist_entry, check if it is
2105 * unfolded, if it is then we should have
2106 * row_offset at its last entry.
2107 */
2108 h = rb_entry(nd, struct hist_entry, rb_node);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002109 if (h->unfolded && h->leaf)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002110 h->row_offset = h->nr_rows;
2111 break;
2112 }
2113 first = false;
2114 }
2115 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002116 browser->top = nd;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002117 h = rb_entry(nd, struct hist_entry, rb_node);
2118 h->row_offset = 0;
2119 }
2120}
2121
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002122static int hist_browser__fprintf_callchain(struct hist_browser *browser,
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002123 struct hist_entry *he, FILE *fp,
2124 int level)
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002125{
Namhyung Kim39ee5332014-08-22 09:13:21 +09002126 struct callchain_print_arg arg = {
2127 .fp = fp,
2128 };
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002129
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002130 hist_browser__show_callchain(browser, he, level, 0,
Namhyung Kim39ee5332014-08-22 09:13:21 +09002131 hist_browser__fprintf_callchain_entry, &arg,
2132 hist_browser__check_dump_full);
2133 return arg.printed;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002134}
2135
2136static int hist_browser__fprintf_entry(struct hist_browser *browser,
2137 struct hist_entry *he, FILE *fp)
2138{
2139 char s[8192];
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002140 int printed = 0;
2141 char folded_sign = ' ';
Namhyung Kim26d8b332014-03-03 16:16:20 +09002142 struct perf_hpp hpp = {
2143 .buf = s,
2144 .size = sizeof(s),
2145 };
2146 struct perf_hpp_fmt *fmt;
2147 bool first = true;
2148 int ret;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002149
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002150 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002151 folded_sign = hist_entry__folded(he);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002152 printed += fprintf(fp, "%c ", folded_sign);
Arnaldo Carvalho de Melo1b6b6782016-04-18 12:24:41 -03002153 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002154
Jiri Olsaf0786af2016-01-18 10:24:23 +01002155 hists__for_each_format(browser->hists, fmt) {
Namhyung Kim361459f2015-12-23 02:07:08 +09002156 if (perf_hpp__should_skip(fmt, he->hists))
Namhyung Kime67d49a2014-03-18 13:00:59 +09002157 continue;
2158
Namhyung Kim26d8b332014-03-03 16:16:20 +09002159 if (!first) {
2160 ret = scnprintf(hpp.buf, hpp.size, " ");
2161 advance_hpp(&hpp, ret);
2162 } else
2163 first = false;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002164
Namhyung Kim26d8b332014-03-03 16:16:20 +09002165 ret = fmt->entry(fmt, &hpp, he);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002166 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
Namhyung Kim26d8b332014-03-03 16:16:20 +09002167 advance_hpp(&hpp, ret);
2168 }
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -03002169 printed += fprintf(fp, "%s\n", s);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002170
2171 if (folded_sign == '-')
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002172 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
2173
2174 return printed;
2175}
2176
2177
2178static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
2179 struct hist_entry *he,
Namhyung Kim325a6282016-03-09 22:47:00 +09002180 FILE *fp, int level)
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002181{
2182 char s[8192];
2183 int printed = 0;
2184 char folded_sign = ' ';
2185 struct perf_hpp hpp = {
2186 .buf = s,
2187 .size = sizeof(s),
2188 };
2189 struct perf_hpp_fmt *fmt;
Namhyung Kim325a6282016-03-09 22:47:00 +09002190 struct perf_hpp_list_node *fmt_node;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002191 bool first = true;
2192 int ret;
Namhyung Kim325a6282016-03-09 22:47:00 +09002193 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002194
2195 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
2196
2197 folded_sign = hist_entry__folded(he);
2198 printed += fprintf(fp, "%c", folded_sign);
2199
Namhyung Kim325a6282016-03-09 22:47:00 +09002200 /* the first hpp_list_node is for overhead columns */
2201 fmt_node = list_first_entry(&he->hists->hpp_formats,
2202 struct perf_hpp_list_node, list);
2203 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002204 if (!first) {
2205 ret = scnprintf(hpp.buf, hpp.size, " ");
2206 advance_hpp(&hpp, ret);
2207 } else
2208 first = false;
2209
2210 ret = fmt->entry(fmt, &hpp, he);
2211 advance_hpp(&hpp, ret);
2212 }
2213
2214 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
2215 advance_hpp(&hpp, ret);
2216
Namhyung Kim1b2dbbf2016-03-07 16:44:46 -03002217 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2218 ret = scnprintf(hpp.buf, hpp.size, " ");
2219 advance_hpp(&hpp, ret);
2220
2221 ret = fmt->entry(fmt, &hpp, he);
2222 advance_hpp(&hpp, ret);
2223 }
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002224
2225 printed += fprintf(fp, "%s\n", rtrim(s));
2226
2227 if (he->leaf && folded_sign == '-') {
2228 printed += hist_browser__fprintf_callchain(browser, he, fp,
2229 he->depth + 1);
2230 }
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002231
2232 return printed;
2233}
2234
2235static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
2236{
Namhyung Kim064f1982013-05-14 11:09:04 +09002237 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
Namhyung Kim064f1982013-05-14 11:09:04 +09002238 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002239 int printed = 0;
2240
2241 while (nd) {
2242 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2243
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002244 if (symbol_conf.report_hierarchy) {
2245 printed += hist_browser__fprintf_hierarchy_entry(browser,
2246 h, fp,
Namhyung Kim325a6282016-03-09 22:47:00 +09002247 h->depth);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002248 } else {
2249 printed += hist_browser__fprintf_entry(browser, h, fp);
2250 }
2251
2252 nd = hists__filter_entries(rb_hierarchy_next(nd),
2253 browser->min_pcnt);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002254 }
2255
2256 return printed;
2257}
2258
2259static int hist_browser__dump(struct hist_browser *browser)
2260{
2261 char filename[64];
2262 FILE *fp;
2263
2264 while (1) {
2265 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
2266 if (access(filename, F_OK))
2267 break;
2268 /*
2269 * XXX: Just an arbitrary lazy upper limit
2270 */
2271 if (++browser->print_seq == 8192) {
2272 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
2273 return -1;
2274 }
2275 }
2276
2277 fp = fopen(filename, "w");
2278 if (fp == NULL) {
2279 char bf[64];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002280 const char *err = str_error_r(errno, bf, sizeof(bf));
Kirill A. Shutemov4cc49d42012-07-24 00:06:54 +03002281 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03002282 return -1;
2283 }
2284
2285 ++browser->print_seq;
2286 hist_browser__fprintf(browser, fp);
2287 fclose(fp);
2288 ui_helpline__fpush("%s written!", filename);
2289
2290 return 0;
2291}
2292
Jiri Olsafcd86422016-06-20 23:58:18 +02002293void hist_browser__init(struct hist_browser *browser,
2294 struct hists *hists)
2295{
2296 struct perf_hpp_fmt *fmt;
2297
2298 browser->hists = hists;
2299 browser->b.refresh = hist_browser__refresh;
2300 browser->b.refresh_dimensions = hist_browser__refresh_dimensions;
2301 browser->b.seek = ui_browser__hists_seek;
2302 browser->b.use_navkeypressed = true;
2303 browser->show_headers = symbol_conf.show_hist_headers;
2304
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002305 if (symbol_conf.report_hierarchy) {
2306 struct perf_hpp_list_node *fmt_node;
2307
2308 /* count overhead columns (in the first node) */
2309 fmt_node = list_first_entry(&hists->hpp_formats,
2310 struct perf_hpp_list_node, list);
2311 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
2312 ++browser->b.columns;
2313
2314 /* add a single column for whole hierarchy sort keys*/
Jiri Olsafcd86422016-06-20 23:58:18 +02002315 ++browser->b.columns;
Namhyung Kim8a06b0b2016-10-25 01:21:10 +09002316 } else {
2317 hists__for_each_format(hists, fmt)
2318 ++browser->b.columns;
2319 }
Namhyung Kime3b60bc2016-09-20 14:30:24 +09002320
2321 hists__reset_column_width(hists);
Jiri Olsafcd86422016-06-20 23:58:18 +02002322}
2323
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002324struct hist_browser *hist_browser__new(struct hists *hists)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002325{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002326 struct hist_browser *browser = zalloc(sizeof(*browser));
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002327
Jiri Olsafcd86422016-06-20 23:58:18 +02002328 if (browser)
2329 hist_browser__init(browser, hists);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002330
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002331 return browser;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002332}
2333
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002334static struct hist_browser *
2335perf_evsel_browser__new(struct perf_evsel *evsel,
2336 struct hist_browser_timer *hbt,
2337 struct perf_env *env)
2338{
2339 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2340
2341 if (browser) {
2342 browser->hbt = hbt;
2343 browser->env = env;
2344 browser->title = perf_evsel_browser_title;
2345 }
2346 return browser;
2347}
2348
Jiri Olsadabd2012016-06-20 23:58:14 +02002349void hist_browser__delete(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002350{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002351 free(browser);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002352}
2353
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002354static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002355{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002356 return browser->he_selection;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002357}
2358
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002359static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002360{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002361 return browser->he_selection->thread;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002362}
2363
Taeung Song1e378eb2014-10-07 16:13:15 +09002364/* Check whether the browser is for 'top' or 'report' */
2365static inline bool is_report_browser(void *timer)
2366{
2367 return timer == NULL;
2368}
2369
Jiri Olsa5b91a862016-06-20 23:58:15 +02002370static int perf_evsel_browser_title(struct hist_browser *browser,
Taeung Song1e378eb2014-10-07 16:13:15 +09002371 char *bf, size_t size)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002372{
Jiri Olsa5b91a862016-06-20 23:58:15 +02002373 struct hist_browser_timer *hbt = browser->hbt;
2374 struct hists *hists = browser->hists;
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002375 char unit;
2376 int printed;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002377 const struct dso *dso = hists->dso_filter;
2378 const struct thread *thread = hists->thread_filter;
Kan Liang84734b02015-09-04 10:45:45 -04002379 int socket_id = hists->socket_filter;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002380 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
2381 u64 nr_events = hists->stats.total_period;
Namhyung Kim717e2632013-01-22 18:09:44 +09002382 struct perf_evsel *evsel = hists_to_evsel(hists);
Jiri Olsadd00d482014-06-19 13:41:13 +02002383 const char *ev_name = perf_evsel__name(evsel);
Namhyung Kim717e2632013-01-22 18:09:44 +09002384 char buf[512];
2385 size_t buflen = sizeof(buf);
Kan Liang9e207dd2015-08-11 06:30:49 -04002386 char ref[30] = " show reference callgraph, ";
2387 bool enable_ref = false;
Namhyung Kim717e2632013-01-22 18:09:44 +09002388
Namhyung Kimf2148332014-01-14 11:52:48 +09002389 if (symbol_conf.filter_relative) {
2390 nr_samples = hists->stats.nr_non_filtered_samples;
2391 nr_events = hists->stats.total_non_filtered_period;
2392 }
2393
Namhyung Kim759ff492013-03-05 14:53:26 +09002394 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09002395 struct perf_evsel *pos;
2396
2397 perf_evsel__group_desc(evsel, buf, buflen);
2398 ev_name = buf;
2399
2400 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002401 struct hists *pos_hists = evsel__hists(pos);
2402
Namhyung Kimf2148332014-01-14 11:52:48 +09002403 if (symbol_conf.filter_relative) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002404 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2405 nr_events += pos_hists->stats.total_non_filtered_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002406 } else {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002407 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
2408 nr_events += pos_hists->stats.total_period;
Namhyung Kimf2148332014-01-14 11:52:48 +09002409 }
Namhyung Kim717e2632013-01-22 18:09:44 +09002410 }
2411 }
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002412
Kan Liang9e207dd2015-08-11 06:30:49 -04002413 if (symbol_conf.show_ref_callgraph &&
2414 strstr(ev_name, "call-graph=no"))
2415 enable_ref = true;
Ashay Ranecc6862802012-04-05 21:01:01 -05002416 nr_samples = convert_unit(nr_samples, &unit);
2417 printed = scnprintf(bf, size,
Kan Liang9e207dd2015-08-11 06:30:49 -04002418 "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
2419 nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
Ashay Ranecc6862802012-04-05 21:01:01 -05002420
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002421
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002422 if (hists->uid_filter_str)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002423 printed += snprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03002424 ", UID: %s", hists->uid_filter_str);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002425 if (thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002426 if (hists__has(hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002427 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002428 ", Thread: %s(%d)",
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +02002429 (thread->comm_set ? thread__comm_str(thread) : ""),
Adrian Hunter38051232013-07-04 16:20:31 +03002430 thread->tid);
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002431 } else {
2432 printed += scnprintf(bf + printed, size - printed,
2433 ", Thread: %s",
2434 (thread->comm_set ? thread__comm_str(thread) : ""));
2435 }
2436 }
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002437 if (dso)
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03002438 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002439 ", DSO: %s", dso->short_name);
Kan Liang84734b02015-09-04 10:45:45 -04002440 if (socket_id > -1)
Kan Liang21394d92015-09-04 10:45:44 -04002441 printed += scnprintf(bf + printed, size - printed,
Kan Liang84734b02015-09-04 10:45:45 -04002442 ", Processor Socket: %d", socket_id);
Taeung Song1e378eb2014-10-07 16:13:15 +09002443 if (!is_report_browser(hbt)) {
2444 struct perf_top *top = hbt->arg;
2445
2446 if (top->zero)
2447 printed += scnprintf(bf + printed, size - printed, " [z]");
2448 }
2449
Arnaldo Carvalho de Melo469917c2010-09-13 10:25:04 -03002450 return printed;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002451}
2452
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002453static inline void free_popup_options(char **options, int n)
2454{
2455 int i;
2456
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03002457 for (i = 0; i < n; ++i)
2458 zfree(&options[i]);
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002459}
2460
Feng Tang341487ab2013-02-03 14:38:20 +08002461/*
2462 * Only runtime switching of perf data file will make "input_name" point
2463 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
2464 * whether we need to call free() for current "input_name" during the switch.
2465 */
2466static bool is_input_name_malloced = false;
2467
2468static int switch_data_file(void)
2469{
2470 char *pwd, *options[32], *abs_path[32], *tmp;
2471 DIR *pwd_dir;
2472 int nr_options = 0, choice = -1, ret = -1;
2473 struct dirent *dent;
2474
2475 pwd = getenv("PWD");
2476 if (!pwd)
2477 return ret;
2478
2479 pwd_dir = opendir(pwd);
2480 if (!pwd_dir)
2481 return ret;
2482
2483 memset(options, 0, sizeof(options));
Changbin Du3ef5b402017-03-13 19:46:52 +08002484 memset(abs_path, 0, sizeof(abs_path));
Feng Tang341487ab2013-02-03 14:38:20 +08002485
2486 while ((dent = readdir(pwd_dir))) {
2487 char path[PATH_MAX];
2488 u64 magic;
2489 char *name = dent->d_name;
2490 FILE *file;
2491
2492 if (!(dent->d_type == DT_REG))
2493 continue;
2494
2495 snprintf(path, sizeof(path), "%s/%s", pwd, name);
2496
2497 file = fopen(path, "r");
2498 if (!file)
2499 continue;
2500
2501 if (fread(&magic, 1, 8, file) < 8)
2502 goto close_file_and_continue;
2503
2504 if (is_perf_magic(magic)) {
2505 options[nr_options] = strdup(name);
2506 if (!options[nr_options])
2507 goto close_file_and_continue;
2508
2509 abs_path[nr_options] = strdup(path);
2510 if (!abs_path[nr_options]) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03002511 zfree(&options[nr_options]);
Feng Tang341487ab2013-02-03 14:38:20 +08002512 ui__warning("Can't search all data files due to memory shortage.\n");
2513 fclose(file);
2514 break;
2515 }
2516
2517 nr_options++;
2518 }
2519
2520close_file_and_continue:
2521 fclose(file);
2522 if (nr_options >= 32) {
2523 ui__warning("Too many perf data files in PWD!\n"
2524 "Only the first 32 files will be listed.\n");
2525 break;
2526 }
2527 }
2528 closedir(pwd_dir);
2529
2530 if (nr_options) {
2531 choice = ui__popup_menu(nr_options, options);
2532 if (choice < nr_options && choice >= 0) {
2533 tmp = strdup(abs_path[choice]);
2534 if (tmp) {
2535 if (is_input_name_malloced)
2536 free((void *)input_name);
2537 input_name = tmp;
2538 is_input_name_malloced = true;
2539 ret = 0;
2540 } else
2541 ui__warning("Data switch failed due to memory shortage!\n");
2542 }
2543 }
2544
2545 free_popup_options(options, nr_options);
2546 free_popup_options(abs_path, nr_options);
2547 return ret;
2548}
2549
Namhyung Kimea7cd592015-04-22 16:18:19 +09002550struct popup_action {
2551 struct thread *thread;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002552 struct map_symbol ms;
Kan Liang84734b02015-09-04 10:45:45 -04002553 int socket;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002554
2555 int (*fn)(struct hist_browser *browser, struct popup_action *act);
2556};
2557
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002558static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002559do_annotate(struct hist_browser *browser, struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002560{
2561 struct perf_evsel *evsel;
2562 struct annotation *notes;
2563 struct hist_entry *he;
2564 int err;
2565
Arnaldo Carvalho de Meloeebd0bf2015-09-08 15:52:20 -03002566 if (!objdump_path && perf_env__lookup_objdump(browser->env))
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002567 return 0;
2568
Namhyung Kimea7cd592015-04-22 16:18:19 +09002569 notes = symbol__annotation(act->ms.sym);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002570 if (!notes->src)
2571 return 0;
2572
2573 evsel = hists_to_evsel(browser->hists);
Namhyung Kimea7cd592015-04-22 16:18:19 +09002574 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002575 he = hist_browser__selected_entry(browser);
2576 /*
2577 * offer option to annotate the other branch source or target
2578 * (if they exists) when returning from annotate
2579 */
2580 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
2581 return 1;
2582
2583 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
2584 if (err)
2585 ui_browser__handle_resize(&browser->b);
2586 return 0;
2587}
2588
2589static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002590add_annotate_opt(struct hist_browser *browser __maybe_unused,
2591 struct popup_action *act, char **optstr,
2592 struct map *map, struct symbol *sym)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002593{
Namhyung Kimea7cd592015-04-22 16:18:19 +09002594 if (sym == NULL || map->dso->annotate_warned)
2595 return 0;
2596
2597 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2598 return 0;
2599
2600 act->ms.map = map;
2601 act->ms.sym = sym;
2602 act->fn = do_annotate;
2603 return 1;
2604}
2605
2606static int
2607do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2608{
2609 struct thread *thread = act->thread;
2610
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002611 if ((!hists__has(browser->hists, thread) &&
2612 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002613 return 0;
2614
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002615 if (browser->hists->thread_filter) {
2616 pstack__remove(browser->pstack, &browser->hists->thread_filter);
2617 perf_hpp__set_elide(HISTC_THREAD, false);
2618 thread__zput(browser->hists->thread_filter);
2619 ui_helpline__pop();
2620 } else {
Jiri Olsafa829112016-05-03 13:54:47 +02002621 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002622 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2623 thread->comm_set ? thread__comm_str(thread) : "",
2624 thread->tid);
2625 } else {
2626 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2627 thread->comm_set ? thread__comm_str(thread) : "");
2628 }
2629
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002630 browser->hists->thread_filter = thread__get(thread);
2631 perf_hpp__set_elide(HISTC_THREAD, false);
2632 pstack__push(browser->pstack, &browser->hists->thread_filter);
2633 }
2634
2635 hists__filter_by_thread(browser->hists);
2636 hist_browser__reset(browser);
2637 return 0;
2638}
2639
2640static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002641add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2642 char **optstr, struct thread *thread)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002643{
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002644 int ret;
2645
Jiri Olsa7cecb7f2016-05-03 13:54:48 +02002646 if ((!hists__has(browser->hists, thread) &&
2647 !hists__has(browser->hists, comm)) || thread == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002648 return 0;
2649
Jiri Olsafa829112016-05-03 13:54:47 +02002650 if (hists__has(browser->hists, thread)) {
Namhyung Kim6962ccb2016-03-10 00:14:50 +09002651 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2652 browser->hists->thread_filter ? "out of" : "into",
2653 thread->comm_set ? thread__comm_str(thread) : "",
2654 thread->tid);
2655 } else {
2656 ret = asprintf(optstr, "Zoom %s %s thread",
2657 browser->hists->thread_filter ? "out of" : "into",
2658 thread->comm_set ? thread__comm_str(thread) : "");
2659 }
2660 if (ret < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002661 return 0;
2662
2663 act->thread = thread;
2664 act->fn = do_zoom_thread;
2665 return 1;
2666}
2667
2668static int
2669do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2670{
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002671 struct map *map = act->ms.map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002672
Jiri Olsa69849fc2016-05-03 13:54:45 +02002673 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002674 return 0;
2675
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002676 if (browser->hists->dso_filter) {
2677 pstack__remove(browser->pstack, &browser->hists->dso_filter);
2678 perf_hpp__set_elide(HISTC_DSO, false);
2679 browser->hists->dso_filter = NULL;
2680 ui_helpline__pop();
2681 } else {
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002682 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002683 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
2684 browser->hists->dso_filter = map->dso;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002685 perf_hpp__set_elide(HISTC_DSO, true);
2686 pstack__push(browser->pstack, &browser->hists->dso_filter);
2687 }
2688
2689 hists__filter_by_dso(browser->hists);
2690 hist_browser__reset(browser);
2691 return 0;
2692}
2693
2694static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002695add_dso_opt(struct hist_browser *browser, struct popup_action *act,
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002696 char **optstr, struct map *map)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002697{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002698 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002699 return 0;
2700
2701 if (asprintf(optstr, "Zoom %s %s DSO",
2702 browser->hists->dso_filter ? "out of" : "into",
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002703 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002704 return 0;
2705
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03002706 act->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09002707 act->fn = do_zoom_dso;
2708 return 1;
2709}
2710
2711static int
2712do_browse_map(struct hist_browser *browser __maybe_unused,
2713 struct popup_action *act)
2714{
2715 map__browse(act->ms.map);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002716 return 0;
2717}
2718
2719static int
Jiri Olsa69849fc2016-05-03 13:54:45 +02002720add_map_opt(struct hist_browser *browser,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002721 struct popup_action *act, char **optstr, struct map *map)
2722{
Jiri Olsa69849fc2016-05-03 13:54:45 +02002723 if (!hists__has(browser->hists, dso) || map == NULL)
Namhyung Kimea7cd592015-04-22 16:18:19 +09002724 return 0;
2725
2726 if (asprintf(optstr, "Browse map details") < 0)
2727 return 0;
2728
2729 act->ms.map = map;
2730 act->fn = do_browse_map;
2731 return 1;
2732}
2733
2734static int
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002735do_run_script(struct hist_browser *browser __maybe_unused,
Namhyung Kimea7cd592015-04-22 16:18:19 +09002736 struct popup_action *act)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002737{
2738 char script_opt[64];
2739 memset(script_opt, 0, sizeof(script_opt));
2740
Namhyung Kimea7cd592015-04-22 16:18:19 +09002741 if (act->thread) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002742 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002743 thread__comm_str(act->thread));
2744 } else if (act->ms.sym) {
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002745 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
Namhyung Kimea7cd592015-04-22 16:18:19 +09002746 act->ms.sym->name);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002747 }
2748
2749 script_browse(script_opt);
2750 return 0;
2751}
2752
2753static int
Namhyung Kimea7cd592015-04-22 16:18:19 +09002754add_script_opt(struct hist_browser *browser __maybe_unused,
2755 struct popup_action *act, char **optstr,
2756 struct thread *thread, struct symbol *sym)
2757{
2758 if (thread) {
2759 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2760 thread__comm_str(thread)) < 0)
2761 return 0;
2762 } else if (sym) {
2763 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2764 sym->name) < 0)
2765 return 0;
2766 } else {
2767 if (asprintf(optstr, "Run scripts for all samples") < 0)
2768 return 0;
2769 }
2770
2771 act->thread = thread;
2772 act->ms.sym = sym;
2773 act->fn = do_run_script;
2774 return 1;
2775}
2776
2777static int
2778do_switch_data(struct hist_browser *browser __maybe_unused,
2779 struct popup_action *act __maybe_unused)
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002780{
2781 if (switch_data_file()) {
2782 ui__warning("Won't switch the data files due to\n"
2783 "no valid data file get selected!\n");
Namhyung Kimea7cd592015-04-22 16:18:19 +09002784 return 0;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09002785 }
2786
2787 return K_SWITCH_INPUT_DATA;
2788}
2789
Namhyung Kimea7cd592015-04-22 16:18:19 +09002790static int
2791add_switch_opt(struct hist_browser *browser,
2792 struct popup_action *act, char **optstr)
2793{
2794 if (!is_report_browser(browser->hbt))
2795 return 0;
2796
2797 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
2798 return 0;
2799
2800 act->fn = do_switch_data;
2801 return 1;
2802}
2803
2804static int
2805do_exit_browser(struct hist_browser *browser __maybe_unused,
2806 struct popup_action *act __maybe_unused)
2807{
2808 return 0;
2809}
2810
2811static int
2812add_exit_opt(struct hist_browser *browser __maybe_unused,
2813 struct popup_action *act, char **optstr)
2814{
2815 if (asprintf(optstr, "Exit") < 0)
2816 return 0;
2817
2818 act->fn = do_exit_browser;
2819 return 1;
2820}
2821
Kan Liang84734b02015-09-04 10:45:45 -04002822static int
2823do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2824{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002825 if (!hists__has(browser->hists, socket) || act->socket < 0)
Namhyung Kim599a2f32016-03-09 23:20:53 +09002826 return 0;
2827
Kan Liang84734b02015-09-04 10:45:45 -04002828 if (browser->hists->socket_filter > -1) {
2829 pstack__remove(browser->pstack, &browser->hists->socket_filter);
2830 browser->hists->socket_filter = -1;
2831 perf_hpp__set_elide(HISTC_SOCKET, false);
2832 } else {
2833 browser->hists->socket_filter = act->socket;
2834 perf_hpp__set_elide(HISTC_SOCKET, true);
2835 pstack__push(browser->pstack, &browser->hists->socket_filter);
2836 }
2837
2838 hists__filter_by_socket(browser->hists);
2839 hist_browser__reset(browser);
2840 return 0;
2841}
2842
2843static int
2844add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2845 char **optstr, int socket_id)
2846{
Jiri Olsa35a634f2016-05-03 13:54:46 +02002847 if (!hists__has(browser->hists, socket) || socket_id < 0)
Kan Liang84734b02015-09-04 10:45:45 -04002848 return 0;
2849
2850 if (asprintf(optstr, "Zoom %s Processor Socket %d",
2851 (browser->hists->socket_filter > -1) ? "out of" : "into",
2852 socket_id) < 0)
2853 return 0;
2854
2855 act->socket = socket_id;
2856 act->fn = do_zoom_socket;
2857 return 1;
2858}
2859
Namhyung Kim112f7612014-04-22 14:05:35 +09002860static void hist_browser__update_nr_entries(struct hist_browser *hb)
Namhyung Kim064f1982013-05-14 11:09:04 +09002861{
2862 u64 nr_entries = 0;
2863 struct rb_node *nd = rb_first(&hb->hists->entries);
2864
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002865 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
Namhyung Kim268397c2014-04-22 14:49:31 +09002866 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
2867 return;
2868 }
2869
Namhyung Kim14135662013-10-31 10:17:39 +09002870 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
Namhyung Kim064f1982013-05-14 11:09:04 +09002871 nr_entries++;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002872 nd = rb_hierarchy_next(nd);
Namhyung Kim064f1982013-05-14 11:09:04 +09002873 }
2874
Namhyung Kim112f7612014-04-22 14:05:35 +09002875 hb->nr_non_filtered_entries = nr_entries;
Namhyung Kimf5b763f2016-02-25 00:13:43 +09002876 hb->nr_hierarchy_entries = nr_entries;
Namhyung Kim064f1982013-05-14 11:09:04 +09002877}
Feng Tang341487ab2013-02-03 14:38:20 +08002878
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002879static void hist_browser__update_percent_limit(struct hist_browser *hb,
2880 double percent)
2881{
2882 struct hist_entry *he;
2883 struct rb_node *nd = rb_first(&hb->hists->entries);
2884 u64 total = hists__total_period(hb->hists);
2885 u64 min_callchain_hits = total * (percent / 100);
2886
2887 hb->min_pcnt = callchain_param.min_percent = percent;
2888
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002889 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2890 he = rb_entry(nd, struct hist_entry, rb_node);
2891
Namhyung Kim79dded82016-02-26 21:13:19 +09002892 if (he->has_no_entry) {
2893 he->has_no_entry = false;
2894 he->nr_rows = 0;
2895 }
2896
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002897 if (!he->leaf || !symbol_conf.use_callchain)
2898 goto next;
2899
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002900 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2901 total = he->stat.period;
2902
2903 if (symbol_conf.cumulate_callchain)
2904 total = he->stat_acc->period;
2905
2906 min_callchain_hits = total * (percent / 100);
2907 }
2908
2909 callchain_param.sort(&he->sorted_chain, he->callchain,
2910 min_callchain_hits, &callchain_param);
2911
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002912next:
Namhyung Kim201fde72016-02-26 21:13:18 +09002913 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
Namhyung Kimd0506ed2016-02-25 00:13:45 +09002914
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002915 /* force to re-evaluate folding state of callchains */
2916 he->init_have_children = false;
Namhyung Kim492b1012016-02-25 00:13:44 +09002917 hist_entry__set_folding(he, hb, false);
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002918 }
2919}
2920
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03002921static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
Jiri Olsadd00d482014-06-19 13:41:13 +02002922 const char *helpline,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03002923 bool left_exits,
Namhyung Kim68d80752012-11-02 14:50:06 +09002924 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09002925 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04002926 struct perf_env *env)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002927{
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03002928 struct hists *hists = evsel__hists(evsel);
Jiri Olsaa6ec8942016-06-20 23:58:17 +02002929 struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01002930 struct branch_info *bi;
Namhyung Kimf2b487d2015-04-22 16:18:14 +09002931#define MAX_OPTIONS 16
2932 char *options[MAX_OPTIONS];
Namhyung Kimea7cd592015-04-22 16:18:19 +09002933 struct popup_action actions[MAX_OPTIONS];
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002934 int nr_options = 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002935 int key = -1;
Namhyung Kim938a23a2012-03-16 17:50:53 +09002936 char buf[64];
Namhyung Kim9783adf2012-11-02 14:50:05 +09002937 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002938
Namhyung Kime8e684a2013-12-26 14:37:58 +09002939#define HIST_BROWSER_HELP_COMMON \
2940 "h/?/F1 Show this window\n" \
2941 "UP/DOWN/PGUP\n" \
2942 "PGDN/SPACE Navigate\n" \
2943 "q/ESC/CTRL+C Exit browser\n\n" \
2944 "For multiple event sessions:\n\n" \
2945 "TAB/UNTAB Switch events\n\n" \
2946 "For symbolic views (--sort has sym):\n\n" \
Arnaldo Carvalho de Melo7727a922015-10-12 13:56:50 -03002947 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2948 "ESC Zoom out\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002949 "a Annotate current symbol\n" \
2950 "C Collapse all callchains\n" \
2951 "d Zoom into current DSO\n" \
2952 "E Expand all callchains\n" \
Namhyung Kim105eb302014-02-10 11:20:10 +09002953 "F Toggle percentage of filtered entries\n" \
Arnaldo Carvalho de Melo025bf7e2014-06-14 15:44:52 +02002954 "H Display column headers\n" \
Namhyung Kimb62e8df2016-02-03 23:11:23 +09002955 "L Change percent limit\n" \
Namhyung Kim31eb4362015-10-13 09:02:01 +09002956 "m Display context menu\n" \
Kan Liang84734b02015-09-04 10:45:45 -04002957 "S Zoom into current Processor Socket\n" \
Namhyung Kime8e684a2013-12-26 14:37:58 +09002958
2959 /* help messages are sorted by lexical order of the hotkey */
2960 const char report_help[] = HIST_BROWSER_HELP_COMMON
Namhyung Kim6dd60132013-12-26 14:37:59 +09002961 "i Show header information\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002962 "P Print histograms to perf.hist.N\n"
2963 "r Run available scripts\n"
2964 "s Switch to another data file in PWD\n"
2965 "t Zoom into current Thread\n"
2966 "V Verbose (DSO names in callchains, etc)\n"
2967 "/ Filter symbol by name";
2968 const char top_help[] = HIST_BROWSER_HELP_COMMON
2969 "P Print histograms to perf.hist.N\n"
2970 "t Zoom into current Thread\n"
2971 "V Verbose (DSO names in callchains, etc)\n"
Namhyung Kim42337a22014-08-12 17:16:06 +09002972 "z Toggle zeroing of samples\n"
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03002973 "f Enable/Disable events\n"
Namhyung Kime8e684a2013-12-26 14:37:58 +09002974 "/ Filter symbol by name";
2975
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002976 if (browser == NULL)
2977 return -1;
2978
Namhyung Kimed426912015-05-29 21:53:44 +09002979 /* reset abort key so that it can get Ctrl-C as a key */
2980 SLang_reset_tty();
2981 SLang_init_tty(0, 0, 0);
2982
Namhyung Kim03905042015-11-28 02:32:39 +09002983 if (min_pcnt)
Namhyung Kim064f1982013-05-14 11:09:04 +09002984 browser->min_pcnt = min_pcnt;
Namhyung Kim03905042015-11-28 02:32:39 +09002985 hist_browser__update_nr_entries(browser);
Namhyung Kim064f1982013-05-14 11:09:04 +09002986
Kan Liang84734b02015-09-04 10:45:45 -04002987 browser->pstack = pstack__new(3);
Namhyung Kim01f00a12015-04-22 16:18:16 +09002988 if (browser->pstack == NULL)
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002989 goto out;
2990
2991 ui_helpline__push(helpline);
2992
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002993 memset(options, 0, sizeof(options));
Namhyung Kimea7cd592015-04-22 16:18:19 +09002994 memset(actions, 0, sizeof(actions));
Stephane Eranian24bff2d2012-03-12 16:13:30 +01002995
Namhyung Kim5b591662014-07-31 14:47:38 +09002996 if (symbol_conf.col_width_list_str)
2997 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
2998
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03002999 while (1) {
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03003000 struct thread *thread = NULL;
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003001 struct map *map = NULL;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003002 int choice = 0;
Kan Liang84734b02015-09-04 10:45:45 -04003003 int socked_id = -1;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003004
Stephane Eranian24bff2d2012-03-12 16:13:30 +01003005 nr_options = 0;
3006
Arnaldo Carvalho de Melo5f00b0f2015-06-19 17:30:20 -03003007 key = hist_browser__run(browser, helpline);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003008
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003009 if (browser->he_selection != NULL) {
3010 thread = hist_browser__selected_thread(browser);
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003011 map = browser->selection->map;
Kan Liang84734b02015-09-04 10:45:45 -04003012 socked_id = browser->he_selection->socket;
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003013 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003014 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003015 case K_TAB:
3016 case K_UNTAB:
David Aherne4419b82011-10-19 11:37:47 -06003017 if (nr_events == 1)
3018 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003019 /*
3020 * Exit the browser, let hists__browser_tree
3021 * go to the next or previous
3022 */
3023 goto out_free_stack;
3024 case 'a':
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003025 if (!hists__has(hists, sym)) {
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003026 ui_browser__warning(&browser->b, delay_secs * 2,
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003027 "Annotation is only available for symbolic views, "
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003028 "include \"sym*\" in --sort to use it.");
Arnaldo Carvalho de Meloa6e51f92011-10-21 10:58:24 -02003029 continue;
3030 }
3031
Arnaldo Carvalho de Melo60098912011-03-04 21:19:21 -03003032 if (browser->selection == NULL ||
Lin Mingdb9a9cbc2011-04-08 14:31:26 +08003033 browser->selection->sym == NULL ||
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003034 browser->selection->map->dso->annotate_warned)
3035 continue;
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003036
Namhyung Kimea7cd592015-04-22 16:18:19 +09003037 actions->ms.map = browser->selection->map;
3038 actions->ms.sym = browser->selection->sym;
3039 do_annotate(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003040 continue;
Arnaldo Carvalho de Meloaff3f3f2012-06-07 19:31:28 -03003041 case 'P':
3042 hist_browser__dump(browser);
3043 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003044 case 'd':
Arnaldo Carvalho de Melofae00652015-11-12 15:59:26 -03003045 actions->ms.map = map;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003046 do_zoom_dso(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003047 continue;
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003048 case 'V':
Alexis Berlemont21e8c812016-10-12 23:48:23 +02003049 verbose = (verbose + 1) % 4;
3050 browser->show_dso = verbose > 0;
3051 ui_helpline__fpush("Verbosity level set to %d\n",
3052 verbose);
Arnaldo Carvalho de Meloa7cb8862012-08-03 13:53:40 -03003053 continue;
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003054 case 't':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003055 actions->thread = thread;
3056 do_zoom_thread(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003057 continue;
Kan Liang84734b02015-09-04 10:45:45 -04003058 case 'S':
3059 actions->socket = socked_id;
3060 do_zoom_socket(browser, actions);
3061 continue;
Arnaldo Carvalho de Melo5a5626b2012-05-09 12:21:22 -03003062 case '/':
Namhyung Kim938a23a2012-03-16 17:50:53 +09003063 if (ui_browser__input_window("Symbol to show",
Arnaldo Carvalho de Melo4aa8e4542015-10-12 14:02:29 -03003064 "Please enter the name of symbol you want to see.\n"
3065 "To remove the filter later, press / + ENTER.",
Namhyung Kim938a23a2012-03-16 17:50:53 +09003066 buf, "ENTER: OK, ESC: Cancel",
3067 delay_secs * 2) == K_ENTER) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -03003068 hists->symbol_filter_str = *buf ? buf : NULL;
3069 hists__filter_by_symbol(hists);
Namhyung Kim938a23a2012-03-16 17:50:53 +09003070 hist_browser__reset(browser);
3071 }
3072 continue;
Feng Tangcdbab7c2012-10-30 11:56:06 +08003073 case 'r':
Namhyung Kimea7cd592015-04-22 16:18:19 +09003074 if (is_report_browser(hbt)) {
3075 actions->thread = NULL;
3076 actions->ms.sym = NULL;
3077 do_run_script(browser, actions);
3078 }
Feng Tangc77d8d72012-11-01 00:00:55 +08003079 continue;
Feng Tang341487ab2013-02-03 14:38:20 +08003080 case 's':
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003081 if (is_report_browser(hbt)) {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003082 key = do_switch_data(browser, actions);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003083 if (key == K_SWITCH_INPUT_DATA)
3084 goto out_free_stack;
3085 }
Feng Tang341487ab2013-02-03 14:38:20 +08003086 continue;
Namhyung Kim6dd60132013-12-26 14:37:59 +09003087 case 'i':
3088 /* env->arch is NULL for live-mode (i.e. perf top) */
3089 if (env->arch)
3090 tui__header_window(env);
3091 continue;
Namhyung Kim105eb302014-02-10 11:20:10 +09003092 case 'F':
3093 symbol_conf.filter_relative ^= 1;
3094 continue;
Namhyung Kim42337a22014-08-12 17:16:06 +09003095 case 'z':
3096 if (!is_report_browser(hbt)) {
3097 struct perf_top *top = hbt->arg;
3098
3099 top->zero = !top->zero;
3100 }
3101 continue;
Namhyung Kimb62e8df2016-02-03 23:11:23 +09003102 case 'L':
3103 if (ui_browser__input_window("Percent Limit",
3104 "Please enter the value you want to hide entries under that percent.",
3105 buf, "ENTER: OK, ESC: Cancel",
3106 delay_secs * 2) == K_ENTER) {
3107 char *end;
3108 double new_percent = strtod(buf, &end);
3109
3110 if (new_percent < 0 || new_percent > 100) {
3111 ui_browser__warning(&browser->b, delay_secs * 2,
3112 "Invalid percent: %.2f", new_percent);
3113 continue;
3114 }
3115
3116 hist_browser__update_percent_limit(browser, new_percent);
3117 hist_browser__reset(browser);
3118 }
3119 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003120 case K_F1:
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003121 case 'h':
3122 case '?':
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003123 ui_browser__help_window(&browser->b,
Namhyung Kime8e684a2013-12-26 14:37:58 +09003124 is_report_browser(hbt) ? report_help : top_help);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003125 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003126 case K_ENTER:
3127 case K_RIGHT:
Namhyung Kim31eb4362015-10-13 09:02:01 +09003128 case 'm':
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003129 /* menu */
3130 break;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003131 case K_ESC:
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003132 case K_LEFT: {
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003133 const void *top;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003134
Namhyung Kim01f00a12015-04-22 16:18:16 +09003135 if (pstack__empty(browser->pstack)) {
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003136 /*
3137 * Go back to the perf_evsel_menu__run or other user
3138 */
3139 if (left_exits)
3140 goto out_free_stack;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003141
3142 if (key == K_ESC &&
3143 ui_browser__dialog_yesno(&browser->b,
3144 "Do you really want to exit?"))
3145 goto out_free_stack;
3146
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003147 continue;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003148 }
Namhyung Kim64221842015-04-24 10:15:33 +09003149 top = pstack__peek(browser->pstack);
Namhyung Kimbc7cad42015-04-22 16:18:18 +09003150 if (top == &browser->hists->dso_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003151 /*
3152 * No need to set actions->dso here since
3153 * it's just to remove the current filter.
3154 * Ditto for thread below.
3155 */
3156 do_zoom_dso(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003157 } else if (top == &browser->hists->thread_filter) {
Namhyung Kim64221842015-04-24 10:15:33 +09003158 do_zoom_thread(browser, actions);
Kan Liang84734b02015-09-04 10:45:45 -04003159 } else if (top == &browser->hists->socket_filter) {
3160 do_zoom_socket(browser, actions);
3161 }
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -03003162 continue;
3163 }
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003164 case 'q':
3165 case CTRL('c'):
Arnaldo Carvalho de Melo516e5362015-06-19 16:59:43 -03003166 goto out_free_stack;
Arnaldo Carvalho de Melofbb79972015-06-19 16:56:04 -03003167 case 'f':
Namhyung Kim13d1e532015-06-21 12:41:16 +09003168 if (!is_report_browser(hbt)) {
3169 struct perf_top *top = hbt->arg;
3170
3171 perf_evlist__toggle_enable(top->evlist);
3172 /*
3173 * No need to refresh, resort/decay histogram
3174 * entries if we are not collecting samples:
3175 */
3176 if (top->evlist->enabled) {
3177 helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
3178 hbt->refresh = delay_secs;
3179 } else {
3180 helpline = "Press 'f' again to re-enable the events";
3181 hbt->refresh = 0;
3182 }
3183 continue;
3184 }
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003185 /* Fall thru */
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003186 default:
Arnaldo Carvalho de Melo3e323dc2015-06-19 17:49:29 -03003187 helpline = "Press '?' for help on key bindings";
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003188 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003189 }
3190
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003191 if (!hists__has(hists, sym) || browser->selection == NULL)
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003192 goto skip_annotation;
3193
Namhyung Kim55369fc2013-04-01 20:35:20 +09003194 if (sort__mode == SORT_MODE__BRANCH) {
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003195 bi = browser->he_selection->branch_info;
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003196
3197 if (bi == NULL)
3198 goto skip_annotation;
3199
Namhyung Kimea7cd592015-04-22 16:18:19 +09003200 nr_options += add_annotate_opt(browser,
3201 &actions[nr_options],
3202 &options[nr_options],
3203 bi->from.map,
3204 bi->from.sym);
3205 if (bi->to.sym != bi->from.sym)
3206 nr_options += add_annotate_opt(browser,
3207 &actions[nr_options],
3208 &options[nr_options],
3209 bi->to.map,
3210 bi->to.sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003211 } else {
Namhyung Kimea7cd592015-04-22 16:18:19 +09003212 nr_options += add_annotate_opt(browser,
3213 &actions[nr_options],
3214 &options[nr_options],
3215 browser->selection->map,
3216 browser->selection->sym);
Stephane Eraniana68c2c52012-03-08 23:47:48 +01003217 }
Arnaldo Carvalho de Melo0ba332f2015-03-16 17:41:52 -03003218skip_annotation:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003219 nr_options += add_thread_opt(browser, &actions[nr_options],
3220 &options[nr_options], thread);
3221 nr_options += add_dso_opt(browser, &actions[nr_options],
Arnaldo Carvalho de Melo045b80d2015-09-23 15:38:55 -03003222 &options[nr_options], map);
Namhyung Kimea7cd592015-04-22 16:18:19 +09003223 nr_options += add_map_opt(browser, &actions[nr_options],
3224 &options[nr_options],
Wang Nanbd315aa2015-09-14 10:23:55 +00003225 browser->selection ?
3226 browser->selection->map : NULL);
Kan Liang84734b02015-09-04 10:45:45 -04003227 nr_options += add_socket_opt(browser, &actions[nr_options],
3228 &options[nr_options],
3229 socked_id);
Feng Tangcdbab7c2012-10-30 11:56:06 +08003230 /* perf script support */
Namhyung Kimb1baae82016-01-26 15:37:30 -03003231 if (!is_report_browser(hbt))
3232 goto skip_scripting;
3233
Feng Tangcdbab7c2012-10-30 11:56:06 +08003234 if (browser->he_selection) {
Jiri Olsafa829112016-05-03 13:54:47 +02003235 if (hists__has(hists, thread) && thread) {
Namhyung Kim2eafd412016-01-21 19:13:24 -03003236 nr_options += add_script_opt(browser,
3237 &actions[nr_options],
3238 &options[nr_options],
3239 thread, NULL);
3240 }
Wang Nanbd315aa2015-09-14 10:23:55 +00003241 /*
3242 * Note that browser->selection != NULL
3243 * when browser->he_selection is not NULL,
3244 * so we don't need to check browser->selection
3245 * before fetching browser->selection->sym like what
3246 * we do before fetching browser->selection->map.
3247 *
3248 * See hist_browser__show_entry.
3249 */
Jiri Olsa2e0453a2016-05-03 13:54:44 +02003250 if (hists__has(hists, sym) && browser->selection->sym) {
Namhyung Kimc221acb2016-01-21 19:50:09 -03003251 nr_options += add_script_opt(browser,
3252 &actions[nr_options],
3253 &options[nr_options],
3254 NULL, browser->selection->sym);
3255 }
Feng Tangcdbab7c2012-10-30 11:56:06 +08003256 }
Namhyung Kimea7cd592015-04-22 16:18:19 +09003257 nr_options += add_script_opt(browser, &actions[nr_options],
3258 &options[nr_options], NULL, NULL);
3259 nr_options += add_switch_opt(browser, &actions[nr_options],
3260 &options[nr_options]);
Namhyung Kimb1baae82016-01-26 15:37:30 -03003261skip_scripting:
Namhyung Kimea7cd592015-04-22 16:18:19 +09003262 nr_options += add_exit_opt(browser, &actions[nr_options],
3263 &options[nr_options]);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003264
Namhyung Kimea7cd592015-04-22 16:18:19 +09003265 do {
3266 struct popup_action *act;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003267
Namhyung Kimea7cd592015-04-22 16:18:19 +09003268 choice = ui__popup_menu(nr_options, options);
3269 if (choice == -1 || choice >= nr_options)
Feng Tang341487ab2013-02-03 14:38:20 +08003270 break;
Namhyung Kimea7cd592015-04-22 16:18:19 +09003271
3272 act = &actions[choice];
3273 key = act->fn(browser, act);
3274 } while (key == 1);
3275
3276 if (key == K_SWITCH_INPUT_DATA)
3277 break;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003278 }
3279out_free_stack:
Namhyung Kim01f00a12015-04-22 16:18:16 +09003280 pstack__delete(browser->pstack);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003281out:
3282 hist_browser__delete(browser);
Namhyung Kimf2b487d2015-04-22 16:18:14 +09003283 free_popup_options(options, MAX_OPTIONS);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003284 return key;
3285}
3286
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003287struct perf_evsel_menu {
3288 struct ui_browser b;
3289 struct perf_evsel *selection;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003290 bool lost_events, lost_events_warned;
Namhyung Kim064f1982013-05-14 11:09:04 +09003291 float min_pcnt;
Kan Liangce80d3b2015-08-28 05:48:04 -04003292 struct perf_env *env;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003293};
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003294
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003295static void perf_evsel_menu__write(struct ui_browser *browser,
3296 void *entry, int row)
3297{
3298 struct perf_evsel_menu *menu = container_of(browser,
3299 struct perf_evsel_menu, b);
3300 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003301 struct hists *hists = evsel__hists(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003302 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003303 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003304 const char *ev_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003305 char bf[256], unit;
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003306 const char *warn = " ";
3307 size_t printed;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003308
3309 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
3310 HE_COLORSET_NORMAL);
3311
Namhyung Kim759ff492013-03-05 14:53:26 +09003312 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kim717e2632013-01-22 18:09:44 +09003313 struct perf_evsel *pos;
3314
3315 ev_name = perf_evsel__group_name(evsel);
3316
3317 for_each_group_member(pos, evsel) {
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003318 struct hists *pos_hists = evsel__hists(pos);
3319 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
Namhyung Kim717e2632013-01-22 18:09:44 +09003320 }
3321 }
3322
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003323 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003324 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003325 unit, unit == ' ' ? "" : " ", ev_name);
Arnaldo Carvalho de Melo517dfdb2015-08-11 12:50:55 -03003326 ui_browser__printf(browser, "%s", bf);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003327
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03003328 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003329 if (nr_events != 0) {
3330 menu->lost_events = true;
3331 if (!current_entry)
3332 ui_browser__set_color(browser, HE_COLORSET_TOP);
3333 nr_events = convert_unit(nr_events, &unit);
Arnaldo Carvalho de Meloe7f01d12012-03-14 12:29:29 -03003334 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
3335 nr_events, unit, unit == ' ' ? "" : " ");
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003336 warn = bf;
3337 }
3338
Arnaldo Carvalho de Melo26270a02015-08-11 12:24:27 -03003339 ui_browser__write_nstring(browser, warn, browser->width - printed);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003340
3341 if (current_entry)
3342 menu->selection = evsel;
3343}
3344
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003345static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3346 int nr_events, const char *help,
Namhyung Kim9783adf2012-11-02 14:50:05 +09003347 struct hist_browser_timer *hbt)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003348{
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003349 struct perf_evlist *evlist = menu->b.priv;
3350 struct perf_evsel *pos;
Jiri Olsadd00d482014-06-19 13:41:13 +02003351 const char *title = "Available samples";
Namhyung Kim9783adf2012-11-02 14:50:05 +09003352 int delay_secs = hbt ? hbt->refresh : 0;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003353 int key;
3354
3355 if (ui_browser__show(&menu->b, title,
3356 "ESC: exit, ENTER|->: Browse histograms") < 0)
3357 return -1;
3358
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003359 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -03003360 key = ui_browser__run(&menu->b, delay_secs);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003361
3362 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003363 case K_TIMER:
Namhyung Kim9783adf2012-11-02 14:50:05 +09003364 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo7b275092011-10-29 12:15:04 -02003365
3366 if (!menu->lost_events_warned && menu->lost_events) {
3367 ui_browser__warn_lost_events(&menu->b);
3368 menu->lost_events_warned = true;
3369 }
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003370 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003371 case K_RIGHT:
3372 case K_ENTER:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003373 if (!menu->selection)
3374 continue;
3375 pos = menu->selection;
3376browse_hists:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003377 perf_evlist__set_selected(evlist, pos);
3378 /*
3379 * Give the calling tool a chance to populate the non
3380 * default evsel resorted hists tree.
3381 */
Namhyung Kim9783adf2012-11-02 14:50:05 +09003382 if (hbt)
3383 hbt->timer(hbt->arg);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -03003384 key = perf_evsel__hists_browse(pos, nr_events, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003385 true, hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003386 menu->min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003387 menu->env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003388 ui_browser__show_title(&menu->b, title);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003389 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003390 case K_TAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003391 if (pos->node.next == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003392 pos = perf_evlist__first(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003393 else
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003394 pos = perf_evsel__next(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003395 goto browse_hists;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003396 case K_UNTAB:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003397 if (pos->node.prev == &evlist->entries)
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003398 pos = perf_evlist__last(evlist);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003399 else
Arnaldo Carvalho de Melod87fcb42013-11-13 15:56:40 -03003400 pos = perf_evsel__prev(pos);
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003401 goto browse_hists;
Feng Tang341487ab2013-02-03 14:38:20 +08003402 case K_SWITCH_INPUT_DATA:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003403 case 'q':
3404 case CTRL('c'):
3405 goto out;
Arnaldo Carvalho de Melo63ab1742015-08-12 12:42:58 -03003406 case K_ESC:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003407 default:
3408 continue;
3409 }
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003410 case K_LEFT:
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003411 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -02003412 case K_ESC:
Arnaldo Carvalho de Melo4610e412011-10-26 12:04:37 -02003413 if (!ui_browser__dialog_yesno(&menu->b,
3414 "Do you really want to exit?"))
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -03003415 continue;
3416 /* Fall thru */
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003417 case 'q':
3418 case CTRL('c'):
3419 goto out;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003420 default:
Arnaldo Carvalho de Melo18eaf0b2011-10-13 12:22:28 -03003421 continue;
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003422 }
3423 }
3424
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003425out:
3426 ui_browser__hide(&menu->b);
3427 return key;
3428}
3429
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03003430static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003431 void *entry)
3432{
3433 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3434
3435 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3436 return true;
3437
3438 return false;
3439}
3440
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003441static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003442 int nr_entries, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003443 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003444 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003445 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003446{
3447 struct perf_evsel *pos;
3448 struct perf_evsel_menu menu = {
3449 .b = {
3450 .entries = &evlist->entries,
3451 .refresh = ui_browser__list_head_refresh,
3452 .seek = ui_browser__list_head_seek,
3453 .write = perf_evsel_menu__write,
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003454 .filter = filter_group_entries,
3455 .nr_entries = nr_entries,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003456 .priv = evlist,
3457 },
Namhyung Kim064f1982013-05-14 11:09:04 +09003458 .min_pcnt = min_pcnt,
Namhyung Kim68d80752012-11-02 14:50:06 +09003459 .env = env,
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003460 };
3461
3462 ui_helpline__push("Press ESC to exit");
3463
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003464 evlist__for_each_entry(evlist, pos) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -03003465 const char *ev_name = perf_evsel__name(pos);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003466 size_t line_len = strlen(ev_name) + 7;
3467
3468 if (menu.b.width < line_len)
3469 menu.b.width = line_len;
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003470 }
3471
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003472 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003473}
3474
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -03003475int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Namhyung Kim68d80752012-11-02 14:50:06 +09003476 struct hist_browser_timer *hbt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003477 float min_pcnt,
Kan Liangce80d3b2015-08-28 05:48:04 -04003478 struct perf_env *env)
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003479{
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003480 int nr_entries = evlist->nr_entries;
3481
3482single_entry:
3483 if (nr_entries == 1) {
Arnaldo Carvalho de Melo9a354cd2013-11-13 15:54:30 -03003484 struct perf_evsel *first = perf_evlist__first(evlist);
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003485
3486 return perf_evsel__hists_browse(first, nr_entries, help,
Jiri Olsadd00d482014-06-19 13:41:13 +02003487 false, hbt, min_pcnt,
Namhyung Kim064f1982013-05-14 11:09:04 +09003488 env);
Arnaldo Carvalho de Melo7f0030b2011-03-06 13:07:30 -03003489 }
3490
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003491 if (symbol_conf.event_group) {
3492 struct perf_evsel *pos;
3493
3494 nr_entries = 0;
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003495 evlist__for_each_entry(evlist, pos) {
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003496 if (perf_evsel__is_group_leader(pos))
3497 nr_entries++;
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -03003498 }
Namhyung Kimfc24d7c2013-01-22 18:09:43 +09003499
3500 if (nr_entries == 1)
3501 goto single_entry;
3502 }
3503
3504 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
Namhyung Kim064f1982013-05-14 11:09:04 +09003505 hbt, min_pcnt, env);
Arnaldo Carvalho de Melod1b4f242010-08-10 15:49:07 -03003506}