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