]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - tools/perf/builtin-report.c
perf tools: Librarize trace_event() helper
[mirror_ubuntu-focal-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
FW
29#include "util/thread.h"
30
23ac9cbe 31static char const *input_name = "perf.data";
bd74137e 32
114cfab2 33static char default_sort_order[] = "comm,dso,symbol";
bd74137e 34static char *sort_order = default_sort_order;
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;
52d422de 38static char *field_sep;
bd74137e 39
8fa66bdc
ACM
40static int input;
41static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
42
b78c07d4 43static int full_paths;
e3d7e183 44static int show_nr_samples;
97b07b69 45
8d513270
BG
46static int show_threads;
47static struct perf_read_values show_threads_values;
48
9f866697
BG
49static char default_pretty_printing_style[] = "normal";
50static char *pretty_printing_style = default_pretty_printing_style;
51
8fa66bdc
ACM
52static unsigned long page_size;
53static unsigned long mmap_window = 32;
54
b8e6d829
IM
55static char default_parent_pattern[] = "^sys_|^do_page_fault";
56static char *parent_pattern = default_parent_pattern;
b25bcf2f 57static regex_t parent_regex;
6e7d6fdc 58
b8e6d829 59static int exclude_other = 1;
be903885 60
805d127d
FW
61static char callchain_default_opt[] = "fractal,0.5";
62
f55c5552 63static int callchain;
805d127d 64
66e274f3
FW
65static char __cwd[PATH_MAX];
66static char *cwd = __cwd;
67static int cwdlen;
68
6baa0a5a
FW
69static struct rb_root threads;
70static struct thread *last_match;
71
0d3a5c88
FW
72static struct perf_header *header;
73
805d127d
FW
74static
75struct callchain_param callchain_param = {
b1a88349 76 .mode = CHAIN_GRAPH_REL,
805d127d
FW
77 .min_percent = 0.5
78};
b8e6d829 79
e6e18ec7
PZ
80static u64 sample_type;
81
52d422de
ACM
82static int repsep_fprintf(FILE *fp, const char *fmt, ...)
83{
84 int n;
85 va_list ap;
86
87 va_start(ap, fmt);
88 if (!field_sep)
89 n = vfprintf(fp, fmt, ap);
90 else {
91 char *bf = NULL;
92 n = vasprintf(&bf, fmt, ap);
93 if (n > 0) {
94 char *sep = bf;
83a0944f 95
52d422de
ACM
96 while (1) {
97 sep = strchr(sep, *field_sep);
98 if (sep == NULL)
99 break;
100 *sep = '.';
101 }
102 }
103 fputs(bf, fp);
104 free(bf);
105 }
106 va_end(ap);
107 return n;
108}
109
52d422de
ACM
110static unsigned int dsos__col_width,
111 comms__col_width,
112 threads__col_width;
113
e7fb08b1
PZ
114/*
115 * histogram, sorted on item, collects counts
116 */
117
118static struct rb_root hist;
119
120struct hist_entry {
f55c5552
FW
121 struct rb_node rb_node;
122
123 struct thread *thread;
124 struct map *map;
125 struct dso *dso;
126 struct symbol *sym;
127 struct symbol *parent;
128 u64 ip;
129 char level;
130 struct callchain_node callchain;
131 struct rb_root sorted_chain;
132
133 u64 count;
e7fb08b1
PZ
134};
135
1aa16738
PZ
136/*
137 * configurable sorting bits
138 */
139
140struct sort_entry {
141 struct list_head list;
142
83a0944f 143 const char *header;
ca8cdeef 144
1aa16738 145 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
8229289b 146 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
52d422de
ACM
147 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
148 unsigned int *width;
021191b3 149 bool elide;
1aa16738
PZ
150};
151
6e7d6fdc
PZ
152static int64_t cmp_null(void *l, void *r)
153{
154 if (!l && !r)
155 return 0;
156 else if (!l)
157 return -1;
158 else
159 return 1;
160}
161
8229289b
PZ
162/* --sort pid */
163
e7fb08b1 164static int64_t
1aa16738 165sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
e7fb08b1 166{
1aa16738
PZ
167 return right->thread->pid - left->thread->pid;
168}
169
170static size_t
52d422de 171sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
1aa16738 172{
52d422de
ACM
173 return repsep_fprintf(fp, "%*s:%5d", width - 6,
174 self->thread->comm ?: "", self->thread->pid);
1aa16738 175}
e7fb08b1 176
1aa16738 177static struct sort_entry sort_thread = {
52d422de 178 .header = "Command: Pid",
1aa16738
PZ
179 .cmp = sort__thread_cmp,
180 .print = sort__thread_print,
52d422de 181 .width = &threads__col_width,
1aa16738
PZ
182};
183
8229289b
PZ
184/* --sort comm */
185
992444b1
PZ
186static int64_t
187sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
8229289b
PZ
188{
189 return right->thread->pid - left->thread->pid;
190}
191
192static int64_t
193sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
992444b1
PZ
194{
195 char *comm_l = left->thread->comm;
196 char *comm_r = right->thread->comm;
197
6e7d6fdc
PZ
198 if (!comm_l || !comm_r)
199 return cmp_null(comm_l, comm_r);
992444b1
PZ
200
201 return strcmp(comm_l, comm_r);
202}
203
204static size_t
52d422de 205sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
992444b1 206{
52d422de 207 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
992444b1
PZ
208}
209
210static struct sort_entry sort_comm = {
52d422de 211 .header = "Command",
8229289b
PZ
212 .cmp = sort__comm_cmp,
213 .collapse = sort__comm_collapse,
214 .print = sort__comm_print,
52d422de 215 .width = &comms__col_width,
992444b1
PZ
216};
217
8229289b
PZ
218/* --sort dso */
219
55e5ec41
PZ
220static int64_t
221sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
222{
223 struct dso *dso_l = left->dso;
224 struct dso *dso_r = right->dso;
225
6e7d6fdc
PZ
226 if (!dso_l || !dso_r)
227 return cmp_null(dso_l, dso_r);
55e5ec41
PZ
228
229 return strcmp(dso_l->name, dso_r->name);
230}
231
232static size_t
52d422de 233sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
55e5ec41 234{
0a520c63 235 if (self->dso)
52d422de 236 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
0a520c63 237
52d422de 238 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
55e5ec41
PZ
239}
240
241static struct sort_entry sort_dso = {
52d422de 242 .header = "Shared Object",
55e5ec41
PZ
243 .cmp = sort__dso_cmp,
244 .print = sort__dso_print,
52d422de 245 .width = &dsos__col_width,
55e5ec41
PZ
246};
247
8229289b
PZ
248/* --sort symbol */
249
1aa16738
PZ
250static int64_t
251sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
252{
9cffa8d5 253 u64 ip_l, ip_r;
e7fb08b1
PZ
254
255 if (left->sym == right->sym)
256 return 0;
257
258 ip_l = left->sym ? left->sym->start : left->ip;
259 ip_r = right->sym ? right->sym->start : right->ip;
260
261 return (int64_t)(ip_r - ip_l);
262}
263
1aa16738 264static size_t
52d422de 265sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
1aa16738
PZ
266{
267 size_t ret = 0;
268
1aa16738 269 if (verbose)
94cb9e38
ACM
270 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
271 dso__symtab_origin(self->dso));
0a520c63 272
60c1baf1 273 ret += repsep_fprintf(fp, "[%c] ", self->level);
8edd4286 274 if (self->sym) {
60c1baf1 275 ret += repsep_fprintf(fp, "%s", self->sym->name);
42976487
MG
276
277 if (self->sym->module)
52d422de
ACM
278 ret += repsep_fprintf(fp, "\t[%s]",
279 self->sym->module->name);
8edd4286 280 } else {
52d422de 281 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
8edd4286 282 }
1aa16738
PZ
283
284 return ret;
285}
286
287static struct sort_entry sort_sym = {
71dd8945 288 .header = "Symbol",
ca8cdeef
PZ
289 .cmp = sort__sym_cmp,
290 .print = sort__sym_print,
1aa16738
PZ
291};
292
b25bcf2f 293/* --sort parent */
6e7d6fdc
PZ
294
295static int64_t
b25bcf2f 296sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
6e7d6fdc 297{
b25bcf2f
IM
298 struct symbol *sym_l = left->parent;
299 struct symbol *sym_r = right->parent;
6e7d6fdc
PZ
300
301 if (!sym_l || !sym_r)
302 return cmp_null(sym_l, sym_r);
303
304 return strcmp(sym_l->name, sym_r->name);
305}
306
307static size_t
52d422de 308sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
6e7d6fdc 309{
52d422de
ACM
310 return repsep_fprintf(fp, "%-*s", width,
311 self->parent ? self->parent->name : "[other]");
6e7d6fdc
PZ
312}
313
52d422de
ACM
314static unsigned int parent_symbol__col_width;
315
b25bcf2f 316static struct sort_entry sort_parent = {
52d422de 317 .header = "Parent symbol",
b25bcf2f
IM
318 .cmp = sort__parent_cmp,
319 .print = sort__parent_print,
52d422de 320 .width = &parent_symbol__col_width,
6e7d6fdc
PZ
321};
322
8229289b 323static int sort__need_collapse = 0;
b25bcf2f 324static int sort__has_parent = 0;
8229289b 325
37f440cb 326struct sort_dimension {
83a0944f 327 const char *name;
8edd4286
IM
328 struct sort_entry *entry;
329 int taken;
37f440cb
PZ
330};
331
332static struct sort_dimension sort_dimensions[] = {
333 { .name = "pid", .entry = &sort_thread, },
992444b1 334 { .name = "comm", .entry = &sort_comm, },
55e5ec41 335 { .name = "dso", .entry = &sort_dso, },
37f440cb 336 { .name = "symbol", .entry = &sort_sym, },
b25bcf2f 337 { .name = "parent", .entry = &sort_parent, },
37f440cb
PZ
338};
339
1aa16738
PZ
340static LIST_HEAD(hist_entry__sort_list);
341
83a0944f 342static int sort_dimension__add(const char *tok)
37f440cb 343{
f37a291c 344 unsigned int i;
37f440cb
PZ
345
346 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
347 struct sort_dimension *sd = &sort_dimensions[i];
348
349 if (sd->taken)
350 continue;
351
5352f35d 352 if (strncasecmp(tok, sd->name, strlen(tok)))
37f440cb
PZ
353 continue;
354
8229289b
PZ
355 if (sd->entry->collapse)
356 sort__need_collapse = 1;
357
b25bcf2f
IM
358 if (sd->entry == &sort_parent) {
359 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
6e7d6fdc
PZ
360 if (ret) {
361 char err[BUFSIZ];
362
b25bcf2f
IM
363 regerror(ret, &parent_regex, err, sizeof(err));
364 fprintf(stderr, "Invalid regex: %s\n%s",
365 parent_pattern, err);
6e7d6fdc
PZ
366 exit(-1);
367 }
b25bcf2f 368 sort__has_parent = 1;
6e7d6fdc
PZ
369 }
370
37f440cb
PZ
371 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
372 sd->taken = 1;
5352f35d 373
37f440cb
PZ
374 return 0;
375 }
376
377 return -ESRCH;
378}
379
1aa16738
PZ
380static int64_t
381hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
382{
383 struct sort_entry *se;
384 int64_t cmp = 0;
385
386 list_for_each_entry(se, &hist_entry__sort_list, list) {
387 cmp = se->cmp(left, right);
388 if (cmp)
389 break;
390 }
391
392 return cmp;
393}
394
8229289b
PZ
395static int64_t
396hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
397{
398 struct sort_entry *se;
399 int64_t cmp = 0;
400
401 list_for_each_entry(se, &hist_entry__sort_list, list) {
402 int64_t (*f)(struct hist_entry *, struct hist_entry *);
403
404 f = se->collapse ?: se->cmp;
405
406 cmp = f(left, right);
407 if (cmp)
408 break;
409 }
410
411 return cmp;
412}
413
4eb3e478
FW
414static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
415{
416 int i;
417 size_t ret = 0;
418
419 ret += fprintf(fp, "%s", " ");
420
421 for (i = 0; i < depth; i++)
422 if (depth_mask & (1 << i))
423 ret += fprintf(fp, "| ");
424 else
425 ret += fprintf(fp, " ");
426
427 ret += fprintf(fp, "\n");
428
429 return ret;
430}
f55c5552 431static size_t
4eb3e478
FW
432ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
433 int depth_mask, int count, u64 total_samples,
434 int hits)
435{
436 int i;
437 size_t ret = 0;
438
439 ret += fprintf(fp, "%s", " ");
440 for (i = 0; i < depth; i++) {
441 if (depth_mask & (1 << i))
442 ret += fprintf(fp, "|");
443 else
444 ret += fprintf(fp, " ");
445 if (!count && i == depth - 1) {
446 double percent;
447
448 percent = hits * 100.0 / total_samples;
24b57c69 449 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
4eb3e478
FW
450 } else
451 ret += fprintf(fp, "%s", " ");
452 }
453 if (chain->sym)
454 ret += fprintf(fp, "%s\n", chain->sym->name);
455 else
456 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
457
458 return ret;
459}
460
25446036
FW
461static struct symbol *rem_sq_bracket;
462static struct callchain_list rem_hits;
463
464static void init_rem_hits(void)
465{
466 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
467 if (!rem_sq_bracket) {
468 fprintf(stderr, "Not enough memory to display remaining hits\n");
469 return;
470 }
471
472 strcpy(rem_sq_bracket->name, "[...]");
473 rem_hits.sym = rem_sq_bracket;
474}
475
4eb3e478
FW
476static size_t
477callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
478 u64 total_samples, int depth, int depth_mask)
479{
480 struct rb_node *node, *next;
481 struct callchain_node *child;
482 struct callchain_list *chain;
483 int new_depth_mask = depth_mask;
805d127d 484 u64 new_total;
25446036 485 u64 remaining;
4eb3e478
FW
486 size_t ret = 0;
487 int i;
488
805d127d 489 if (callchain_param.mode == CHAIN_GRAPH_REL)
1953287b 490 new_total = self->children_hit;
805d127d
FW
491 else
492 new_total = total_samples;
493
25446036
FW
494 remaining = new_total;
495
4eb3e478
FW
496 node = rb_first(&self->rb_root);
497 while (node) {
25446036
FW
498 u64 cumul;
499
4eb3e478 500 child = rb_entry(node, struct callchain_node, rb_node);
25446036
FW
501 cumul = cumul_hits(child);
502 remaining -= cumul;
4eb3e478
FW
503
504 /*
505 * The depth mask manages the output of pipes that show
506 * the depth. We don't want to keep the pipes of the current
25446036
FW
507 * level for the last child of this depth.
508 * Except if we have remaining filtered hits. They will
509 * supersede the last child
4eb3e478
FW
510 */
511 next = rb_next(node);
25446036 512 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
4eb3e478
FW
513 new_depth_mask &= ~(1 << (depth - 1));
514
515 /*
516 * But we keep the older depth mask for the line seperator
517 * to keep the level link until we reach the last child
518 */
519 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
520 i = 0;
521 list_for_each_entry(chain, &child->val, list) {
522 if (chain->ip >= PERF_CONTEXT_MAX)
523 continue;
524 ret += ipchain__fprintf_graph(fp, chain, depth,
525 new_depth_mask, i++,
805d127d 526 new_total,
25446036 527 cumul);
4eb3e478 528 }
805d127d 529 ret += callchain__fprintf_graph(fp, child, new_total,
4eb3e478
FW
530 depth + 1,
531 new_depth_mask | (1 << depth));
532 node = next;
533 }
534
25446036
FW
535 if (callchain_param.mode == CHAIN_GRAPH_REL &&
536 remaining && remaining != new_total) {
537
538 if (!rem_sq_bracket)
539 return ret;
540
541 new_depth_mask &= ~(1 << (depth - 1));
542
543 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
544 new_depth_mask, 0, new_total,
545 remaining);
546 }
547
4eb3e478
FW
548 return ret;
549}
550
551static size_t
552callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
553 u64 total_samples)
f55c5552
FW
554{
555 struct callchain_list *chain;
556 size_t ret = 0;
557
558 if (!self)
559 return 0;
560
4eb3e478 561 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
f55c5552
FW
562
563
4424961a
FW
564 list_for_each_entry(chain, &self->val, list) {
565 if (chain->ip >= PERF_CONTEXT_MAX)
566 continue;
567 if (chain->sym)
568 ret += fprintf(fp, " %s\n", chain->sym->name);
569 else
570 ret += fprintf(fp, " %p\n",
f37a291c 571 (void *)(long)chain->ip);
4424961a 572 }
f55c5552
FW
573
574 return ret;
575}
576
577static size_t
578hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
579 u64 total_samples)
580{
581 struct rb_node *rb_node;
582 struct callchain_node *chain;
583 size_t ret = 0;
584
585 rb_node = rb_first(&self->sorted_chain);
586 while (rb_node) {
587 double percent;
588
589 chain = rb_entry(rb_node, struct callchain_node, rb_node);
590 percent = chain->hit * 100.0 / total_samples;
805d127d
FW
591 switch (callchain_param.mode) {
592 case CHAIN_FLAT:
24b57c69
FW
593 ret += percent_color_fprintf(fp, " %6.2f%%\n",
594 percent);
4eb3e478 595 ret += callchain__fprintf_flat(fp, chain, total_samples);
805d127d
FW
596 break;
597 case CHAIN_GRAPH_ABS: /* Falldown */
598 case CHAIN_GRAPH_REL:
4eb3e478
FW
599 ret += callchain__fprintf_graph(fp, chain,
600 total_samples, 1, 1);
83a0944f 601 case CHAIN_NONE:
805d127d
FW
602 default:
603 break;
4eb3e478 604 }
f55c5552
FW
605 ret += fprintf(fp, "\n");
606 rb_node = rb_next(rb_node);
607 }
608
609 return ret;
610}
611
612
1aa16738 613static size_t
9cffa8d5 614hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
1aa16738
PZ
615{
616 struct sort_entry *se;
617 size_t ret;
618
b8e6d829
IM
619 if (exclude_other && !self->parent)
620 return 0;
621
1e11fd82 622 if (total_samples)
52d422de
ACM
623 ret = percent_color_fprintf(fp,
624 field_sep ? "%.2f" : " %6.2f%%",
625 (self->count * 100.0) / total_samples);
1e11fd82 626 else
52d422de 627 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
1aa16738 628
e3d7e183
ACM
629 if (show_nr_samples) {
630 if (field_sep)
631 fprintf(fp, "%c%lld", *field_sep, self->count);
632 else
633 fprintf(fp, "%11lld", self->count);
634 }
1aa16738 635
71dd8945 636 list_for_each_entry(se, &hist_entry__sort_list, list) {
021191b3 637 if (se->elide)
b8e6d829
IM
638 continue;
639
52d422de
ACM
640 fprintf(fp, "%s", field_sep ?: " ");
641 ret += se->print(fp, self, se->width ? *se->width : 0);
71dd8945 642 }
1aa16738
PZ
643
644 ret += fprintf(fp, "\n");
645
f55c5552
FW
646 if (callchain)
647 hist_entry_callchain__fprintf(fp, self, total_samples);
648
1aa16738
PZ
649 return ret;
650}
651
6e7d6fdc
PZ
652/*
653 *
654 */
655
52d422de
ACM
656static void dso__calc_col_width(struct dso *self)
657{
658 if (!col_width_list_str && !field_sep &&
659 (!dso_list || strlist__has_entry(dso_list, self->name))) {
660 unsigned int slen = strlen(self->name);
661 if (slen > dsos__col_width)
662 dsos__col_width = slen;
663 }
664
665 self->slen_calculated = 1;
666}
667
6e7d6fdc
PZ
668static struct symbol *
669resolve_symbol(struct thread *thread, struct map **mapp,
9cffa8d5 670 struct dso **dsop, u64 *ipp)
6e7d6fdc
PZ
671{
672 struct dso *dso = dsop ? *dsop : NULL;
673 struct map *map = mapp ? *mapp : NULL;
520f2c34 674 u64 ip = *ipp;
6e7d6fdc
PZ
675
676 if (!thread)
677 return NULL;
678
679 if (dso)
680 goto got_dso;
681
682 if (map)
683 goto got_map;
684
685 map = thread__find_map(thread, ip);
686 if (map != NULL) {
52d422de
ACM
687 /*
688 * We have to do this here as we may have a dso
689 * with no symbol hit that has a name longer than
690 * the ones with symbols sampled.
691 */
021191b3 692 if (!sort_dso.elide && !map->dso->slen_calculated)
52d422de
ACM
693 dso__calc_col_width(map->dso);
694
6e7d6fdc
PZ
695 if (mapp)
696 *mapp = map;
697got_map:
698 ip = map->map_ip(map, ip);
6e7d6fdc
PZ
699
700 dso = map->dso;
701 } else {
702 /*
703 * If this is outside of all known maps,
704 * and is a negative address, try to look it
705 * up in the kernel dso, as it might be a
706 * vsyscall (which executes in user-mode):
707 */
708 if ((long long)ip < 0)
709 dso = kernel_dso;
710 }
2cec19d9
FW
711 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
712 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
520f2c34 713 *ipp = ip;
6e7d6fdc
PZ
714
715 if (dsop)
716 *dsop = dso;
717
718 if (!dso)
719 return NULL;
720got_dso:
721 return dso->find_symbol(dso, ip);
722}
723
2a0a50fe 724static int call__match(struct symbol *sym)
6e7d6fdc 725{
b25bcf2f 726 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
2a0a50fe 727 return 1;
6e7d6fdc 728
2a0a50fe 729 return 0;
6e7d6fdc
PZ
730}
731
4424961a 732static struct symbol **
f37a291c 733resolve_callchain(struct thread *thread, struct map *map __used,
4424961a
FW
734 struct ip_callchain *chain, struct hist_entry *entry)
735{
4424961a 736 u64 context = PERF_CONTEXT_MAX;
029e5b16 737 struct symbol **syms = NULL;
f37a291c 738 unsigned int i;
4424961a
FW
739
740 if (callchain) {
741 syms = calloc(chain->nr, sizeof(*syms));
742 if (!syms) {
743 fprintf(stderr, "Can't allocate memory for symbols\n");
744 exit(-1);
745 }
746 }
747
748 for (i = 0; i < chain->nr; i++) {
749 u64 ip = chain->ips[i];
750 struct dso *dso = NULL;
751 struct symbol *sym;
752
753 if (ip >= PERF_CONTEXT_MAX) {
754 context = ip;
755 continue;
756 }
757
758 switch (context) {
88a69dfb
IM
759 case PERF_CONTEXT_HV:
760 dso = hypervisor_dso;
761 break;
4424961a
FW
762 case PERF_CONTEXT_KERNEL:
763 dso = kernel_dso;
764 break;
765 default:
766 break;
767 }
768
769 sym = resolve_symbol(thread, NULL, &dso, &ip);
770
771 if (sym) {
772 if (sort__has_parent && call__match(sym) &&
773 !entry->parent)
774 entry->parent = sym;
775 if (!callchain)
776 break;
777 syms[i] = sym;
778 }
779 }
780
781 return syms;
782}
783
1aa16738
PZ
784/*
785 * collect histogram counts
786 */
787
e7fb08b1
PZ
788static int
789hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
9cffa8d5
PM
790 struct symbol *sym, u64 ip, struct ip_callchain *chain,
791 char level, u64 count)
8fa66bdc 792{
e7fb08b1
PZ
793 struct rb_node **p = &hist.rb_node;
794 struct rb_node *parent = NULL;
795 struct hist_entry *he;
4424961a 796 struct symbol **syms = NULL;
e7fb08b1
PZ
797 struct hist_entry entry = {
798 .thread = thread,
799 .map = map,
800 .dso = dso,
801 .sym = sym,
802 .ip = ip,
803 .level = level,
ea1900e5 804 .count = count,
b8e6d829 805 .parent = NULL,
f55c5552 806 .sorted_chain = RB_ROOT
e7fb08b1
PZ
807 };
808 int cmp;
809
4424961a
FW
810 if ((sort__has_parent || callchain) && chain)
811 syms = resolve_callchain(thread, map, chain, &entry);
6e7d6fdc 812
e7fb08b1
PZ
813 while (*p != NULL) {
814 parent = *p;
815 he = rb_entry(parent, struct hist_entry, rb_node);
816
817 cmp = hist_entry__cmp(&entry, he);
818
819 if (!cmp) {
ea1900e5 820 he->count += count;
4424961a
FW
821 if (callchain) {
822 append_chain(&he->callchain, chain, syms);
823 free(syms);
824 }
e7fb08b1
PZ
825 return 0;
826 }
827
828 if (cmp < 0)
829 p = &(*p)->rb_left;
830 else
831 p = &(*p)->rb_right;
ce7e4365 832 }
e7fb08b1
PZ
833
834 he = malloc(sizeof(*he));
835 if (!he)
836 return -ENOMEM;
837 *he = entry;
f55c5552
FW
838 if (callchain) {
839 callchain_init(&he->callchain);
4424961a
FW
840 append_chain(&he->callchain, chain, syms);
841 free(syms);
f55c5552 842 }
e7fb08b1
PZ
843 rb_link_node(&he->rb_node, parent, p);
844 rb_insert_color(&he->rb_node, &hist);
845
846 return 0;
8fa66bdc
ACM
847}
848
8229289b
PZ
849static void hist_entry__free(struct hist_entry *he)
850{
851 free(he);
852}
853
854/*
855 * collapse the histogram
856 */
857
858static struct rb_root collapse_hists;
859
860static void collapse__insert_entry(struct hist_entry *he)
861{
862 struct rb_node **p = &collapse_hists.rb_node;
863 struct rb_node *parent = NULL;
864 struct hist_entry *iter;
865 int64_t cmp;
866
867 while (*p != NULL) {
868 parent = *p;
869 iter = rb_entry(parent, struct hist_entry, rb_node);
870
871 cmp = hist_entry__collapse(iter, he);
872
873 if (!cmp) {
874 iter->count += he->count;
875 hist_entry__free(he);
876 return;
877 }
878
879 if (cmp < 0)
880 p = &(*p)->rb_left;
881 else
882 p = &(*p)->rb_right;
883 }
884
885 rb_link_node(&he->rb_node, parent, p);
886 rb_insert_color(&he->rb_node, &collapse_hists);
887}
888
889static void collapse__resort(void)
890{
891 struct rb_node *next;
892 struct hist_entry *n;
893
894 if (!sort__need_collapse)
895 return;
896
897 next = rb_first(&hist);
898 while (next) {
899 n = rb_entry(next, struct hist_entry, rb_node);
900 next = rb_next(&n->rb_node);
901
902 rb_erase(&n->rb_node, &hist);
903 collapse__insert_entry(n);
904 }
905}
906
e7fb08b1
PZ
907/*
908 * reverse the map, sort on count.
909 */
910
911static struct rb_root output_hists;
912
c20ab37e 913static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
3a4b8cc7 914{
e7fb08b1 915 struct rb_node **p = &output_hists.rb_node;
3a4b8cc7 916 struct rb_node *parent = NULL;
e7fb08b1 917 struct hist_entry *iter;
3a4b8cc7 918
805d127d
FW
919 if (callchain)
920 callchain_param.sort(&he->sorted_chain, &he->callchain,
921 min_callchain_hits, &callchain_param);
f55c5552 922
3a4b8cc7
ACM
923 while (*p != NULL) {
924 parent = *p;
e7fb08b1 925 iter = rb_entry(parent, struct hist_entry, rb_node);
3a4b8cc7 926
e7fb08b1 927 if (he->count > iter->count)
3a4b8cc7
ACM
928 p = &(*p)->rb_left;
929 else
930 p = &(*p)->rb_right;
931 }
932
e7fb08b1
PZ
933 rb_link_node(&he->rb_node, parent, p);
934 rb_insert_color(&he->rb_node, &output_hists);
3a4b8cc7
ACM
935}
936
c20ab37e 937static void output__resort(u64 total_samples)
3a4b8cc7 938{
8229289b 939 struct rb_node *next;
e7fb08b1 940 struct hist_entry *n;
a4c43bea 941 struct rb_root *tree = &hist;
c20ab37e
FW
942 u64 min_callchain_hits;
943
805d127d 944 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
3a4b8cc7 945
8229289b 946 if (sort__need_collapse)
a4c43bea
ACM
947 tree = &collapse_hists;
948
949 next = rb_first(tree);
8229289b 950
e7fb08b1
PZ
951 while (next) {
952 n = rb_entry(next, struct hist_entry, rb_node);
953 next = rb_next(&n->rb_node);
3a4b8cc7 954
a4c43bea 955 rb_erase(&n->rb_node, tree);
c20ab37e 956 output__insert_entry(n, min_callchain_hits);
3a4b8cc7
ACM
957 }
958}
959
9cffa8d5 960static size_t output__fprintf(FILE *fp, u64 total_samples)
3a4b8cc7 961{
e7fb08b1 962 struct hist_entry *pos;
2d65537e 963 struct sort_entry *se;
3a4b8cc7
ACM
964 struct rb_node *nd;
965 size_t ret = 0;
52d422de
ACM
966 unsigned int width;
967 char *col_width = col_width_list_str;
9f866697
BG
968 int raw_printing_style;
969
970 raw_printing_style = !strcmp(pretty_printing_style, "raw");
3a4b8cc7 971
25446036
FW
972 init_rem_hits();
973
021191b3 974 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
ca8cdeef
PZ
975 fprintf(fp, "#\n");
976
977 fprintf(fp, "# Overhead");
e3d7e183
ACM
978 if (show_nr_samples) {
979 if (field_sep)
980 fprintf(fp, "%cSamples", *field_sep);
981 else
982 fputs(" Samples ", fp);
983 }
b8e6d829 984 list_for_each_entry(se, &hist_entry__sort_list, list) {
021191b3 985 if (se->elide)
b8e6d829 986 continue;
52d422de
ACM
987 if (field_sep) {
988 fprintf(fp, "%c%s", *field_sep, se->header);
b8e6d829 989 continue;
52d422de
ACM
990 }
991 width = strlen(se->header);
992 if (se->width) {
993 if (col_width_list_str) {
994 if (col_width) {
995 *se->width = atoi(col_width);
996 col_width = strchr(col_width, ',');
997 if (col_width)
998 ++col_width;
999 }
1000 }
1001 width = *se->width = max(*se->width, width);
1002 }
1003 fprintf(fp, " %*s", width, se->header);
b8e6d829 1004 }
ca8cdeef
PZ
1005 fprintf(fp, "\n");
1006
52d422de
ACM
1007 if (field_sep)
1008 goto print_entries;
1009
ca8cdeef 1010 fprintf(fp, "# ........");
e3d7e183
ACM
1011 if (show_nr_samples)
1012 fprintf(fp, " ..........");
2d65537e 1013 list_for_each_entry(se, &hist_entry__sort_list, list) {
f37a291c 1014 unsigned int i;
ca8cdeef 1015
021191b3 1016 if (se->elide)
b8e6d829
IM
1017 continue;
1018
4593bba8 1019 fprintf(fp, " ");
52d422de
ACM
1020 if (se->width)
1021 width = *se->width;
1022 else
1023 width = strlen(se->header);
1024 for (i = 0; i < width; i++)
ca8cdeef 1025 fprintf(fp, ".");
2d65537e 1026 }
ca8cdeef
PZ
1027 fprintf(fp, "\n");
1028
1029 fprintf(fp, "#\n");
2d65537e 1030
52d422de 1031print_entries:
e7fb08b1
PZ
1032 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1033 pos = rb_entry(nd, struct hist_entry, rb_node);
1034 ret += hist_entry__fprintf(fp, pos, total_samples);
3a4b8cc7
ACM
1035 }
1036
b8e6d829
IM
1037 if (sort_order == default_sort_order &&
1038 parent_pattern == default_parent_pattern) {
bd74137e 1039 fprintf(fp, "#\n");
114cfab2 1040 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
bd74137e
IM
1041 fprintf(fp, "#\n");
1042 }
71dd8945 1043 fprintf(fp, "\n");
bd74137e 1044
25446036
FW
1045 free(rem_sq_bracket);
1046
8d513270 1047 if (show_threads)
9f866697
BG
1048 perf_read_values_display(fp, &show_threads_values,
1049 raw_printing_style);
8d513270 1050
3a4b8cc7
ACM
1051 return ret;
1052}
1053
436224a6
PZ
1054static void register_idle_thread(void)
1055{
6baa0a5a 1056 struct thread *thread = threads__findnew(0, &threads, &last_match);
436224a6
PZ
1057
1058 if (thread == NULL ||
1059 thread__set_comm(thread, "[idle]")) {
1060 fprintf(stderr, "problem inserting idle task.\n");
1061 exit(-1);
1062 }
1063}
1064
62fc4453
PZ
1065static unsigned long total = 0,
1066 total_mmap = 0,
1067 total_comm = 0,
1068 total_fork = 0,
9d91a6f7
PZ
1069 total_unknown = 0,
1070 total_lost = 0;
e7fb08b1 1071
2a0a50fe 1072static int validate_chain(struct ip_callchain *chain, event_t *event)
7522060c
IM
1073{
1074 unsigned int chain_size;
1075
7522060c
IM
1076 chain_size = event->header.size;
1077 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
1078
9cffa8d5 1079 if (chain->nr*sizeof(u64) > chain_size)
7522060c
IM
1080 return -1;
1081
1082 return 0;
1083}
1084
d80d338d 1085static int
e6e18ec7 1086process_sample_event(event_t *event, unsigned long offset, unsigned long head)
75051724
IM
1087{
1088 char level;
1089 int show = 0;
1090 struct dso *dso = NULL;
6baa0a5a 1091 struct thread *thread;
9cffa8d5
PM
1092 u64 ip = event->ip.ip;
1093 u64 period = 1;
75051724 1094 struct map *map = NULL;
3efa1cc9 1095 void *more_data = event->ip.__more_data;
2a0a50fe 1096 struct ip_callchain *chain = NULL;
d8db1b57 1097 int cpumode;
75051724 1098
6baa0a5a
FW
1099 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1100
e6e18ec7 1101 if (sample_type & PERF_SAMPLE_PERIOD) {
9cffa8d5
PM
1102 period = *(u64 *)more_data;
1103 more_data += sizeof(u64);
3efa1cc9 1104 }
ea1900e5 1105
2cec19d9 1106 dump_printf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
75051724
IM
1107 (void *)(offset + head),
1108 (void *)(long)(event->header.size),
1109 event->header.misc,
94a24752 1110 event->ip.pid, event->ip.tid,
4502d77c 1111 (void *)(long)ip,
ea1900e5 1112 (long long)period);
75051724 1113
e6e18ec7 1114 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
f37a291c 1115 unsigned int i;
3efa1cc9
IM
1116
1117 chain = (void *)more_data;
1118
2cec19d9 1119 dump_printf("... chain: nr:%Lu\n", chain->nr);
3efa1cc9 1120
7522060c
IM
1121 if (validate_chain(chain, event) < 0) {
1122 eprintf("call-chain problem with event, skipping it.\n");
1123 return 0;
1124 }
1125
1126 if (dump_trace) {
3efa1cc9 1127 for (i = 0; i < chain->nr; i++)
2cec19d9 1128 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
3efa1cc9
IM
1129 }
1130 }
1131
2cec19d9 1132 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
75051724
IM
1133
1134 if (thread == NULL) {
7522060c 1135 eprintf("problem processing %d event, skipping it.\n",
75051724
IM
1136 event->header.type);
1137 return -1;
1138 }
e7fb08b1 1139
cc8b88b1
ACM
1140 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1141 return 0;
1142
d8db1b57
AB
1143 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
1144
1145 if (cpumode == PERF_EVENT_MISC_KERNEL) {
75051724
IM
1146 show = SHOW_KERNEL;
1147 level = 'k';
e7fb08b1 1148
75051724 1149 dso = kernel_dso;
ed966aac 1150
2cec19d9 1151 dump_printf(" ...... dso: %s\n", dso->name);
16f762a2 1152
d8db1b57 1153 } else if (cpumode == PERF_EVENT_MISC_USER) {
16f762a2 1154
75051724
IM
1155 show = SHOW_USER;
1156 level = '.';
e7fb08b1 1157
75051724
IM
1158 } else {
1159 show = SHOW_HV;
1160 level = 'H';
fb9c8188
AB
1161
1162 dso = hypervisor_dso;
1163
2cec19d9 1164 dump_printf(" ...... dso: [hypervisor]\n");
75051724 1165 }
8fa66bdc 1166
75051724 1167 if (show & show_mask) {
6e7d6fdc 1168 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
8fa66bdc 1169
8fd101f2
ACM
1170 if (dso_list && (!dso || !dso->name ||
1171 !strlist__has_entry(dso_list, dso->name)))
25903407
ACM
1172 return 0;
1173
8fd101f2 1174 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
7bec7a91
ACM
1175 return 0;
1176
6e7d6fdc 1177 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
7522060c 1178 eprintf("problem incrementing symbol count, skipping event\n");
d80d338d 1179 return -1;
ce7e4365 1180 }
8fa66bdc 1181 }
ea1900e5 1182 total += period;
8fa66bdc 1183
75051724
IM
1184 return 0;
1185}
3502973d 1186
75051724
IM
1187static int
1188process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1189{
6baa0a5a 1190 struct thread *thread;
66e274f3 1191 struct map *map = map__new(&event->mmap, cwd, cwdlen);
75051724 1192
6baa0a5a
FW
1193 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
1194
2cec19d9 1195 dump_printf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
75051724
IM
1196 (void *)(offset + head),
1197 (void *)(long)(event->header.size),
62fc4453 1198 event->mmap.pid,
94a24752 1199 event->mmap.tid,
75051724
IM
1200 (void *)(long)event->mmap.start,
1201 (void *)(long)event->mmap.len,
1202 (void *)(long)event->mmap.pgoff,
1203 event->mmap.filename);
1204
1205 if (thread == NULL || map == NULL) {
2cec19d9 1206 dump_printf("problem processing PERF_EVENT_MMAP, skipping event.\n");
df97992c 1207 return 0;
75051724
IM
1208 }
1209
1210 thread__insert_map(thread, map);
1211 total_mmap++;
1212
1213 return 0;
1214}
1215
1216static int
1217process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1218{
6baa0a5a
FW
1219 struct thread *thread;
1220
1221 thread = threads__findnew(event->comm.pid, &threads, &last_match);
75051724 1222
2cec19d9 1223 dump_printf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
75051724
IM
1224 (void *)(offset + head),
1225 (void *)(long)(event->header.size),
1226 event->comm.comm, event->comm.pid);
1227
1228 if (thread == NULL ||
1229 thread__set_comm(thread, event->comm.comm)) {
2cec19d9 1230 dump_printf("problem processing PERF_EVENT_COMM, skipping event.\n");
75051724 1231 return -1;
8fa66bdc 1232 }
75051724
IM
1233 total_comm++;
1234
1235 return 0;
1236}
1237
62fc4453 1238static int
27d028de 1239process_task_event(event_t *event, unsigned long offset, unsigned long head)
62fc4453 1240{
6baa0a5a
FW
1241 struct thread *thread;
1242 struct thread *parent;
1243
1244 thread = threads__findnew(event->fork.pid, &threads, &last_match);
1245 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
62fc4453 1246
2cec19d9 1247 dump_printf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
62fc4453
PZ
1248 (void *)(offset + head),
1249 (void *)(long)(event->header.size),
27d028de
PZ
1250 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1251 event->fork.pid, event->fork.tid,
1252 event->fork.ppid, event->fork.ptid);
1253
1254 /*
1255 * A thread clone will have the same PID for both
1256 * parent and child.
1257 */
1258 if (thread == parent)
1259 return 0;
1260
1261 if (event->header.type == PERF_EVENT_EXIT)
1262 return 0;
62fc4453
PZ
1263
1264 if (!thread || !parent || thread__fork(thread, parent)) {
2cec19d9 1265 dump_printf("problem processing PERF_EVENT_FORK, skipping event.\n");
62fc4453
PZ
1266 return -1;
1267 }
1268 total_fork++;
1269
1270 return 0;
1271}
1272
9d91a6f7
PZ
1273static int
1274process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1275{
2cec19d9 1276 dump_printf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
9d91a6f7
PZ
1277 (void *)(offset + head),
1278 (void *)(long)(event->header.size),
1279 event->lost.id,
1280 event->lost.lost);
1281
1282 total_lost += event->lost.lost;
1283
1284 return 0;
1285}
1286
e9ea2fde
PZ
1287static int
1288process_read_event(event_t *event, unsigned long offset, unsigned long head)
1289{
0d3a5c88
FW
1290 struct perf_counter_attr *attr;
1291
1292 attr = perf_header__find_attr(event->read.id, header);
8f18aec5 1293
8d513270 1294 if (show_threads) {
83a0944f 1295 const char *name = attr ? __event_name(attr->type, attr->config)
8d513270
BG
1296 : "unknown";
1297 perf_read_values_add_value(&show_threads_values,
1298 event->read.pid, event->read.tid,
1299 event->read.id,
1300 name,
1301 event->read.value);
1302 }
1303
2cec19d9 1304 dump_printf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
e9ea2fde
PZ
1305 (void *)(offset + head),
1306 (void *)(long)(event->header.size),
1307 event->read.pid,
1308 event->read.tid,
8f18aec5
PZ
1309 attr ? __event_name(attr->type, attr->config)
1310 : "FAIL",
e9ea2fde
PZ
1311 event->read.value);
1312
1313 return 0;
1314}
1315
75051724
IM
1316static int
1317process_event(event_t *event, unsigned long offset, unsigned long head)
1318{
8465b050
IM
1319 trace_event(event);
1320
75051724 1321 switch (event->header.type) {
e6e18ec7
PZ
1322 case PERF_EVENT_SAMPLE:
1323 return process_sample_event(event, offset, head);
1324
75051724
IM
1325 case PERF_EVENT_MMAP:
1326 return process_mmap_event(event, offset, head);
1327
1328 case PERF_EVENT_COMM:
1329 return process_comm_event(event, offset, head);
1330
62fc4453 1331 case PERF_EVENT_FORK:
27d028de
PZ
1332 case PERF_EVENT_EXIT:
1333 return process_task_event(event, offset, head);
62fc4453 1334
9d91a6f7
PZ
1335 case PERF_EVENT_LOST:
1336 return process_lost_event(event, offset, head);
1337
e9ea2fde
PZ
1338 case PERF_EVENT_READ:
1339 return process_read_event(event, offset, head);
1340
d11444df
IM
1341 /*
1342 * We dont process them right now but they are fine:
1343 */
62fc4453 1344
d11444df
IM
1345 case PERF_EVENT_THROTTLE:
1346 case PERF_EVENT_UNTHROTTLE:
1347 return 0;
1348
d80d338d
IM
1349 default:
1350 return -1;
1351 }
1352
1353 return 0;
1354}
1355
1356static int __cmd_report(void)
1357{
75051724 1358 int ret, rc = EXIT_FAILURE;
d80d338d 1359 unsigned long offset = 0;
7c6a1c65 1360 unsigned long head, shift;
83a0944f 1361 struct stat input_stat;
d80d338d 1362 event_t *event;
d80d338d 1363 uint32_t size;
75051724 1364 char *buf;
d80d338d
IM
1365
1366 register_idle_thread();
1367
8d513270
BG
1368 if (show_threads)
1369 perf_read_values_init(&show_threads_values);
1370
d80d338d
IM
1371 input = open(input_name, O_RDONLY);
1372 if (input < 0) {
a14832ff
IM
1373 fprintf(stderr, " failed to open file: %s", input_name);
1374 if (!strcmp(input_name, "perf.data"))
1375 fprintf(stderr, " (try 'perf record' first)");
1376 fprintf(stderr, "\n");
d80d338d
IM
1377 exit(-1);
1378 }
1379
83a0944f 1380 ret = fstat(input, &input_stat);
d80d338d
IM
1381 if (ret < 0) {
1382 perror("failed to stat file");
1383 exit(-1);
1384 }
1385
83a0944f 1386 if (!input_stat.st_size) {
d80d338d
IM
1387 fprintf(stderr, "zero-sized file, nothing to do!\n");
1388 exit(0);
1389 }
1390
7c6a1c65
PZ
1391 header = perf_header__read(input);
1392 head = header->data_offset;
f5970550 1393
0d3a5c88 1394 sample_type = perf_header__sample_type(header);
e6e18ec7 1395
91b4eaea
FW
1396 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1397 if (sort__has_parent) {
1398 fprintf(stderr, "selected --sort parent, but no"
1399 " callchain data. Did you call"
1400 " perf record without -g?\n");
1401 exit(-1);
1402 }
1403 if (callchain) {
1404 fprintf(stderr, "selected -c but no callchain data."
1405 " Did you call perf record without"
1406 " -g?\n");
1407 exit(-1);
1408 }
b1a88349
FW
1409 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1410 callchain = 1;
1411 if (register_callchain_param(&callchain_param) < 0) {
1412 fprintf(stderr, "Can't register callchain"
1413 " params\n");
1414 exit(-1);
1415 }
f5970550
PZ
1416 }
1417
d80d338d
IM
1418 if (load_kernel() < 0) {
1419 perror("failed to load kernel symbols");
1420 return EXIT_FAILURE;
1421 }
1422
1423 if (!full_paths) {
1424 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1425 perror("failed to get the current directory");
1426 return EXIT_FAILURE;
1427 }
1428 cwdlen = strlen(cwd);
1429 } else {
1430 cwd = NULL;
1431 cwdlen = 0;
1432 }
7c6a1c65
PZ
1433
1434 shift = page_size * (head / page_size);
1435 offset += shift;
1436 head -= shift;
1437
d80d338d
IM
1438remap:
1439 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1440 MAP_SHARED, input, offset);
1441 if (buf == MAP_FAILED) {
1442 perror("failed to mmap file");
1443 exit(-1);
1444 }
1445
1446more:
1447 event = (event_t *)(buf + head);
1448
1449 size = event->header.size;
1450 if (!size)
1451 size = 8;
1452
1453 if (head + event->header.size >= page_size * mmap_window) {
83a0944f 1454 int munmap_ret;
d80d338d 1455
7c6a1c65
PZ
1456 shift = page_size * (head / page_size);
1457
83a0944f
IM
1458 munmap_ret = munmap(buf, page_size * mmap_window);
1459 assert(munmap_ret == 0);
d80d338d
IM
1460
1461 offset += shift;
1462 head -= shift;
1463 goto remap;
1464 }
1465
1466 size = event->header.size;
1467
2cec19d9 1468 dump_printf("\n%p [%p]: event: %d\n",
b2fef076
IM
1469 (void *)(offset + head),
1470 (void *)(long)event->header.size,
1471 event->header.type);
1472
d80d338d
IM
1473 if (!size || process_event(event, offset, head) < 0) {
1474
2cec19d9 1475 dump_printf("%p [%p]: skipping unknown header type: %d\n",
3502973d
IM
1476 (void *)(offset + head),
1477 (void *)(long)(event->header.size),
1478 event->header.type);
b7a16eac 1479
3e706114 1480 total_unknown++;
6142f9ec
PZ
1481
1482 /*
1483 * assume we lost track of the stream, check alignment, and
1484 * increment a single u64 in the hope to catch on again 'soon'.
1485 */
1486
1487 if (unlikely(head & 7))
1488 head &= ~7ULL;
1489
1490 size = 8;
97b07b69 1491 }
8fa66bdc 1492
6142f9ec 1493 head += size;
f49515b1 1494
7c6a1c65 1495 if (offset + head >= header->data_offset + header->data_size)
f5970550
PZ
1496 goto done;
1497
83a0944f 1498 if (offset + head < (unsigned long)input_stat.st_size)
8fa66bdc
ACM
1499 goto more;
1500
f5970550 1501done:
8fa66bdc 1502 rc = EXIT_SUCCESS;
8fa66bdc 1503 close(input);
97b07b69 1504
2cec19d9
FW
1505 dump_printf(" IP events: %10ld\n", total);
1506 dump_printf(" mmap events: %10ld\n", total_mmap);
1507 dump_printf(" comm events: %10ld\n", total_comm);
1508 dump_printf(" fork events: %10ld\n", total_fork);
1509 dump_printf(" lost events: %10ld\n", total_lost);
1510 dump_printf(" unknown events: %10ld\n", total_unknown);
97b07b69 1511
3502973d 1512 if (dump_trace)
97b07b69 1513 return 0;
97b07b69 1514
9ac99545 1515 if (verbose >= 3)
6baa0a5a 1516 threads__fprintf(stdout, &threads);
9ac99545 1517
e7fb08b1 1518 if (verbose >= 2)
16f762a2 1519 dsos__fprintf(stdout);
16f762a2 1520
8229289b 1521 collapse__resort();
c20ab37e 1522 output__resort(total);
e7fb08b1 1523 output__fprintf(stdout, total);
8fa66bdc 1524
8d513270
BG
1525 if (show_threads)
1526 perf_read_values_destroy(&show_threads_values);
1527
8fa66bdc
ACM
1528 return rc;
1529}
1530
4eb3e478
FW
1531static int
1532parse_callchain_opt(const struct option *opt __used, const char *arg,
1533 int unset __used)
1534{
c20ab37e
FW
1535 char *tok;
1536 char *endptr;
1537
4eb3e478
FW
1538 callchain = 1;
1539
1540 if (!arg)
1541 return 0;
1542
c20ab37e
FW
1543 tok = strtok((char *)arg, ",");
1544 if (!tok)
1545 return -1;
1546
1547 /* get the output mode */
1548 if (!strncmp(tok, "graph", strlen(arg)))
805d127d 1549 callchain_param.mode = CHAIN_GRAPH_ABS;
4eb3e478 1550
c20ab37e 1551 else if (!strncmp(tok, "flat", strlen(arg)))
805d127d
FW
1552 callchain_param.mode = CHAIN_FLAT;
1553
1554 else if (!strncmp(tok, "fractal", strlen(arg)))
1555 callchain_param.mode = CHAIN_GRAPH_REL;
1556
b1a88349
FW
1557 else if (!strncmp(tok, "none", strlen(arg))) {
1558 callchain_param.mode = CHAIN_NONE;
1559 callchain = 0;
1560
1561 return 0;
1562 }
1563
4eb3e478
FW
1564 else
1565 return -1;
1566
c20ab37e
FW
1567 /* get the min percentage */
1568 tok = strtok(NULL, ",");
1569 if (!tok)
805d127d 1570 goto setup;
c20ab37e 1571
805d127d 1572 callchain_param.min_percent = strtod(tok, &endptr);
c20ab37e
FW
1573 if (tok == endptr)
1574 return -1;
1575
805d127d
FW
1576setup:
1577 if (register_callchain_param(&callchain_param) < 0) {
1578 fprintf(stderr, "Can't register callchain params\n");
1579 return -1;
1580 }
4eb3e478
FW
1581 return 0;
1582}
1583
53cb8bc2
IM
1584static const char * const report_usage[] = {
1585 "perf report [<options>] <command>",
1586 NULL
1587};
1588
1589static const struct option options[] = {
1590 OPT_STRING('i', "input", &input_name, "file",
1591 "input file name"),
815e777f
ACM
1592 OPT_BOOLEAN('v', "verbose", &verbose,
1593 "be more verbose (show symbol address, etc)"),
97b07b69
IM
1594 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1595 "dump raw trace in ASCII"),
83a0944f 1596 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
42976487
MG
1597 OPT_BOOLEAN('m', "modules", &modules,
1598 "load module symbols - WARNING: use only with -k and LIVE kernel"),
e3d7e183
ACM
1599 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1600 "Show a column with the number of samples"),
8d513270
BG
1601 OPT_BOOLEAN('T', "threads", &show_threads,
1602 "Show per-thread event counters"),
9f866697
BG
1603 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
1604 "pretty printing style key: normal raw"),
63299f05 1605 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
b25bcf2f 1606 "sort by key(s): pid, comm, dso, symbol, parent"),
b78c07d4
ACM
1607 OPT_BOOLEAN('P', "full-paths", &full_paths,
1608 "Don't shorten the pathnames taking into account the cwd"),
b25bcf2f
IM
1609 OPT_STRING('p', "parent", &parent_pattern, "regex",
1610 "regex filter to identify parent, see: '--sort parent'"),
b8e6d829
IM
1611 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1612 "Only display entries with parent-match"),
1483b19f 1613 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
c20ab37e 1614 "Display callchains using output_type and min percent threshold. "
1483b19f 1615 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
25903407
ACM
1616 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1617 "only consider symbols in these dsos"),
cc8b88b1
ACM
1618 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1619 "only consider symbols in these comms"),
7bec7a91
ACM
1620 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1621 "only consider these symbols"),
52d422de
ACM
1622 OPT_STRING('w', "column-widths", &col_width_list_str,
1623 "width[,width...]",
1624 "don't try to adjust column width, use these fixed values"),
1625 OPT_STRING('t', "field-separator", &field_sep, "separator",
1626 "separator for columns, no spaces will be added between "
1627 "columns '.' is reserved."),
53cb8bc2
IM
1628 OPT_END()
1629};
1630
5352f35d
IM
1631static void setup_sorting(void)
1632{
1633 char *tmp, *tok, *str = strdup(sort_order);
1634
1635 for (tok = strtok_r(str, ", ", &tmp);
1636 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1637 if (sort_dimension__add(tok) < 0) {
1638 error("Unknown --sort key: `%s'", tok);
1639 usage_with_options(report_usage, options);
1640 }
1641 }
1642
1643 free(str);
1644}
1645
cc8b88b1 1646static void setup_list(struct strlist **list, const char *list_str,
021191b3
ACM
1647 struct sort_entry *se, const char *list_name,
1648 FILE *fp)
cc8b88b1
ACM
1649{
1650 if (list_str) {
1651 *list = strlist__new(true, list_str);
1652 if (!*list) {
1653 fprintf(stderr, "problems parsing %s list\n",
1654 list_name);
1655 exit(129);
1656 }
021191b3
ACM
1657 if (strlist__nr_entries(*list) == 1) {
1658 fprintf(fp, "# %s: %s\n", list_name,
1659 strlist__entry(*list, 0)->s);
1660 se->elide = true;
1661 }
cc8b88b1
ACM
1662 }
1663}
1664
f37a291c 1665int cmd_report(int argc, const char **argv, const char *prefix __used)
53cb8bc2 1666{
a2928c42 1667 symbol__init();
53cb8bc2
IM
1668
1669 page_size = getpagesize();
1670
edc52dea 1671 argc = parse_options(argc, argv, options, report_usage, 0);
53cb8bc2 1672
1aa16738
PZ
1673 setup_sorting();
1674
021191b3 1675 if (parent_pattern != default_parent_pattern) {
b8e6d829 1676 sort_dimension__add("parent");
021191b3
ACM
1677 sort_parent.elide = 1;
1678 } else
b8e6d829
IM
1679 exclude_other = 0;
1680
edc52dea
IM
1681 /*
1682 * Any (unrecognized) arguments left?
1683 */
1684 if (argc)
1685 usage_with_options(report_usage, options);
1686
a930d2c0
IM
1687 setup_pager();
1688
021191b3
ACM
1689 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
1690 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1691 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
25903407 1692
52d422de
ACM
1693 if (field_sep && *field_sep == '.') {
1694 fputs("'.' is the only non valid --field-separator argument\n",
1695 stderr);
1696 exit(129);
1697 }
1698
53cb8bc2
IM
1699 return __cmd_report();
1700}