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.c751
1 files changed, 589 insertions, 162 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 135b7837e6bf..b53a60fc12de 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_REL,
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 {
@@ -104,7 +112,9 @@ struct read_event {
104 struct perf_event_header header; 112 struct perf_event_header header;
105 u32 pid,tid; 113 u32 pid,tid;
106 u64 value; 114 u64 value;
107 u64 format[3]; 115 u64 time_enabled;
116 u64 time_running;
117 u64 id;
108}; 118};
109 119
110typedef union event_union { 120typedef union event_union {
@@ -113,14 +123,41 @@ typedef union event_union {
113 struct mmap_event mmap; 123 struct mmap_event mmap;
114 struct comm_event comm; 124 struct comm_event comm;
115 struct fork_event fork; 125 struct fork_event fork;
116 struct period_event period;
117 struct lost_event lost; 126 struct lost_event lost;
118 struct read_event read; 127 struct read_event read;
119} event_t; 128} event_t;
120 129
130static int repsep_fprintf(FILE *fp, const char *fmt, ...)
131{
132 int n;
133 va_list ap;
134
135 va_start(ap, fmt);
136 if (!field_sep)
137 n = vfprintf(fp, fmt, ap);
138 else {
139 char *bf = NULL;
140 n = vasprintf(&bf, fmt, ap);
141 if (n > 0) {
142 char *sep = bf;
143 while (1) {
144 sep = strchr(sep, *field_sep);
145 if (sep == NULL)
146 break;
147 *sep = '.';
148 }
149 }
150 fputs(bf, fp);
151 free(bf);
152 }
153 va_end(ap);
154 return n;
155}
156
121static LIST_HEAD(dsos); 157static LIST_HEAD(dsos);
122static struct dso *kernel_dso; 158static struct dso *kernel_dso;
123static struct dso *vdso; 159static struct dso *vdso;
160static struct dso *hypervisor_dso;
124 161
125static void dsos__add(struct dso *dso) 162static void dsos__add(struct dso *dso)
126{ 163{
@@ -176,7 +213,7 @@ static void dsos__fprintf(FILE *fp)
176 213
177static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 214static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
178{ 215{
179 return dso__find_symbol(kernel_dso, ip); 216 return dso__find_symbol(dso, ip);
180} 217}
181 218
182static int load_kernel(void) 219static int load_kernel(void)
@@ -187,8 +224,8 @@ static int load_kernel(void)
187 if (!kernel_dso) 224 if (!kernel_dso)
188 return -1; 225 return -1;
189 226
190 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); 227 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
191 if (err) { 228 if (err <= 0) {
192 dso__delete(kernel_dso); 229 dso__delete(kernel_dso);
193 kernel_dso = NULL; 230 kernel_dso = NULL;
194 } else 231 } else
@@ -202,6 +239,11 @@ static int load_kernel(void)
202 239
203 dsos__add(vdso); 240 dsos__add(vdso);
204 241
242 hypervisor_dso = dso__new("[hypervisor]", 0);
243 if (!hypervisor_dso)
244 return -1;
245 dsos__add(hypervisor_dso);
246
205 return err; 247 return err;
206} 248}
207 249
@@ -213,7 +255,7 @@ static int strcommon(const char *pathname)
213{ 255{
214 int n = 0; 256 int n = 0;
215 257
216 while (pathname[n] == cwd[n] && n < cwdlen) 258 while (n < cwdlen && pathname[n] == cwd[n])
217 ++n; 259 ++n;
218 260
219 return n; 261 return n;
@@ -233,7 +275,7 @@ static u64 map__map_ip(struct map *map, u64 ip)
233 return ip - map->start + map->pgoff; 275 return ip - map->start + map->pgoff;
234} 276}
235 277
236static u64 vdso__map_ip(struct map *map, u64 ip) 278static u64 vdso__map_ip(struct map *map __used, u64 ip)
237{ 279{
238 return ip; 280 return ip;
239} 281}
@@ -343,12 +385,28 @@ static struct thread *thread__new(pid_t pid)
343 return self; 385 return self;
344} 386}
345 387
388static unsigned int dsos__col_width,
389 comms__col_width,
390 threads__col_width;
391
346static int thread__set_comm(struct thread *self, const char *comm) 392static int thread__set_comm(struct thread *self, const char *comm)
347{ 393{
348 if (self->comm) 394 if (self->comm)
349 free(self->comm); 395 free(self->comm);
350 self->comm = strdup(comm); 396 self->comm = strdup(comm);
351 return self->comm ? 0 : -ENOMEM; 397 if (!self->comm)
398 return -ENOMEM;
399
400 if (!col_width_list_str && !field_sep &&
401 (!comm_list || strlist__has_entry(comm_list, comm))) {
402 unsigned int slen = strlen(comm);
403 if (slen > comms__col_width) {
404 comms__col_width = slen;
405 threads__col_width = slen + 6;
406 }
407 }
408
409 return 0;
352} 410}
353 411
354static size_t thread__fprintf(struct thread *self, FILE *fp) 412static size_t thread__fprintf(struct thread *self, FILE *fp)
@@ -519,7 +577,9 @@ struct sort_entry {
519 577
520 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 578 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
521 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 579 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
522 size_t (*print)(FILE *fp, struct hist_entry *); 580 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
581 unsigned int *width;
582 bool elide;
523}; 583};
524 584
525static int64_t cmp_null(void *l, void *r) 585static int64_t cmp_null(void *l, void *r)
@@ -541,15 +601,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
541} 601}
542 602
543static size_t 603static size_t
544sort__thread_print(FILE *fp, struct hist_entry *self) 604sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
545{ 605{
546 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 606 return repsep_fprintf(fp, "%*s:%5d", width - 6,
607 self->thread->comm ?: "", self->thread->pid);
547} 608}
548 609
549static struct sort_entry sort_thread = { 610static struct sort_entry sort_thread = {
550 .header = " Command: Pid", 611 .header = "Command: Pid",
551 .cmp = sort__thread_cmp, 612 .cmp = sort__thread_cmp,
552 .print = sort__thread_print, 613 .print = sort__thread_print,
614 .width = &threads__col_width,
553}; 615};
554 616
555/* --sort comm */ 617/* --sort comm */
@@ -573,16 +635,17 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
573} 635}
574 636
575static size_t 637static size_t
576sort__comm_print(FILE *fp, struct hist_entry *self) 638sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
577{ 639{
578 return fprintf(fp, "%16s", self->thread->comm); 640 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
579} 641}
580 642
581static struct sort_entry sort_comm = { 643static struct sort_entry sort_comm = {
582 .header = " Command", 644 .header = "Command",
583 .cmp = sort__comm_cmp, 645 .cmp = sort__comm_cmp,
584 .collapse = sort__comm_collapse, 646 .collapse = sort__comm_collapse,
585 .print = sort__comm_print, 647 .print = sort__comm_print,
648 .width = &comms__col_width,
586}; 649};
587 650
588/* --sort dso */ 651/* --sort dso */
@@ -600,18 +663,19 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
600} 663}
601 664
602static size_t 665static size_t
603sort__dso_print(FILE *fp, struct hist_entry *self) 666sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
604{ 667{
605 if (self->dso) 668 if (self->dso)
606 return fprintf(fp, "%-25s", self->dso->name); 669 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
607 670
608 return fprintf(fp, "%016llx ", (u64)self->ip); 671 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
609} 672}
610 673
611static struct sort_entry sort_dso = { 674static struct sort_entry sort_dso = {
612 .header = "Shared Object ", 675 .header = "Shared Object",
613 .cmp = sort__dso_cmp, 676 .cmp = sort__dso_cmp,
614 .print = sort__dso_print, 677 .print = sort__dso_print,
678 .width = &dsos__col_width,
615}; 679};
616 680
617/* --sort symbol */ 681/* --sort symbol */
@@ -631,18 +695,23 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
631} 695}
632 696
633static size_t 697static size_t
634sort__sym_print(FILE *fp, struct hist_entry *self) 698sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
635{ 699{
636 size_t ret = 0; 700 size_t ret = 0;
637 701
638 if (verbose) 702 if (verbose)
639 ret += fprintf(fp, "%#018llx ", (u64)self->ip); 703 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
704 dso__symtab_origin(self->dso));
640 705
706 ret += repsep_fprintf(fp, "[%c] ", self->level);
641 if (self->sym) { 707 if (self->sym) {
642 ret += fprintf(fp, "[%c] %s", 708 ret += repsep_fprintf(fp, "%s", self->sym->name);
643 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 709
710 if (self->sym->module)
711 ret += repsep_fprintf(fp, "\t[%s]",
712 self->sym->module->name);
644 } else { 713 } else {
645 ret += fprintf(fp, "%#016llx", (u64)self->ip); 714 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
646 } 715 }
647 716
648 return ret; 717 return ret;
@@ -669,19 +738,19 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
669} 738}
670 739
671static size_t 740static size_t
672sort__parent_print(FILE *fp, struct hist_entry *self) 741sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
673{ 742{
674 size_t ret = 0; 743 return repsep_fprintf(fp, "%-*s", width,
675 744 self->parent ? self->parent->name : "[other]");
676 ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
677
678 return ret;
679} 745}
680 746
747static unsigned int parent_symbol__col_width;
748
681static struct sort_entry sort_parent = { 749static struct sort_entry sort_parent = {
682 .header = "Parent symbol ", 750 .header = "Parent symbol",
683 .cmp = sort__parent_cmp, 751 .cmp = sort__parent_cmp,
684 .print = sort__parent_print, 752 .print = sort__parent_print,
753 .width = &parent_symbol__col_width,
685}; 754};
686 755
687static int sort__need_collapse = 0; 756static int sort__need_collapse = 0;
@@ -705,7 +774,7 @@ static LIST_HEAD(hist_entry__sort_list);
705 774
706static int sort_dimension__add(char *tok) 775static int sort_dimension__add(char *tok)
707{ 776{
708 int i; 777 unsigned int i;
709 778
710 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 779 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
711 struct sort_dimension *sd = &sort_dimensions[i]; 780 struct sort_dimension *sd = &sort_dimensions[i];
@@ -775,8 +844,146 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
775 return cmp; 844 return cmp;
776} 845}
777 846
847static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
848{
849 int i;
850 size_t ret = 0;
851
852 ret += fprintf(fp, "%s", " ");
853
854 for (i = 0; i < depth; i++)
855 if (depth_mask & (1 << i))
856 ret += fprintf(fp, "| ");
857 else
858 ret += fprintf(fp, " ");
859
860 ret += fprintf(fp, "\n");
861
862 return ret;
863}
778static size_t 864static size_t
779callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples) 865ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
866 int depth_mask, int count, u64 total_samples,
867 int hits)
868{
869 int i;
870 size_t ret = 0;
871
872 ret += fprintf(fp, "%s", " ");
873 for (i = 0; i < depth; i++) {
874 if (depth_mask & (1 << i))
875 ret += fprintf(fp, "|");
876 else
877 ret += fprintf(fp, " ");
878 if (!count && i == depth - 1) {
879 double percent;
880
881 percent = hits * 100.0 / total_samples;
882 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
883 } else
884 ret += fprintf(fp, "%s", " ");
885 }
886 if (chain->sym)
887 ret += fprintf(fp, "%s\n", chain->sym->name);
888 else
889 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
890
891 return ret;
892}
893
894static struct symbol *rem_sq_bracket;
895static struct callchain_list rem_hits;
896
897static void init_rem_hits(void)
898{
899 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
900 if (!rem_sq_bracket) {
901 fprintf(stderr, "Not enough memory to display remaining hits\n");
902 return;
903 }
904
905 strcpy(rem_sq_bracket->name, "[...]");
906 rem_hits.sym = rem_sq_bracket;
907}
908
909static size_t
910callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
911 u64 total_samples, int depth, int depth_mask)
912{
913 struct rb_node *node, *next;
914 struct callchain_node *child;
915 struct callchain_list *chain;
916 int new_depth_mask = depth_mask;
917 u64 new_total;
918 u64 remaining;
919 size_t ret = 0;
920 int i;
921
922 if (callchain_param.mode == CHAIN_GRAPH_REL)
923 new_total = self->children_hit;
924 else
925 new_total = total_samples;
926
927 remaining = new_total;
928
929 node = rb_first(&self->rb_root);
930 while (node) {
931 u64 cumul;
932
933 child = rb_entry(node, struct callchain_node, rb_node);
934 cumul = cumul_hits(child);
935 remaining -= cumul;
936
937 /*
938 * The depth mask manages the output of pipes that show
939 * the depth. We don't want to keep the pipes of the current
940 * level for the last child of this depth.
941 * Except if we have remaining filtered hits. They will
942 * supersede the last child
943 */
944 next = rb_next(node);
945 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
946 new_depth_mask &= ~(1 << (depth - 1));
947
948 /*
949 * But we keep the older depth mask for the line seperator
950 * to keep the level link until we reach the last child
951 */
952 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
953 i = 0;
954 list_for_each_entry(chain, &child->val, list) {
955 if (chain->ip >= PERF_CONTEXT_MAX)
956 continue;
957 ret += ipchain__fprintf_graph(fp, chain, depth,
958 new_depth_mask, i++,
959 new_total,
960 cumul);
961 }
962 ret += callchain__fprintf_graph(fp, child, new_total,
963 depth + 1,
964 new_depth_mask | (1 << depth));
965 node = next;
966 }
967
968 if (callchain_param.mode == CHAIN_GRAPH_REL &&
969 remaining && remaining != new_total) {
970
971 if (!rem_sq_bracket)
972 return ret;
973
974 new_depth_mask &= ~(1 << (depth - 1));
975
976 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
977 new_depth_mask, 0, new_total,
978 remaining);
979 }
980
981 return ret;
982}
983
984static size_t
985callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
986 u64 total_samples)
780{ 987{
781 struct callchain_list *chain; 988 struct callchain_list *chain;
782 size_t ret = 0; 989 size_t ret = 0;
@@ -784,11 +991,18 @@ callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
784 if (!self) 991 if (!self)
785 return 0; 992 return 0;
786 993
787 ret += callchain__fprintf(fp, self->parent, total_samples); 994 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
788 995
789 996
790 list_for_each_entry(chain, &self->val, list) 997 list_for_each_entry(chain, &self->val, list) {
791 ret += fprintf(fp, " %p\n", (void *)chain->ip); 998 if (chain->ip >= PERF_CONTEXT_MAX)
999 continue;
1000 if (chain->sym)
1001 ret += fprintf(fp, " %s\n", chain->sym->name);
1002 else
1003 ret += fprintf(fp, " %p\n",
1004 (void *)(long)chain->ip);
1005 }
792 1006
793 return ret; 1007 return ret;
794} 1008}
@@ -807,8 +1021,19 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
807 1021
808 chain = rb_entry(rb_node, struct callchain_node, rb_node); 1022 chain = rb_entry(rb_node, struct callchain_node, rb_node);
809 percent = chain->hit * 100.0 / total_samples; 1023 percent = chain->hit * 100.0 / total_samples;
810 ret += fprintf(fp, " %6.2f%%\n", percent); 1024 switch (callchain_param.mode) {
811 ret += callchain__fprintf(fp, chain, total_samples); 1025 case CHAIN_FLAT:
1026 ret += percent_color_fprintf(fp, " %6.2f%%\n",
1027 percent);
1028 ret += callchain__fprintf_flat(fp, chain, total_samples);
1029 break;
1030 case CHAIN_GRAPH_ABS: /* Falldown */
1031 case CHAIN_GRAPH_REL:
1032 ret += callchain__fprintf_graph(fp, chain,
1033 total_samples, 1, 1);
1034 default:
1035 break;
1036 }
812 ret += fprintf(fp, "\n"); 1037 ret += fprintf(fp, "\n");
813 rb_node = rb_next(rb_node); 1038 rb_node = rb_next(rb_node);
814 } 1039 }
@@ -826,33 +1051,26 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
826 if (exclude_other && !self->parent) 1051 if (exclude_other && !self->parent)
827 return 0; 1052 return 0;
828 1053
829 if (total_samples) { 1054 if (total_samples)
830 double percent = self->count * 100.0 / total_samples; 1055 ret = percent_color_fprintf(fp,
831 char *color = PERF_COLOR_NORMAL; 1056 field_sep ? "%.2f" : " %6.2f%%",
832 1057 (self->count * 100.0) / total_samples);
833 /* 1058 else
834 * We color high-overhead entries in red, mid-overhead 1059 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 1060
845 ret = color_fprintf(fp, color, " %6.2f%%", 1061 if (show_nr_samples) {
846 (self->count * 100.0) / total_samples); 1062 if (field_sep)
847 } else 1063 fprintf(fp, "%c%lld", *field_sep, self->count);
848 ret = fprintf(fp, "%12Ld ", self->count); 1064 else
1065 fprintf(fp, "%11lld", self->count);
1066 }
849 1067
850 list_for_each_entry(se, &hist_entry__sort_list, list) { 1068 list_for_each_entry(se, &hist_entry__sort_list, list) {
851 if (exclude_other && (se == &sort_parent)) 1069 if (se->elide)
852 continue; 1070 continue;
853 1071
854 fprintf(fp, " "); 1072 fprintf(fp, "%s", field_sep ?: " ");
855 ret += se->print(fp, self); 1073 ret += se->print(fp, self, se->width ? *se->width : 0);
856 } 1074 }
857 1075
858 ret += fprintf(fp, "\n"); 1076 ret += fprintf(fp, "\n");
@@ -867,6 +1085,18 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
867 * 1085 *
868 */ 1086 */
869 1087
1088static void dso__calc_col_width(struct dso *self)
1089{
1090 if (!col_width_list_str && !field_sep &&
1091 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1092 unsigned int slen = strlen(self->name);
1093 if (slen > dsos__col_width)
1094 dsos__col_width = slen;
1095 }
1096
1097 self->slen_calculated = 1;
1098}
1099
870static struct symbol * 1100static struct symbol *
871resolve_symbol(struct thread *thread, struct map **mapp, 1101resolve_symbol(struct thread *thread, struct map **mapp,
872 struct dso **dsop, u64 *ipp) 1102 struct dso **dsop, u64 *ipp)
@@ -886,6 +1116,14 @@ resolve_symbol(struct thread *thread, struct map **mapp,
886 1116
887 map = thread__find_map(thread, ip); 1117 map = thread__find_map(thread, ip);
888 if (map != NULL) { 1118 if (map != NULL) {
1119 /*
1120 * We have to do this here as we may have a dso
1121 * with no symbol hit that has a name longer than
1122 * the ones with symbols sampled.
1123 */
1124 if (!sort_dso.elide && !map->dso->slen_calculated)
1125 dso__calc_col_width(map->dso);
1126
889 if (mapp) 1127 if (mapp)
890 *mapp = map; 1128 *mapp = map;
891got_map: 1129got_map:
@@ -923,6 +1161,58 @@ static int call__match(struct symbol *sym)
923 return 0; 1161 return 0;
924} 1162}
925 1163
1164static struct symbol **
1165resolve_callchain(struct thread *thread, struct map *map __used,
1166 struct ip_callchain *chain, struct hist_entry *entry)
1167{
1168 u64 context = PERF_CONTEXT_MAX;
1169 struct symbol **syms = NULL;
1170 unsigned int i;
1171
1172 if (callchain) {
1173 syms = calloc(chain->nr, sizeof(*syms));
1174 if (!syms) {
1175 fprintf(stderr, "Can't allocate memory for symbols\n");
1176 exit(-1);
1177 }
1178 }
1179
1180 for (i = 0; i < chain->nr; i++) {
1181 u64 ip = chain->ips[i];
1182 struct dso *dso = NULL;
1183 struct symbol *sym;
1184
1185 if (ip >= PERF_CONTEXT_MAX) {
1186 context = ip;
1187 continue;
1188 }
1189
1190 switch (context) {
1191 case PERF_CONTEXT_HV:
1192 dso = hypervisor_dso;
1193 break;
1194 case PERF_CONTEXT_KERNEL:
1195 dso = kernel_dso;
1196 break;
1197 default:
1198 break;
1199 }
1200
1201 sym = resolve_symbol(thread, NULL, &dso, &ip);
1202
1203 if (sym) {
1204 if (sort__has_parent && call__match(sym) &&
1205 !entry->parent)
1206 entry->parent = sym;
1207 if (!callchain)
1208 break;
1209 syms[i] = sym;
1210 }
1211 }
1212
1213 return syms;
1214}
1215
926/* 1216/*
927 * collect histogram counts 1217 * collect histogram counts
928 */ 1218 */
@@ -935,6 +1225,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
935 struct rb_node **p = &hist.rb_node; 1225 struct rb_node **p = &hist.rb_node;
936 struct rb_node *parent = NULL; 1226 struct rb_node *parent = NULL;
937 struct hist_entry *he; 1227 struct hist_entry *he;
1228 struct symbol **syms = NULL;
938 struct hist_entry entry = { 1229 struct hist_entry entry = {
939 .thread = thread, 1230 .thread = thread,
940 .map = map, 1231 .map = map,
@@ -948,36 +1239,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
948 }; 1239 };
949 int cmp; 1240 int cmp;
950 1241
951 if (sort__has_parent && chain) { 1242 if ((sort__has_parent || callchain) && chain)
952 u64 context = PERF_CONTEXT_MAX; 1243 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 1244
982 while (*p != NULL) { 1245 while (*p != NULL) {
983 parent = *p; 1246 parent = *p;
@@ -987,8 +1250,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
987 1250
988 if (!cmp) { 1251 if (!cmp) {
989 he->count += count; 1252 he->count += count;
990 if (callchain) 1253 if (callchain) {
991 append_chain(&he->callchain, chain); 1254 append_chain(&he->callchain, chain, syms);
1255 free(syms);
1256 }
992 return 0; 1257 return 0;
993 } 1258 }
994 1259
@@ -1004,7 +1269,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
1004 *he = entry; 1269 *he = entry;
1005 if (callchain) { 1270 if (callchain) {
1006 callchain_init(&he->callchain); 1271 callchain_init(&he->callchain);
1007 append_chain(&he->callchain, chain); 1272 append_chain(&he->callchain, chain, syms);
1273 free(syms);
1008 } 1274 }
1009 rb_link_node(&he->rb_node, parent, p); 1275 rb_link_node(&he->rb_node, parent, p);
1010 rb_insert_color(&he->rb_node, &hist); 1276 rb_insert_color(&he->rb_node, &hist);
@@ -1076,14 +1342,15 @@ static void collapse__resort(void)
1076 1342
1077static struct rb_root output_hists; 1343static struct rb_root output_hists;
1078 1344
1079static void output__insert_entry(struct hist_entry *he) 1345static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
1080{ 1346{
1081 struct rb_node **p = &output_hists.rb_node; 1347 struct rb_node **p = &output_hists.rb_node;
1082 struct rb_node *parent = NULL; 1348 struct rb_node *parent = NULL;
1083 struct hist_entry *iter; 1349 struct hist_entry *iter;
1084 1350
1085 if (callchain) 1351 if (callchain)
1086 sort_chain_to_rbtree(&he->sorted_chain, &he->callchain); 1352 callchain_param.sort(&he->sorted_chain, &he->callchain,
1353 min_callchain_hits, &callchain_param);
1087 1354
1088 while (*p != NULL) { 1355 while (*p != NULL) {
1089 parent = *p; 1356 parent = *p;
@@ -1099,11 +1366,14 @@ static void output__insert_entry(struct hist_entry *he)
1099 rb_insert_color(&he->rb_node, &output_hists); 1366 rb_insert_color(&he->rb_node, &output_hists);
1100} 1367}
1101 1368
1102static void output__resort(void) 1369static void output__resort(u64 total_samples)
1103{ 1370{
1104 struct rb_node *next; 1371 struct rb_node *next;
1105 struct hist_entry *n; 1372 struct hist_entry *n;
1106 struct rb_root *tree = &hist; 1373 struct rb_root *tree = &hist;
1374 u64 min_callchain_hits;
1375
1376 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
1107 1377
1108 if (sort__need_collapse) 1378 if (sort__need_collapse)
1109 tree = &collapse_hists; 1379 tree = &collapse_hists;
@@ -1115,7 +1385,7 @@ static void output__resort(void)
1115 next = rb_next(&n->rb_node); 1385 next = rb_next(&n->rb_node);
1116 1386
1117 rb_erase(&n->rb_node, tree); 1387 rb_erase(&n->rb_node, tree);
1118 output__insert_entry(n); 1388 output__insert_entry(n, min_callchain_hits);
1119 } 1389 }
1120} 1390}
1121 1391
@@ -1125,35 +1395,69 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1125 struct sort_entry *se; 1395 struct sort_entry *se;
1126 struct rb_node *nd; 1396 struct rb_node *nd;
1127 size_t ret = 0; 1397 size_t ret = 0;
1398 unsigned int width;
1399 char *col_width = col_width_list_str;
1128 1400
1129 fprintf(fp, "\n"); 1401 init_rem_hits();
1130 fprintf(fp, "#\n"); 1402
1131 fprintf(fp, "# (%Ld samples)\n", (u64)total_samples); 1403 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1132 fprintf(fp, "#\n"); 1404 fprintf(fp, "#\n");
1133 1405
1134 fprintf(fp, "# Overhead"); 1406 fprintf(fp, "# Overhead");
1407 if (show_nr_samples) {
1408 if (field_sep)
1409 fprintf(fp, "%cSamples", *field_sep);
1410 else
1411 fputs(" Samples ", fp);
1412 }
1135 list_for_each_entry(se, &hist_entry__sort_list, list) { 1413 list_for_each_entry(se, &hist_entry__sort_list, list) {
1136 if (exclude_other && (se == &sort_parent)) 1414 if (se->elide)
1137 continue; 1415 continue;
1138 fprintf(fp, " %s", se->header); 1416 if (field_sep) {
1417 fprintf(fp, "%c%s", *field_sep, se->header);
1418 continue;
1419 }
1420 width = strlen(se->header);
1421 if (se->width) {
1422 if (col_width_list_str) {
1423 if (col_width) {
1424 *se->width = atoi(col_width);
1425 col_width = strchr(col_width, ',');
1426 if (col_width)
1427 ++col_width;
1428 }
1429 }
1430 width = *se->width = max(*se->width, width);
1431 }
1432 fprintf(fp, " %*s", width, se->header);
1139 } 1433 }
1140 fprintf(fp, "\n"); 1434 fprintf(fp, "\n");
1141 1435
1436 if (field_sep)
1437 goto print_entries;
1438
1142 fprintf(fp, "# ........"); 1439 fprintf(fp, "# ........");
1440 if (show_nr_samples)
1441 fprintf(fp, " ..........");
1143 list_for_each_entry(se, &hist_entry__sort_list, list) { 1442 list_for_each_entry(se, &hist_entry__sort_list, list) {
1144 int i; 1443 unsigned int i;
1145 1444
1146 if (exclude_other && (se == &sort_parent)) 1445 if (se->elide)
1147 continue; 1446 continue;
1148 1447
1149 fprintf(fp, " "); 1448 fprintf(fp, " ");
1150 for (i = 0; i < strlen(se->header); i++) 1449 if (se->width)
1450 width = *se->width;
1451 else
1452 width = strlen(se->header);
1453 for (i = 0; i < width; i++)
1151 fprintf(fp, "."); 1454 fprintf(fp, ".");
1152 } 1455 }
1153 fprintf(fp, "\n"); 1456 fprintf(fp, "\n");
1154 1457
1155 fprintf(fp, "#\n"); 1458 fprintf(fp, "#\n");
1156 1459
1460print_entries:
1157 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 1461 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1158 pos = rb_entry(nd, struct hist_entry, rb_node); 1462 pos = rb_entry(nd, struct hist_entry, rb_node);
1159 ret += hist_entry__fprintf(fp, pos, total_samples); 1463 ret += hist_entry__fprintf(fp, pos, total_samples);
@@ -1162,11 +1466,13 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1162 if (sort_order == default_sort_order && 1466 if (sort_order == default_sort_order &&
1163 parent_pattern == default_parent_pattern) { 1467 parent_pattern == default_parent_pattern) {
1164 fprintf(fp, "#\n"); 1468 fprintf(fp, "#\n");
1165 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); 1469 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1166 fprintf(fp, "#\n"); 1470 fprintf(fp, "#\n");
1167 } 1471 }
1168 fprintf(fp, "\n"); 1472 fprintf(fp, "\n");
1169 1473
1474 free(rem_sq_bracket);
1475
1170 return ret; 1476 return ret;
1171} 1477}
1172 1478
@@ -1213,22 +1519,23 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1213 struct map *map = NULL; 1519 struct map *map = NULL;
1214 void *more_data = event->ip.__more_data; 1520 void *more_data = event->ip.__more_data;
1215 struct ip_callchain *chain = NULL; 1521 struct ip_callchain *chain = NULL;
1522 int cpumode;
1216 1523
1217 if (sample_type & PERF_SAMPLE_PERIOD) { 1524 if (sample_type & PERF_SAMPLE_PERIOD) {
1218 period = *(u64 *)more_data; 1525 period = *(u64 *)more_data;
1219 more_data += sizeof(u64); 1526 more_data += sizeof(u64);
1220 } 1527 }
1221 1528
1222 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n", 1529 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1223 (void *)(offset + head), 1530 (void *)(offset + head),
1224 (void *)(long)(event->header.size), 1531 (void *)(long)(event->header.size),
1225 event->header.misc, 1532 event->header.misc,
1226 event->ip.pid, 1533 event->ip.pid, event->ip.tid,
1227 (void *)(long)ip, 1534 (void *)(long)ip,
1228 (long long)period); 1535 (long long)period);
1229 1536
1230 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 1537 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1231 int i; 1538 unsigned int i;
1232 1539
1233 chain = (void *)more_data; 1540 chain = (void *)more_data;
1234 1541
@@ -1256,7 +1563,9 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1256 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 1563 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1257 return 0; 1564 return 0;
1258 1565
1259 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 1566 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
1567
1568 if (cpumode == PERF_EVENT_MISC_KERNEL) {
1260 show = SHOW_KERNEL; 1569 show = SHOW_KERNEL;
1261 level = 'k'; 1570 level = 'k';
1262 1571
@@ -1264,7 +1573,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1264 1573
1265 dprintf(" ...... dso: %s\n", dso->name); 1574 dprintf(" ...... dso: %s\n", dso->name);
1266 1575
1267 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 1576 } else if (cpumode == PERF_EVENT_MISC_USER) {
1268 1577
1269 show = SHOW_USER; 1578 show = SHOW_USER;
1270 level = '.'; 1579 level = '.';
@@ -1272,16 +1581,20 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1272 } else { 1581 } else {
1273 show = SHOW_HV; 1582 show = SHOW_HV;
1274 level = 'H'; 1583 level = 'H';
1584
1585 dso = hypervisor_dso;
1586
1275 dprintf(" ...... dso: [hypervisor]\n"); 1587 dprintf(" ...... dso: [hypervisor]\n");
1276 } 1588 }
1277 1589
1278 if (show & show_mask) { 1590 if (show & show_mask) {
1279 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 1591 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1280 1592
1281 if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name)) 1593 if (dso_list && (!dso || !dso->name ||
1594 !strlist__has_entry(dso_list, dso->name)))
1282 return 0; 1595 return 0;
1283 1596
1284 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) 1597 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1285 return 0; 1598 return 0;
1286 1599
1287 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 1600 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
@@ -1300,10 +1613,11 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1300 struct thread *thread = threads__findnew(event->mmap.pid); 1613 struct thread *thread = threads__findnew(event->mmap.pid);
1301 struct map *map = map__new(&event->mmap); 1614 struct map *map = map__new(&event->mmap);
1302 1615
1303 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", 1616 dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1304 (void *)(offset + head), 1617 (void *)(offset + head),
1305 (void *)(long)(event->header.size), 1618 (void *)(long)(event->header.size),
1306 event->mmap.pid, 1619 event->mmap.pid,
1620 event->mmap.tid,
1307 (void *)(long)event->mmap.start, 1621 (void *)(long)event->mmap.start,
1308 (void *)(long)event->mmap.len, 1622 (void *)(long)event->mmap.len,
1309 (void *)(long)event->mmap.pgoff, 1623 (void *)(long)event->mmap.pgoff,
@@ -1341,15 +1655,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1341} 1655}
1342 1656
1343static int 1657static int
1344process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1658process_task_event(event_t *event, unsigned long offset, unsigned long head)
1345{ 1659{
1346 struct thread *thread = threads__findnew(event->fork.pid); 1660 struct thread *thread = threads__findnew(event->fork.pid);
1347 struct thread *parent = threads__findnew(event->fork.ppid); 1661 struct thread *parent = threads__findnew(event->fork.ppid);
1348 1662
1349 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1663 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1350 (void *)(offset + head), 1664 (void *)(offset + head),
1351 (void *)(long)(event->header.size), 1665 (void *)(long)(event->header.size),
1352 event->fork.pid, event->fork.ppid); 1666 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1667 event->fork.pid, event->fork.tid,
1668 event->fork.ppid, event->fork.ptid);
1669
1670 /*
1671 * A thread clone will have the same PID for both
1672 * parent and child.
1673 */
1674 if (thread == parent)
1675 return 0;
1676
1677 if (event->header.type == PERF_EVENT_EXIT)
1678 return 0;
1353 1679
1354 if (!thread || !parent || thread__fork(thread, parent)) { 1680 if (!thread || !parent || thread__fork(thread, parent)) {
1355 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1681 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1361,19 +1687,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1361} 1687}
1362 1688
1363static int 1689static 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) 1690process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1378{ 1691{
1379 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", 1692 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
@@ -1423,14 +1736,37 @@ static void trace_event(event_t *event)
1423 dprintf(".\n"); 1736 dprintf(".\n");
1424} 1737}
1425 1738
1739static struct perf_header *header;
1740
1741static struct perf_counter_attr *perf_header__find_attr(u64 id)
1742{
1743 int i;
1744
1745 for (i = 0; i < header->attrs; i++) {
1746 struct perf_header_attr *attr = header->attr[i];
1747 int j;
1748
1749 for (j = 0; j < attr->ids; j++) {
1750 if (attr->id[j] == id)
1751 return &attr->attr;
1752 }
1753 }
1754
1755 return NULL;
1756}
1757
1426static int 1758static int
1427process_read_event(event_t *event, unsigned long offset, unsigned long head) 1759process_read_event(event_t *event, unsigned long offset, unsigned long head)
1428{ 1760{
1429 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n", 1761 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1762
1763 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1430 (void *)(offset + head), 1764 (void *)(offset + head),
1431 (void *)(long)(event->header.size), 1765 (void *)(long)(event->header.size),
1432 event->read.pid, 1766 event->read.pid,
1433 event->read.tid, 1767 event->read.tid,
1768 attr ? __event_name(attr->type, attr->config)
1769 : "FAIL",
1434 event->read.value); 1770 event->read.value);
1435 1771
1436 return 0; 1772 return 0;
@@ -1452,10 +1788,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1452 return process_comm_event(event, offset, head); 1788 return process_comm_event(event, offset, head);
1453 1789
1454 case PERF_EVENT_FORK: 1790 case PERF_EVENT_FORK:
1455 return process_fork_event(event, offset, head); 1791 case PERF_EVENT_EXIT:
1456 1792 return process_task_event(event, offset, head);
1457 case PERF_EVENT_PERIOD:
1458 return process_period_event(event, offset, head);
1459 1793
1460 case PERF_EVENT_LOST: 1794 case PERF_EVENT_LOST:
1461 return process_lost_event(event, offset, head); 1795 return process_lost_event(event, offset, head);
@@ -1478,8 +1812,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1478 return 0; 1812 return 0;
1479} 1813}
1480 1814
1481static struct perf_header *header;
1482
1483static u64 perf_header__sample_type(void) 1815static u64 perf_header__sample_type(void)
1484{ 1816{
1485 u64 sample_type = 0; 1817 u64 sample_type = 0;
@@ -1534,9 +1866,26 @@ static int __cmd_report(void)
1534 1866
1535 sample_type = perf_header__sample_type(); 1867 sample_type = perf_header__sample_type();
1536 1868
1537 if (sort__has_parent && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 1869 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1538 fprintf(stderr, "selected --sort parent, but no callchain data\n"); 1870 if (sort__has_parent) {
1539 exit(-1); 1871 fprintf(stderr, "selected --sort parent, but no"
1872 " callchain data. Did you call"
1873 " perf record without -g?\n");
1874 exit(-1);
1875 }
1876 if (callchain) {
1877 fprintf(stderr, "selected -c but no callchain data."
1878 " Did you call perf record without"
1879 " -g?\n");
1880 exit(-1);
1881 }
1882 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1883 callchain = 1;
1884 if (register_callchain_param(&callchain_param) < 0) {
1885 fprintf(stderr, "Can't register callchain"
1886 " params\n");
1887 exit(-1);
1888 }
1540 } 1889 }
1541 1890
1542 if (load_kernel() < 0) { 1891 if (load_kernel() < 0) {
@@ -1619,7 +1968,7 @@ more:
1619 if (offset + head >= header->data_offset + header->data_size) 1968 if (offset + head >= header->data_offset + header->data_size)
1620 goto done; 1969 goto done;
1621 1970
1622 if (offset + head < stat.st_size) 1971 if (offset + head < (unsigned long)stat.st_size)
1623 goto more; 1972 goto more;
1624 1973
1625done: 1974done:
@@ -1643,12 +1992,65 @@ done:
1643 dsos__fprintf(stdout); 1992 dsos__fprintf(stdout);
1644 1993
1645 collapse__resort(); 1994 collapse__resort();
1646 output__resort(); 1995 output__resort(total);
1647 output__fprintf(stdout, total); 1996 output__fprintf(stdout, total);
1648 1997
1649 return rc; 1998 return rc;
1650} 1999}
1651 2000
2001static int
2002parse_callchain_opt(const struct option *opt __used, const char *arg,
2003 int unset __used)
2004{
2005 char *tok;
2006 char *endptr;
2007
2008 callchain = 1;
2009
2010 if (!arg)
2011 return 0;
2012
2013 tok = strtok((char *)arg, ",");
2014 if (!tok)
2015 return -1;
2016
2017 /* get the output mode */
2018 if (!strncmp(tok, "graph", strlen(arg)))
2019 callchain_param.mode = CHAIN_GRAPH_ABS;
2020
2021 else if (!strncmp(tok, "flat", strlen(arg)))
2022 callchain_param.mode = CHAIN_FLAT;
2023
2024 else if (!strncmp(tok, "fractal", strlen(arg)))
2025 callchain_param.mode = CHAIN_GRAPH_REL;
2026
2027 else if (!strncmp(tok, "none", strlen(arg))) {
2028 callchain_param.mode = CHAIN_NONE;
2029 callchain = 0;
2030
2031 return 0;
2032 }
2033
2034 else
2035 return -1;
2036
2037 /* get the min percentage */
2038 tok = strtok(NULL, ",");
2039 if (!tok)
2040 goto setup;
2041
2042 callchain_param.min_percent = strtod(tok, &endptr);
2043 if (tok == endptr)
2044 return -1;
2045
2046setup:
2047 if (register_callchain_param(&callchain_param) < 0) {
2048 fprintf(stderr, "Can't register callchain params\n");
2049 return -1;
2050 }
2051 return 0;
2052}
2053
1652static const char * const report_usage[] = { 2054static const char * const report_usage[] = {
1653 "perf report [<options>] <command>", 2055 "perf report [<options>] <command>",
1654 NULL 2056 NULL
@@ -1662,6 +2064,10 @@ static const struct option options[] = {
1662 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 2064 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1663 "dump raw trace in ASCII"), 2065 "dump raw trace in ASCII"),
1664 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 2066 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
2067 OPT_BOOLEAN('m', "modules", &modules,
2068 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2069 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2070 "Show a column with the number of samples"),
1665 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 2071 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1666 "sort by key(s): pid, comm, dso, symbol, parent"), 2072 "sort by key(s): pid, comm, dso, symbol, parent"),
1667 OPT_BOOLEAN('P', "full-paths", &full_paths, 2073 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1670,13 +2076,21 @@ static const struct option options[] = {
1670 "regex filter to identify parent, see: '--sort parent'"), 2076 "regex filter to identify parent, see: '--sort parent'"),
1671 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 2077 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1672 "Only display entries with parent-match"), 2078 "Only display entries with parent-match"),
1673 OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"), 2079 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
2080 "Display callchains using output_type and min percent threshold. "
2081 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1674 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 2082 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1675 "only consider symbols in these dsos"), 2083 "only consider symbols in these dsos"),
1676 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 2084 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1677 "only consider symbols in these comms"), 2085 "only consider symbols in these comms"),
1678 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 2086 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1679 "only consider these symbols"), 2087 "only consider these symbols"),
2088 OPT_STRING('w', "column-widths", &col_width_list_str,
2089 "width[,width...]",
2090 "don't try to adjust column width, use these fixed values"),
2091 OPT_STRING('t', "field-separator", &field_sep, "separator",
2092 "separator for columns, no spaces will be added between "
2093 "columns '.' is reserved."),
1680 OPT_END() 2094 OPT_END()
1681}; 2095};
1682 2096
@@ -1696,7 +2110,8 @@ static void setup_sorting(void)
1696} 2110}
1697 2111
1698static void setup_list(struct strlist **list, const char *list_str, 2112static void setup_list(struct strlist **list, const char *list_str,
1699 const char *list_name) 2113 struct sort_entry *se, const char *list_name,
2114 FILE *fp)
1700{ 2115{
1701 if (list_str) { 2116 if (list_str) {
1702 *list = strlist__new(true, list_str); 2117 *list = strlist__new(true, list_str);
@@ -1705,10 +2120,15 @@ static void setup_list(struct strlist **list, const char *list_str,
1705 list_name); 2120 list_name);
1706 exit(129); 2121 exit(129);
1707 } 2122 }
2123 if (strlist__nr_entries(*list) == 1) {
2124 fprintf(fp, "# %s: %s\n", list_name,
2125 strlist__entry(*list, 0)->s);
2126 se->elide = true;
2127 }
1708 } 2128 }
1709} 2129}
1710 2130
1711int cmd_report(int argc, const char **argv, const char *prefix) 2131int cmd_report(int argc, const char **argv, const char *prefix __used)
1712{ 2132{
1713 symbol__init(); 2133 symbol__init();
1714 2134
@@ -1718,9 +2138,10 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1718 2138
1719 setup_sorting(); 2139 setup_sorting();
1720 2140
1721 if (parent_pattern != default_parent_pattern) 2141 if (parent_pattern != default_parent_pattern) {
1722 sort_dimension__add("parent"); 2142 sort_dimension__add("parent");
1723 else 2143 sort_parent.elide = 1;
2144 } else
1724 exclude_other = 0; 2145 exclude_other = 0;
1725 2146
1726 /* 2147 /*
@@ -1729,11 +2150,17 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1729 if (argc) 2150 if (argc)
1730 usage_with_options(report_usage, options); 2151 usage_with_options(report_usage, options);
1731 2152
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(); 2153 setup_pager();
1737 2154
2155 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2156 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2157 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2158
2159 if (field_sep && *field_sep == '.') {
2160 fputs("'.' is the only non valid --field-separator argument\n",
2161 stderr);
2162 exit(129);
2163 }
2164
1738 return __cmd_report(); 2165 return __cmd_report();
1739} 2166}