]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - tools/perf/builtin-report.c
perf tools: Merge trace.info content into perf.data
[mirror_ubuntu-zesty-kernel.git] / tools / perf / builtin-report.c
CommitLineData
bf9e1876
IM
1/*
2 * builtin-report.c
3 *
4 * Builtin report command: Analyze the perf.data input file,
5 * look up and read DSOs and symbol information and display
6 * a histogram of results, along various sorting keys.
7 */
16f762a2 8#include "builtin.h"
53cb8bc2 9
bf9e1876
IM
10#include "util/util.h"
11
8fc0321f 12#include "util/color.h"
5da50258 13#include <linux/list.h>
a930d2c0 14#include "util/cache.h"
43cbcd8a 15#include <linux/rbtree.h>
a2928c42 16#include "util/symbol.h"
a0055ae2 17#include "util/string.h"
f55c5552 18#include "util/callchain.h"
25903407 19#include "util/strlist.h"
8d513270 20#include "util/values.h"
8fa66bdc 21
53cb8bc2 22#include "perf.h"
8f28827a 23#include "util/debug.h"
7c6a1c65 24#include "util/header.h"
53cb8bc2
IM
25
26#include "util/parse-options.h"
27#include "util/parse-events.h"
28
6baa0a5a 29#include "util/thread.h"
dd68ada2 30#include "util/sort.h"
3d1d07ec 31#include "util/hist.h"
6baa0a5a 32
23ac9cbe 33static char const *input_name = "perf.data";
bd74137e 34
52d422de
ACM
35static char *dso_list_str, *comm_list_str, *sym_list_str,
36 *col_width_list_str;
7bec7a91 37static struct strlist *dso_list, *comm_list, *sym_list;
bd74137e 38
fa6963b2 39static int force;
8fa66bdc 40static int input;
8fa66bdc 41
b78c07d4 42static int full_paths;
e3d7e183 43static int show_nr_samples;
97b07b69 44
8d513270
BG
45static int show_threads;
46static struct perf_read_values show_threads_values;
47
9f866697
BG
48static char default_pretty_printing_style[] = "normal";
49static char *pretty_printing_style = default_pretty_printing_style;
50
8fa66bdc
ACM
51static unsigned long page_size;
52static unsigned long mmap_window = 32;
53
b8e6d829 54static int exclude_other = 1;
be903885 55
805d127d
FW
56static char callchain_default_opt[] = "fractal,0.5";
57
66e274f3
FW
58static char __cwd[PATH_MAX];
59static char *cwd = __cwd;
60static int cwdlen;
61
6baa0a5a
FW
62static struct rb_root threads;
63static struct thread *last_match;
64
0d3a5c88
FW
65static struct perf_header *header;
66
e6e18ec7
PZ
67static u64 sample_type;
68
4eb3e478
FW
69static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
70{
71 int i;
72 size_t ret = 0;
73
74 ret += fprintf(fp, "%s", " ");
75
76 for (i = 0; i < depth; i++)
77 if (depth_mask & (1 << i))
78 ret += fprintf(fp, "| ");
79 else
80 ret += fprintf(fp, " ");
81
82 ret += fprintf(fp, "\n");
83
84 return ret;
85}
f55c5552 86static size_t
4eb3e478
FW
87ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
88 int depth_mask, int count, u64 total_samples,
89 int hits)
90{
91 int i;
92 size_t ret = 0;
93
94 ret += fprintf(fp, "%s", " ");
95 for (i = 0; i < depth; i++) {
96 if (depth_mask & (1 << i))
97 ret += fprintf(fp, "|");
98 else
99 ret += fprintf(fp, " ");
100 if (!count && i == depth - 1) {
101 double percent;
102
103 percent = hits * 100.0 / total_samples;
24b57c69 104 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
4eb3e478
FW
105 } else
106 ret += fprintf(fp, "%s", " ");
107 }
108 if (chain->sym)
109 ret += fprintf(fp, "%s\n", chain->sym->name);
110 else
111 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
112
113 return ret;
114}
115
25446036
FW
116static struct symbol *rem_sq_bracket;
117static struct callchain_list rem_hits;
118
119static void init_rem_hits(void)
120{
121 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
122 if (!rem_sq_bracket) {
123 fprintf(stderr, "Not enough memory to display remaining hits\n");
124 return;
125 }
126
127 strcpy(rem_sq_bracket->name, "[...]");
128 rem_hits.sym = rem_sq_bracket;
129}
130
4eb3e478
FW
131static size_t
132callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
133 u64 total_samples, int depth, int depth_mask)
134{
135 struct rb_node *node, *next;
136 struct callchain_node *child;
137 struct callchain_list *chain;
138 int new_depth_mask = depth_mask;
805d127d 139 u64 new_total;
25446036 140 u64 remaining;
4eb3e478
FW
141 size_t ret = 0;
142 int i;
143
805d127d 144 if (callchain_param.mode == CHAIN_GRAPH_REL)
1953287b 145 new_total = self->children_hit;
805d127d
FW
146 else
147 new_total = total_samples;
148
25446036
FW
149 remaining = new_total;
150
4eb3e478
FW
151 node = rb_first(&self->rb_root);
152 while (node) {
25446036
FW
153 u64 cumul;
154
4eb3e478 155 child = rb_entry(node, struct callchain_node, rb_node);
25446036
FW
156 cumul = cumul_hits(child);
157 remaining -= cumul;
4eb3e478
FW
158
159 /*
160 * The depth mask manages the output of pipes that show
161 * the depth. We don't want to keep the pipes of the current
25446036
FW
162 * level for the last child of this depth.
163 * Except if we have remaining filtered hits. They will
164 * supersede the last child
4eb3e478
FW
165 */
166 next = rb_next(node);
25446036 167 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
4eb3e478
FW
168 new_depth_mask &= ~(1 << (depth - 1));
169
170 /*
171 * But we keep the older depth mask for the line seperator
172 * to keep the level link until we reach the last child
173 */
174 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
175 i = 0;
176 list_for_each_entry(chain, &child->val, list) {
177 if (chain->ip >= PERF_CONTEXT_MAX)
178 continue;
179 ret += ipchain__fprintf_graph(fp, chain, depth,
180 new_depth_mask, i++,
805d127d 181 new_total,
25446036 182 cumul);
4eb3e478 183 }
805d127d 184 ret += callchain__fprintf_graph(fp, child, new_total,
4eb3e478
FW
185 depth + 1,
186 new_depth_mask | (1 << depth));
187 node = next;
188 }
189
25446036
FW
190 if (callchain_param.mode == CHAIN_GRAPH_REL &&
191 remaining && remaining != new_total) {
192
193 if (!rem_sq_bracket)
194 return ret;
195
196 new_depth_mask &= ~(1 << (depth - 1));
197
198 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
199 new_depth_mask, 0, new_total,
200 remaining);
201 }
202
4eb3e478
FW
203 return ret;
204}
205
206static size_t
207callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
208 u64 total_samples)
f55c5552
FW
209{
210 struct callchain_list *chain;
211 size_t ret = 0;
212
213 if (!self)
214 return 0;
215
4eb3e478 216 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
f55c5552
FW
217
218
4424961a
FW
219 list_for_each_entry(chain, &self->val, list) {
220 if (chain->ip >= PERF_CONTEXT_MAX)
221 continue;
222 if (chain->sym)
223 ret += fprintf(fp, " %s\n", chain->sym->name);
224 else
225 ret += fprintf(fp, " %p\n",
f37a291c 226 (void *)(long)chain->ip);
4424961a 227 }
f55c5552
FW
228
229 return ret;
230}
231
232static size_t
233hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
234 u64 total_samples)
235{
236 struct rb_node *rb_node;
237 struct callchain_node *chain;
238 size_t ret = 0;
239
240 rb_node = rb_first(&self->sorted_chain);
241 while (rb_node) {
242 double percent;
243
244 chain = rb_entry(rb_node, struct callchain_node, rb_node);
245 percent = chain->hit * 100.0 / total_samples;
805d127d
FW
246 switch (callchain_param.mode) {
247 case CHAIN_FLAT:
24b57c69
FW
248 ret += percent_color_fprintf(fp, " %6.2f%%\n",
249 percent);
4eb3e478 250 ret += callchain__fprintf_flat(fp, chain, total_samples);
805d127d
FW
251 break;
252 case CHAIN_GRAPH_ABS: /* Falldown */
253 case CHAIN_GRAPH_REL:
4eb3e478
FW
254 ret += callchain__fprintf_graph(fp, chain,
255 total_samples, 1, 1);
83a0944f 256 case CHAIN_NONE:
805d127d
FW
257 default:
258 break;
4eb3e478 259 }
f55c5552
FW
260 ret += fprintf(fp, "\n");
261 rb_node = rb_next(rb_node);
262 }
263
264 return ret;
265}
266
1aa16738 267static size_t
9cffa8d5 268hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
1aa16738
PZ
269{
270 struct sort_entry *se;
271 size_t ret;
272
b8e6d829
IM
273 if (exclude_other && !self->parent)
274 return 0;
275
1e11fd82 276 if (total_samples)
52d422de
ACM
277 ret = percent_color_fprintf(fp,
278 field_sep ? "%.2f" : " %6.2f%%",
279 (self->count * 100.0) / total_samples);
1e11fd82 280 else
52d422de 281 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
1aa16738 282
e3d7e183
ACM
283 if (show_nr_samples) {
284 if (field_sep)
285 fprintf(fp, "%c%lld", *field_sep, self->count);
286 else
287 fprintf(fp, "%11lld", self->count);
288 }
1aa16738 289
71dd8945 290 list_for_each_entry(se, &hist_entry__sort_list, list) {
021191b3 291 if (se->elide)
b8e6d829
IM
292 continue;
293
52d422de
ACM
294 fprintf(fp, "%s", field_sep ?: " ");
295 ret += se->print(fp, self, se->width ? *se->width : 0);
71dd8945 296 }
1aa16738
PZ
297
298 ret += fprintf(fp, "\n");
299
f55c5552
FW
300 if (callchain)
301 hist_entry_callchain__fprintf(fp, self, total_samples);
302
1aa16738
PZ
303 return ret;
304}
305
6e7d6fdc
PZ
306/*
307 *
308 */
309
52d422de
ACM
310static void dso__calc_col_width(struct dso *self)
311{
312 if (!col_width_list_str && !field_sep &&
313 (!dso_list || strlist__has_entry(dso_list, self->name))) {
314 unsigned int slen = strlen(self->name);
315 if (slen > dsos__col_width)
316 dsos__col_width = slen;
317 }
318
319 self->slen_calculated = 1;
320}
321
5b447a6a 322static void thread__comm_adjust(struct thread *self)
4273b005 323{
5b447a6a 324 char *comm = self->comm;
4273b005
FW
325
326 if (!col_width_list_str && !field_sep &&
327 (!comm_list || strlist__has_entry(comm_list, comm))) {
328 unsigned int slen = strlen(comm);
329
330 if (slen > comms__col_width) {
331 comms__col_width = slen;
332 threads__col_width = slen + 6;
333 }
334 }
5b447a6a
FW
335}
336
337static int thread__set_comm_adjust(struct thread *self, const char *comm)
338{
339 int ret = thread__set_comm(self, comm);
340
341 if (ret)
342 return ret;
343
344 thread__comm_adjust(self);
4273b005
FW
345
346 return 0;
347}
348
349
6e7d6fdc 350static struct symbol *
439d473b 351resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
6e7d6fdc 352{
6e7d6fdc 353 struct map *map = mapp ? *mapp : NULL;
520f2c34 354 u64 ip = *ipp;
6e7d6fdc 355
6e7d6fdc
PZ
356 if (map)
357 goto got_map;
358
439d473b
ACM
359 if (!thread)
360 return NULL;
361
6e7d6fdc
PZ
362 map = thread__find_map(thread, ip);
363 if (map != NULL) {
52d422de
ACM
364 /*
365 * We have to do this here as we may have a dso
366 * with no symbol hit that has a name longer than
367 * the ones with symbols sampled.
368 */
021191b3 369 if (!sort_dso.elide && !map->dso->slen_calculated)
52d422de
ACM
370 dso__calc_col_width(map->dso);
371
6e7d6fdc
PZ
372 if (mapp)
373 *mapp = map;
374got_map:
375 ip = map->map_ip(map, ip);
6e7d6fdc
PZ
376 } else {
377 /*
378 * If this is outside of all known maps,
379 * and is a negative address, try to look it
380 * up in the kernel dso, as it might be a
439d473b
ACM
381 * vsyscall or vdso (which executes in user-mode).
382 *
383 * XXX This is nasty, we should have a symbol list in
384 * the "[vdso]" dso, but for now lets use the old
385 * trick of looking in the whole kernel symbol list.
6e7d6fdc 386 */
c3b32fcb
ACM
387 if ((long long)ip < 0)
388 return kernel_maps__find_symbol(ip, mapp);
6e7d6fdc 389 }
439d473b
ACM
390 dump_printf(" ...... dso: %s\n",
391 map ? map->dso->long_name : "<not found>");
2cec19d9 392 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
520f2c34 393 *ipp = ip;
6e7d6fdc 394
439d473b 395 return map ? map->dso->find_symbol(map->dso, ip) : NULL;
6e7d6fdc
PZ
396}
397
2a0a50fe 398static int call__match(struct symbol *sym)
6e7d6fdc 399{
b25bcf2f 400 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
2a0a50fe 401 return 1;
6e7d6fdc 402
2a0a50fe 403 return 0;
6e7d6fdc
PZ
404}
405
9735abf1
ACM
406static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
407 struct ip_callchain *chain,
408 struct symbol **parent)
4424961a 409{
4424961a 410 u64 context = PERF_CONTEXT_MAX;
029e5b16 411 struct symbol **syms = NULL;
f37a291c 412 unsigned int i;
4424961a
FW
413
414 if (callchain) {
415 syms = calloc(chain->nr, sizeof(*syms));
416 if (!syms) {
417 fprintf(stderr, "Can't allocate memory for symbols\n");
418 exit(-1);
419 }
420 }
421
422 for (i = 0; i < chain->nr; i++) {
423 u64 ip = chain->ips[i];
439d473b 424 struct symbol *sym = NULL;
4424961a
FW
425
426 if (ip >= PERF_CONTEXT_MAX) {
427 context = ip;
428 continue;
429 }
430
431 switch (context) {
88a69dfb 432 case PERF_CONTEXT_HV:
88a69dfb 433 break;
4424961a 434 case PERF_CONTEXT_KERNEL:
439d473b 435 sym = kernel_maps__find_symbol(ip, &map);
4424961a
FW
436 break;
437 default:
439d473b 438 sym = resolve_symbol(thread, &map, &ip);
4424961a
FW
439 break;
440 }
441
4424961a 442 if (sym) {
9735abf1
ACM
443 if (sort__has_parent && !*parent && call__match(sym))
444 *parent = sym;
4424961a
FW
445 if (!callchain)
446 break;
447 syms[i] = sym;
448 }
449 }
450
451 return syms;
452}
453
1aa16738
PZ
454/*
455 * collect histogram counts
456 */
457
e7fb08b1 458static int
439d473b 459hist_entry__add(struct thread *thread, struct map *map,
9cffa8d5
PM
460 struct symbol *sym, u64 ip, struct ip_callchain *chain,
461 char level, u64 count)
8fa66bdc 462{
9735abf1
ACM
463 struct symbol **syms = NULL, *parent = NULL;
464 bool hit;
e7fb08b1 465 struct hist_entry *he;
e7fb08b1 466
4424961a 467 if ((sort__has_parent || callchain) && chain)
9735abf1 468 syms = resolve_callchain(thread, map, chain, &parent);
e7fb08b1 469
9735abf1
ACM
470 he = __hist_entry__add(thread, map, sym, parent,
471 ip, count, level, &hit);
472 if (he == NULL)
473 return -ENOMEM;
e7fb08b1 474
9735abf1
ACM
475 if (hit)
476 he->count += count;
e7fb08b1 477
f55c5552 478 if (callchain) {
9735abf1
ACM
479 if (!hit)
480 callchain_init(&he->callchain);
4424961a
FW
481 append_chain(&he->callchain, chain, syms);
482 free(syms);
f55c5552 483 }
e7fb08b1
PZ
484
485 return 0;
8fa66bdc
ACM
486}
487
9cffa8d5 488static size_t output__fprintf(FILE *fp, u64 total_samples)
3a4b8cc7 489{
e7fb08b1 490 struct hist_entry *pos;
2d65537e 491 struct sort_entry *se;
3a4b8cc7
ACM
492 struct rb_node *nd;
493 size_t ret = 0;
52d422de
ACM
494 unsigned int width;
495 char *col_width = col_width_list_str;
9f866697
BG
496 int raw_printing_style;
497
498 raw_printing_style = !strcmp(pretty_printing_style, "raw");
3a4b8cc7 499
25446036
FW
500 init_rem_hits();
501
021191b3 502 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
ca8cdeef
PZ
503 fprintf(fp, "#\n");
504
505 fprintf(fp, "# Overhead");
e3d7e183
ACM
506 if (show_nr_samples) {
507 if (field_sep)
508 fprintf(fp, "%cSamples", *field_sep);
509 else
510 fputs(" Samples ", fp);
511 }
b8e6d829 512 list_for_each_entry(se, &hist_entry__sort_list, list) {
021191b3 513 if (se->elide)
b8e6d829 514 continue;
52d422de
ACM
515 if (field_sep) {
516 fprintf(fp, "%c%s", *field_sep, se->header);
b8e6d829 517 continue;
52d422de
ACM
518 }
519 width = strlen(se->header);
520 if (se->width) {
521 if (col_width_list_str) {
522 if (col_width) {
523 *se->width = atoi(col_width);
524 col_width = strchr(col_width, ',');
525 if (col_width)
526 ++col_width;
527 }
528 }
529 width = *se->width = max(*se->width, width);
530 }
531 fprintf(fp, " %*s", width, se->header);
b8e6d829 532 }
ca8cdeef
PZ
533 fprintf(fp, "\n");
534
52d422de
ACM
535 if (field_sep)
536 goto print_entries;
537
ca8cdeef 538 fprintf(fp, "# ........");
e3d7e183
ACM
539 if (show_nr_samples)
540 fprintf(fp, " ..........");
2d65537e 541 list_for_each_entry(se, &hist_entry__sort_list, list) {
f37a291c 542 unsigned int i;
ca8cdeef 543
021191b3 544 if (se->elide)
b8e6d829
IM
545 continue;
546
4593bba8 547 fprintf(fp, " ");
52d422de
ACM
548 if (se->width)
549 width = *se->width;
550 else
551 width = strlen(se->header);
552 for (i = 0; i < width; i++)
ca8cdeef 553 fprintf(fp, ".");
2d65537e 554 }
ca8cdeef
PZ
555 fprintf(fp, "\n");
556
557 fprintf(fp, "#\n");
2d65537e 558
52d422de 559print_entries:
e7fb08b1
PZ
560 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
561 pos = rb_entry(nd, struct hist_entry, rb_node);
562 ret += hist_entry__fprintf(fp, pos, total_samples);
3a4b8cc7
ACM
563 }
564
b8e6d829
IM
565 if (sort_order == default_sort_order &&
566 parent_pattern == default_parent_pattern) {
bd74137e 567 fprintf(fp, "#\n");
114cfab2 568 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
bd74137e
IM
569 fprintf(fp, "#\n");
570 }
71dd8945 571 fprintf(fp, "\n");
bd74137e 572
25446036
FW
573 free(rem_sq_bracket);
574
8d513270 575 if (show_threads)
9f866697
BG
576 perf_read_values_display(fp, &show_threads_values,
577 raw_printing_style);
8d513270 578
3a4b8cc7
ACM
579 return ret;
580}
581
2a0a50fe 582static int validate_chain(struct ip_callchain *chain, event_t *event)
7522060c
IM
583{
584 unsigned int chain_size;
585
7522060c
IM
586 chain_size = event->header.size;
587 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
588
9cffa8d5 589 if (chain->nr*sizeof(u64) > chain_size)
7522060c
IM
590 return -1;
591
592 return 0;
593}
594
d80d338d 595static int
e6e18ec7 596process_sample_event(event_t *event, unsigned long offset, unsigned long head)
75051724
IM
597{
598 char level;
439d473b 599 struct symbol *sym = NULL;
6baa0a5a 600 struct thread *thread;
9cffa8d5
PM
601 u64 ip = event->ip.ip;
602 u64 period = 1;
75051724 603 struct map *map = NULL;
3efa1cc9 604 void *more_data = event->ip.__more_data;
2a0a50fe 605 struct ip_callchain *chain = NULL;
d8db1b57 606 int cpumode;
75051724 607
6baa0a5a
FW
608 thread = threads__findnew(event->ip.pid, &threads, &last_match);
609
e6e18ec7 610 if (sample_type & PERF_SAMPLE_PERIOD) {
9cffa8d5
PM
611 period = *(u64 *)more_data;
612 more_data += sizeof(u64);
3efa1cc9 613 }
ea1900e5 614
cdd6c482 615 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
75051724
IM
616 (void *)(offset + head),
617 (void *)(long)(event->header.size),
618 event->header.misc,
94a24752 619 event->ip.pid, event->ip.tid,
4502d77c 620 (void *)(long)ip,
ea1900e5 621 (long long)period);
75051724 622
e6e18ec7 623 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
f37a291c 624 unsigned int i;
3efa1cc9
IM
625
626 chain = (void *)more_data;
627
2cec19d9 628 dump_printf("... chain: nr:%Lu\n", chain->nr);
3efa1cc9 629
7522060c
IM
630 if (validate_chain(chain, event) < 0) {
631 eprintf("call-chain problem with event, skipping it.\n");
632 return 0;
633 }
634
635 if (dump_trace) {
3efa1cc9 636 for (i = 0; i < chain->nr; i++)
2cec19d9 637 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
3efa1cc9
IM
638 }
639 }
640
2cec19d9 641 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
75051724
IM
642
643 if (thread == NULL) {
7522060c 644 eprintf("problem processing %d event, skipping it.\n",
75051724
IM
645 event->header.type);
646 return -1;
647 }
e7fb08b1 648
cc8b88b1
ACM
649 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
650 return 0;
651
cdd6c482 652 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
d8db1b57 653
cdd6c482 654 if (cpumode == PERF_RECORD_MISC_KERNEL) {
75051724 655 level = 'k';
439d473b
ACM
656 sym = kernel_maps__find_symbol(ip, &map);
657 dump_printf(" ...... dso: %s\n",
658 map ? map->dso->long_name : "<not found>");
cdd6c482 659 } else if (cpumode == PERF_RECORD_MISC_USER) {
75051724 660 level = '.';
439d473b 661 sym = resolve_symbol(thread, &map, &ip);
e7fb08b1 662
75051724 663 } else {
75051724 664 level = 'H';
2cec19d9 665 dump_printf(" ...... dso: [hypervisor]\n");
75051724 666 }
8fa66bdc 667
ec218fc4
ACM
668 if (dso_list &&
669 (!map || !map->dso ||
670 !(strlist__has_entry(dso_list, map->dso->short_name) ||
671 (map->dso->short_name != map->dso->long_name &&
672 strlist__has_entry(dso_list, map->dso->long_name)))))
673 return 0;
25903407 674
ec218fc4
ACM
675 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
676 return 0;
7bec7a91 677
ec218fc4
ACM
678 if (hist_entry__add(thread, map, sym, ip,
679 chain, level, period)) {
680 eprintf("problem incrementing symbol count, skipping event\n");
681 return -1;
8fa66bdc 682 }
ec218fc4 683
ea1900e5 684 total += period;
8fa66bdc 685
75051724
IM
686 return 0;
687}
3502973d 688
75051724
IM
689static int
690process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
691{
6baa0a5a 692 struct thread *thread;
66e274f3 693 struct map *map = map__new(&event->mmap, cwd, cwdlen);
75051724 694
6baa0a5a
FW
695 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
696
cdd6c482 697 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
75051724
IM
698 (void *)(offset + head),
699 (void *)(long)(event->header.size),
62fc4453 700 event->mmap.pid,
94a24752 701 event->mmap.tid,
75051724
IM
702 (void *)(long)event->mmap.start,
703 (void *)(long)event->mmap.len,
704 (void *)(long)event->mmap.pgoff,
705 event->mmap.filename);
706
707 if (thread == NULL || map == NULL) {
cdd6c482 708 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
df97992c 709 return 0;
75051724
IM
710 }
711
712 thread__insert_map(thread, map);
713 total_mmap++;
714
715 return 0;
716}
717
718static int
719process_comm_event(event_t *event, unsigned long offset, unsigned long head)
720{
6baa0a5a
FW
721 struct thread *thread;
722
723 thread = threads__findnew(event->comm.pid, &threads, &last_match);
75051724 724
cdd6c482 725 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
75051724
IM
726 (void *)(offset + head),
727 (void *)(long)(event->header.size),
728 event->comm.comm, event->comm.pid);
729
730 if (thread == NULL ||
4273b005 731 thread__set_comm_adjust(thread, event->comm.comm)) {
cdd6c482 732 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
75051724 733 return -1;
8fa66bdc 734 }
75051724
IM
735 total_comm++;
736
737 return 0;
738}
739
62fc4453 740static int
27d028de 741process_task_event(event_t *event, unsigned long offset, unsigned long head)
62fc4453 742{
6baa0a5a
FW
743 struct thread *thread;
744 struct thread *parent;
745
746 thread = threads__findnew(event->fork.pid, &threads, &last_match);
747 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
62fc4453 748
cdd6c482 749 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
62fc4453
PZ
750 (void *)(offset + head),
751 (void *)(long)(event->header.size),
cdd6c482 752 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
27d028de
PZ
753 event->fork.pid, event->fork.tid,
754 event->fork.ppid, event->fork.ptid);
755
756 /*
757 * A thread clone will have the same PID for both
758 * parent and child.
759 */
760 if (thread == parent)
761 return 0;
762
cdd6c482 763 if (event->header.type == PERF_RECORD_EXIT)
27d028de 764 return 0;
62fc4453
PZ
765
766 if (!thread || !parent || thread__fork(thread, parent)) {
cdd6c482 767 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
62fc4453
PZ
768 return -1;
769 }
770 total_fork++;
771
772 return 0;
773}
774
9d91a6f7
PZ
775static int
776process_lost_event(event_t *event, unsigned long offset, unsigned long head)
777{
cdd6c482 778 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
9d91a6f7
PZ
779 (void *)(offset + head),
780 (void *)(long)(event->header.size),
781 event->lost.id,
782 event->lost.lost);
783
784 total_lost += event->lost.lost;
785
786 return 0;
787}
788
e9ea2fde
PZ
789static int
790process_read_event(event_t *event, unsigned long offset, unsigned long head)
791{
cdd6c482 792 struct perf_event_attr *attr;
0d3a5c88
FW
793
794 attr = perf_header__find_attr(event->read.id, header);
8f18aec5 795
8d513270 796 if (show_threads) {
83a0944f 797 const char *name = attr ? __event_name(attr->type, attr->config)
8d513270
BG
798 : "unknown";
799 perf_read_values_add_value(&show_threads_values,
800 event->read.pid, event->read.tid,
801 event->read.id,
802 name,
803 event->read.value);
804 }
805
cdd6c482 806 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
e9ea2fde
PZ
807 (void *)(offset + head),
808 (void *)(long)(event->header.size),
809 event->read.pid,
810 event->read.tid,
8f18aec5
PZ
811 attr ? __event_name(attr->type, attr->config)
812 : "FAIL",
e9ea2fde
PZ
813 event->read.value);
814
815 return 0;
816}
817
75051724
IM
818static int
819process_event(event_t *event, unsigned long offset, unsigned long head)
820{
8465b050
IM
821 trace_event(event);
822
75051724 823 switch (event->header.type) {
cdd6c482 824 case PERF_RECORD_SAMPLE:
e6e18ec7
PZ
825 return process_sample_event(event, offset, head);
826
cdd6c482 827 case PERF_RECORD_MMAP:
75051724
IM
828 return process_mmap_event(event, offset, head);
829
cdd6c482 830 case PERF_RECORD_COMM:
75051724
IM
831 return process_comm_event(event, offset, head);
832
cdd6c482
IM
833 case PERF_RECORD_FORK:
834 case PERF_RECORD_EXIT:
27d028de 835 return process_task_event(event, offset, head);
62fc4453 836
cdd6c482 837 case PERF_RECORD_LOST:
9d91a6f7
PZ
838 return process_lost_event(event, offset, head);
839
cdd6c482 840 case PERF_RECORD_READ:
e9ea2fde
PZ
841 return process_read_event(event, offset, head);
842
d11444df
IM
843 /*
844 * We dont process them right now but they are fine:
845 */
62fc4453 846
cdd6c482
IM
847 case PERF_RECORD_THROTTLE:
848 case PERF_RECORD_UNTHROTTLE:
d11444df
IM
849 return 0;
850
d80d338d
IM
851 default:
852 return -1;
853 }
854
855 return 0;
856}
857
858static int __cmd_report(void)
859{
75051724 860 int ret, rc = EXIT_FAILURE;
d80d338d 861 unsigned long offset = 0;
7c6a1c65 862 unsigned long head, shift;
83a0944f 863 struct stat input_stat;
5b447a6a 864 struct thread *idle;
d80d338d 865 event_t *event;
d80d338d 866 uint32_t size;
75051724 867 char *buf;
d80d338d 868
5b447a6a
FW
869 idle = register_idle_thread(&threads, &last_match);
870 thread__comm_adjust(idle);
d80d338d 871
8d513270
BG
872 if (show_threads)
873 perf_read_values_init(&show_threads_values);
874
d80d338d
IM
875 input = open(input_name, O_RDONLY);
876 if (input < 0) {
a14832ff
IM
877 fprintf(stderr, " failed to open file: %s", input_name);
878 if (!strcmp(input_name, "perf.data"))
879 fprintf(stderr, " (try 'perf record' first)");
880 fprintf(stderr, "\n");
d80d338d
IM
881 exit(-1);
882 }
883
83a0944f 884 ret = fstat(input, &input_stat);
d80d338d
IM
885 if (ret < 0) {
886 perror("failed to stat file");
887 exit(-1);
888 }
889
119e7a22
PH
890 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
891 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
fa6963b2
PZ
892 exit(-1);
893 }
894
83a0944f 895 if (!input_stat.st_size) {
d80d338d
IM
896 fprintf(stderr, "zero-sized file, nothing to do!\n");
897 exit(0);
898 }
899
7c6a1c65
PZ
900 header = perf_header__read(input);
901 head = header->data_offset;
f5970550 902
0d3a5c88 903 sample_type = perf_header__sample_type(header);
e6e18ec7 904
91b4eaea
FW
905 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
906 if (sort__has_parent) {
907 fprintf(stderr, "selected --sort parent, but no"
908 " callchain data. Did you call"
909 " perf record without -g?\n");
910 exit(-1);
911 }
912 if (callchain) {
6ede59c4 913 fprintf(stderr, "selected -g but no callchain data."
91b4eaea
FW
914 " Did you call perf record without"
915 " -g?\n");
916 exit(-1);
917 }
b1a88349
FW
918 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
919 callchain = 1;
920 if (register_callchain_param(&callchain_param) < 0) {
921 fprintf(stderr, "Can't register callchain"
922 " params\n");
923 exit(-1);
924 }
f5970550
PZ
925 }
926
d80d338d
IM
927 if (load_kernel() < 0) {
928 perror("failed to load kernel symbols");
929 return EXIT_FAILURE;
930 }
931
932 if (!full_paths) {
933 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
934 perror("failed to get the current directory");
935 return EXIT_FAILURE;
936 }
937 cwdlen = strlen(cwd);
938 } else {
939 cwd = NULL;
940 cwdlen = 0;
941 }
7c6a1c65
PZ
942
943 shift = page_size * (head / page_size);
944 offset += shift;
945 head -= shift;
946
d80d338d
IM
947remap:
948 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
949 MAP_SHARED, input, offset);
950 if (buf == MAP_FAILED) {
951 perror("failed to mmap file");
952 exit(-1);
953 }
954
955more:
956 event = (event_t *)(buf + head);
957
958 size = event->header.size;
959 if (!size)
960 size = 8;
961
962 if (head + event->header.size >= page_size * mmap_window) {
83a0944f 963 int munmap_ret;
d80d338d 964
7c6a1c65
PZ
965 shift = page_size * (head / page_size);
966
83a0944f
IM
967 munmap_ret = munmap(buf, page_size * mmap_window);
968 assert(munmap_ret == 0);
d80d338d
IM
969
970 offset += shift;
971 head -= shift;
972 goto remap;
973 }
974
975 size = event->header.size;
976
2cec19d9 977 dump_printf("\n%p [%p]: event: %d\n",
b2fef076
IM
978 (void *)(offset + head),
979 (void *)(long)event->header.size,
980 event->header.type);
981
d80d338d
IM
982 if (!size || process_event(event, offset, head) < 0) {
983
2cec19d9 984 dump_printf("%p [%p]: skipping unknown header type: %d\n",
3502973d
IM
985 (void *)(offset + head),
986 (void *)(long)(event->header.size),
987 event->header.type);
b7a16eac 988
3e706114 989 total_unknown++;
6142f9ec
PZ
990
991 /*
992 * assume we lost track of the stream, check alignment, and
993 * increment a single u64 in the hope to catch on again 'soon'.
994 */
995
996 if (unlikely(head & 7))
997 head &= ~7ULL;
998
999 size = 8;
97b07b69 1000 }
8fa66bdc 1001
6142f9ec 1002 head += size;
f49515b1 1003
7c6a1c65 1004 if (offset + head >= header->data_offset + header->data_size)
f5970550
PZ
1005 goto done;
1006
83a0944f 1007 if (offset + head < (unsigned long)input_stat.st_size)
8fa66bdc
ACM
1008 goto more;
1009
f5970550 1010done:
8fa66bdc 1011 rc = EXIT_SUCCESS;
8fa66bdc 1012 close(input);
97b07b69 1013
2cec19d9
FW
1014 dump_printf(" IP events: %10ld\n", total);
1015 dump_printf(" mmap events: %10ld\n", total_mmap);
1016 dump_printf(" comm events: %10ld\n", total_comm);
1017 dump_printf(" fork events: %10ld\n", total_fork);
1018 dump_printf(" lost events: %10ld\n", total_lost);
1019 dump_printf(" unknown events: %10ld\n", total_unknown);
97b07b69 1020
3502973d 1021 if (dump_trace)
97b07b69 1022 return 0;
97b07b69 1023
9ac99545 1024 if (verbose >= 3)
6baa0a5a 1025 threads__fprintf(stdout, &threads);
9ac99545 1026
e7fb08b1 1027 if (verbose >= 2)
16f762a2 1028 dsos__fprintf(stdout);
16f762a2 1029
8229289b 1030 collapse__resort();
c20ab37e 1031 output__resort(total);
e7fb08b1 1032 output__fprintf(stdout, total);
8fa66bdc 1033
8d513270
BG
1034 if (show_threads)
1035 perf_read_values_destroy(&show_threads_values);
1036
8fa66bdc
ACM
1037 return rc;
1038}
1039
4eb3e478
FW
1040static int
1041parse_callchain_opt(const struct option *opt __used, const char *arg,
1042 int unset __used)
1043{
c20ab37e
FW
1044 char *tok;
1045 char *endptr;
1046
4eb3e478
FW
1047 callchain = 1;
1048
1049 if (!arg)
1050 return 0;
1051
c20ab37e
FW
1052 tok = strtok((char *)arg, ",");
1053 if (!tok)
1054 return -1;
1055
1056 /* get the output mode */
1057 if (!strncmp(tok, "graph", strlen(arg)))
805d127d 1058 callchain_param.mode = CHAIN_GRAPH_ABS;
4eb3e478 1059
c20ab37e 1060 else if (!strncmp(tok, "flat", strlen(arg)))
805d127d
FW
1061 callchain_param.mode = CHAIN_FLAT;
1062
1063 else if (!strncmp(tok, "fractal", strlen(arg)))
1064 callchain_param.mode = CHAIN_GRAPH_REL;
1065
b1a88349
FW
1066 else if (!strncmp(tok, "none", strlen(arg))) {
1067 callchain_param.mode = CHAIN_NONE;
1068 callchain = 0;
1069
1070 return 0;
1071 }
1072
4eb3e478
FW
1073 else
1074 return -1;
1075
c20ab37e
FW
1076 /* get the min percentage */
1077 tok = strtok(NULL, ",");
1078 if (!tok)
805d127d 1079 goto setup;
c20ab37e 1080
805d127d 1081 callchain_param.min_percent = strtod(tok, &endptr);
c20ab37e
FW
1082 if (tok == endptr)
1083 return -1;
1084
805d127d
FW
1085setup:
1086 if (register_callchain_param(&callchain_param) < 0) {
1087 fprintf(stderr, "Can't register callchain params\n");
1088 return -1;
1089 }
4eb3e478
FW
1090 return 0;
1091}
1092
dd68ada2
JK
1093//static const char * const report_usage[] = {
1094const char * const report_usage[] = {
53cb8bc2
IM
1095 "perf report [<options>] <command>",
1096 NULL
1097};
1098
1099static const struct option options[] = {
1100 OPT_STRING('i', "input", &input_name, "file",
1101 "input file name"),
815e777f
ACM
1102 OPT_BOOLEAN('v', "verbose", &verbose,
1103 "be more verbose (show symbol address, etc)"),
97b07b69
IM
1104 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1105 "dump raw trace in ASCII"),
83a0944f 1106 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
fa6963b2 1107 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
42976487
MG
1108 OPT_BOOLEAN('m', "modules", &modules,
1109 "load module symbols - WARNING: use only with -k and LIVE kernel"),
e3d7e183
ACM
1110 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1111 "Show a column with the number of samples"),
8d513270
BG
1112 OPT_BOOLEAN('T', "threads", &show_threads,
1113 "Show per-thread event counters"),
9f866697
BG
1114 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
1115 "pretty printing style key: normal raw"),
63299f05 1116 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
b25bcf2f 1117 "sort by key(s): pid, comm, dso, symbol, parent"),
b78c07d4
ACM
1118 OPT_BOOLEAN('P', "full-paths", &full_paths,
1119 "Don't shorten the pathnames taking into account the cwd"),
b25bcf2f
IM
1120 OPT_STRING('p', "parent", &parent_pattern, "regex",
1121 "regex filter to identify parent, see: '--sort parent'"),
b8e6d829
IM
1122 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1123 "Only display entries with parent-match"),
1483b19f 1124 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
c20ab37e 1125 "Display callchains using output_type and min percent threshold. "
1483b19f 1126 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
25903407
ACM
1127 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1128 "only consider symbols in these dsos"),
cc8b88b1
ACM
1129 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1130 "only consider symbols in these comms"),
7bec7a91
ACM
1131 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1132 "only consider these symbols"),
52d422de
ACM
1133 OPT_STRING('w', "column-widths", &col_width_list_str,
1134 "width[,width...]",
1135 "don't try to adjust column width, use these fixed values"),
1136 OPT_STRING('t', "field-separator", &field_sep, "separator",
1137 "separator for columns, no spaces will be added between "
1138 "columns '.' is reserved."),
53cb8bc2
IM
1139 OPT_END()
1140};
1141
5352f35d
IM
1142static void setup_sorting(void)
1143{
1144 char *tmp, *tok, *str = strdup(sort_order);
1145
1146 for (tok = strtok_r(str, ", ", &tmp);
1147 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1148 if (sort_dimension__add(tok) < 0) {
1149 error("Unknown --sort key: `%s'", tok);
1150 usage_with_options(report_usage, options);
1151 }
1152 }
1153
1154 free(str);
1155}
1156
cc8b88b1 1157static void setup_list(struct strlist **list, const char *list_str,
021191b3
ACM
1158 struct sort_entry *se, const char *list_name,
1159 FILE *fp)
cc8b88b1
ACM
1160{
1161 if (list_str) {
1162 *list = strlist__new(true, list_str);
1163 if (!*list) {
1164 fprintf(stderr, "problems parsing %s list\n",
1165 list_name);
1166 exit(129);
1167 }
021191b3
ACM
1168 if (strlist__nr_entries(*list) == 1) {
1169 fprintf(fp, "# %s: %s\n", list_name,
1170 strlist__entry(*list, 0)->s);
1171 se->elide = true;
1172 }
cc8b88b1
ACM
1173 }
1174}
1175
f37a291c 1176int cmd_report(int argc, const char **argv, const char *prefix __used)
53cb8bc2 1177{
a2928c42 1178 symbol__init();
53cb8bc2
IM
1179
1180 page_size = getpagesize();
1181
edc52dea 1182 argc = parse_options(argc, argv, options, report_usage, 0);
53cb8bc2 1183
1aa16738
PZ
1184 setup_sorting();
1185
021191b3 1186 if (parent_pattern != default_parent_pattern) {
b8e6d829 1187 sort_dimension__add("parent");
021191b3
ACM
1188 sort_parent.elide = 1;
1189 } else
b8e6d829
IM
1190 exclude_other = 0;
1191
edc52dea
IM
1192 /*
1193 * Any (unrecognized) arguments left?
1194 */
1195 if (argc)
1196 usage_with_options(report_usage, options);
1197
a930d2c0
IM
1198 setup_pager();
1199
021191b3
ACM
1200 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
1201 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1202 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
25903407 1203
52d422de
ACM
1204 if (field_sep && *field_sep == '.') {
1205 fputs("'.' is the only non valid --field-separator argument\n",
1206 stderr);
1207 exit(129);
1208 }
1209
53cb8bc2
IM
1210 return __cmd_report();
1211}