aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c652
1 files changed, 499 insertions, 153 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 135b7837e6bf..8cb58d68a006 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -10,9 +10,9 @@
10#include "util/util.h" 10#include "util/util.h"
11 11
12#include "util/color.h" 12#include "util/color.h"
13#include "util/list.h" 13#include <linux/list.h>
14#include "util/cache.h" 14#include "util/cache.h"
15#include "util/rbtree.h" 15#include <linux/rbtree.h>
16#include "util/symbol.h" 16#include "util/symbol.h"
17#include "util/string.h" 17#include "util/string.h"
18#include "util/callchain.h" 18#include "util/callchain.h"
@@ -31,10 +31,12 @@
31static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
32static char *vmlinux = NULL; 32static char *vmlinux = NULL;
33 33
34static char default_sort_order[] = "comm,dso"; 34static char default_sort_order[] = "comm,dso,symbol";
35static char *sort_order = default_sort_order; 35static char *sort_order = default_sort_order;
36static char *dso_list_str, *comm_list_str, *sym_list_str; 36static char *dso_list_str, *comm_list_str, *sym_list_str,
37 *col_width_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list; 38static struct strlist *dso_list, *comm_list, *sym_list;
39static char *field_sep;
38 40
39static int input; 41static int input;
40static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
@@ -46,7 +48,10 @@ static int dump_trace = 0;
46static int verbose; 48static int verbose;
47#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0) 49#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
48 50
51static int modules;
52
49static int full_paths; 53static int full_paths;
54static int show_nr_samples;
50 55
51static unsigned long page_size; 56static unsigned long page_size;
52static unsigned long mmap_window = 32; 57static unsigned long mmap_window = 32;
@@ -56,8 +61,17 @@ static char *parent_pattern = default_parent_pattern;
56static regex_t parent_regex; 61static regex_t parent_regex;
57 62
58static int exclude_other = 1; 63static int exclude_other = 1;
64
65static char callchain_default_opt[] = "fractal,0.5";
66
59static int callchain; 67static int callchain;
60 68
69static
70struct callchain_param callchain_param = {
71 .mode = CHAIN_GRAPH_ABS,
72 .min_percent = 0.5
73};
74
61static u64 sample_type; 75static u64 sample_type;
62 76
63struct ip_event { 77struct ip_event {
@@ -85,13 +99,7 @@ struct comm_event {
85struct fork_event { 99struct fork_event {
86 struct perf_event_header header; 100 struct perf_event_header header;
87 u32 pid, ppid; 101 u32 pid, ppid;
88}; 102 u32 tid, ptid;
89
90struct period_event {
91 struct perf_event_header header;
92 u64 time;
93 u64 id;
94 u64 sample_period;
95}; 103};
96 104
97struct lost_event { 105struct lost_event {
@@ -113,14 +121,41 @@ typedef union event_union {
113 struct mmap_event mmap; 121 struct mmap_event mmap;
114 struct comm_event comm; 122 struct comm_event comm;
115 struct fork_event fork; 123 struct fork_event fork;
116 struct period_event period;
117 struct lost_event lost; 124 struct lost_event lost;
118 struct read_event read; 125 struct read_event read;
119} event_t; 126} event_t;
120 127
128static int repsep_fprintf(FILE *fp, const char *fmt, ...)
129{
130 int n;
131 va_list ap;
132
133 va_start(ap, fmt);
134 if (!field_sep)
135 n = vfprintf(fp, fmt, ap);
136 else {
137 char *bf = NULL;
138 n = vasprintf(&bf, fmt, ap);
139 if (n > 0) {
140 char *sep = bf;
141 while (1) {
142 sep = strchr(sep, *field_sep);
143 if (sep == NULL)
144 break;
145 *sep = '.';
146 }
147 }
148 fputs(bf, fp);
149 free(bf);
150 }
151 va_end(ap);
152 return n;
153}
154
121static LIST_HEAD(dsos); 155static LIST_HEAD(dsos);
122static struct dso *kernel_dso; 156static struct dso *kernel_dso;
123static struct dso *vdso; 157static struct dso *vdso;
158static struct dso *hypervisor_dso;
124 159
125static void dsos__add(struct dso *dso) 160static void dsos__add(struct dso *dso)
126{ 161{
@@ -176,7 +211,7 @@ static void dsos__fprintf(FILE *fp)
176 211
177static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 212static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
178{ 213{
179 return dso__find_symbol(kernel_dso, ip); 214 return dso__find_symbol(dso, ip);
180} 215}
181 216
182static int load_kernel(void) 217static int load_kernel(void)
@@ -187,8 +222,8 @@ static int load_kernel(void)
187 if (!kernel_dso) 222 if (!kernel_dso)
188 return -1; 223 return -1;
189 224
190 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); 225 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
191 if (err) { 226 if (err <= 0) {
192 dso__delete(kernel_dso); 227 dso__delete(kernel_dso);
193 kernel_dso = NULL; 228 kernel_dso = NULL;
194 } else 229 } else
@@ -202,6 +237,11 @@ static int load_kernel(void)
202 237
203 dsos__add(vdso); 238 dsos__add(vdso);
204 239
240 hypervisor_dso = dso__new("[hypervisor]", 0);
241 if (!hypervisor_dso)
242 return -1;
243 dsos__add(hypervisor_dso);
244
205 return err; 245 return err;
206} 246}
207 247
@@ -213,7 +253,7 @@ static int strcommon(const char *pathname)
213{ 253{
214 int n = 0; 254 int n = 0;
215 255
216 while (pathname[n] == cwd[n] && n < cwdlen) 256 while (n < cwdlen && pathname[n] == cwd[n])
217 ++n; 257 ++n;
218 258
219 return n; 259 return n;
@@ -233,7 +273,7 @@ static u64 map__map_ip(struct map *map, u64 ip)
233 return ip - map->start + map->pgoff; 273 return ip - map->start + map->pgoff;
234} 274}
235 275
236static u64 vdso__map_ip(struct map *map, u64 ip) 276static u64 vdso__map_ip(struct map *map __used, u64 ip)
237{ 277{
238 return ip; 278 return ip;
239} 279}
@@ -343,12 +383,28 @@ static struct thread *thread__new(pid_t pid)
343 return self; 383 return self;
344} 384}
345 385
386static unsigned int dsos__col_width,
387 comms__col_width,
388 threads__col_width;
389
346static int thread__set_comm(struct thread *self, const char *comm) 390static int thread__set_comm(struct thread *self, const char *comm)
347{ 391{
348 if (self->comm) 392 if (self->comm)
349 free(self->comm); 393 free(self->comm);
350 self->comm = strdup(comm); 394 self->comm = strdup(comm);
351 return self->comm ? 0 : -ENOMEM; 395 if (!self->comm)
396 return -ENOMEM;
397
398 if (!col_width_list_str && !field_sep &&
399 (!comm_list || strlist__has_entry(comm_list, comm))) {
400 unsigned int slen = strlen(comm);
401 if (slen > comms__col_width) {
402 comms__col_width = slen;
403 threads__col_width = slen + 6;
404 }
405 }
406
407 return 0;
352} 408}
353 409
354static size_t thread__fprintf(struct thread *self, FILE *fp) 410static size_t thread__fprintf(struct thread *self, FILE *fp)
@@ -519,7 +575,9 @@ struct sort_entry {
519 575
520 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 576 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
521 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 577 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
522 size_t (*print)(FILE *fp, struct hist_entry *); 578 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
579 unsigned int *width;
580 bool elide;
523}; 581};
524 582
525static int64_t cmp_null(void *l, void *r) 583static int64_t cmp_null(void *l, void *r)
@@ -541,15 +599,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
541} 599}
542 600
543static size_t 601static size_t
544sort__thread_print(FILE *fp, struct hist_entry *self) 602sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
545{ 603{
546 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 604 return repsep_fprintf(fp, "%*s:%5d", width - 6,
605 self->thread->comm ?: "", self->thread->pid);
547} 606}
548 607
549static struct sort_entry sort_thread = { 608static struct sort_entry sort_thread = {
550 .header = " Command: Pid", 609 .header = "Command: Pid",
551 .cmp = sort__thread_cmp, 610 .cmp = sort__thread_cmp,
552 .print = sort__thread_print, 611 .print = sort__thread_print,
612 .width = &threads__col_width,
553}; 613};
554 614
555/* --sort comm */ 615/* --sort comm */
@@ -573,16 +633,17 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
573} 633}
574 634
575static size_t 635static size_t
576sort__comm_print(FILE *fp, struct hist_entry *self) 636sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
577{ 637{
578 return fprintf(fp, "%16s", self->thread->comm); 638 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
579} 639}
580 640
581static struct sort_entry sort_comm = { 641static struct sort_entry sort_comm = {
582 .header = " Command", 642 .header = "Command",
583 .cmp = sort__comm_cmp, 643 .cmp = sort__comm_cmp,
584 .collapse = sort__comm_collapse, 644 .collapse = sort__comm_collapse,
585 .print = sort__comm_print, 645 .print = sort__comm_print,
646 .width = &comms__col_width,
586}; 647};
587 648
588/* --sort dso */ 649/* --sort dso */
@@ -600,18 +661,19 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
600} 661}
601 662
602static size_t 663static size_t
603sort__dso_print(FILE *fp, struct hist_entry *self) 664sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
604{ 665{
605 if (self->dso) 666 if (self->dso)
606 return fprintf(fp, "%-25s", self->dso->name); 667 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
607 668
608 return fprintf(fp, "%016llx ", (u64)self->ip); 669 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
609} 670}
610 671
611static struct sort_entry sort_dso = { 672static struct sort_entry sort_dso = {
612 .header = "Shared Object ", 673 .header = "Shared Object",
613 .cmp = sort__dso_cmp, 674 .cmp = sort__dso_cmp,
614 .print = sort__dso_print, 675 .print = sort__dso_print,
676 .width = &dsos__col_width,
615}; 677};
616 678
617/* --sort symbol */ 679/* --sort symbol */
@@ -631,18 +693,22 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
631} 693}
632 694
633static size_t 695static size_t
634sort__sym_print(FILE *fp, struct hist_entry *self) 696sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
635{ 697{
636 size_t ret = 0; 698 size_t ret = 0;
637 699
638 if (verbose) 700 if (verbose)
639 ret += fprintf(fp, "%#018llx ", (u64)self->ip); 701 ret += repsep_fprintf(fp, "%#018llx ", (u64)self->ip);
640 702
703 ret += repsep_fprintf(fp, "[%c] ", self->level);
641 if (self->sym) { 704 if (self->sym) {
642 ret += fprintf(fp, "[%c] %s", 705 ret += repsep_fprintf(fp, "%s", self->sym->name);
643 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 706
707 if (self->sym->module)
708 ret += repsep_fprintf(fp, "\t[%s]",
709 self->sym->module->name);
644 } else { 710 } else {
645 ret += fprintf(fp, "%#016llx", (u64)self->ip); 711 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
646 } 712 }
647 713
648 return ret; 714 return ret;
@@ -669,19 +735,19 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
669} 735}
670 736
671static size_t 737static size_t
672sort__parent_print(FILE *fp, struct hist_entry *self) 738sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
673{ 739{
674 size_t ret = 0; 740 return repsep_fprintf(fp, "%-*s", width,
675 741 self->parent ? self->parent->name : "[other]");
676 ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
677
678 return ret;
679} 742}
680 743
744static unsigned int parent_symbol__col_width;
745
681static struct sort_entry sort_parent = { 746static struct sort_entry sort_parent = {
682 .header = "Parent symbol ", 747 .header = "Parent symbol",
683 .cmp = sort__parent_cmp, 748 .cmp = sort__parent_cmp,
684 .print = sort__parent_print, 749 .print = sort__parent_print,
750 .width = &parent_symbol__col_width,
685}; 751};
686 752
687static int sort__need_collapse = 0; 753static int sort__need_collapse = 0;
@@ -705,7 +771,7 @@ static LIST_HEAD(hist_entry__sort_list);
705 771
706static int sort_dimension__add(char *tok) 772static int sort_dimension__add(char *tok)
707{ 773{
708 int i; 774 unsigned int i;
709 775
710 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 776 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
711 struct sort_dimension *sd = &sort_dimensions[i]; 777 struct sort_dimension *sd = &sort_dimensions[i];
@@ -775,8 +841,109 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
775 return cmp; 841 return cmp;
776} 842}
777 843
844static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
845{
846 int i;
847 size_t ret = 0;
848
849 ret += fprintf(fp, "%s", " ");
850
851 for (i = 0; i < depth; i++)
852 if (depth_mask & (1 << i))
853 ret += fprintf(fp, "| ");
854 else
855 ret += fprintf(fp, " ");
856
857 ret += fprintf(fp, "\n");
858
859 return ret;
860}
778static size_t 861static size_t
779callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples) 862ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
863 int depth_mask, int count, u64 total_samples,
864 int hits)
865{
866 int i;
867 size_t ret = 0;
868
869 ret += fprintf(fp, "%s", " ");
870 for (i = 0; i < depth; i++) {
871 if (depth_mask & (1 << i))
872 ret += fprintf(fp, "|");
873 else
874 ret += fprintf(fp, " ");
875 if (!count && i == depth - 1) {
876 double percent;
877
878 percent = hits * 100.0 / total_samples;
879 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
880 } else
881 ret += fprintf(fp, "%s", " ");
882 }
883 if (chain->sym)
884 ret += fprintf(fp, "%s\n", chain->sym->name);
885 else
886 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
887
888 return ret;
889}
890
891static size_t
892callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
893 u64 total_samples, int depth, int depth_mask)
894{
895 struct rb_node *node, *next;
896 struct callchain_node *child;
897 struct callchain_list *chain;
898 int new_depth_mask = depth_mask;
899 u64 new_total;
900 size_t ret = 0;
901 int i;
902
903 if (callchain_param.mode == CHAIN_GRAPH_REL)
904 new_total = self->cumul_hit;
905 else
906 new_total = total_samples;
907
908 node = rb_first(&self->rb_root);
909 while (node) {
910 child = rb_entry(node, struct callchain_node, rb_node);
911
912 /*
913 * The depth mask manages the output of pipes that show
914 * the depth. We don't want to keep the pipes of the current
915 * level for the last child of this depth
916 */
917 next = rb_next(node);
918 if (!next)
919 new_depth_mask &= ~(1 << (depth - 1));
920
921 /*
922 * But we keep the older depth mask for the line seperator
923 * to keep the level link until we reach the last child
924 */
925 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
926 i = 0;
927 list_for_each_entry(chain, &child->val, list) {
928 if (chain->ip >= PERF_CONTEXT_MAX)
929 continue;
930 ret += ipchain__fprintf_graph(fp, chain, depth,
931 new_depth_mask, i++,
932 new_total,
933 child->cumul_hit);
934 }
935 ret += callchain__fprintf_graph(fp, child, new_total,
936 depth + 1,
937 new_depth_mask | (1 << depth));
938 node = next;
939 }
940
941 return ret;
942}
943
944static size_t
945callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
946 u64 total_samples)
780{ 947{
781 struct callchain_list *chain; 948 struct callchain_list *chain;
782 size_t ret = 0; 949 size_t ret = 0;
@@ -784,11 +951,18 @@ callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
784 if (!self) 951 if (!self)
785 return 0; 952 return 0;
786 953
787 ret += callchain__fprintf(fp, self->parent, total_samples); 954 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
788 955
789 956
790 list_for_each_entry(chain, &self->val, list) 957 list_for_each_entry(chain, &self->val, list) {
791 ret += fprintf(fp, " %p\n", (void *)chain->ip); 958 if (chain->ip >= PERF_CONTEXT_MAX)
959 continue;
960 if (chain->sym)
961 ret += fprintf(fp, " %s\n", chain->sym->name);
962 else
963 ret += fprintf(fp, " %p\n",
964 (void *)(long)chain->ip);
965 }
792 966
793 return ret; 967 return ret;
794} 968}
@@ -807,8 +981,19 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
807 981
808 chain = rb_entry(rb_node, struct callchain_node, rb_node); 982 chain = rb_entry(rb_node, struct callchain_node, rb_node);
809 percent = chain->hit * 100.0 / total_samples; 983 percent = chain->hit * 100.0 / total_samples;
810 ret += fprintf(fp, " %6.2f%%\n", percent); 984 switch (callchain_param.mode) {
811 ret += callchain__fprintf(fp, chain, total_samples); 985 case CHAIN_FLAT:
986 ret += percent_color_fprintf(fp, " %6.2f%%\n",
987 percent);
988 ret += callchain__fprintf_flat(fp, chain, total_samples);
989 break;
990 case CHAIN_GRAPH_ABS: /* Falldown */
991 case CHAIN_GRAPH_REL:
992 ret += callchain__fprintf_graph(fp, chain,
993 total_samples, 1, 1);
994 default:
995 break;
996 }
812 ret += fprintf(fp, "\n"); 997 ret += fprintf(fp, "\n");
813 rb_node = rb_next(rb_node); 998 rb_node = rb_next(rb_node);
814 } 999 }
@@ -826,33 +1011,26 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
826 if (exclude_other && !self->parent) 1011 if (exclude_other && !self->parent)
827 return 0; 1012 return 0;
828 1013
829 if (total_samples) { 1014 if (total_samples)
830 double percent = self->count * 100.0 / total_samples; 1015 ret = percent_color_fprintf(fp,
831 char *color = PERF_COLOR_NORMAL; 1016 field_sep ? "%.2f" : " %6.2f%%",
832 1017 (self->count * 100.0) / total_samples);
833 /* 1018 else
834 * We color high-overhead entries in red, mid-overhead 1019 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
835 * entries in green - and keep the low overhead places
836 * normal:
837 */
838 if (percent >= 5.0) {
839 color = PERF_COLOR_RED;
840 } else {
841 if (percent >= 0.5)
842 color = PERF_COLOR_GREEN;
843 }
844 1020
845 ret = color_fprintf(fp, color, " %6.2f%%", 1021 if (show_nr_samples) {
846 (self->count * 100.0) / total_samples); 1022 if (field_sep)
847 } else 1023 fprintf(fp, "%c%lld", *field_sep, self->count);
848 ret = fprintf(fp, "%12Ld ", self->count); 1024 else
1025 fprintf(fp, "%11lld", self->count);
1026 }
849 1027
850 list_for_each_entry(se, &hist_entry__sort_list, list) { 1028 list_for_each_entry(se, &hist_entry__sort_list, list) {
851 if (exclude_other && (se == &sort_parent)) 1029 if (se->elide)
852 continue; 1030 continue;
853 1031
854 fprintf(fp, " "); 1032 fprintf(fp, "%s", field_sep ?: " ");
855 ret += se->print(fp, self); 1033 ret += se->print(fp, self, se->width ? *se->width : 0);
856 } 1034 }
857 1035
858 ret += fprintf(fp, "\n"); 1036 ret += fprintf(fp, "\n");
@@ -867,6 +1045,18 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
867 * 1045 *
868 */ 1046 */
869 1047
1048static void dso__calc_col_width(struct dso *self)
1049{
1050 if (!col_width_list_str && !field_sep &&
1051 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1052 unsigned int slen = strlen(self->name);
1053 if (slen > dsos__col_width)
1054 dsos__col_width = slen;
1055 }
1056
1057 self->slen_calculated = 1;
1058}
1059
870static struct symbol * 1060static struct symbol *
871resolve_symbol(struct thread *thread, struct map **mapp, 1061resolve_symbol(struct thread *thread, struct map **mapp,
872 struct dso **dsop, u64 *ipp) 1062 struct dso **dsop, u64 *ipp)
@@ -886,6 +1076,14 @@ resolve_symbol(struct thread *thread, struct map **mapp,
886 1076
887 map = thread__find_map(thread, ip); 1077 map = thread__find_map(thread, ip);
888 if (map != NULL) { 1078 if (map != NULL) {
1079 /*
1080 * We have to do this here as we may have a dso
1081 * with no symbol hit that has a name longer than
1082 * the ones with symbols sampled.
1083 */
1084 if (!sort_dso.elide && !map->dso->slen_calculated)
1085 dso__calc_col_width(map->dso);
1086
889 if (mapp) 1087 if (mapp)
890 *mapp = map; 1088 *mapp = map;
891got_map: 1089got_map:
@@ -923,6 +1121,58 @@ static int call__match(struct symbol *sym)
923 return 0; 1121 return 0;
924} 1122}
925 1123
1124static struct symbol **
1125resolve_callchain(struct thread *thread, struct map *map __used,
1126 struct ip_callchain *chain, struct hist_entry *entry)
1127{
1128 u64 context = PERF_CONTEXT_MAX;
1129 struct symbol **syms = NULL;
1130 unsigned int i;
1131
1132 if (callchain) {
1133 syms = calloc(chain->nr, sizeof(*syms));
1134 if (!syms) {
1135 fprintf(stderr, "Can't allocate memory for symbols\n");
1136 exit(-1);
1137 }
1138 }
1139
1140 for (i = 0; i < chain->nr; i++) {
1141 u64 ip = chain->ips[i];
1142 struct dso *dso = NULL;
1143 struct symbol *sym;
1144
1145 if (ip >= PERF_CONTEXT_MAX) {
1146 context = ip;
1147 continue;
1148 }
1149
1150 switch (context) {
1151 case PERF_CONTEXT_HV:
1152 dso = hypervisor_dso;
1153 break;
1154 case PERF_CONTEXT_KERNEL:
1155 dso = kernel_dso;
1156 break;
1157 default:
1158 break;
1159 }
1160
1161 sym = resolve_symbol(thread, NULL, &dso, &ip);
1162
1163 if (sym) {
1164 if (sort__has_parent && call__match(sym) &&
1165 !entry->parent)
1166 entry->parent = sym;
1167 if (!callchain)
1168 break;
1169 syms[i] = sym;
1170 }
1171 }
1172
1173 return syms;
1174}
1175
926/* 1176/*
927 * collect histogram counts 1177 * collect histogram counts
928 */ 1178 */
@@ -935,6 +1185,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
935 struct rb_node **p = &hist.rb_node; 1185 struct rb_node **p = &hist.rb_node;
936 struct rb_node *parent = NULL; 1186 struct rb_node *parent = NULL;
937 struct hist_entry *he; 1187 struct hist_entry *he;
1188 struct symbol **syms = NULL;
938 struct hist_entry entry = { 1189 struct hist_entry entry = {
939 .thread = thread, 1190 .thread = thread,
940 .map = map, 1191 .map = map,
@@ -948,36 +1199,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
948 }; 1199 };
949 int cmp; 1200 int cmp;
950 1201
951 if (sort__has_parent && chain) { 1202 if ((sort__has_parent || callchain) && chain)
952 u64 context = PERF_CONTEXT_MAX; 1203 syms = resolve_callchain(thread, map, chain, &entry);
953 int i;
954
955 for (i = 0; i < chain->nr; i++) {
956 u64 ip = chain->ips[i];
957 struct dso *dso = NULL;
958 struct symbol *sym;
959
960 if (ip >= PERF_CONTEXT_MAX) {
961 context = ip;
962 continue;
963 }
964
965 switch (context) {
966 case PERF_CONTEXT_KERNEL:
967 dso = kernel_dso;
968 break;
969 default:
970 break;
971 }
972
973 sym = resolve_symbol(thread, NULL, &dso, &ip);
974
975 if (sym && call__match(sym)) {
976 entry.parent = sym;
977 break;
978 }
979 }
980 }
981 1204
982 while (*p != NULL) { 1205 while (*p != NULL) {
983 parent = *p; 1206 parent = *p;
@@ -987,8 +1210,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
987 1210
988 if (!cmp) { 1211 if (!cmp) {
989 he->count += count; 1212 he->count += count;
990 if (callchain) 1213 if (callchain) {
991 append_chain(&he->callchain, chain); 1214 append_chain(&he->callchain, chain, syms);
1215 free(syms);
1216 }
992 return 0; 1217 return 0;
993 } 1218 }
994 1219
@@ -1004,7 +1229,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
1004 *he = entry; 1229 *he = entry;
1005 if (callchain) { 1230 if (callchain) {
1006 callchain_init(&he->callchain); 1231 callchain_init(&he->callchain);
1007 append_chain(&he->callchain, chain); 1232 append_chain(&he->callchain, chain, syms);
1233 free(syms);
1008 } 1234 }
1009 rb_link_node(&he->rb_node, parent, p); 1235 rb_link_node(&he->rb_node, parent, p);
1010 rb_insert_color(&he->rb_node, &hist); 1236 rb_insert_color(&he->rb_node, &hist);
@@ -1076,14 +1302,15 @@ static void collapse__resort(void)
1076 1302
1077static struct rb_root output_hists; 1303static struct rb_root output_hists;
1078 1304
1079static void output__insert_entry(struct hist_entry *he) 1305static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
1080{ 1306{
1081 struct rb_node **p = &output_hists.rb_node; 1307 struct rb_node **p = &output_hists.rb_node;
1082 struct rb_node *parent = NULL; 1308 struct rb_node *parent = NULL;
1083 struct hist_entry *iter; 1309 struct hist_entry *iter;
1084 1310
1085 if (callchain) 1311 if (callchain)
1086 sort_chain_to_rbtree(&he->sorted_chain, &he->callchain); 1312 callchain_param.sort(&he->sorted_chain, &he->callchain,
1313 min_callchain_hits, &callchain_param);
1087 1314
1088 while (*p != NULL) { 1315 while (*p != NULL) {
1089 parent = *p; 1316 parent = *p;
@@ -1099,11 +1326,14 @@ static void output__insert_entry(struct hist_entry *he)
1099 rb_insert_color(&he->rb_node, &output_hists); 1326 rb_insert_color(&he->rb_node, &output_hists);
1100} 1327}
1101 1328
1102static void output__resort(void) 1329static void output__resort(u64 total_samples)
1103{ 1330{
1104 struct rb_node *next; 1331 struct rb_node *next;
1105 struct hist_entry *n; 1332 struct hist_entry *n;
1106 struct rb_root *tree = &hist; 1333 struct rb_root *tree = &hist;
1334 u64 min_callchain_hits;
1335
1336 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
1107 1337
1108 if (sort__need_collapse) 1338 if (sort__need_collapse)
1109 tree = &collapse_hists; 1339 tree = &collapse_hists;
@@ -1115,7 +1345,7 @@ static void output__resort(void)
1115 next = rb_next(&n->rb_node); 1345 next = rb_next(&n->rb_node);
1116 1346
1117 rb_erase(&n->rb_node, tree); 1347 rb_erase(&n->rb_node, tree);
1118 output__insert_entry(n); 1348 output__insert_entry(n, min_callchain_hits);
1119 } 1349 }
1120} 1350}
1121 1351
@@ -1125,35 +1355,67 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1125 struct sort_entry *se; 1355 struct sort_entry *se;
1126 struct rb_node *nd; 1356 struct rb_node *nd;
1127 size_t ret = 0; 1357 size_t ret = 0;
1358 unsigned int width;
1359 char *col_width = col_width_list_str;
1128 1360
1129 fprintf(fp, "\n"); 1361 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1130 fprintf(fp, "#\n");
1131 fprintf(fp, "# (%Ld samples)\n", (u64)total_samples);
1132 fprintf(fp, "#\n"); 1362 fprintf(fp, "#\n");
1133 1363
1134 fprintf(fp, "# Overhead"); 1364 fprintf(fp, "# Overhead");
1365 if (show_nr_samples) {
1366 if (field_sep)
1367 fprintf(fp, "%cSamples", *field_sep);
1368 else
1369 fputs(" Samples ", fp);
1370 }
1135 list_for_each_entry(se, &hist_entry__sort_list, list) { 1371 list_for_each_entry(se, &hist_entry__sort_list, list) {
1136 if (exclude_other && (se == &sort_parent)) 1372 if (se->elide)
1373 continue;
1374 if (field_sep) {
1375 fprintf(fp, "%c%s", *field_sep, se->header);
1137 continue; 1376 continue;
1138 fprintf(fp, " %s", se->header); 1377 }
1378 width = strlen(se->header);
1379 if (se->width) {
1380 if (col_width_list_str) {
1381 if (col_width) {
1382 *se->width = atoi(col_width);
1383 col_width = strchr(col_width, ',');
1384 if (col_width)
1385 ++col_width;
1386 }
1387 }
1388 width = *se->width = max(*se->width, width);
1389 }
1390 fprintf(fp, " %*s", width, se->header);
1139 } 1391 }
1140 fprintf(fp, "\n"); 1392 fprintf(fp, "\n");
1141 1393
1394 if (field_sep)
1395 goto print_entries;
1396
1142 fprintf(fp, "# ........"); 1397 fprintf(fp, "# ........");
1398 if (show_nr_samples)
1399 fprintf(fp, " ..........");
1143 list_for_each_entry(se, &hist_entry__sort_list, list) { 1400 list_for_each_entry(se, &hist_entry__sort_list, list) {
1144 int i; 1401 unsigned int i;
1145 1402
1146 if (exclude_other && (se == &sort_parent)) 1403 if (se->elide)
1147 continue; 1404 continue;
1148 1405
1149 fprintf(fp, " "); 1406 fprintf(fp, " ");
1150 for (i = 0; i < strlen(se->header); i++) 1407 if (se->width)
1408 width = *se->width;
1409 else
1410 width = strlen(se->header);
1411 for (i = 0; i < width; i++)
1151 fprintf(fp, "."); 1412 fprintf(fp, ".");
1152 } 1413 }
1153 fprintf(fp, "\n"); 1414 fprintf(fp, "\n");
1154 1415
1155 fprintf(fp, "#\n"); 1416 fprintf(fp, "#\n");
1156 1417
1418print_entries:
1157 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 1419 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1158 pos = rb_entry(nd, struct hist_entry, rb_node); 1420 pos = rb_entry(nd, struct hist_entry, rb_node);
1159 ret += hist_entry__fprintf(fp, pos, total_samples); 1421 ret += hist_entry__fprintf(fp, pos, total_samples);
@@ -1162,7 +1424,7 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1162 if (sort_order == default_sort_order && 1424 if (sort_order == default_sort_order &&
1163 parent_pattern == default_parent_pattern) { 1425 parent_pattern == default_parent_pattern) {
1164 fprintf(fp, "#\n"); 1426 fprintf(fp, "#\n");
1165 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); 1427 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1166 fprintf(fp, "#\n"); 1428 fprintf(fp, "#\n");
1167 } 1429 }
1168 fprintf(fp, "\n"); 1430 fprintf(fp, "\n");
@@ -1213,6 +1475,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1213 struct map *map = NULL; 1475 struct map *map = NULL;
1214 void *more_data = event->ip.__more_data; 1476 void *more_data = event->ip.__more_data;
1215 struct ip_callchain *chain = NULL; 1477 struct ip_callchain *chain = NULL;
1478 int cpumode;
1216 1479
1217 if (sample_type & PERF_SAMPLE_PERIOD) { 1480 if (sample_type & PERF_SAMPLE_PERIOD) {
1218 period = *(u64 *)more_data; 1481 period = *(u64 *)more_data;
@@ -1228,7 +1491,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1228 (long long)period); 1491 (long long)period);
1229 1492
1230 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 1493 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1231 int i; 1494 unsigned int i;
1232 1495
1233 chain = (void *)more_data; 1496 chain = (void *)more_data;
1234 1497
@@ -1256,7 +1519,9 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1256 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 1519 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1257 return 0; 1520 return 0;
1258 1521
1259 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 1522 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
1523
1524 if (cpumode == PERF_EVENT_MISC_KERNEL) {
1260 show = SHOW_KERNEL; 1525 show = SHOW_KERNEL;
1261 level = 'k'; 1526 level = 'k';
1262 1527
@@ -1264,7 +1529,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1264 1529
1265 dprintf(" ...... dso: %s\n", dso->name); 1530 dprintf(" ...... dso: %s\n", dso->name);
1266 1531
1267 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 1532 } else if (cpumode == PERF_EVENT_MISC_USER) {
1268 1533
1269 show = SHOW_USER; 1534 show = SHOW_USER;
1270 level = '.'; 1535 level = '.';
@@ -1272,6 +1537,9 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1272 } else { 1537 } else {
1273 show = SHOW_HV; 1538 show = SHOW_HV;
1274 level = 'H'; 1539 level = 'H';
1540
1541 dso = hypervisor_dso;
1542
1275 dprintf(" ...... dso: [hypervisor]\n"); 1543 dprintf(" ...... dso: [hypervisor]\n");
1276 } 1544 }
1277 1545
@@ -1341,15 +1609,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1341} 1609}
1342 1610
1343static int 1611static int
1344process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1612process_task_event(event_t *event, unsigned long offset, unsigned long head)
1345{ 1613{
1346 struct thread *thread = threads__findnew(event->fork.pid); 1614 struct thread *thread = threads__findnew(event->fork.pid);
1347 struct thread *parent = threads__findnew(event->fork.ppid); 1615 struct thread *parent = threads__findnew(event->fork.ppid);
1348 1616
1349 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1617 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1350 (void *)(offset + head), 1618 (void *)(offset + head),
1351 (void *)(long)(event->header.size), 1619 (void *)(long)(event->header.size),
1352 event->fork.pid, event->fork.ppid); 1620 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1621 event->fork.pid, event->fork.tid,
1622 event->fork.ppid, event->fork.ptid);
1623
1624 /*
1625 * A thread clone will have the same PID for both
1626 * parent and child.
1627 */
1628 if (thread == parent)
1629 return 0;
1630
1631 if (event->header.type == PERF_EVENT_EXIT)
1632 return 0;
1353 1633
1354 if (!thread || !parent || thread__fork(thread, parent)) { 1634 if (!thread || !parent || thread__fork(thread, parent)) {
1355 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1635 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1361,19 +1641,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1361} 1641}
1362 1642
1363static int 1643static int
1364process_period_event(event_t *event, unsigned long offset, unsigned long head)
1365{
1366 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1367 (void *)(offset + head),
1368 (void *)(long)(event->header.size),
1369 event->period.time,
1370 event->period.id,
1371 event->period.sample_period);
1372
1373 return 0;
1374}
1375
1376static int
1377process_lost_event(event_t *event, unsigned long offset, unsigned long head) 1644process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1378{ 1645{
1379 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", 1646 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
@@ -1452,10 +1719,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1452 return process_comm_event(event, offset, head); 1719 return process_comm_event(event, offset, head);
1453 1720
1454 case PERF_EVENT_FORK: 1721 case PERF_EVENT_FORK:
1455 return process_fork_event(event, offset, head); 1722 case PERF_EVENT_EXIT:
1456 1723 return process_task_event(event, offset, head);
1457 case PERF_EVENT_PERIOD:
1458 return process_period_event(event, offset, head);
1459 1724
1460 case PERF_EVENT_LOST: 1725 case PERF_EVENT_LOST:
1461 return process_lost_event(event, offset, head); 1726 return process_lost_event(event, offset, head);
@@ -1534,9 +1799,19 @@ static int __cmd_report(void)
1534 1799
1535 sample_type = perf_header__sample_type(); 1800 sample_type = perf_header__sample_type();
1536 1801
1537 if (sort__has_parent && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 1802 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1538 fprintf(stderr, "selected --sort parent, but no callchain data\n"); 1803 if (sort__has_parent) {
1539 exit(-1); 1804 fprintf(stderr, "selected --sort parent, but no"
1805 " callchain data. Did you call"
1806 " perf record without -g?\n");
1807 exit(-1);
1808 }
1809 if (callchain) {
1810 fprintf(stderr, "selected -c but no callchain data."
1811 " Did you call perf record without"
1812 " -g?\n");
1813 exit(-1);
1814 }
1540 } 1815 }
1541 1816
1542 if (load_kernel() < 0) { 1817 if (load_kernel() < 0) {
@@ -1619,7 +1894,7 @@ more:
1619 if (offset + head >= header->data_offset + header->data_size) 1894 if (offset + head >= header->data_offset + header->data_size)
1620 goto done; 1895 goto done;
1621 1896
1622 if (offset + head < stat.st_size) 1897 if (offset + head < (unsigned long)stat.st_size)
1623 goto more; 1898 goto more;
1624 1899
1625done: 1900done:
@@ -1643,12 +1918,58 @@ done:
1643 dsos__fprintf(stdout); 1918 dsos__fprintf(stdout);
1644 1919
1645 collapse__resort(); 1920 collapse__resort();
1646 output__resort(); 1921 output__resort(total);
1647 output__fprintf(stdout, total); 1922 output__fprintf(stdout, total);
1648 1923
1649 return rc; 1924 return rc;
1650} 1925}
1651 1926
1927static int
1928parse_callchain_opt(const struct option *opt __used, const char *arg,
1929 int unset __used)
1930{
1931 char *tok;
1932 char *endptr;
1933
1934 callchain = 1;
1935
1936 if (!arg)
1937 return 0;
1938
1939 tok = strtok((char *)arg, ",");
1940 if (!tok)
1941 return -1;
1942
1943 /* get the output mode */
1944 if (!strncmp(tok, "graph", strlen(arg)))
1945 callchain_param.mode = CHAIN_GRAPH_ABS;
1946
1947 else if (!strncmp(tok, "flat", strlen(arg)))
1948 callchain_param.mode = CHAIN_FLAT;
1949
1950 else if (!strncmp(tok, "fractal", strlen(arg)))
1951 callchain_param.mode = CHAIN_GRAPH_REL;
1952
1953 else
1954 return -1;
1955
1956 /* get the min percentage */
1957 tok = strtok(NULL, ",");
1958 if (!tok)
1959 goto setup;
1960
1961 callchain_param.min_percent = strtod(tok, &endptr);
1962 if (tok == endptr)
1963 return -1;
1964
1965setup:
1966 if (register_callchain_param(&callchain_param) < 0) {
1967 fprintf(stderr, "Can't register callchain params\n");
1968 return -1;
1969 }
1970 return 0;
1971}
1972
1652static const char * const report_usage[] = { 1973static const char * const report_usage[] = {
1653 "perf report [<options>] <command>", 1974 "perf report [<options>] <command>",
1654 NULL 1975 NULL
@@ -1662,6 +1983,10 @@ static const struct option options[] = {
1662 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1983 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1663 "dump raw trace in ASCII"), 1984 "dump raw trace in ASCII"),
1664 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1985 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1986 OPT_BOOLEAN('m', "modules", &modules,
1987 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1988 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1989 "Show a column with the number of samples"),
1665 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1990 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1666 "sort by key(s): pid, comm, dso, symbol, parent"), 1991 "sort by key(s): pid, comm, dso, symbol, parent"),
1667 OPT_BOOLEAN('P', "full-paths", &full_paths, 1992 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1670,13 +1995,21 @@ static const struct option options[] = {
1670 "regex filter to identify parent, see: '--sort parent'"), 1995 "regex filter to identify parent, see: '--sort parent'"),
1671 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 1996 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1672 "Only display entries with parent-match"), 1997 "Only display entries with parent-match"),
1673 OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"), 1998 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1999 "Display callchains using output_type and min percent threshold. "
2000 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1674 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 2001 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1675 "only consider symbols in these dsos"), 2002 "only consider symbols in these dsos"),
1676 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 2003 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1677 "only consider symbols in these comms"), 2004 "only consider symbols in these comms"),
1678 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 2005 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1679 "only consider these symbols"), 2006 "only consider these symbols"),
2007 OPT_STRING('w', "column-widths", &col_width_list_str,
2008 "width[,width...]",
2009 "don't try to adjust column width, use these fixed values"),
2010 OPT_STRING('t', "field-separator", &field_sep, "separator",
2011 "separator for columns, no spaces will be added between "
2012 "columns '.' is reserved."),
1680 OPT_END() 2013 OPT_END()
1681}; 2014};
1682 2015
@@ -1696,7 +2029,8 @@ static void setup_sorting(void)
1696} 2029}
1697 2030
1698static void setup_list(struct strlist **list, const char *list_str, 2031static void setup_list(struct strlist **list, const char *list_str,
1699 const char *list_name) 2032 struct sort_entry *se, const char *list_name,
2033 FILE *fp)
1700{ 2034{
1701 if (list_str) { 2035 if (list_str) {
1702 *list = strlist__new(true, list_str); 2036 *list = strlist__new(true, list_str);
@@ -1705,10 +2039,15 @@ static void setup_list(struct strlist **list, const char *list_str,
1705 list_name); 2039 list_name);
1706 exit(129); 2040 exit(129);
1707 } 2041 }
2042 if (strlist__nr_entries(*list) == 1) {
2043 fprintf(fp, "# %s: %s\n", list_name,
2044 strlist__entry(*list, 0)->s);
2045 se->elide = true;
2046 }
1708 } 2047 }
1709} 2048}
1710 2049
1711int cmd_report(int argc, const char **argv, const char *prefix) 2050int cmd_report(int argc, const char **argv, const char *prefix __used)
1712{ 2051{
1713 symbol__init(); 2052 symbol__init();
1714 2053
@@ -1718,9 +2057,10 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1718 2057
1719 setup_sorting(); 2058 setup_sorting();
1720 2059
1721 if (parent_pattern != default_parent_pattern) 2060 if (parent_pattern != default_parent_pattern) {
1722 sort_dimension__add("parent"); 2061 sort_dimension__add("parent");
1723 else 2062 sort_parent.elide = 1;
2063 } else
1724 exclude_other = 0; 2064 exclude_other = 0;
1725 2065
1726 /* 2066 /*
@@ -1729,11 +2069,17 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1729 if (argc) 2069 if (argc)
1730 usage_with_options(report_usage, options); 2070 usage_with_options(report_usage, options);
1731 2071
1732 setup_list(&dso_list, dso_list_str, "dso");
1733 setup_list(&comm_list, comm_list_str, "comm");
1734 setup_list(&sym_list, sym_list_str, "symbol");
1735
1736 setup_pager(); 2072 setup_pager();
1737 2073
2074 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2075 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2076 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2077
2078 if (field_sep && *field_sep == '.') {
2079 fputs("'.' is the only non valid --field-separator argument\n",
2080 stderr);
2081 exit(129);
2082 }
2083
1738 return __cmd_report(); 2084 return __cmd_report();
1739} 2085}