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.c383
1 files changed, 303 insertions, 80 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 135b7837e6bf..4e5cc266311e 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"
@@ -46,6 +46,8 @@ static int dump_trace = 0;
46static int verbose; 46static int verbose;
47#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0) 47#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
48 48
49static int modules;
50
49static int full_paths; 51static int full_paths;
50 52
51static unsigned long page_size; 53static unsigned long page_size;
@@ -56,8 +58,17 @@ static char *parent_pattern = default_parent_pattern;
56static regex_t parent_regex; 58static regex_t parent_regex;
57 59
58static int exclude_other = 1; 60static int exclude_other = 1;
61
62static char callchain_default_opt[] = "fractal,0.5";
63
59static int callchain; 64static int callchain;
60 65
66static
67struct callchain_param callchain_param = {
68 .mode = CHAIN_GRAPH_ABS,
69 .min_percent = 0.5
70};
71
61static u64 sample_type; 72static u64 sample_type;
62 73
63struct ip_event { 74struct ip_event {
@@ -121,6 +132,7 @@ typedef union event_union {
121static LIST_HEAD(dsos); 132static LIST_HEAD(dsos);
122static struct dso *kernel_dso; 133static struct dso *kernel_dso;
123static struct dso *vdso; 134static struct dso *vdso;
135static struct dso *hypervisor_dso;
124 136
125static void dsos__add(struct dso *dso) 137static void dsos__add(struct dso *dso)
126{ 138{
@@ -176,7 +188,7 @@ static void dsos__fprintf(FILE *fp)
176 188
177static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 189static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
178{ 190{
179 return dso__find_symbol(kernel_dso, ip); 191 return dso__find_symbol(dso, ip);
180} 192}
181 193
182static int load_kernel(void) 194static int load_kernel(void)
@@ -187,8 +199,8 @@ static int load_kernel(void)
187 if (!kernel_dso) 199 if (!kernel_dso)
188 return -1; 200 return -1;
189 201
190 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); 202 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
191 if (err) { 203 if (err <= 0) {
192 dso__delete(kernel_dso); 204 dso__delete(kernel_dso);
193 kernel_dso = NULL; 205 kernel_dso = NULL;
194 } else 206 } else
@@ -202,6 +214,11 @@ static int load_kernel(void)
202 214
203 dsos__add(vdso); 215 dsos__add(vdso);
204 216
217 hypervisor_dso = dso__new("[hypervisor]", 0);
218 if (!hypervisor_dso)
219 return -1;
220 dsos__add(hypervisor_dso);
221
205 return err; 222 return err;
206} 223}
207 224
@@ -233,7 +250,7 @@ static u64 map__map_ip(struct map *map, u64 ip)
233 return ip - map->start + map->pgoff; 250 return ip - map->start + map->pgoff;
234} 251}
235 252
236static u64 vdso__map_ip(struct map *map, u64 ip) 253static u64 vdso__map_ip(struct map *map __used, u64 ip)
237{ 254{
238 return ip; 255 return ip;
239} 256}
@@ -640,7 +657,11 @@ sort__sym_print(FILE *fp, struct hist_entry *self)
640 657
641 if (self->sym) { 658 if (self->sym) {
642 ret += fprintf(fp, "[%c] %s", 659 ret += fprintf(fp, "[%c] %s",
643 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 660 self->dso == kernel_dso ? 'k' :
661 self->dso == hypervisor_dso ? 'h' : '.', self->sym->name);
662
663 if (self->sym->module)
664 ret += fprintf(fp, "\t[%s]", self->sym->module->name);
644 } else { 665 } else {
645 ret += fprintf(fp, "%#016llx", (u64)self->ip); 666 ret += fprintf(fp, "%#016llx", (u64)self->ip);
646 } 667 }
@@ -705,7 +726,7 @@ static LIST_HEAD(hist_entry__sort_list);
705 726
706static int sort_dimension__add(char *tok) 727static int sort_dimension__add(char *tok)
707{ 728{
708 int i; 729 unsigned int i;
709 730
710 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 731 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
711 struct sort_dimension *sd = &sort_dimensions[i]; 732 struct sort_dimension *sd = &sort_dimensions[i];
@@ -775,8 +796,109 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
775 return cmp; 796 return cmp;
776} 797}
777 798
799static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
800{
801 int i;
802 size_t ret = 0;
803
804 ret += fprintf(fp, "%s", " ");
805
806 for (i = 0; i < depth; i++)
807 if (depth_mask & (1 << i))
808 ret += fprintf(fp, "| ");
809 else
810 ret += fprintf(fp, " ");
811
812 ret += fprintf(fp, "\n");
813
814 return ret;
815}
816static size_t
817ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
818 int depth_mask, int count, u64 total_samples,
819 int hits)
820{
821 int i;
822 size_t ret = 0;
823
824 ret += fprintf(fp, "%s", " ");
825 for (i = 0; i < depth; i++) {
826 if (depth_mask & (1 << i))
827 ret += fprintf(fp, "|");
828 else
829 ret += fprintf(fp, " ");
830 if (!count && i == depth - 1) {
831 double percent;
832
833 percent = hits * 100.0 / total_samples;
834 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
835 } else
836 ret += fprintf(fp, "%s", " ");
837 }
838 if (chain->sym)
839 ret += fprintf(fp, "%s\n", chain->sym->name);
840 else
841 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
842
843 return ret;
844}
845
846static size_t
847callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
848 u64 total_samples, int depth, int depth_mask)
849{
850 struct rb_node *node, *next;
851 struct callchain_node *child;
852 struct callchain_list *chain;
853 int new_depth_mask = depth_mask;
854 u64 new_total;
855 size_t ret = 0;
856 int i;
857
858 if (callchain_param.mode == CHAIN_GRAPH_REL)
859 new_total = self->cumul_hit;
860 else
861 new_total = total_samples;
862
863 node = rb_first(&self->rb_root);
864 while (node) {
865 child = rb_entry(node, struct callchain_node, rb_node);
866
867 /*
868 * The depth mask manages the output of pipes that show
869 * the depth. We don't want to keep the pipes of the current
870 * level for the last child of this depth
871 */
872 next = rb_next(node);
873 if (!next)
874 new_depth_mask &= ~(1 << (depth - 1));
875
876 /*
877 * But we keep the older depth mask for the line seperator
878 * to keep the level link until we reach the last child
879 */
880 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
881 i = 0;
882 list_for_each_entry(chain, &child->val, list) {
883 if (chain->ip >= PERF_CONTEXT_MAX)
884 continue;
885 ret += ipchain__fprintf_graph(fp, chain, depth,
886 new_depth_mask, i++,
887 new_total,
888 child->cumul_hit);
889 }
890 ret += callchain__fprintf_graph(fp, child, new_total,
891 depth + 1,
892 new_depth_mask | (1 << depth));
893 node = next;
894 }
895
896 return ret;
897}
898
778static size_t 899static size_t
779callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples) 900callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
901 u64 total_samples)
780{ 902{
781 struct callchain_list *chain; 903 struct callchain_list *chain;
782 size_t ret = 0; 904 size_t ret = 0;
@@ -784,11 +906,18 @@ callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
784 if (!self) 906 if (!self)
785 return 0; 907 return 0;
786 908
787 ret += callchain__fprintf(fp, self->parent, total_samples); 909 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
788 910
789 911
790 list_for_each_entry(chain, &self->val, list) 912 list_for_each_entry(chain, &self->val, list) {
791 ret += fprintf(fp, " %p\n", (void *)chain->ip); 913 if (chain->ip >= PERF_CONTEXT_MAX)
914 continue;
915 if (chain->sym)
916 ret += fprintf(fp, " %s\n", chain->sym->name);
917 else
918 ret += fprintf(fp, " %p\n",
919 (void *)(long)chain->ip);
920 }
792 921
793 return ret; 922 return ret;
794} 923}
@@ -807,8 +936,19 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
807 936
808 chain = rb_entry(rb_node, struct callchain_node, rb_node); 937 chain = rb_entry(rb_node, struct callchain_node, rb_node);
809 percent = chain->hit * 100.0 / total_samples; 938 percent = chain->hit * 100.0 / total_samples;
810 ret += fprintf(fp, " %6.2f%%\n", percent); 939 switch (callchain_param.mode) {
811 ret += callchain__fprintf(fp, chain, total_samples); 940 case CHAIN_FLAT:
941 ret += percent_color_fprintf(fp, " %6.2f%%\n",
942 percent);
943 ret += callchain__fprintf_flat(fp, chain, total_samples);
944 break;
945 case CHAIN_GRAPH_ABS: /* Falldown */
946 case CHAIN_GRAPH_REL:
947 ret += callchain__fprintf_graph(fp, chain,
948 total_samples, 1, 1);
949 default:
950 break;
951 }
812 ret += fprintf(fp, "\n"); 952 ret += fprintf(fp, "\n");
813 rb_node = rb_next(rb_node); 953 rb_node = rb_next(rb_node);
814 } 954 }
@@ -826,25 +966,10 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
826 if (exclude_other && !self->parent) 966 if (exclude_other && !self->parent)
827 return 0; 967 return 0;
828 968
829 if (total_samples) { 969 if (total_samples)
830 double percent = self->count * 100.0 / total_samples; 970 ret = percent_color_fprintf(fp, " %6.2f%%",
831 char *color = PERF_COLOR_NORMAL;
832
833 /*
834 * We color high-overhead entries in red, mid-overhead
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
845 ret = color_fprintf(fp, color, " %6.2f%%",
846 (self->count * 100.0) / total_samples); 971 (self->count * 100.0) / total_samples);
847 } else 972 else
848 ret = fprintf(fp, "%12Ld ", self->count); 973 ret = fprintf(fp, "%12Ld ", self->count);
849 974
850 list_for_each_entry(se, &hist_entry__sort_list, list) { 975 list_for_each_entry(se, &hist_entry__sort_list, list) {
@@ -923,6 +1048,58 @@ static int call__match(struct symbol *sym)
923 return 0; 1048 return 0;
924} 1049}
925 1050
1051static struct symbol **
1052resolve_callchain(struct thread *thread, struct map *map __used,
1053 struct ip_callchain *chain, struct hist_entry *entry)
1054{
1055 u64 context = PERF_CONTEXT_MAX;
1056 struct symbol **syms = NULL;
1057 unsigned int i;
1058
1059 if (callchain) {
1060 syms = calloc(chain->nr, sizeof(*syms));
1061 if (!syms) {
1062 fprintf(stderr, "Can't allocate memory for symbols\n");
1063 exit(-1);
1064 }
1065 }
1066
1067 for (i = 0; i < chain->nr; i++) {
1068 u64 ip = chain->ips[i];
1069 struct dso *dso = NULL;
1070 struct symbol *sym;
1071
1072 if (ip >= PERF_CONTEXT_MAX) {
1073 context = ip;
1074 continue;
1075 }
1076
1077 switch (context) {
1078 case PERF_CONTEXT_HV:
1079 dso = hypervisor_dso;
1080 break;
1081 case PERF_CONTEXT_KERNEL:
1082 dso = kernel_dso;
1083 break;
1084 default:
1085 break;
1086 }
1087
1088 sym = resolve_symbol(thread, NULL, &dso, &ip);
1089
1090 if (sym) {
1091 if (sort__has_parent && call__match(sym) &&
1092 !entry->parent)
1093 entry->parent = sym;
1094 if (!callchain)
1095 break;
1096 syms[i] = sym;
1097 }
1098 }
1099
1100 return syms;
1101}
1102
926/* 1103/*
927 * collect histogram counts 1104 * collect histogram counts
928 */ 1105 */
@@ -935,6 +1112,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
935 struct rb_node **p = &hist.rb_node; 1112 struct rb_node **p = &hist.rb_node;
936 struct rb_node *parent = NULL; 1113 struct rb_node *parent = NULL;
937 struct hist_entry *he; 1114 struct hist_entry *he;
1115 struct symbol **syms = NULL;
938 struct hist_entry entry = { 1116 struct hist_entry entry = {
939 .thread = thread, 1117 .thread = thread,
940 .map = map, 1118 .map = map,
@@ -948,36 +1126,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
948 }; 1126 };
949 int cmp; 1127 int cmp;
950 1128
951 if (sort__has_parent && chain) { 1129 if ((sort__has_parent || callchain) && chain)
952 u64 context = PERF_CONTEXT_MAX; 1130 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 1131
982 while (*p != NULL) { 1132 while (*p != NULL) {
983 parent = *p; 1133 parent = *p;
@@ -987,8 +1137,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
987 1137
988 if (!cmp) { 1138 if (!cmp) {
989 he->count += count; 1139 he->count += count;
990 if (callchain) 1140 if (callchain) {
991 append_chain(&he->callchain, chain); 1141 append_chain(&he->callchain, chain, syms);
1142 free(syms);
1143 }
992 return 0; 1144 return 0;
993 } 1145 }
994 1146
@@ -1004,7 +1156,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
1004 *he = entry; 1156 *he = entry;
1005 if (callchain) { 1157 if (callchain) {
1006 callchain_init(&he->callchain); 1158 callchain_init(&he->callchain);
1007 append_chain(&he->callchain, chain); 1159 append_chain(&he->callchain, chain, syms);
1160 free(syms);
1008 } 1161 }
1009 rb_link_node(&he->rb_node, parent, p); 1162 rb_link_node(&he->rb_node, parent, p);
1010 rb_insert_color(&he->rb_node, &hist); 1163 rb_insert_color(&he->rb_node, &hist);
@@ -1076,14 +1229,15 @@ static void collapse__resort(void)
1076 1229
1077static struct rb_root output_hists; 1230static struct rb_root output_hists;
1078 1231
1079static void output__insert_entry(struct hist_entry *he) 1232static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
1080{ 1233{
1081 struct rb_node **p = &output_hists.rb_node; 1234 struct rb_node **p = &output_hists.rb_node;
1082 struct rb_node *parent = NULL; 1235 struct rb_node *parent = NULL;
1083 struct hist_entry *iter; 1236 struct hist_entry *iter;
1084 1237
1085 if (callchain) 1238 if (callchain)
1086 sort_chain_to_rbtree(&he->sorted_chain, &he->callchain); 1239 callchain_param.sort(&he->sorted_chain, &he->callchain,
1240 min_callchain_hits, &callchain_param);
1087 1241
1088 while (*p != NULL) { 1242 while (*p != NULL) {
1089 parent = *p; 1243 parent = *p;
@@ -1099,11 +1253,14 @@ static void output__insert_entry(struct hist_entry *he)
1099 rb_insert_color(&he->rb_node, &output_hists); 1253 rb_insert_color(&he->rb_node, &output_hists);
1100} 1254}
1101 1255
1102static void output__resort(void) 1256static void output__resort(u64 total_samples)
1103{ 1257{
1104 struct rb_node *next; 1258 struct rb_node *next;
1105 struct hist_entry *n; 1259 struct hist_entry *n;
1106 struct rb_root *tree = &hist; 1260 struct rb_root *tree = &hist;
1261 u64 min_callchain_hits;
1262
1263 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
1107 1264
1108 if (sort__need_collapse) 1265 if (sort__need_collapse)
1109 tree = &collapse_hists; 1266 tree = &collapse_hists;
@@ -1115,7 +1272,7 @@ static void output__resort(void)
1115 next = rb_next(&n->rb_node); 1272 next = rb_next(&n->rb_node);
1116 1273
1117 rb_erase(&n->rb_node, tree); 1274 rb_erase(&n->rb_node, tree);
1118 output__insert_entry(n); 1275 output__insert_entry(n, min_callchain_hits);
1119 } 1276 }
1120} 1277}
1121 1278
@@ -1141,7 +1298,7 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1141 1298
1142 fprintf(fp, "# ........"); 1299 fprintf(fp, "# ........");
1143 list_for_each_entry(se, &hist_entry__sort_list, list) { 1300 list_for_each_entry(se, &hist_entry__sort_list, list) {
1144 int i; 1301 unsigned int i;
1145 1302
1146 if (exclude_other && (se == &sort_parent)) 1303 if (exclude_other && (se == &sort_parent))
1147 continue; 1304 continue;
@@ -1213,6 +1370,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1213 struct map *map = NULL; 1370 struct map *map = NULL;
1214 void *more_data = event->ip.__more_data; 1371 void *more_data = event->ip.__more_data;
1215 struct ip_callchain *chain = NULL; 1372 struct ip_callchain *chain = NULL;
1373 int cpumode;
1216 1374
1217 if (sample_type & PERF_SAMPLE_PERIOD) { 1375 if (sample_type & PERF_SAMPLE_PERIOD) {
1218 period = *(u64 *)more_data; 1376 period = *(u64 *)more_data;
@@ -1228,7 +1386,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1228 (long long)period); 1386 (long long)period);
1229 1387
1230 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 1388 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1231 int i; 1389 unsigned int i;
1232 1390
1233 chain = (void *)more_data; 1391 chain = (void *)more_data;
1234 1392
@@ -1256,7 +1414,9 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1256 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 1414 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1257 return 0; 1415 return 0;
1258 1416
1259 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 1417 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
1418
1419 if (cpumode == PERF_EVENT_MISC_KERNEL) {
1260 show = SHOW_KERNEL; 1420 show = SHOW_KERNEL;
1261 level = 'k'; 1421 level = 'k';
1262 1422
@@ -1264,7 +1424,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1264 1424
1265 dprintf(" ...... dso: %s\n", dso->name); 1425 dprintf(" ...... dso: %s\n", dso->name);
1266 1426
1267 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 1427 } else if (cpumode == PERF_EVENT_MISC_USER) {
1268 1428
1269 show = SHOW_USER; 1429 show = SHOW_USER;
1270 level = '.'; 1430 level = '.';
@@ -1272,6 +1432,9 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1272 } else { 1432 } else {
1273 show = SHOW_HV; 1433 show = SHOW_HV;
1274 level = 'H'; 1434 level = 'H';
1435
1436 dso = hypervisor_dso;
1437
1275 dprintf(" ...... dso: [hypervisor]\n"); 1438 dprintf(" ...... dso: [hypervisor]\n");
1276 } 1439 }
1277 1440
@@ -1534,9 +1697,19 @@ static int __cmd_report(void)
1534 1697
1535 sample_type = perf_header__sample_type(); 1698 sample_type = perf_header__sample_type();
1536 1699
1537 if (sort__has_parent && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 1700 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1538 fprintf(stderr, "selected --sort parent, but no callchain data\n"); 1701 if (sort__has_parent) {
1539 exit(-1); 1702 fprintf(stderr, "selected --sort parent, but no"
1703 " callchain data. Did you call"
1704 " perf record without -g?\n");
1705 exit(-1);
1706 }
1707 if (callchain) {
1708 fprintf(stderr, "selected -c but no callchain data."
1709 " Did you call perf record without"
1710 " -g?\n");
1711 exit(-1);
1712 }
1540 } 1713 }
1541 1714
1542 if (load_kernel() < 0) { 1715 if (load_kernel() < 0) {
@@ -1619,7 +1792,7 @@ more:
1619 if (offset + head >= header->data_offset + header->data_size) 1792 if (offset + head >= header->data_offset + header->data_size)
1620 goto done; 1793 goto done;
1621 1794
1622 if (offset + head < stat.st_size) 1795 if (offset + head < (unsigned long)stat.st_size)
1623 goto more; 1796 goto more;
1624 1797
1625done: 1798done:
@@ -1643,12 +1816,58 @@ done:
1643 dsos__fprintf(stdout); 1816 dsos__fprintf(stdout);
1644 1817
1645 collapse__resort(); 1818 collapse__resort();
1646 output__resort(); 1819 output__resort(total);
1647 output__fprintf(stdout, total); 1820 output__fprintf(stdout, total);
1648 1821
1649 return rc; 1822 return rc;
1650} 1823}
1651 1824
1825static int
1826parse_callchain_opt(const struct option *opt __used, const char *arg,
1827 int unset __used)
1828{
1829 char *tok;
1830 char *endptr;
1831
1832 callchain = 1;
1833
1834 if (!arg)
1835 return 0;
1836
1837 tok = strtok((char *)arg, ",");
1838 if (!tok)
1839 return -1;
1840
1841 /* get the output mode */
1842 if (!strncmp(tok, "graph", strlen(arg)))
1843 callchain_param.mode = CHAIN_GRAPH_ABS;
1844
1845 else if (!strncmp(tok, "flat", strlen(arg)))
1846 callchain_param.mode = CHAIN_FLAT;
1847
1848 else if (!strncmp(tok, "fractal", strlen(arg)))
1849 callchain_param.mode = CHAIN_GRAPH_REL;
1850
1851 else
1852 return -1;
1853
1854 /* get the min percentage */
1855 tok = strtok(NULL, ",");
1856 if (!tok)
1857 goto setup;
1858
1859 callchain_param.min_percent = strtod(tok, &endptr);
1860 if (tok == endptr)
1861 return -1;
1862
1863setup:
1864 if (register_callchain_param(&callchain_param) < 0) {
1865 fprintf(stderr, "Can't register callchain params\n");
1866 return -1;
1867 }
1868 return 0;
1869}
1870
1652static const char * const report_usage[] = { 1871static const char * const report_usage[] = {
1653 "perf report [<options>] <command>", 1872 "perf report [<options>] <command>",
1654 NULL 1873 NULL
@@ -1662,6 +1881,8 @@ static const struct option options[] = {
1662 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1881 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1663 "dump raw trace in ASCII"), 1882 "dump raw trace in ASCII"),
1664 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1883 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1884 OPT_BOOLEAN('m', "modules", &modules,
1885 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1665 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1886 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1666 "sort by key(s): pid, comm, dso, symbol, parent"), 1887 "sort by key(s): pid, comm, dso, symbol, parent"),
1667 OPT_BOOLEAN('P', "full-paths", &full_paths, 1888 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1670,7 +1891,9 @@ static const struct option options[] = {
1670 "regex filter to identify parent, see: '--sort parent'"), 1891 "regex filter to identify parent, see: '--sort parent'"),
1671 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 1892 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1672 "Only display entries with parent-match"), 1893 "Only display entries with parent-match"),
1673 OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"), 1894 OPT_CALLBACK_DEFAULT('c', "callchain", NULL, "output_type,min_percent",
1895 "Display callchains using output_type and min percent threshold. "
1896 "Default: flat,0", &parse_callchain_opt, callchain_default_opt),
1674 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 1897 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1675 "only consider symbols in these dsos"), 1898 "only consider symbols in these dsos"),
1676 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 1899 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
@@ -1708,7 +1931,7 @@ static void setup_list(struct strlist **list, const char *list_str,
1708 } 1931 }
1709} 1932}
1710 1933
1711int cmd_report(int argc, const char **argv, const char *prefix) 1934int cmd_report(int argc, const char **argv, const char *prefix __used)
1712{ 1935{
1713 symbol__init(); 1936 symbol__init();
1714 1937