aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-annotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r--tools/perf/builtin-annotate.c283
1 files changed, 221 insertions, 62 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index b1ed5f766cb3..5f9eefecc574 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
@@ -39,40 +39,46 @@ static int dump_trace = 0;
39 39
40static int verbose; 40static int verbose;
41 41
42static int modules;
43
44static int full_paths;
45
46static int print_line;
47
42static unsigned long page_size; 48static unsigned long page_size;
43static unsigned long mmap_window = 32; 49static unsigned long mmap_window = 32;
44 50
45struct ip_event { 51struct ip_event {
46 struct perf_event_header header; 52 struct perf_event_header header;
47 __u64 ip; 53 u64 ip;
48 __u32 pid, tid; 54 u32 pid, tid;
49}; 55};
50 56
51struct mmap_event { 57struct mmap_event {
52 struct perf_event_header header; 58 struct perf_event_header header;
53 __u32 pid, tid; 59 u32 pid, tid;
54 __u64 start; 60 u64 start;
55 __u64 len; 61 u64 len;
56 __u64 pgoff; 62 u64 pgoff;
57 char filename[PATH_MAX]; 63 char filename[PATH_MAX];
58}; 64};
59 65
60struct comm_event { 66struct comm_event {
61 struct perf_event_header header; 67 struct perf_event_header header;
62 __u32 pid, tid; 68 u32 pid, tid;
63 char comm[16]; 69 char comm[16];
64}; 70};
65 71
66struct fork_event { 72struct fork_event {
67 struct perf_event_header header; 73 struct perf_event_header header;
68 __u32 pid, ppid; 74 u32 pid, ppid;
69}; 75};
70 76
71struct period_event { 77struct period_event {
72 struct perf_event_header header; 78 struct perf_event_header header;
73 __u64 time; 79 u64 time;
74 __u64 id; 80 u64 id;
75 __u64 sample_period; 81 u64 sample_period;
76}; 82};
77 83
78typedef union event_union { 84typedef union event_union {
@@ -84,6 +90,13 @@ typedef union event_union {
84 struct period_event period; 90 struct period_event period;
85} event_t; 91} event_t;
86 92
93
94struct sym_ext {
95 struct rb_node node;
96 double percent;
97 char *path;
98};
99
87static LIST_HEAD(dsos); 100static LIST_HEAD(dsos);
88static struct dso *kernel_dso; 101static struct dso *kernel_dso;
89static struct dso *vdso; 102static struct dso *vdso;
@@ -145,9 +158,9 @@ static void dsos__fprintf(FILE *fp)
145 dso__fprintf(pos, fp); 158 dso__fprintf(pos, fp);
146} 159}
147 160
148static struct symbol *vdso__find_symbol(struct dso *dso, __u64 ip) 161static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
149{ 162{
150 return dso__find_symbol(kernel_dso, ip); 163 return dso__find_symbol(dso, ip);
151} 164}
152 165
153static int load_kernel(void) 166static int load_kernel(void)
@@ -158,8 +171,8 @@ static int load_kernel(void)
158 if (!kernel_dso) 171 if (!kernel_dso)
159 return -1; 172 return -1;
160 173
161 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); 174 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
162 if (err) { 175 if (err <= 0) {
163 dso__delete(kernel_dso); 176 dso__delete(kernel_dso);
164 kernel_dso = NULL; 177 kernel_dso = NULL;
165 } else 178 } else
@@ -178,19 +191,19 @@ static int load_kernel(void)
178 191
179struct map { 192struct map {
180 struct list_head node; 193 struct list_head node;
181 __u64 start; 194 u64 start;
182 __u64 end; 195 u64 end;
183 __u64 pgoff; 196 u64 pgoff;
184 __u64 (*map_ip)(struct map *, __u64); 197 u64 (*map_ip)(struct map *, u64);
185 struct dso *dso; 198 struct dso *dso;
186}; 199};
187 200
188static __u64 map__map_ip(struct map *map, __u64 ip) 201static u64 map__map_ip(struct map *map, u64 ip)
189{ 202{
190 return ip - map->start + map->pgoff; 203 return ip - map->start + map->pgoff;
191} 204}
192 205
193static __u64 vdso__map_ip(struct map *map, __u64 ip) 206static u64 vdso__map_ip(struct map *map __used, u64 ip)
194{ 207{
195 return ip; 208 return ip;
196} 209}
@@ -373,7 +386,7 @@ static int thread__fork(struct thread *self, struct thread *parent)
373 return 0; 386 return 0;
374} 387}
375 388
376static struct map *thread__find_map(struct thread *self, __u64 ip) 389static struct map *thread__find_map(struct thread *self, u64 ip)
377{ 390{
378 struct map *pos; 391 struct map *pos;
379 392
@@ -414,7 +427,7 @@ struct hist_entry {
414 struct map *map; 427 struct map *map;
415 struct dso *dso; 428 struct dso *dso;
416 struct symbol *sym; 429 struct symbol *sym;
417 __u64 ip; 430 u64 ip;
418 char level; 431 char level;
419 432
420 uint32_t count; 433 uint32_t count;
@@ -519,7 +532,7 @@ sort__dso_print(FILE *fp, struct hist_entry *self)
519 if (self->dso) 532 if (self->dso)
520 return fprintf(fp, "%-25s", self->dso->name); 533 return fprintf(fp, "%-25s", self->dso->name);
521 534
522 return fprintf(fp, "%016llx ", (__u64)self->ip); 535 return fprintf(fp, "%016llx ", (u64)self->ip);
523} 536}
524 537
525static struct sort_entry sort_dso = { 538static struct sort_entry sort_dso = {
@@ -533,7 +546,7 @@ static struct sort_entry sort_dso = {
533static int64_t 546static int64_t
534sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 547sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
535{ 548{
536 __u64 ip_l, ip_r; 549 u64 ip_l, ip_r;
537 550
538 if (left->sym == right->sym) 551 if (left->sym == right->sym)
539 return 0; 552 return 0;
@@ -550,13 +563,13 @@ sort__sym_print(FILE *fp, struct hist_entry *self)
550 size_t ret = 0; 563 size_t ret = 0;
551 564
552 if (verbose) 565 if (verbose)
553 ret += fprintf(fp, "%#018llx ", (__u64)self->ip); 566 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
554 567
555 if (self->sym) { 568 if (self->sym) {
556 ret += fprintf(fp, "[%c] %s", 569 ret += fprintf(fp, "[%c] %s",
557 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 570 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
558 } else { 571 } else {
559 ret += fprintf(fp, "%#016llx", (__u64)self->ip); 572 ret += fprintf(fp, "%#016llx", (u64)self->ip);
560 } 573 }
561 574
562 return ret; 575 return ret;
@@ -587,7 +600,7 @@ static LIST_HEAD(hist_entry__sort_list);
587 600
588static int sort_dimension__add(char *tok) 601static int sort_dimension__add(char *tok)
589{ 602{
590 int i; 603 unsigned int i;
591 604
592 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 605 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
593 struct sort_dimension *sd = &sort_dimensions[i]; 606 struct sort_dimension *sd = &sort_dimensions[i];
@@ -647,7 +660,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
647/* 660/*
648 * collect histogram counts 661 * collect histogram counts
649 */ 662 */
650static void hist_hit(struct hist_entry *he, __u64 ip) 663static void hist_hit(struct hist_entry *he, u64 ip)
651{ 664{
652 unsigned int sym_size, offset; 665 unsigned int sym_size, offset;
653 struct symbol *sym = he->sym; 666 struct symbol *sym = he->sym;
@@ -676,7 +689,7 @@ static void hist_hit(struct hist_entry *he, __u64 ip)
676 689
677static int 690static int
678hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 691hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
679 struct symbol *sym, __u64 ip, char level) 692 struct symbol *sym, u64 ip, char level)
680{ 693{
681 struct rb_node **p = &hist.rb_node; 694 struct rb_node **p = &hist.rb_node;
682 struct rb_node *parent = NULL; 695 struct rb_node *parent = NULL;
@@ -842,13 +855,13 @@ static unsigned long total = 0,
842 total_unknown = 0; 855 total_unknown = 0;
843 856
844static int 857static int
845process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 858process_sample_event(event_t *event, unsigned long offset, unsigned long head)
846{ 859{
847 char level; 860 char level;
848 int show = 0; 861 int show = 0;
849 struct dso *dso = NULL; 862 struct dso *dso = NULL;
850 struct thread *thread = threads__findnew(event->ip.pid); 863 struct thread *thread = threads__findnew(event->ip.pid);
851 __u64 ip = event->ip.ip; 864 u64 ip = event->ip.ip;
852 struct map *map = NULL; 865 struct map *map = NULL;
853 866
854 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", 867 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
@@ -1000,10 +1013,10 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head)
1000static int 1013static int
1001process_event(event_t *event, unsigned long offset, unsigned long head) 1014process_event(event_t *event, unsigned long offset, unsigned long head)
1002{ 1015{
1003 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1004 return process_overflow_event(event, offset, head);
1005
1006 switch (event->header.type) { 1016 switch (event->header.type) {
1017 case PERF_EVENT_SAMPLE:
1018 return process_sample_event(event, offset, head);
1019
1007 case PERF_EVENT_MMAP: 1020 case PERF_EVENT_MMAP:
1008 return process_mmap_event(event, offset, head); 1021 return process_mmap_event(event, offset, head);
1009 1022
@@ -1031,12 +1044,14 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1031} 1044}
1032 1045
1033static int 1046static int
1034parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) 1047parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1035{ 1048{
1036 char *line = NULL, *tmp, *tmp2; 1049 char *line = NULL, *tmp, *tmp2;
1050 static const char *prev_line;
1051 static const char *prev_color;
1037 unsigned int offset; 1052 unsigned int offset;
1038 size_t line_len; 1053 size_t line_len;
1039 __u64 line_ip; 1054 s64 line_ip;
1040 int ret; 1055 int ret;
1041 char *c; 1056 char *c;
1042 1057
@@ -1073,27 +1088,36 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1073 } 1088 }
1074 1089
1075 if (line_ip != -1) { 1090 if (line_ip != -1) {
1091 const char *path = NULL;
1076 unsigned int hits = 0; 1092 unsigned int hits = 0;
1077 double percent = 0.0; 1093 double percent = 0.0;
1078 char *color = PERF_COLOR_NORMAL; 1094 char *color;
1095 struct sym_ext *sym_ext = sym->priv;
1079 1096
1080 offset = line_ip - start; 1097 offset = line_ip - start;
1081 if (offset < len) 1098 if (offset < len)
1082 hits = sym->hist[offset]; 1099 hits = sym->hist[offset];
1083 1100
1084 if (sym->hist_sum) 1101 if (offset < len && sym_ext) {
1102 path = sym_ext[offset].path;
1103 percent = sym_ext[offset].percent;
1104 } else if (sym->hist_sum)
1085 percent = 100.0 * hits / sym->hist_sum; 1105 percent = 100.0 * hits / sym->hist_sum;
1086 1106
1107 color = get_percent_color(percent);
1108
1087 /* 1109 /*
1088 * We color high-overhead entries in red, mid-overhead 1110 * Also color the filename and line if needed, with
1089 * entries in green - and keep the low overhead places 1111 * the same color than the percentage. Don't print it
1090 * normal: 1112 * twice for close colored ip with the same filename:line
1091 */ 1113 */
1092 if (percent >= 5.0) 1114 if (path) {
1093 color = PERF_COLOR_RED; 1115 if (!prev_line || strcmp(prev_line, path)
1094 else { 1116 || color != prev_color) {
1095 if (percent > 0.5) 1117 color_fprintf(stdout, color, " %s", path);
1096 color = PERF_COLOR_GREEN; 1118 prev_line = path;
1119 prev_color = color;
1120 }
1097 } 1121 }
1098 1122
1099 color_fprintf(stdout, color, " %7.2f", percent); 1123 color_fprintf(stdout, color, " %7.2f", percent);
@@ -1109,33 +1133,160 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1109 return 0; 1133 return 0;
1110} 1134}
1111 1135
1136static struct rb_root root_sym_ext;
1137
1138static void insert_source_line(struct sym_ext *sym_ext)
1139{
1140 struct sym_ext *iter;
1141 struct rb_node **p = &root_sym_ext.rb_node;
1142 struct rb_node *parent = NULL;
1143
1144 while (*p != NULL) {
1145 parent = *p;
1146 iter = rb_entry(parent, struct sym_ext, node);
1147
1148 if (sym_ext->percent > iter->percent)
1149 p = &(*p)->rb_left;
1150 else
1151 p = &(*p)->rb_right;
1152 }
1153
1154 rb_link_node(&sym_ext->node, parent, p);
1155 rb_insert_color(&sym_ext->node, &root_sym_ext);
1156}
1157
1158static void free_source_line(struct symbol *sym, int len)
1159{
1160 struct sym_ext *sym_ext = sym->priv;
1161 int i;
1162
1163 if (!sym_ext)
1164 return;
1165
1166 for (i = 0; i < len; i++)
1167 free(sym_ext[i].path);
1168 free(sym_ext);
1169
1170 sym->priv = NULL;
1171 root_sym_ext = RB_ROOT;
1172}
1173
1174/* Get the filename:line for the colored entries */
1175static void
1176get_source_line(struct symbol *sym, u64 start, int len, char *filename)
1177{
1178 int i;
1179 char cmd[PATH_MAX * 2];
1180 struct sym_ext *sym_ext;
1181
1182 if (!sym->hist_sum)
1183 return;
1184
1185 sym->priv = calloc(len, sizeof(struct sym_ext));
1186 if (!sym->priv)
1187 return;
1188
1189 sym_ext = sym->priv;
1190
1191 for (i = 0; i < len; i++) {
1192 char *path = NULL;
1193 size_t line_len;
1194 u64 offset;
1195 FILE *fp;
1196
1197 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
1198 if (sym_ext[i].percent <= 0.5)
1199 continue;
1200
1201 offset = start + i;
1202 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
1203 fp = popen(cmd, "r");
1204 if (!fp)
1205 continue;
1206
1207 if (getline(&path, &line_len, fp) < 0 || !line_len)
1208 goto next;
1209
1210 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
1211 if (!sym_ext[i].path)
1212 goto next;
1213
1214 strcpy(sym_ext[i].path, path);
1215 insert_source_line(&sym_ext[i]);
1216
1217 next:
1218 pclose(fp);
1219 }
1220}
1221
1222static void print_summary(char *filename)
1223{
1224 struct sym_ext *sym_ext;
1225 struct rb_node *node;
1226
1227 printf("\nSorted summary for file %s\n", filename);
1228 printf("----------------------------------------------\n\n");
1229
1230 if (RB_EMPTY_ROOT(&root_sym_ext)) {
1231 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
1232 return;
1233 }
1234
1235 node = rb_first(&root_sym_ext);
1236 while (node) {
1237 double percent;
1238 char *color;
1239 char *path;
1240
1241 sym_ext = rb_entry(node, struct sym_ext, node);
1242 percent = sym_ext->percent;
1243 color = get_percent_color(percent);
1244 path = sym_ext->path;
1245
1246 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1247 node = rb_next(node);
1248 }
1249}
1250
1112static void annotate_sym(struct dso *dso, struct symbol *sym) 1251static void annotate_sym(struct dso *dso, struct symbol *sym)
1113{ 1252{
1114 char *filename = dso->name; 1253 char *filename = dso->name, *d_filename;
1115 __u64 start, end, len; 1254 u64 start, end, len;
1116 char command[PATH_MAX*2]; 1255 char command[PATH_MAX*2];
1117 FILE *file; 1256 FILE *file;
1118 1257
1119 if (!filename) 1258 if (!filename)
1120 return; 1259 return;
1121 if (dso == kernel_dso) 1260 if (sym->module)
1261 filename = sym->module->path;
1262 else if (dso == kernel_dso)
1122 filename = vmlinux; 1263 filename = vmlinux;
1123 1264
1124 printf("\n------------------------------------------------\n");
1125 printf(" Percent | Source code & Disassembly of %s\n", filename);
1126 printf("------------------------------------------------\n");
1127
1128 if (verbose >= 2)
1129 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1130
1131 start = sym->obj_start; 1265 start = sym->obj_start;
1132 if (!start) 1266 if (!start)
1133 start = sym->start; 1267 start = sym->start;
1268 if (full_paths)
1269 d_filename = filename;
1270 else
1271 d_filename = basename(filename);
1134 1272
1135 end = start + sym->end - sym->start + 1; 1273 end = start + sym->end - sym->start + 1;
1136 len = sym->end - sym->start; 1274 len = sym->end - sym->start;
1137 1275
1138 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); 1276 if (print_line) {
1277 get_source_line(sym, start, len, filename);
1278 print_summary(filename);
1279 }
1280
1281 printf("\n\n------------------------------------------------\n");
1282 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
1283 printf("------------------------------------------------\n");
1284
1285 if (verbose >= 2)
1286 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1287
1288 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
1289 (u64)start, (u64)end, filename, filename);
1139 1290
1140 if (verbose >= 3) 1291 if (verbose >= 3)
1141 printf("doing: %s\n", command); 1292 printf("doing: %s\n", command);
@@ -1150,6 +1301,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1150 } 1301 }
1151 1302
1152 pclose(file); 1303 pclose(file);
1304 if (print_line)
1305 free_source_line(sym, len);
1153} 1306}
1154 1307
1155static void find_annotations(void) 1308static void find_annotations(void)
@@ -1264,7 +1417,7 @@ more:
1264 1417
1265 head += size; 1418 head += size;
1266 1419
1267 if (offset + head < stat.st_size) 1420 if (offset + head < (unsigned long)stat.st_size)
1268 goto more; 1421 goto more;
1269 1422
1270 rc = EXIT_SUCCESS; 1423 rc = EXIT_SUCCESS;
@@ -1308,6 +1461,12 @@ static const struct option options[] = {
1308 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1461 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1309 "dump raw trace in ASCII"), 1462 "dump raw trace in ASCII"),
1310 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1463 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1464 OPT_BOOLEAN('m', "modules", &modules,
1465 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1466 OPT_BOOLEAN('l', "print-line", &print_line,
1467 "print matching source lines (may be slow)"),
1468 OPT_BOOLEAN('P', "full-paths", &full_paths,
1469 "Don't shorten the displayed pathnames"),
1311 OPT_END() 1470 OPT_END()
1312}; 1471};
1313 1472
@@ -1326,7 +1485,7 @@ static void setup_sorting(void)
1326 free(str); 1485 free(str);
1327} 1486}
1328 1487
1329int cmd_annotate(int argc, const char **argv, const char *prefix) 1488int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1330{ 1489{
1331 symbol__init(); 1490 symbol__init();
1332 1491