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