diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 107 |
1 files changed, 45 insertions, 62 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 722c0f54e549..5e17de984dc8 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.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 | 18 | ||
@@ -25,16 +25,13 @@ | |||
25 | #define SHOW_USER 2 | 25 | #define SHOW_USER 2 |
26 | #define SHOW_HV 4 | 26 | #define SHOW_HV 4 |
27 | 27 | ||
28 | #define MIN_GREEN 0.5 | ||
29 | #define MIN_RED 5.0 | ||
30 | |||
31 | |||
32 | static char const *input_name = "perf.data"; | 28 | static char const *input_name = "perf.data"; |
33 | static char *vmlinux = "vmlinux"; | 29 | static char *vmlinux = "vmlinux"; |
34 | 30 | ||
35 | static char default_sort_order[] = "comm,symbol"; | 31 | static char default_sort_order[] = "comm,symbol"; |
36 | static char *sort_order = default_sort_order; | 32 | static char *sort_order = default_sort_order; |
37 | 33 | ||
34 | static int force; | ||
38 | static int input; | 35 | static int input; |
39 | static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; | 36 | static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; |
40 | 37 | ||
@@ -43,6 +40,10 @@ static int dump_trace = 0; | |||
43 | 40 | ||
44 | static int verbose; | 41 | static int verbose; |
45 | 42 | ||
43 | static int modules; | ||
44 | |||
45 | static int full_paths; | ||
46 | |||
46 | static int print_line; | 47 | static int print_line; |
47 | 48 | ||
48 | static unsigned long page_size; | 49 | static unsigned long page_size; |
@@ -74,20 +75,12 @@ struct fork_event { | |||
74 | u32 pid, ppid; | 75 | u32 pid, ppid; |
75 | }; | 76 | }; |
76 | 77 | ||
77 | struct period_event { | ||
78 | struct perf_event_header header; | ||
79 | u64 time; | ||
80 | u64 id; | ||
81 | u64 sample_period; | ||
82 | }; | ||
83 | |||
84 | typedef union event_union { | 78 | typedef union event_union { |
85 | struct perf_event_header header; | 79 | struct perf_event_header header; |
86 | struct ip_event ip; | 80 | struct ip_event ip; |
87 | struct mmap_event mmap; | 81 | struct mmap_event mmap; |
88 | struct comm_event comm; | 82 | struct comm_event comm; |
89 | struct fork_event fork; | 83 | struct fork_event fork; |
90 | struct period_event period; | ||
91 | } event_t; | 84 | } event_t; |
92 | 85 | ||
93 | 86 | ||
@@ -160,7 +153,7 @@ static void dsos__fprintf(FILE *fp) | |||
160 | 153 | ||
161 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) | 154 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) |
162 | { | 155 | { |
163 | return dso__find_symbol(kernel_dso, ip); | 156 | return dso__find_symbol(dso, ip); |
164 | } | 157 | } |
165 | 158 | ||
166 | static int load_kernel(void) | 159 | static int load_kernel(void) |
@@ -171,8 +164,8 @@ static int load_kernel(void) | |||
171 | if (!kernel_dso) | 164 | if (!kernel_dso) |
172 | return -1; | 165 | return -1; |
173 | 166 | ||
174 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); | 167 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); |
175 | if (err) { | 168 | if (err <= 0) { |
176 | dso__delete(kernel_dso); | 169 | dso__delete(kernel_dso); |
177 | kernel_dso = NULL; | 170 | kernel_dso = NULL; |
178 | } else | 171 | } else |
@@ -203,7 +196,7 @@ static u64 map__map_ip(struct map *map, u64 ip) | |||
203 | return ip - map->start + map->pgoff; | 196 | return ip - map->start + map->pgoff; |
204 | } | 197 | } |
205 | 198 | ||
206 | static u64 vdso__map_ip(struct map *map, u64 ip) | 199 | static u64 vdso__map_ip(struct map *map __used, u64 ip) |
207 | { | 200 | { |
208 | return ip; | 201 | return ip; |
209 | } | 202 | } |
@@ -600,7 +593,7 @@ static LIST_HEAD(hist_entry__sort_list); | |||
600 | 593 | ||
601 | static int sort_dimension__add(char *tok) | 594 | static int sort_dimension__add(char *tok) |
602 | { | 595 | { |
603 | int i; | 596 | unsigned int i; |
604 | 597 | ||
605 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { | 598 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { |
606 | struct sort_dimension *sd = &sort_dimensions[i]; | 599 | struct sort_dimension *sd = &sort_dimensions[i]; |
@@ -988,6 +981,13 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head) | |||
988 | (void *)(long)(event->header.size), | 981 | (void *)(long)(event->header.size), |
989 | event->fork.pid, event->fork.ppid); | 982 | event->fork.pid, event->fork.ppid); |
990 | 983 | ||
984 | /* | ||
985 | * A thread clone will have the same PID for both | ||
986 | * parent and child. | ||
987 | */ | ||
988 | if (thread == parent) | ||
989 | return 0; | ||
990 | |||
991 | if (!thread || !parent || thread__fork(thread, parent)) { | 991 | if (!thread || !parent || thread__fork(thread, parent)) { |
992 | dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); | 992 | dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); |
993 | return -1; | 993 | return -1; |
@@ -998,19 +998,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head) | |||
998 | } | 998 | } |
999 | 999 | ||
1000 | static int | 1000 | static int |
1001 | process_period_event(event_t *event, unsigned long offset, unsigned long head) | ||
1002 | { | ||
1003 | dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n", | ||
1004 | (void *)(offset + head), | ||
1005 | (void *)(long)(event->header.size), | ||
1006 | event->period.time, | ||
1007 | event->period.id, | ||
1008 | event->period.sample_period); | ||
1009 | |||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static int | ||
1014 | process_event(event_t *event, unsigned long offset, unsigned long head) | 1001 | process_event(event_t *event, unsigned long offset, unsigned long head) |
1015 | { | 1002 | { |
1016 | switch (event->header.type) { | 1003 | switch (event->header.type) { |
@@ -1025,9 +1012,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1025 | 1012 | ||
1026 | case PERF_EVENT_FORK: | 1013 | case PERF_EVENT_FORK: |
1027 | return process_fork_event(event, offset, head); | 1014 | return process_fork_event(event, offset, head); |
1028 | |||
1029 | case PERF_EVENT_PERIOD: | ||
1030 | return process_period_event(event, offset, head); | ||
1031 | /* | 1015 | /* |
1032 | * We dont process them right now but they are fine: | 1016 | * We dont process them right now but they are fine: |
1033 | */ | 1017 | */ |
@@ -1043,24 +1027,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1043 | return 0; | 1027 | return 0; |
1044 | } | 1028 | } |
1045 | 1029 | ||
1046 | static char *get_color(double percent) | ||
1047 | { | ||
1048 | char *color = PERF_COLOR_NORMAL; | ||
1049 | |||
1050 | /* | ||
1051 | * We color high-overhead entries in red, mid-overhead | ||
1052 | * entries in green - and keep the low overhead places | ||
1053 | * normal: | ||
1054 | */ | ||
1055 | if (percent >= MIN_RED) | ||
1056 | color = PERF_COLOR_RED; | ||
1057 | else { | ||
1058 | if (percent > MIN_GREEN) | ||
1059 | color = PERF_COLOR_GREEN; | ||
1060 | } | ||
1061 | return color; | ||
1062 | } | ||
1063 | |||
1064 | static int | 1030 | static int |
1065 | parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) | 1031 | parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) |
1066 | { | 1032 | { |
@@ -1069,7 +1035,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) | |||
1069 | static const char *prev_color; | 1035 | static const char *prev_color; |
1070 | unsigned int offset; | 1036 | unsigned int offset; |
1071 | size_t line_len; | 1037 | size_t line_len; |
1072 | u64 line_ip; | 1038 | s64 line_ip; |
1073 | int ret; | 1039 | int ret; |
1074 | char *c; | 1040 | char *c; |
1075 | 1041 | ||
@@ -1122,7 +1088,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) | |||
1122 | } else if (sym->hist_sum) | 1088 | } else if (sym->hist_sum) |
1123 | percent = 100.0 * hits / sym->hist_sum; | 1089 | percent = 100.0 * hits / sym->hist_sum; |
1124 | 1090 | ||
1125 | color = get_color(percent); | 1091 | color = get_percent_color(percent); |
1126 | 1092 | ||
1127 | /* | 1093 | /* |
1128 | * Also color the filename and line if needed, with | 1094 | * Also color the filename and line if needed, with |
@@ -1258,7 +1224,7 @@ static void print_summary(char *filename) | |||
1258 | 1224 | ||
1259 | sym_ext = rb_entry(node, struct sym_ext, node); | 1225 | sym_ext = rb_entry(node, struct sym_ext, node); |
1260 | percent = sym_ext->percent; | 1226 | percent = sym_ext->percent; |
1261 | color = get_color(percent); | 1227 | color = get_percent_color(percent); |
1262 | path = sym_ext->path; | 1228 | path = sym_ext->path; |
1263 | 1229 | ||
1264 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | 1230 | color_fprintf(stdout, color, " %7.2f %s", percent, path); |
@@ -1268,19 +1234,25 @@ static void print_summary(char *filename) | |||
1268 | 1234 | ||
1269 | static void annotate_sym(struct dso *dso, struct symbol *sym) | 1235 | static void annotate_sym(struct dso *dso, struct symbol *sym) |
1270 | { | 1236 | { |
1271 | char *filename = dso->name; | 1237 | char *filename = dso->name, *d_filename; |
1272 | u64 start, end, len; | 1238 | u64 start, end, len; |
1273 | char command[PATH_MAX*2]; | 1239 | char command[PATH_MAX*2]; |
1274 | FILE *file; | 1240 | FILE *file; |
1275 | 1241 | ||
1276 | if (!filename) | 1242 | if (!filename) |
1277 | return; | 1243 | return; |
1278 | if (dso == kernel_dso) | 1244 | if (sym->module) |
1245 | filename = sym->module->path; | ||
1246 | else if (dso == kernel_dso) | ||
1279 | filename = vmlinux; | 1247 | filename = vmlinux; |
1280 | 1248 | ||
1281 | start = sym->obj_start; | 1249 | start = sym->obj_start; |
1282 | if (!start) | 1250 | if (!start) |
1283 | start = sym->start; | 1251 | start = sym->start; |
1252 | if (full_paths) | ||
1253 | d_filename = filename; | ||
1254 | else | ||
1255 | d_filename = basename(filename); | ||
1284 | 1256 | ||
1285 | end = start + sym->end - sym->start + 1; | 1257 | end = start + sym->end - sym->start + 1; |
1286 | len = sym->end - sym->start; | 1258 | len = sym->end - sym->start; |
@@ -1291,13 +1263,14 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
1291 | } | 1263 | } |
1292 | 1264 | ||
1293 | printf("\n\n------------------------------------------------\n"); | 1265 | printf("\n\n------------------------------------------------\n"); |
1294 | printf(" Percent | Source code & Disassembly of %s\n", filename); | 1266 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); |
1295 | printf("------------------------------------------------\n"); | 1267 | printf("------------------------------------------------\n"); |
1296 | 1268 | ||
1297 | if (verbose >= 2) | 1269 | if (verbose >= 2) |
1298 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | 1270 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); |
1299 | 1271 | ||
1300 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename); | 1272 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", |
1273 | (u64)start, (u64)end, filename, filename); | ||
1301 | 1274 | ||
1302 | if (verbose >= 3) | 1275 | if (verbose >= 3) |
1303 | printf("doing: %s\n", command); | 1276 | printf("doing: %s\n", command); |
@@ -1362,6 +1335,11 @@ static int __cmd_annotate(void) | |||
1362 | exit(-1); | 1335 | exit(-1); |
1363 | } | 1336 | } |
1364 | 1337 | ||
1338 | if (!force && (stat.st_uid != geteuid())) { | ||
1339 | fprintf(stderr, "file: %s not owned by current user\n", input_name); | ||
1340 | exit(-1); | ||
1341 | } | ||
1342 | |||
1365 | if (!stat.st_size) { | 1343 | if (!stat.st_size) { |
1366 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | 1344 | fprintf(stderr, "zero-sized file, nothing to do!\n"); |
1367 | exit(0); | 1345 | exit(0); |
@@ -1428,7 +1406,7 @@ more: | |||
1428 | 1406 | ||
1429 | head += size; | 1407 | head += size; |
1430 | 1408 | ||
1431 | if (offset + head < stat.st_size) | 1409 | if (offset + head < (unsigned long)stat.st_size) |
1432 | goto more; | 1410 | goto more; |
1433 | 1411 | ||
1434 | rc = EXIT_SUCCESS; | 1412 | rc = EXIT_SUCCESS; |
@@ -1467,13 +1445,18 @@ static const struct option options[] = { | |||
1467 | "input file name"), | 1445 | "input file name"), |
1468 | OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", | 1446 | OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", |
1469 | "symbol to annotate"), | 1447 | "symbol to annotate"), |
1448 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | ||
1470 | OPT_BOOLEAN('v', "verbose", &verbose, | 1449 | OPT_BOOLEAN('v', "verbose", &verbose, |
1471 | "be more verbose (show symbol address, etc)"), | 1450 | "be more verbose (show symbol address, etc)"), |
1472 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1451 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
1473 | "dump raw trace in ASCII"), | 1452 | "dump raw trace in ASCII"), |
1474 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), | 1453 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), |
1454 | OPT_BOOLEAN('m', "modules", &modules, | ||
1455 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | ||
1475 | OPT_BOOLEAN('l', "print-line", &print_line, | 1456 | OPT_BOOLEAN('l', "print-line", &print_line, |
1476 | "print matching source lines (may be slow)"), | 1457 | "print matching source lines (may be slow)"), |
1458 | OPT_BOOLEAN('P', "full-paths", &full_paths, | ||
1459 | "Don't shorten the displayed pathnames"), | ||
1477 | OPT_END() | 1460 | OPT_END() |
1478 | }; | 1461 | }; |
1479 | 1462 | ||
@@ -1492,7 +1475,7 @@ static void setup_sorting(void) | |||
1492 | free(str); | 1475 | free(str); |
1493 | } | 1476 | } |
1494 | 1477 | ||
1495 | int cmd_annotate(int argc, const char **argv, const char *prefix) | 1478 | int cmd_annotate(int argc, const char **argv, const char *prefix __used) |
1496 | { | 1479 | { |
1497 | symbol__init(); | 1480 | symbol__init(); |
1498 | 1481 | ||