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