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