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