aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c260
1 files changed, 124 insertions, 136 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 55fc1f46892a..287a173523a7 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -9,6 +9,7 @@
9 9
10#include "util/util.h" 10#include "util/util.h"
11 11
12#include "util/annotate.h"
12#include "util/color.h" 13#include "util/color.h"
13#include <linux/list.h> 14#include <linux/list.h>
14#include "util/cache.h" 15#include "util/cache.h"
@@ -20,6 +21,8 @@
20 21
21#include "perf.h" 22#include "perf.h"
22#include "util/debug.h" 23#include "util/debug.h"
24#include "util/evlist.h"
25#include "util/evsel.h"
23#include "util/header.h" 26#include "util/header.h"
24#include "util/session.h" 27#include "util/session.h"
25 28
@@ -32,7 +35,7 @@
32 35
33static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
34 37
35static bool force; 38static bool force, use_tui, use_stdio;
36static bool hide_unresolved; 39static bool hide_unresolved;
37static bool dont_use_callchains; 40static bool dont_use_callchains;
38 41
@@ -43,119 +46,68 @@ static const char default_pretty_printing_style[] = "normal";
43static const char *pretty_printing_style = default_pretty_printing_style; 46static const char *pretty_printing_style = default_pretty_printing_style;
44 47
45static char callchain_default_opt[] = "fractal,0.5"; 48static char callchain_default_opt[] = "fractal,0.5";
49static symbol_filter_t annotate_init;
46 50
47static struct hists *perf_session__hists_findnew(struct perf_session *self, 51static int perf_session__add_hist_entry(struct perf_session *session,
48 u64 event_stream, u32 type,
49 u64 config)
50{
51 struct rb_node **p = &self->hists_tree.rb_node;
52 struct rb_node *parent = NULL;
53 struct hists *iter, *new;
54
55 while (*p != NULL) {
56 parent = *p;
57 iter = rb_entry(parent, struct hists, rb_node);
58 if (iter->config == config)
59 return iter;
60
61
62 if (config > iter->config)
63 p = &(*p)->rb_right;
64 else
65 p = &(*p)->rb_left;
66 }
67
68 new = malloc(sizeof(struct hists));
69 if (new == NULL)
70 return NULL;
71 memset(new, 0, sizeof(struct hists));
72 new->event_stream = event_stream;
73 new->config = config;
74 new->type = type;
75 rb_link_node(&new->rb_node, parent, p);
76 rb_insert_color(&new->rb_node, &self->hists_tree);
77 return new;
78}
79
80static int perf_session__add_hist_entry(struct perf_session *self,
81 struct addr_location *al, 52 struct addr_location *al,
82 struct sample_data *data) 53 struct perf_sample *sample,
54 struct perf_evsel *evsel)
83{ 55{
84 struct map_symbol *syms = NULL;
85 struct symbol *parent = NULL; 56 struct symbol *parent = NULL;
86 int err = -ENOMEM; 57 int err = 0;
87 struct hist_entry *he; 58 struct hist_entry *he;
88 struct hists *hists; 59
89 struct perf_event_attr *attr; 60 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
90 61 err = perf_session__resolve_callchain(session, al->thread,
91 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { 62 sample->callchain, &parent);
92 syms = perf_session__resolve_callchain(self, al->thread, 63 if (err)
93 data->callchain, &parent); 64 return err;
94 if (syms == NULL)
95 return -ENOMEM;
96 } 65 }
97 66
98 attr = perf_header__find_attr(data->id, &self->header); 67 he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
99 if (attr)
100 hists = perf_session__hists_findnew(self, data->id, attr->type, attr->config);
101 else
102 hists = perf_session__hists_findnew(self, data->id, 0, 0);
103 if (hists == NULL)
104 goto out_free_syms;
105 he = __hists__add_entry(hists, al, parent, data->period);
106 if (he == NULL) 68 if (he == NULL)
107 goto out_free_syms; 69 return -ENOMEM;
108 err = 0; 70
109 if (symbol_conf.use_callchain) { 71 if (symbol_conf.use_callchain) {
110 err = append_chain(he->callchain, data->callchain, syms, data->period); 72 err = callchain_append(he->callchain, &session->callchain_cursor,
73 sample->period);
111 if (err) 74 if (err)
112 goto out_free_syms; 75 return err;
113 } 76 }
114 /* 77 /*
115 * Only in the newt browser we are doing integrated annotation, 78 * Only in the newt browser we are doing integrated annotation,
116 * so we don't allocated the extra space needed because the stdio 79 * so we don't allocated the extra space needed because the stdio
117 * code will not use it. 80 * code will not use it.
118 */ 81 */
119 if (use_browser > 0) 82 if (al->sym != NULL && use_browser > 0) {
120 err = hist_entry__inc_addr_samples(he, al->addr); 83 struct annotation *notes = symbol__annotation(he->ms.sym);
121out_free_syms:
122 free(syms);
123 return err;
124}
125 84
126static int add_event_total(struct perf_session *session, 85 assert(evsel != NULL);
127 struct sample_data *data,
128 struct perf_event_attr *attr)
129{
130 struct hists *hists;
131 86
132 if (attr) 87 err = -ENOMEM;
133 hists = perf_session__hists_findnew(session, data->id, 88 if (notes->src == NULL &&
134 attr->type, attr->config); 89 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
135 else 90 goto out;
136 hists = perf_session__hists_findnew(session, data->id, 0, 0);
137 91
138 if (!hists) 92 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
139 return -ENOMEM; 93 }
140 94
141 hists->stats.total_period += data->period; 95 evsel->hists.stats.total_period += sample->period;
142 /* 96 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
143 * FIXME: add_event_total should be moved from here to 97out:
144 * perf_session__process_event so that the proper hist is passed to 98 return err;
145 * the event_op methods.
146 */
147 hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
148 session->hists.stats.total_period += data->period;
149 return 0;
150} 99}
151 100
152static int process_sample_event(event_t *event, struct perf_session *session) 101
102static int process_sample_event(union perf_event *event,
103 struct perf_sample *sample,
104 struct perf_evsel *evsel,
105 struct perf_session *session)
153{ 106{
154 struct sample_data data = { .period = 1, };
155 struct addr_location al; 107 struct addr_location al;
156 struct perf_event_attr *attr;
157 108
158 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { 109 if (perf_event__preprocess_sample(event, session, &al, sample,
110 annotate_init) < 0) {
159 fprintf(stderr, "problem processing %d event, skipping it.\n", 111 fprintf(stderr, "problem processing %d event, skipping it.\n",
160 event->header.type); 112 event->header.type);
161 return -1; 113 return -1;
@@ -164,30 +116,25 @@ static int process_sample_event(event_t *event, struct perf_session *session)
164 if (al.filtered || (hide_unresolved && al.sym == NULL)) 116 if (al.filtered || (hide_unresolved && al.sym == NULL))
165 return 0; 117 return 0;
166 118
167 if (perf_session__add_hist_entry(session, &al, &data)) { 119 if (al.map != NULL)
168 pr_debug("problem incrementing symbol period, skipping event\n"); 120 al.map->dso->hit = 1;
169 return -1;
170 }
171 121
172 attr = perf_header__find_attr(data.id, &session->header); 122 if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
173 123 pr_debug("problem incrementing symbol period, skipping event\n");
174 if (add_event_total(session, &data, attr)) {
175 pr_debug("problem adding event period\n");
176 return -1; 124 return -1;
177 } 125 }
178 126
179 return 0; 127 return 0;
180} 128}
181 129
182static int process_read_event(event_t *event, struct perf_session *session __used) 130static int process_read_event(union perf_event *event,
131 struct perf_sample *sample __used,
132 struct perf_session *session)
183{ 133{
184 struct perf_event_attr *attr; 134 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
185 135 event->read.id);
186 attr = perf_header__find_attr(event->read.id, &session->header);
187
188 if (show_threads) { 136 if (show_threads) {
189 const char *name = attr ? __event_name(attr->type, attr->config) 137 const char *name = evsel ? event_name(evsel) : "unknown";
190 : "unknown";
191 perf_read_values_add_value(&show_threads_values, 138 perf_read_values_add_value(&show_threads_values,
192 event->read.pid, event->read.tid, 139 event->read.pid, event->read.tid,
193 event->read.id, 140 event->read.id,
@@ -195,8 +142,8 @@ static int process_read_event(event_t *event, struct perf_session *session __use
195 event->read.value); 142 event->read.value);
196 } 143 }
197 144
198 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid, 145 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
199 attr ? __event_name(attr->type, attr->config) : "FAIL", 146 evsel ? event_name(evsel) : "FAIL",
200 event->read.value); 147 event->read.value);
201 148
202 return 0; 149 return 0;
@@ -220,7 +167,7 @@ static int perf_session__setup_sample_type(struct perf_session *self)
220 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 167 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
221 !symbol_conf.use_callchain) { 168 !symbol_conf.use_callchain) {
222 symbol_conf.use_callchain = true; 169 symbol_conf.use_callchain = true;
223 if (register_callchain_param(&callchain_param) < 0) { 170 if (callchain_register_param(&callchain_param) < 0) {
224 fprintf(stderr, "Can't register callchain" 171 fprintf(stderr, "Can't register callchain"
225 " params\n"); 172 " params\n");
226 return -EINVAL; 173 return -EINVAL;
@@ -231,17 +178,19 @@ static int perf_session__setup_sample_type(struct perf_session *self)
231} 178}
232 179
233static struct perf_event_ops event_ops = { 180static struct perf_event_ops event_ops = {
234 .sample = process_sample_event, 181 .sample = process_sample_event,
235 .mmap = event__process_mmap, 182 .mmap = perf_event__process_mmap,
236 .comm = event__process_comm, 183 .comm = perf_event__process_comm,
237 .exit = event__process_task, 184 .exit = perf_event__process_task,
238 .fork = event__process_task, 185 .fork = perf_event__process_task,
239 .lost = event__process_lost, 186 .lost = perf_event__process_lost,
240 .read = process_read_event, 187 .read = process_read_event,
241 .attr = event__process_attr, 188 .attr = perf_event__process_attr,
242 .event_type = event__process_event_type, 189 .event_type = perf_event__process_event_type,
243 .tracing_data = event__process_tracing_data, 190 .tracing_data = perf_event__process_tracing_data,
244 .build_id = event__process_build_id, 191 .build_id = perf_event__process_build_id,
192 .ordered_samples = true,
193 .ordering_requires_timestamps = true,
245}; 194};
246 195
247extern volatile int session_done; 196extern volatile int session_done;
@@ -265,21 +214,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
265 return ret + fprintf(fp, "\n#\n"); 214 return ret + fprintf(fp, "\n#\n");
266} 215}
267 216
268static int hists__tty_browse_tree(struct rb_root *tree, const char *help) 217static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
218 const char *help)
269{ 219{
270 struct rb_node *next = rb_first(tree); 220 struct perf_evsel *pos;
271 221
272 while (next) { 222 list_for_each_entry(pos, &evlist->entries, node) {
273 struct hists *hists = rb_entry(next, struct hists, rb_node); 223 struct hists *hists = &pos->hists;
274 const char *evname = NULL; 224 const char *evname = NULL;
275 225
276 if (rb_first(&hists->entries) != rb_last(&hists->entries)) 226 if (rb_first(&hists->entries) != rb_last(&hists->entries))
277 evname = __event_name(hists->type, hists->config); 227 evname = event_name(pos);
278 228
279 hists__fprintf_nr_sample_events(hists, evname, stdout); 229 hists__fprintf_nr_sample_events(hists, evname, stdout);
280 hists__fprintf(hists, NULL, false, stdout); 230 hists__fprintf(hists, NULL, false, stdout);
281 fprintf(stdout, "\n\n"); 231 fprintf(stdout, "\n\n");
282 next = rb_next(&hists->rb_node);
283 } 232 }
284 233
285 if (sort_order == default_sort_order && 234 if (sort_order == default_sort_order &&
@@ -300,13 +249,16 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
300static int __cmd_report(void) 249static int __cmd_report(void)
301{ 250{
302 int ret = -EINVAL; 251 int ret = -EINVAL;
252 u64 nr_samples;
303 struct perf_session *session; 253 struct perf_session *session;
304 struct rb_node *next; 254 struct perf_evsel *pos;
255 struct map *kernel_map;
256 struct kmap *kernel_kmap;
305 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 257 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
306 258
307 signal(SIGINT, sig_handler); 259 signal(SIGINT, sig_handler);
308 260
309 session = perf_session__new(input_name, O_RDONLY, force, false); 261 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
310 if (session == NULL) 262 if (session == NULL)
311 return -ENOMEM; 263 return -ENOMEM;
312 264
@@ -321,6 +273,24 @@ static int __cmd_report(void)
321 if (ret) 273 if (ret)
322 goto out_delete; 274 goto out_delete;
323 275
276 kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION];
277 kernel_kmap = map__kmap(kernel_map);
278 if (kernel_map == NULL ||
279 (kernel_map->dso->hit &&
280 (kernel_kmap->ref_reloc_sym == NULL ||
281 kernel_kmap->ref_reloc_sym->addr == 0))) {
282 const struct dso *kdso = kernel_map->dso;
283
284 ui__warning(
285"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
286"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
287"Samples in kernel modules can't be resolved as well.\n\n",
288 RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION]) ?
289"As no suitable kallsyms nor vmlinux was found, kernel samples\n"
290"can't be resolved." :
291"If some relocation was applied (e.g. kexec) symbols may be misresolved.");
292 }
293
324 if (dump_trace) { 294 if (dump_trace) {
325 perf_session__fprintf_nr_events(session, stdout); 295 perf_session__fprintf_nr_events(session, stdout);
326 goto out_delete; 296 goto out_delete;
@@ -332,20 +302,24 @@ static int __cmd_report(void)
332 if (verbose > 2) 302 if (verbose > 2)
333 perf_session__fprintf_dsos(session, stdout); 303 perf_session__fprintf_dsos(session, stdout);
334 304
335 next = rb_first(&session->hists_tree); 305 nr_samples = 0;
336 while (next) { 306 list_for_each_entry(pos, &session->evlist->entries, node) {
337 struct hists *hists; 307 struct hists *hists = &pos->hists;
338 308
339 hists = rb_entry(next, struct hists, rb_node);
340 hists__collapse_resort(hists); 309 hists__collapse_resort(hists);
341 hists__output_resort(hists); 310 hists__output_resort(hists);
342 next = rb_next(&hists->rb_node); 311 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
312 }
313
314 if (nr_samples == 0) {
315 ui__warning("The %s file has no samples!\n", input_name);
316 goto out_delete;
343 } 317 }
344 318
345 if (use_browser > 0) 319 if (use_browser > 0)
346 hists__tui_browse_tree(&session->hists_tree, help); 320 perf_evlist__tui_browse_hists(session->evlist, help);
347 else 321 else
348 hists__tty_browse_tree(&session->hists_tree, help); 322 perf_evlist__tty_browse_hists(session->evlist, help);
349 323
350out_delete: 324out_delete:
351 /* 325 /*
@@ -420,7 +394,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
420 if (tok2) 394 if (tok2)
421 callchain_param.print_limit = strtod(tok2, &endptr); 395 callchain_param.print_limit = strtod(tok2, &endptr);
422setup: 396setup:
423 if (register_callchain_param(&callchain_param) < 0) { 397 if (callchain_register_param(&callchain_param) < 0) {
424 fprintf(stderr, "Can't register callchain params\n"); 398 fprintf(stderr, "Can't register callchain params\n");
425 return -1; 399 return -1;
426 } 400 }
@@ -441,6 +415,8 @@ static const struct option options[] = {
441 "dump raw trace in ASCII"), 415 "dump raw trace in ASCII"),
442 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 416 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
443 "file", "vmlinux pathname"), 417 "file", "vmlinux pathname"),
418 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
419 "file", "kallsyms pathname"),
444 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 420 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
445 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 421 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
446 "load module symbols - WARNING: use only with -k and LIVE kernel"), 422 "load module symbols - WARNING: use only with -k and LIVE kernel"),
@@ -450,6 +426,8 @@ static const struct option options[] = {
450 "Show per-thread event counters"), 426 "Show per-thread event counters"),
451 OPT_STRING(0, "pretty", &pretty_printing_style, "key", 427 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
452 "pretty printing style key: normal raw"), 428 "pretty printing style key: normal raw"),
429 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
430 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
453 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 431 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
454 "sort by key(s): pid, comm, dso, symbol, parent"), 432 "sort by key(s): pid, comm, dso, symbol, parent"),
455 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 433 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
@@ -475,6 +453,8 @@ static const struct option options[] = {
475 "columns '.' is reserved."), 453 "columns '.' is reserved."),
476 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, 454 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
477 "Only display entries resolved to a symbol"), 455 "Only display entries resolved to a symbol"),
456 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
457 "Look for files with symbols relative to this directory"),
478 OPT_END() 458 OPT_END()
479}; 459};
480 460
@@ -482,15 +462,23 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
482{ 462{
483 argc = parse_options(argc, argv, options, report_usage, 0); 463 argc = parse_options(argc, argv, options, report_usage, 0);
484 464
465 if (use_stdio)
466 use_browser = 0;
467 else if (use_tui)
468 use_browser = 1;
469
485 if (strcmp(input_name, "-") != 0) 470 if (strcmp(input_name, "-") != 0)
486 setup_browser(); 471 setup_browser(true);
472 else
473 use_browser = 0;
487 /* 474 /*
488 * Only in the newt browser we are doing integrated annotation, 475 * Only in the newt browser we are doing integrated annotation,
489 * so don't allocate extra space that won't be used in the stdio 476 * so don't allocate extra space that won't be used in the stdio
490 * implementation. 477 * implementation.
491 */ 478 */
492 if (use_browser > 0) { 479 if (use_browser > 0) {
493 symbol_conf.priv_size = sizeof(struct sym_priv); 480 symbol_conf.priv_size = sizeof(struct annotation);
481 annotate_init = symbol__annotate_init;
494 /* 482 /*
495 * For searching by name on the "Browse map details". 483 * For searching by name on the "Browse map details".
496 * providing it only in verbose mode not to bloat too 484 * providing it only in verbose mode not to bloat too