12f8c868fcd7dda57da90918321af4cbb4c70fbd
[pandora-kernel.git] / 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/thread.h"
30 #include "util/sort.h"
31 #include "util/hist.h"
32
33 static char             const *input_name = "perf.data";
34
35 static char             *dso_list_str, *comm_list_str, *sym_list_str,
36                         *col_width_list_str;
37 static struct strlist   *dso_list, *comm_list, *sym_list;
38
39 static int              force;
40 static int              input;
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 unsigned long    page_size;
52 static unsigned long    mmap_window = 32;
53
54 static int              exclude_other = 1;
55
56 static char             callchain_default_opt[] = "fractal,0.5";
57
58 static char             __cwd[PATH_MAX];
59 static char             *cwd = __cwd;
60 static int              cwdlen;
61
62 static struct rb_root   threads;
63 static struct thread    *last_match;
64
65 static struct perf_header *header;
66
67 static u64              sample_type;
68
69 static 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 }
86 static size_t
87 ipchain__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;
104                         ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
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
116 static struct symbol *rem_sq_bracket;
117 static struct callchain_list rem_hits;
118
119 static 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
131 static size_t
132 callchain__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;
139         u64 new_total;
140         u64 remaining;
141         size_t ret = 0;
142         int i;
143
144         if (callchain_param.mode == CHAIN_GRAPH_REL)
145                 new_total = self->children_hit;
146         else
147                 new_total = total_samples;
148
149         remaining = new_total;
150
151         node = rb_first(&self->rb_root);
152         while (node) {
153                 u64 cumul;
154
155                 child = rb_entry(node, struct callchain_node, rb_node);
156                 cumul = cumul_hits(child);
157                 remaining -= cumul;
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
162                  * level for the last child of this depth.
163                  * Except if we have remaining filtered hits. They will
164                  * supersede the last child
165                  */
166                 next = rb_next(node);
167                 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
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++,
181                                                       new_total,
182                                                       cumul);
183                 }
184                 ret += callchain__fprintf_graph(fp, child, new_total,
185                                                 depth + 1,
186                                                 new_depth_mask | (1 << depth));
187                 node = next;
188         }
189
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
203         return ret;
204 }
205
206 static size_t
207 callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
208                         u64 total_samples)
209 {
210         struct callchain_list *chain;
211         size_t ret = 0;
212
213         if (!self)
214                 return 0;
215
216         ret += callchain__fprintf_flat(fp, self->parent, total_samples);
217
218
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",
226                                         (void *)(long)chain->ip);
227         }
228
229         return ret;
230 }
231
232 static size_t
233 hist_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;
246                 switch (callchain_param.mode) {
247                 case CHAIN_FLAT:
248                         ret += percent_color_fprintf(fp, "           %6.2f%%\n",
249                                                      percent);
250                         ret += callchain__fprintf_flat(fp, chain, total_samples);
251                         break;
252                 case CHAIN_GRAPH_ABS: /* Falldown */
253                 case CHAIN_GRAPH_REL:
254                         ret += callchain__fprintf_graph(fp, chain,
255                                                         total_samples, 1, 1);
256                 case CHAIN_NONE:
257                 default:
258                         break;
259                 }
260                 ret += fprintf(fp, "\n");
261                 rb_node = rb_next(rb_node);
262         }
263
264         return ret;
265 }
266
267 static size_t
268 hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
269 {
270         struct sort_entry *se;
271         size_t ret;
272
273         if (exclude_other && !self->parent)
274                 return 0;
275
276         if (total_samples)
277                 ret = percent_color_fprintf(fp,
278                                             field_sep ? "%.2f" : "   %6.2f%%",
279                                         (self->count * 100.0) / total_samples);
280         else
281                 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
282
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         }
289
290         list_for_each_entry(se, &hist_entry__sort_list, list) {
291                 if (se->elide)
292                         continue;
293
294                 fprintf(fp, "%s", field_sep ?: "  ");
295                 ret += se->print(fp, self, se->width ? *se->width : 0);
296         }
297
298         ret += fprintf(fp, "\n");
299
300         if (callchain)
301                 hist_entry_callchain__fprintf(fp, self, total_samples);
302
303         return ret;
304 }
305
306 /*
307  *
308  */
309
310 static 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
322 static void thread__comm_adjust(struct thread *self)
323 {
324         char *comm = self->comm;
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         }
335 }
336
337 static 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);
345
346         return 0;
347 }
348
349
350 static struct symbol *
351 resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
352 {
353         struct map *map = mapp ? *mapp : NULL;
354         u64 ip = *ipp;
355
356         if (map)
357                 goto got_map;
358
359         if (!thread)
360                 return NULL;
361
362         map = thread__find_map(thread, ip);
363         if (map != NULL) {
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                  */
369                 if (!sort_dso.elide && !map->dso->slen_calculated)
370                         dso__calc_col_width(map->dso);
371
372                 if (mapp)
373                         *mapp = map;
374 got_map:
375                 ip = map->map_ip(map, ip);
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
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.
386                  */
387                 if ((long long)ip < 0)
388                         return kernel_maps__find_symbol(ip, mapp);
389         }
390         dump_printf(" ...... dso: %s\n",
391                     map ? map->dso->long_name : "<not found>");
392         dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
393         *ipp  = ip;
394
395         return map ? map->dso->find_symbol(map->dso, ip) : NULL;
396 }
397
398 static int call__match(struct symbol *sym)
399 {
400         if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
401                 return 1;
402
403         return 0;
404 }
405
406 static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
407                                          struct ip_callchain *chain,
408                                          struct symbol **parent)
409 {
410         u64 context = PERF_CONTEXT_MAX;
411         struct symbol **syms = NULL;
412         unsigned int i;
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];
424                 struct symbol *sym = NULL;
425
426                 if (ip >= PERF_CONTEXT_MAX) {
427                         context = ip;
428                         continue;
429                 }
430
431                 switch (context) {
432                 case PERF_CONTEXT_HV:
433                         break;
434                 case PERF_CONTEXT_KERNEL:
435                         sym = kernel_maps__find_symbol(ip, &map);
436                         break;
437                 default:
438                         sym = resolve_symbol(thread, &map, &ip);
439                         break;
440                 }
441
442                 if (sym) {
443                         if (sort__has_parent && !*parent && call__match(sym))
444                                 *parent = sym;
445                         if (!callchain)
446                                 break;
447                         syms[i] = sym;
448                 }
449         }
450
451         return syms;
452 }
453
454 /*
455  * collect histogram counts
456  */
457
458 static int
459 hist_entry__add(struct thread *thread, struct map *map,
460                 struct symbol *sym, u64 ip, struct ip_callchain *chain,
461                 char level, u64 count)
462 {
463         struct symbol **syms = NULL, *parent = NULL;
464         bool hit;
465         struct hist_entry *he;
466
467         if ((sort__has_parent || callchain) && chain)
468                 syms = resolve_callchain(thread, map, chain, &parent);
469
470         he = __hist_entry__add(thread, map, sym, parent,
471                                ip, count, level, &hit);
472         if (he == NULL)
473                 return -ENOMEM;
474
475         if (hit)
476                 he->count += count;
477
478         if (callchain) {
479                 if (!hit)
480                         callchain_init(&he->callchain);
481                 append_chain(&he->callchain, chain, syms);
482                 free(syms);
483         }
484
485         return 0;
486 }
487
488 static size_t output__fprintf(FILE *fp, u64 total_samples)
489 {
490         struct hist_entry *pos;
491         struct sort_entry *se;
492         struct rb_node *nd;
493         size_t ret = 0;
494         unsigned int width;
495         char *col_width = col_width_list_str;
496         int raw_printing_style;
497
498         raw_printing_style = !strcmp(pretty_printing_style, "raw");
499
500         init_rem_hits();
501
502         fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
503         fprintf(fp, "#\n");
504
505         fprintf(fp, "# Overhead");
506         if (show_nr_samples) {
507                 if (field_sep)
508                         fprintf(fp, "%cSamples", *field_sep);
509                 else
510                         fputs("  Samples  ", fp);
511         }
512         list_for_each_entry(se, &hist_entry__sort_list, list) {
513                 if (se->elide)
514                         continue;
515                 if (field_sep) {
516                         fprintf(fp, "%c%s", *field_sep, se->header);
517                         continue;
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);
532         }
533         fprintf(fp, "\n");
534
535         if (field_sep)
536                 goto print_entries;
537
538         fprintf(fp, "# ........");
539         if (show_nr_samples)
540                 fprintf(fp, " ..........");
541         list_for_each_entry(se, &hist_entry__sort_list, list) {
542                 unsigned int i;
543
544                 if (se->elide)
545                         continue;
546
547                 fprintf(fp, "  ");
548                 if (se->width)
549                         width = *se->width;
550                 else
551                         width = strlen(se->header);
552                 for (i = 0; i < width; i++)
553                         fprintf(fp, ".");
554         }
555         fprintf(fp, "\n");
556
557         fprintf(fp, "#\n");
558
559 print_entries:
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);
563         }
564
565         if (sort_order == default_sort_order &&
566                         parent_pattern == default_parent_pattern) {
567                 fprintf(fp, "#\n");
568                 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
569                 fprintf(fp, "#\n");
570         }
571         fprintf(fp, "\n");
572
573         free(rem_sq_bracket);
574
575         if (show_threads)
576                 perf_read_values_display(fp, &show_threads_values,
577                                          raw_printing_style);
578
579         return ret;
580 }
581
582 static int validate_chain(struct ip_callchain *chain, event_t *event)
583 {
584         unsigned int chain_size;
585
586         chain_size = event->header.size;
587         chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
588
589         if (chain->nr*sizeof(u64) > chain_size)
590                 return -1;
591
592         return 0;
593 }
594
595 static int
596 process_sample_event(event_t *event, unsigned long offset, unsigned long head)
597 {
598         char level;
599         struct symbol *sym = NULL;
600         struct thread *thread;
601         u64 ip = event->ip.ip;
602         u64 period = 1;
603         struct map *map = NULL;
604         void *more_data = event->ip.__more_data;
605         struct ip_callchain *chain = NULL;
606         int cpumode;
607
608         thread = threads__findnew(event->ip.pid, &threads, &last_match);
609
610         if (sample_type & PERF_SAMPLE_PERIOD) {
611                 period = *(u64 *)more_data;
612                 more_data += sizeof(u64);
613         }
614
615         dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
616                 (void *)(offset + head),
617                 (void *)(long)(event->header.size),
618                 event->header.misc,
619                 event->ip.pid, event->ip.tid,
620                 (void *)(long)ip,
621                 (long long)period);
622
623         if (sample_type & PERF_SAMPLE_CALLCHAIN) {
624                 unsigned int i;
625
626                 chain = (void *)more_data;
627
628                 dump_printf("... chain: nr:%Lu\n", chain->nr);
629
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) {
636                         for (i = 0; i < chain->nr; i++)
637                                 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
638                 }
639         }
640
641         dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
642
643         if (thread == NULL) {
644                 eprintf("problem processing %d event, skipping it.\n",
645                         event->header.type);
646                 return -1;
647         }
648
649         if (comm_list && !strlist__has_entry(comm_list, thread->comm))
650                 return 0;
651
652         cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
653
654         if (cpumode == PERF_RECORD_MISC_KERNEL) {
655                 level = 'k';
656                 sym = kernel_maps__find_symbol(ip, &map);
657                 dump_printf(" ...... dso: %s\n",
658                             map ? map->dso->long_name : "<not found>");
659         } else if (cpumode == PERF_RECORD_MISC_USER) {
660                 level = '.';
661                 sym = resolve_symbol(thread, &map, &ip);
662
663         } else {
664                 level = 'H';
665                 dump_printf(" ...... dso: [hypervisor]\n");
666         }
667
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;
674
675         if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
676                 return 0;
677
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;
682         }
683
684         total += period;
685
686         return 0;
687 }
688
689 static int
690 process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
691 {
692         struct thread *thread;
693         struct map *map = map__new(&event->mmap, cwd, cwdlen);
694
695         thread = threads__findnew(event->mmap.pid, &threads, &last_match);
696
697         dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
698                 (void *)(offset + head),
699                 (void *)(long)(event->header.size),
700                 event->mmap.pid,
701                 event->mmap.tid,
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) {
708                 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
709                 return 0;
710         }
711
712         thread__insert_map(thread, map);
713         total_mmap++;
714
715         return 0;
716 }
717
718 static int
719 process_comm_event(event_t *event, unsigned long offset, unsigned long head)
720 {
721         struct thread *thread;
722
723         thread = threads__findnew(event->comm.pid, &threads, &last_match);
724
725         dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
726                 (void *)(offset + head),
727                 (void *)(long)(event->header.size),
728                 event->comm.comm, event->comm.pid);
729
730         if (thread == NULL ||
731             thread__set_comm_adjust(thread, event->comm.comm)) {
732                 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
733                 return -1;
734         }
735         total_comm++;
736
737         return 0;
738 }
739
740 static int
741 process_task_event(event_t *event, unsigned long offset, unsigned long head)
742 {
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);
748
749         dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
750                 (void *)(offset + head),
751                 (void *)(long)(event->header.size),
752                 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
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
763         if (event->header.type == PERF_RECORD_EXIT)
764                 return 0;
765
766         if (!thread || !parent || thread__fork(thread, parent)) {
767                 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
768                 return -1;
769         }
770         total_fork++;
771
772         return 0;
773 }
774
775 static int
776 process_lost_event(event_t *event, unsigned long offset, unsigned long head)
777 {
778         dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
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
789 static int
790 process_read_event(event_t *event, unsigned long offset, unsigned long head)
791 {
792         struct perf_event_attr *attr;
793
794         attr = perf_header__find_attr(event->read.id, header);
795
796         if (show_threads) {
797                 const char *name = attr ? __event_name(attr->type, attr->config)
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
806         dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
807                         (void *)(offset + head),
808                         (void *)(long)(event->header.size),
809                         event->read.pid,
810                         event->read.tid,
811                         attr ? __event_name(attr->type, attr->config)
812                              : "FAIL",
813                         event->read.value);
814
815         return 0;
816 }
817
818 static int
819 process_event(event_t *event, unsigned long offset, unsigned long head)
820 {
821         trace_event(event);
822
823         switch (event->header.type) {
824         case PERF_RECORD_SAMPLE:
825                 return process_sample_event(event, offset, head);
826
827         case PERF_RECORD_MMAP:
828                 return process_mmap_event(event, offset, head);
829
830         case PERF_RECORD_COMM:
831                 return process_comm_event(event, offset, head);
832
833         case PERF_RECORD_FORK:
834         case PERF_RECORD_EXIT:
835                 return process_task_event(event, offset, head);
836
837         case PERF_RECORD_LOST:
838                 return process_lost_event(event, offset, head);
839
840         case PERF_RECORD_READ:
841                 return process_read_event(event, offset, head);
842
843         /*
844          * We dont process them right now but they are fine:
845          */
846
847         case PERF_RECORD_THROTTLE:
848         case PERF_RECORD_UNTHROTTLE:
849                 return 0;
850
851         default:
852                 return -1;
853         }
854
855         return 0;
856 }
857
858 static int __cmd_report(void)
859 {
860         int ret, rc = EXIT_FAILURE;
861         unsigned long offset = 0;
862         unsigned long head, shift;
863         struct stat input_stat;
864         struct thread *idle;
865         event_t *event;
866         uint32_t size;
867         char *buf;
868
869         idle = register_idle_thread(&threads, &last_match);
870         thread__comm_adjust(idle);
871
872         if (show_threads)
873                 perf_read_values_init(&show_threads_values);
874
875         input = open(input_name, O_RDONLY);
876         if (input < 0) {
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");
881                 exit(-1);
882         }
883
884         ret = fstat(input, &input_stat);
885         if (ret < 0) {
886                 perror("failed to stat file");
887                 exit(-1);
888         }
889
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);
892                 exit(-1);
893         }
894
895         if (!input_stat.st_size) {
896                 fprintf(stderr, "zero-sized file, nothing to do!\n");
897                 exit(0);
898         }
899
900         header = perf_header__read(input);
901         head = header->data_offset;
902
903         sample_type = perf_header__sample_type(header);
904
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) {
913                         fprintf(stderr, "selected -g but no callchain data."
914                                         " Did you call perf record without"
915                                         " -g?\n");
916                         exit(-1);
917                 }
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                         }
925         }
926
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         }
942
943         shift = page_size * (head / page_size);
944         offset += shift;
945         head -= shift;
946
947 remap:
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
955 more:
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) {
963                 int munmap_ret;
964
965                 shift = page_size * (head / page_size);
966
967                 munmap_ret = munmap(buf, page_size * mmap_window);
968                 assert(munmap_ret == 0);
969
970                 offset += shift;
971                 head -= shift;
972                 goto remap;
973         }
974
975         size = event->header.size;
976
977         dump_printf("\n%p [%p]: event: %d\n",
978                         (void *)(offset + head),
979                         (void *)(long)event->header.size,
980                         event->header.type);
981
982         if (!size || process_event(event, offset, head) < 0) {
983
984                 dump_printf("%p [%p]: skipping unknown header type: %d\n",
985                         (void *)(offset + head),
986                         (void *)(long)(event->header.size),
987                         event->header.type);
988
989                 total_unknown++;
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;
1000         }
1001
1002         head += size;
1003
1004         if (offset + head >= header->data_offset + header->data_size)
1005                 goto done;
1006
1007         if (offset + head < (unsigned long)input_stat.st_size)
1008                 goto more;
1009
1010 done:
1011         rc = EXIT_SUCCESS;
1012         close(input);
1013
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);
1020
1021         if (dump_trace)
1022                 return 0;
1023
1024         if (verbose >= 3)
1025                 threads__fprintf(stdout, &threads);
1026
1027         if (verbose >= 2)
1028                 dsos__fprintf(stdout);
1029
1030         collapse__resort();
1031         output__resort(total);
1032         output__fprintf(stdout, total);
1033
1034         if (show_threads)
1035                 perf_read_values_destroy(&show_threads_values);
1036
1037         return rc;
1038 }
1039
1040 static int
1041 parse_callchain_opt(const struct option *opt __used, const char *arg,
1042                     int unset __used)
1043 {
1044         char *tok;
1045         char *endptr;
1046
1047         callchain = 1;
1048
1049         if (!arg)
1050                 return 0;
1051
1052         tok = strtok((char *)arg, ",");
1053         if (!tok)
1054                 return -1;
1055
1056         /* get the output mode */
1057         if (!strncmp(tok, "graph", strlen(arg)))
1058                 callchain_param.mode = CHAIN_GRAPH_ABS;
1059
1060         else if (!strncmp(tok, "flat", strlen(arg)))
1061                 callchain_param.mode = CHAIN_FLAT;
1062
1063         else if (!strncmp(tok, "fractal", strlen(arg)))
1064                 callchain_param.mode = CHAIN_GRAPH_REL;
1065
1066         else if (!strncmp(tok, "none", strlen(arg))) {
1067                 callchain_param.mode = CHAIN_NONE;
1068                 callchain = 0;
1069
1070                 return 0;
1071         }
1072
1073         else
1074                 return -1;
1075
1076         /* get the min percentage */
1077         tok = strtok(NULL, ",");
1078         if (!tok)
1079                 goto setup;
1080
1081         callchain_param.min_percent = strtod(tok, &endptr);
1082         if (tok == endptr)
1083                 return -1;
1084
1085 setup:
1086         if (register_callchain_param(&callchain_param) < 0) {
1087                 fprintf(stderr, "Can't register callchain params\n");
1088                 return -1;
1089         }
1090         return 0;
1091 }
1092
1093 //static const char * const report_usage[] = {
1094 const char * const report_usage[] = {
1095         "perf report [<options>] <command>",
1096         NULL
1097 };
1098
1099 static const struct option options[] = {
1100         OPT_STRING('i', "input", &input_name, "file",
1101                     "input file name"),
1102         OPT_BOOLEAN('v', "verbose", &verbose,
1103                     "be more verbose (show symbol address, etc)"),
1104         OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1105                     "dump raw trace in ASCII"),
1106         OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1107         OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1108         OPT_BOOLEAN('m', "modules", &modules,
1109                     "load module symbols - WARNING: use only with -k and LIVE kernel"),
1110         OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1111                     "Show a column with the number of samples"),
1112         OPT_BOOLEAN('T', "threads", &show_threads,
1113                     "Show per-thread event counters"),
1114         OPT_STRING(0, "pretty", &pretty_printing_style, "key",
1115                    "pretty printing style key: normal raw"),
1116         OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1117                    "sort by key(s): pid, comm, dso, symbol, parent"),
1118         OPT_BOOLEAN('P', "full-paths", &full_paths,
1119                     "Don't shorten the pathnames taking into account the cwd"),
1120         OPT_STRING('p', "parent", &parent_pattern, "regex",
1121                    "regex filter to identify parent, see: '--sort parent'"),
1122         OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1123                     "Only display entries with parent-match"),
1124         OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1125                      "Display callchains using output_type and min percent threshold. "
1126                      "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1127         OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1128                    "only consider symbols in these dsos"),
1129         OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1130                    "only consider symbols in these comms"),
1131         OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1132                    "only consider these symbols"),
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."),
1139         OPT_END()
1140 };
1141
1142 static 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
1157 static void setup_list(struct strlist **list, const char *list_str,
1158                        struct sort_entry *se, const char *list_name,
1159                        FILE *fp)
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                 }
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                 }
1173         }
1174 }
1175
1176 int cmd_report(int argc, const char **argv, const char *prefix __used)
1177 {
1178         symbol__init();
1179
1180         page_size = getpagesize();
1181
1182         argc = parse_options(argc, argv, options, report_usage, 0);
1183
1184         setup_sorting();
1185
1186         if (parent_pattern != default_parent_pattern) {
1187                 sort_dimension__add("parent");
1188                 sort_parent.elide = 1;
1189         } else
1190                 exclude_other = 0;
1191
1192         /*
1193          * Any (unrecognized) arguments left?
1194          */
1195         if (argc)
1196                 usage_with_options(report_usage, options);
1197
1198         setup_pager();
1199
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);
1203
1204         if (field_sep && *field_sep == '.') {
1205                 fputs("'.' is the only non valid --field-separator argument\n",
1206                       stderr);
1207                 exit(129);
1208         }
1209
1210         return __cmd_report();
1211 }