diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
| -rw-r--r-- | tools/perf/builtin-annotate.c | 108 |
1 files changed, 42 insertions, 66 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 7e58e3ad1508..343e7b14bf01 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,10 +25,6 @@ | |||
| 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 | ||
| @@ -43,6 +39,10 @@ static int dump_trace = 0; | |||
| 43 | 39 | ||
| 44 | static int verbose; | 40 | static int verbose; |
| 45 | 41 | ||
| 42 | static int modules; | ||
| 43 | |||
| 44 | static int full_paths; | ||
| 45 | |||
| 46 | static int print_line; | 46 | static int print_line; |
| 47 | 47 | ||
| 48 | static unsigned long page_size; | 48 | static unsigned long page_size; |
| @@ -74,20 +74,12 @@ struct fork_event { | |||
| 74 | u32 pid, ppid; | 74 | u32 pid, ppid; |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 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 { | 77 | typedef union event_union { |
| 85 | struct perf_event_header header; | 78 | struct perf_event_header header; |
| 86 | struct ip_event ip; | 79 | struct ip_event ip; |
| 87 | struct mmap_event mmap; | 80 | struct mmap_event mmap; |
| 88 | struct comm_event comm; | 81 | struct comm_event comm; |
| 89 | struct fork_event fork; | 82 | struct fork_event fork; |
| 90 | struct period_event period; | ||
| 91 | } event_t; | 83 | } event_t; |
| 92 | 84 | ||
| 93 | 85 | ||
| @@ -160,7 +152,7 @@ static void dsos__fprintf(FILE *fp) | |||
| 160 | 152 | ||
| 161 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) | 153 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) |
| 162 | { | 154 | { |
| 163 | return dso__find_symbol(kernel_dso, ip); | 155 | return dso__find_symbol(dso, ip); |
| 164 | } | 156 | } |
| 165 | 157 | ||
| 166 | static int load_kernel(void) | 158 | static int load_kernel(void) |
| @@ -171,8 +163,8 @@ static int load_kernel(void) | |||
| 171 | if (!kernel_dso) | 163 | if (!kernel_dso) |
| 172 | return -1; | 164 | return -1; |
| 173 | 165 | ||
| 174 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); | 166 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); |
| 175 | if (err) { | 167 | if (err <= 0) { |
| 176 | dso__delete(kernel_dso); | 168 | dso__delete(kernel_dso); |
| 177 | kernel_dso = NULL; | 169 | kernel_dso = NULL; |
| 178 | } else | 170 | } else |
| @@ -203,7 +195,7 @@ static u64 map__map_ip(struct map *map, u64 ip) | |||
| 203 | return ip - map->start + map->pgoff; | 195 | return ip - map->start + map->pgoff; |
| 204 | } | 196 | } |
| 205 | 197 | ||
| 206 | static u64 vdso__map_ip(struct map *map, u64 ip) | 198 | static u64 vdso__map_ip(struct map *map __used, u64 ip) |
| 207 | { | 199 | { |
| 208 | return ip; | 200 | return ip; |
| 209 | } | 201 | } |
| @@ -600,7 +592,7 @@ static LIST_HEAD(hist_entry__sort_list); | |||
| 600 | 592 | ||
| 601 | static int sort_dimension__add(char *tok) | 593 | static int sort_dimension__add(char *tok) |
| 602 | { | 594 | { |
| 603 | int i; | 595 | unsigned int i; |
| 604 | 596 | ||
| 605 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { | 597 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { |
| 606 | struct sort_dimension *sd = &sort_dimensions[i]; | 598 | struct sort_dimension *sd = &sort_dimensions[i]; |
| @@ -855,7 +847,7 @@ static unsigned long total = 0, | |||
| 855 | total_unknown = 0; | 847 | total_unknown = 0; |
| 856 | 848 | ||
| 857 | static int | 849 | static int |
| 858 | process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | 850 | process_sample_event(event_t *event, unsigned long offset, unsigned long head) |
| 859 | { | 851 | { |
| 860 | char level; | 852 | char level; |
| 861 | int show = 0; | 853 | int show = 0; |
| @@ -988,6 +980,13 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 988 | (void *)(long)(event->header.size), | 980 | (void *)(long)(event->header.size), |
| 989 | event->fork.pid, event->fork.ppid); | 981 | event->fork.pid, event->fork.ppid); |
| 990 | 982 | ||
| 983 | /* | ||
| 984 | * A thread clone will have the same PID for both | ||
| 985 | * parent and child. | ||
| 986 | */ | ||
| 987 | if (thread == parent) | ||
| 988 | return 0; | ||
| 989 | |||
| 991 | if (!thread || !parent || thread__fork(thread, parent)) { | 990 | if (!thread || !parent || thread__fork(thread, parent)) { |
| 992 | dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); | 991 | dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); |
| 993 | return -1; | 992 | return -1; |
| @@ -998,25 +997,12 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 998 | } | 997 | } |
| 999 | 998 | ||
| 1000 | static int | 999 | 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) | 1000 | process_event(event_t *event, unsigned long offset, unsigned long head) |
| 1015 | { | 1001 | { |
| 1016 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) | ||
| 1017 | return process_overflow_event(event, offset, head); | ||
| 1018 | |||
| 1019 | switch (event->header.type) { | 1002 | switch (event->header.type) { |
| 1003 | case PERF_EVENT_SAMPLE: | ||
| 1004 | return process_sample_event(event, offset, head); | ||
| 1005 | |||
| 1020 | case PERF_EVENT_MMAP: | 1006 | case PERF_EVENT_MMAP: |
| 1021 | return process_mmap_event(event, offset, head); | 1007 | return process_mmap_event(event, offset, head); |
| 1022 | 1008 | ||
| @@ -1025,9 +1011,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1025 | 1011 | ||
| 1026 | case PERF_EVENT_FORK: | 1012 | case PERF_EVENT_FORK: |
| 1027 | return process_fork_event(event, offset, head); | 1013 | return process_fork_event(event, offset, head); |
| 1028 | |||
| 1029 | case PERF_EVENT_PERIOD: | ||
| 1030 | return process_period_event(event, offset, head); | ||
| 1031 | /* | 1014 | /* |
| 1032 | * We dont process them right now but they are fine: | 1015 | * We dont process them right now but they are fine: |
| 1033 | */ | 1016 | */ |
| @@ -1043,24 +1026,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1043 | return 0; | 1026 | return 0; |
| 1044 | } | 1027 | } |
| 1045 | 1028 | ||
| 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 | 1029 | static int |
| 1065 | parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) | 1030 | parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) |
| 1066 | { | 1031 | { |
| @@ -1069,7 +1034,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) | |||
| 1069 | static const char *prev_color; | 1034 | static const char *prev_color; |
| 1070 | unsigned int offset; | 1035 | unsigned int offset; |
| 1071 | size_t line_len; | 1036 | size_t line_len; |
| 1072 | u64 line_ip; | 1037 | s64 line_ip; |
| 1073 | int ret; | 1038 | int ret; |
| 1074 | char *c; | 1039 | char *c; |
| 1075 | 1040 | ||
| @@ -1122,7 +1087,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) | |||
| 1122 | } else if (sym->hist_sum) | 1087 | } else if (sym->hist_sum) |
| 1123 | percent = 100.0 * hits / sym->hist_sum; | 1088 | percent = 100.0 * hits / sym->hist_sum; |
| 1124 | 1089 | ||
| 1125 | color = get_color(percent); | 1090 | color = get_percent_color(percent); |
| 1126 | 1091 | ||
| 1127 | /* | 1092 | /* |
| 1128 | * Also color the filename and line if needed, with | 1093 | * Also color the filename and line if needed, with |
| @@ -1258,7 +1223,7 @@ static void print_summary(char *filename) | |||
| 1258 | 1223 | ||
| 1259 | sym_ext = rb_entry(node, struct sym_ext, node); | 1224 | sym_ext = rb_entry(node, struct sym_ext, node); |
| 1260 | percent = sym_ext->percent; | 1225 | percent = sym_ext->percent; |
| 1261 | color = get_color(percent); | 1226 | color = get_percent_color(percent); |
| 1262 | path = sym_ext->path; | 1227 | path = sym_ext->path; |
| 1263 | 1228 | ||
| 1264 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | 1229 | color_fprintf(stdout, color, " %7.2f %s", percent, path); |
| @@ -1268,19 +1233,25 @@ static void print_summary(char *filename) | |||
| 1268 | 1233 | ||
| 1269 | static void annotate_sym(struct dso *dso, struct symbol *sym) | 1234 | static void annotate_sym(struct dso *dso, struct symbol *sym) |
| 1270 | { | 1235 | { |
| 1271 | char *filename = dso->name; | 1236 | char *filename = dso->name, *d_filename; |
| 1272 | u64 start, end, len; | 1237 | u64 start, end, len; |
| 1273 | char command[PATH_MAX*2]; | 1238 | char command[PATH_MAX*2]; |
| 1274 | FILE *file; | 1239 | FILE *file; |
| 1275 | 1240 | ||
| 1276 | if (!filename) | 1241 | if (!filename) |
| 1277 | return; | 1242 | return; |
| 1278 | if (dso == kernel_dso) | 1243 | if (sym->module) |
| 1244 | filename = sym->module->path; | ||
| 1245 | else if (dso == kernel_dso) | ||
| 1279 | filename = vmlinux; | 1246 | filename = vmlinux; |
| 1280 | 1247 | ||
| 1281 | start = sym->obj_start; | 1248 | start = sym->obj_start; |
| 1282 | if (!start) | 1249 | if (!start) |
| 1283 | start = sym->start; | 1250 | start = sym->start; |
| 1251 | if (full_paths) | ||
| 1252 | d_filename = filename; | ||
| 1253 | else | ||
| 1254 | d_filename = basename(filename); | ||
| 1284 | 1255 | ||
| 1285 | end = start + sym->end - sym->start + 1; | 1256 | end = start + sym->end - sym->start + 1; |
| 1286 | len = sym->end - sym->start; | 1257 | len = sym->end - sym->start; |
| @@ -1291,13 +1262,14 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
| 1291 | } | 1262 | } |
| 1292 | 1263 | ||
| 1293 | printf("\n\n------------------------------------------------\n"); | 1264 | printf("\n\n------------------------------------------------\n"); |
| 1294 | printf(" Percent | Source code & Disassembly of %s\n", filename); | 1265 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); |
| 1295 | printf("------------------------------------------------\n"); | 1266 | printf("------------------------------------------------\n"); |
| 1296 | 1267 | ||
| 1297 | if (verbose >= 2) | 1268 | if (verbose >= 2) |
| 1298 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | 1269 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); |
| 1299 | 1270 | ||
| 1300 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename); | 1271 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", |
| 1272 | (u64)start, (u64)end, filename, filename); | ||
| 1301 | 1273 | ||
| 1302 | if (verbose >= 3) | 1274 | if (verbose >= 3) |
| 1303 | printf("doing: %s\n", command); | 1275 | printf("doing: %s\n", command); |
| @@ -1428,7 +1400,7 @@ more: | |||
| 1428 | 1400 | ||
| 1429 | head += size; | 1401 | head += size; |
| 1430 | 1402 | ||
| 1431 | if (offset + head < stat.st_size) | 1403 | if (offset + head < (unsigned long)stat.st_size) |
| 1432 | goto more; | 1404 | goto more; |
| 1433 | 1405 | ||
| 1434 | rc = EXIT_SUCCESS; | 1406 | rc = EXIT_SUCCESS; |
| @@ -1472,8 +1444,12 @@ static const struct option options[] = { | |||
| 1472 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1444 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
| 1473 | "dump raw trace in ASCII"), | 1445 | "dump raw trace in ASCII"), |
| 1474 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), | 1446 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), |
| 1447 | OPT_BOOLEAN('m', "modules", &modules, | ||
| 1448 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | ||
| 1475 | OPT_BOOLEAN('l', "print-line", &print_line, | 1449 | OPT_BOOLEAN('l', "print-line", &print_line, |
| 1476 | "print matching source lines (may be slow)"), | 1450 | "print matching source lines (may be slow)"), |
| 1451 | OPT_BOOLEAN('P', "full-paths", &full_paths, | ||
| 1452 | "Don't shorten the displayed pathnames"), | ||
| 1477 | OPT_END() | 1453 | OPT_END() |
| 1478 | }; | 1454 | }; |
| 1479 | 1455 | ||
| @@ -1492,7 +1468,7 @@ static void setup_sorting(void) | |||
| 1492 | free(str); | 1468 | free(str); |
| 1493 | } | 1469 | } |
| 1494 | 1470 | ||
| 1495 | int cmd_annotate(int argc, const char **argv, const char *prefix) | 1471 | int cmd_annotate(int argc, const char **argv, const char *prefix __used) |
| 1496 | { | 1472 | { |
| 1497 | symbol__init(); | 1473 | symbol__init(); |
| 1498 | 1474 | ||
