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.c301
1 files changed, 218 insertions, 83 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index b1ed5f766cb3..1dba568e1941 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,39 @@ 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};
70
71struct period_event {
72 struct perf_event_header header;
73 __u64 time;
74 __u64 id;
75 __u64 sample_period;
76}; 75};
77 76
78typedef union event_union { 77typedef union event_union {
@@ -81,9 +80,15 @@ typedef union event_union {
81 struct mmap_event mmap; 80 struct mmap_event mmap;
82 struct comm_event comm; 81 struct comm_event comm;
83 struct fork_event fork; 82 struct fork_event fork;
84 struct period_event period;
85} event_t; 83} event_t;
86 84
85
86struct sym_ext {
87 struct rb_node node;
88 double percent;
89 char *path;
90};
91
87static LIST_HEAD(dsos); 92static LIST_HEAD(dsos);
88static struct dso *kernel_dso; 93static struct dso *kernel_dso;
89static struct dso *vdso; 94static struct dso *vdso;
@@ -145,9 +150,9 @@ static void dsos__fprintf(FILE *fp)
145 dso__fprintf(pos, fp); 150 dso__fprintf(pos, fp);
146} 151}
147 152
148static struct symbol *vdso__find_symbol(struct dso *dso, __u64 ip) 153static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
149{ 154{
150 return dso__find_symbol(kernel_dso, ip); 155 return dso__find_symbol(dso, ip);
151} 156}
152 157
153static int load_kernel(void) 158static int load_kernel(void)
@@ -158,8 +163,8 @@ static int load_kernel(void)
158 if (!kernel_dso) 163 if (!kernel_dso)
159 return -1; 164 return -1;
160 165
161 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); 166 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
162 if (err) { 167 if (err <= 0) {
163 dso__delete(kernel_dso); 168 dso__delete(kernel_dso);
164 kernel_dso = NULL; 169 kernel_dso = NULL;
165 } else 170 } else
@@ -178,19 +183,19 @@ static int load_kernel(void)
178 183
179struct map { 184struct map {
180 struct list_head node; 185 struct list_head node;
181 __u64 start; 186 u64 start;
182 __u64 end; 187 u64 end;
183 __u64 pgoff; 188 u64 pgoff;
184 __u64 (*map_ip)(struct map *, __u64); 189 u64 (*map_ip)(struct map *, u64);
185 struct dso *dso; 190 struct dso *dso;
186}; 191};
187 192
188static __u64 map__map_ip(struct map *map, __u64 ip) 193static u64 map__map_ip(struct map *map, u64 ip)
189{ 194{
190 return ip - map->start + map->pgoff; 195 return ip - map->start + map->pgoff;
191} 196}
192 197
193static __u64 vdso__map_ip(struct map *map, __u64 ip) 198static u64 vdso__map_ip(struct map *map __used, u64 ip)
194{ 199{
195 return ip; 200 return ip;
196} 201}
@@ -373,7 +378,7 @@ static int thread__fork(struct thread *self, struct thread *parent)
373 return 0; 378 return 0;
374} 379}
375 380
376static struct map *thread__find_map(struct thread *self, __u64 ip) 381static struct map *thread__find_map(struct thread *self, u64 ip)
377{ 382{
378 struct map *pos; 383 struct map *pos;
379 384
@@ -414,7 +419,7 @@ struct hist_entry {
414 struct map *map; 419 struct map *map;
415 struct dso *dso; 420 struct dso *dso;
416 struct symbol *sym; 421 struct symbol *sym;
417 __u64 ip; 422 u64 ip;
418 char level; 423 char level;
419 424
420 uint32_t count; 425 uint32_t count;
@@ -519,7 +524,7 @@ sort__dso_print(FILE *fp, struct hist_entry *self)
519 if (self->dso) 524 if (self->dso)
520 return fprintf(fp, "%-25s", self->dso->name); 525 return fprintf(fp, "%-25s", self->dso->name);
521 526
522 return fprintf(fp, "%016llx ", (__u64)self->ip); 527 return fprintf(fp, "%016llx ", (u64)self->ip);
523} 528}
524 529
525static struct sort_entry sort_dso = { 530static struct sort_entry sort_dso = {
@@ -533,7 +538,7 @@ static struct sort_entry sort_dso = {
533static int64_t 538static int64_t
534sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 539sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
535{ 540{
536 __u64 ip_l, ip_r; 541 u64 ip_l, ip_r;
537 542
538 if (left->sym == right->sym) 543 if (left->sym == right->sym)
539 return 0; 544 return 0;
@@ -550,13 +555,13 @@ sort__sym_print(FILE *fp, struct hist_entry *self)
550 size_t ret = 0; 555 size_t ret = 0;
551 556
552 if (verbose) 557 if (verbose)
553 ret += fprintf(fp, "%#018llx ", (__u64)self->ip); 558 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
554 559
555 if (self->sym) { 560 if (self->sym) {
556 ret += fprintf(fp, "[%c] %s", 561 ret += fprintf(fp, "[%c] %s",
557 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 562 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
558 } else { 563 } else {
559 ret += fprintf(fp, "%#016llx", (__u64)self->ip); 564 ret += fprintf(fp, "%#016llx", (u64)self->ip);
560 } 565 }
561 566
562 return ret; 567 return ret;
@@ -587,7 +592,7 @@ static LIST_HEAD(hist_entry__sort_list);
587 592
588static int sort_dimension__add(char *tok) 593static int sort_dimension__add(char *tok)
589{ 594{
590 int i; 595 unsigned int i;
591 596
592 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 597 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
593 struct sort_dimension *sd = &sort_dimensions[i]; 598 struct sort_dimension *sd = &sort_dimensions[i];
@@ -647,7 +652,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
647/* 652/*
648 * collect histogram counts 653 * collect histogram counts
649 */ 654 */
650static void hist_hit(struct hist_entry *he, __u64 ip) 655static void hist_hit(struct hist_entry *he, u64 ip)
651{ 656{
652 unsigned int sym_size, offset; 657 unsigned int sym_size, offset;
653 struct symbol *sym = he->sym; 658 struct symbol *sym = he->sym;
@@ -676,7 +681,7 @@ static void hist_hit(struct hist_entry *he, __u64 ip)
676 681
677static int 682static int
678hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 683hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
679 struct symbol *sym, __u64 ip, char level) 684 struct symbol *sym, u64 ip, char level)
680{ 685{
681 struct rb_node **p = &hist.rb_node; 686 struct rb_node **p = &hist.rb_node;
682 struct rb_node *parent = NULL; 687 struct rb_node *parent = NULL;
@@ -842,13 +847,13 @@ static unsigned long total = 0,
842 total_unknown = 0; 847 total_unknown = 0;
843 848
844static int 849static int
845process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 850process_sample_event(event_t *event, unsigned long offset, unsigned long head)
846{ 851{
847 char level; 852 char level;
848 int show = 0; 853 int show = 0;
849 struct dso *dso = NULL; 854 struct dso *dso = NULL;
850 struct thread *thread = threads__findnew(event->ip.pid); 855 struct thread *thread = threads__findnew(event->ip.pid);
851 __u64 ip = event->ip.ip; 856 u64 ip = event->ip.ip;
852 struct map *map = NULL; 857 struct map *map = NULL;
853 858
854 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", 859 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
@@ -985,25 +990,12 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
985} 990}
986 991
987static int 992static int
988process_period_event(event_t *event, unsigned long offset, unsigned long head)
989{
990 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
991 (void *)(offset + head),
992 (void *)(long)(event->header.size),
993 event->period.time,
994 event->period.id,
995 event->period.sample_period);
996
997 return 0;
998}
999
1000static int
1001process_event(event_t *event, unsigned long offset, unsigned long head) 993process_event(event_t *event, unsigned long offset, unsigned long head)
1002{ 994{
1003 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1004 return process_overflow_event(event, offset, head);
1005
1006 switch (event->header.type) { 995 switch (event->header.type) {
996 case PERF_EVENT_SAMPLE:
997 return process_sample_event(event, offset, head);
998
1007 case PERF_EVENT_MMAP: 999 case PERF_EVENT_MMAP:
1008 return process_mmap_event(event, offset, head); 1000 return process_mmap_event(event, offset, head);
1009 1001
@@ -1012,9 +1004,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1012 1004
1013 case PERF_EVENT_FORK: 1005 case PERF_EVENT_FORK:
1014 return process_fork_event(event, offset, head); 1006 return process_fork_event(event, offset, head);
1015
1016 case PERF_EVENT_PERIOD:
1017 return process_period_event(event, offset, head);
1018 /* 1007 /*
1019 * We dont process them right now but they are fine: 1008 * We dont process them right now but they are fine:
1020 */ 1009 */
@@ -1031,12 +1020,14 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1031} 1020}
1032 1021
1033static int 1022static int
1034parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) 1023parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1035{ 1024{
1036 char *line = NULL, *tmp, *tmp2; 1025 char *line = NULL, *tmp, *tmp2;
1026 static const char *prev_line;
1027 static const char *prev_color;
1037 unsigned int offset; 1028 unsigned int offset;
1038 size_t line_len; 1029 size_t line_len;
1039 __u64 line_ip; 1030 s64 line_ip;
1040 int ret; 1031 int ret;
1041 char *c; 1032 char *c;
1042 1033
@@ -1073,27 +1064,36 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1073 } 1064 }
1074 1065
1075 if (line_ip != -1) { 1066 if (line_ip != -1) {
1067 const char *path = NULL;
1076 unsigned int hits = 0; 1068 unsigned int hits = 0;
1077 double percent = 0.0; 1069 double percent = 0.0;
1078 char *color = PERF_COLOR_NORMAL; 1070 char *color;
1071 struct sym_ext *sym_ext = sym->priv;
1079 1072
1080 offset = line_ip - start; 1073 offset = line_ip - start;
1081 if (offset < len) 1074 if (offset < len)
1082 hits = sym->hist[offset]; 1075 hits = sym->hist[offset];
1083 1076
1084 if (sym->hist_sum) 1077 if (offset < len && sym_ext) {
1078 path = sym_ext[offset].path;
1079 percent = sym_ext[offset].percent;
1080 } else if (sym->hist_sum)
1085 percent = 100.0 * hits / sym->hist_sum; 1081 percent = 100.0 * hits / sym->hist_sum;
1086 1082
1083 color = get_percent_color(percent);
1084
1087 /* 1085 /*
1088 * We color high-overhead entries in red, mid-overhead 1086 * Also color the filename and line if needed, with
1089 * entries in green - and keep the low overhead places 1087 * the same color than the percentage. Don't print it
1090 * normal: 1088 * twice for close colored ip with the same filename:line
1091 */ 1089 */
1092 if (percent >= 5.0) 1090 if (path) {
1093 color = PERF_COLOR_RED; 1091 if (!prev_line || strcmp(prev_line, path)
1094 else { 1092 || color != prev_color) {
1095 if (percent > 0.5) 1093 color_fprintf(stdout, color, " %s", path);
1096 color = PERF_COLOR_GREEN; 1094 prev_line = path;
1095 prev_color = color;
1096 }
1097 } 1097 }
1098 1098
1099 color_fprintf(stdout, color, " %7.2f", percent); 1099 color_fprintf(stdout, color, " %7.2f", percent);
@@ -1109,33 +1109,160 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1109 return 0; 1109 return 0;
1110} 1110}
1111 1111
1112static struct rb_root root_sym_ext;
1113
1114static void insert_source_line(struct sym_ext *sym_ext)
1115{
1116 struct sym_ext *iter;
1117 struct rb_node **p = &root_sym_ext.rb_node;
1118 struct rb_node *parent = NULL;
1119
1120 while (*p != NULL) {
1121 parent = *p;
1122 iter = rb_entry(parent, struct sym_ext, node);
1123
1124 if (sym_ext->percent > iter->percent)
1125 p = &(*p)->rb_left;
1126 else
1127 p = &(*p)->rb_right;
1128 }
1129
1130 rb_link_node(&sym_ext->node, parent, p);
1131 rb_insert_color(&sym_ext->node, &root_sym_ext);
1132}
1133
1134static void free_source_line(struct symbol *sym, int len)
1135{
1136 struct sym_ext *sym_ext = sym->priv;
1137 int i;
1138
1139 if (!sym_ext)
1140 return;
1141
1142 for (i = 0; i < len; i++)
1143 free(sym_ext[i].path);
1144 free(sym_ext);
1145
1146 sym->priv = NULL;
1147 root_sym_ext = RB_ROOT;
1148}
1149
1150/* Get the filename:line for the colored entries */
1151static void
1152get_source_line(struct symbol *sym, u64 start, int len, char *filename)
1153{
1154 int i;
1155 char cmd[PATH_MAX * 2];
1156 struct sym_ext *sym_ext;
1157
1158 if (!sym->hist_sum)
1159 return;
1160
1161 sym->priv = calloc(len, sizeof(struct sym_ext));
1162 if (!sym->priv)
1163 return;
1164
1165 sym_ext = sym->priv;
1166
1167 for (i = 0; i < len; i++) {
1168 char *path = NULL;
1169 size_t line_len;
1170 u64 offset;
1171 FILE *fp;
1172
1173 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
1174 if (sym_ext[i].percent <= 0.5)
1175 continue;
1176
1177 offset = start + i;
1178 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
1179 fp = popen(cmd, "r");
1180 if (!fp)
1181 continue;
1182
1183 if (getline(&path, &line_len, fp) < 0 || !line_len)
1184 goto next;
1185
1186 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
1187 if (!sym_ext[i].path)
1188 goto next;
1189
1190 strcpy(sym_ext[i].path, path);
1191 insert_source_line(&sym_ext[i]);
1192
1193 next:
1194 pclose(fp);
1195 }
1196}
1197
1198static void print_summary(char *filename)
1199{
1200 struct sym_ext *sym_ext;
1201 struct rb_node *node;
1202
1203 printf("\nSorted summary for file %s\n", filename);
1204 printf("----------------------------------------------\n\n");
1205
1206 if (RB_EMPTY_ROOT(&root_sym_ext)) {
1207 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
1208 return;
1209 }
1210
1211 node = rb_first(&root_sym_ext);
1212 while (node) {
1213 double percent;
1214 char *color;
1215 char *path;
1216
1217 sym_ext = rb_entry(node, struct sym_ext, node);
1218 percent = sym_ext->percent;
1219 color = get_percent_color(percent);
1220 path = sym_ext->path;
1221
1222 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1223 node = rb_next(node);
1224 }
1225}
1226
1112static void annotate_sym(struct dso *dso, struct symbol *sym) 1227static void annotate_sym(struct dso *dso, struct symbol *sym)
1113{ 1228{
1114 char *filename = dso->name; 1229 char *filename = dso->name, *d_filename;
1115 __u64 start, end, len; 1230 u64 start, end, len;
1116 char command[PATH_MAX*2]; 1231 char command[PATH_MAX*2];
1117 FILE *file; 1232 FILE *file;
1118 1233
1119 if (!filename) 1234 if (!filename)
1120 return; 1235 return;
1121 if (dso == kernel_dso) 1236 if (sym->module)
1237 filename = sym->module->path;
1238 else if (dso == kernel_dso)
1122 filename = vmlinux; 1239 filename = vmlinux;
1123 1240
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; 1241 start = sym->obj_start;
1132 if (!start) 1242 if (!start)
1133 start = sym->start; 1243 start = sym->start;
1244 if (full_paths)
1245 d_filename = filename;
1246 else
1247 d_filename = basename(filename);
1134 1248
1135 end = start + sym->end - sym->start + 1; 1249 end = start + sym->end - sym->start + 1;
1136 len = sym->end - sym->start; 1250 len = sym->end - sym->start;
1137 1251
1138 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); 1252 if (print_line) {
1253 get_source_line(sym, start, len, filename);
1254 print_summary(filename);
1255 }
1256
1257 printf("\n\n------------------------------------------------\n");
1258 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
1259 printf("------------------------------------------------\n");
1260
1261 if (verbose >= 2)
1262 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1263
1264 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
1265 (u64)start, (u64)end, filename, filename);
1139 1266
1140 if (verbose >= 3) 1267 if (verbose >= 3)
1141 printf("doing: %s\n", command); 1268 printf("doing: %s\n", command);
@@ -1150,6 +1277,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1150 } 1277 }
1151 1278
1152 pclose(file); 1279 pclose(file);
1280 if (print_line)
1281 free_source_line(sym, len);
1153} 1282}
1154 1283
1155static void find_annotations(void) 1284static void find_annotations(void)
@@ -1264,7 +1393,7 @@ more:
1264 1393
1265 head += size; 1394 head += size;
1266 1395
1267 if (offset + head < stat.st_size) 1396 if (offset + head < (unsigned long)stat.st_size)
1268 goto more; 1397 goto more;
1269 1398
1270 rc = EXIT_SUCCESS; 1399 rc = EXIT_SUCCESS;
@@ -1308,6 +1437,12 @@ static const struct option options[] = {
1308 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1437 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1309 "dump raw trace in ASCII"), 1438 "dump raw trace in ASCII"),
1310 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1439 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1440 OPT_BOOLEAN('m', "modules", &modules,
1441 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1442 OPT_BOOLEAN('l', "print-line", &print_line,
1443 "print matching source lines (may be slow)"),
1444 OPT_BOOLEAN('P', "full-paths", &full_paths,
1445 "Don't shorten the displayed pathnames"),
1311 OPT_END() 1446 OPT_END()
1312}; 1447};
1313 1448
@@ -1326,7 +1461,7 @@ static void setup_sorting(void)
1326 free(str); 1461 free(str);
1327} 1462}
1328 1463
1329int cmd_annotate(int argc, const char **argv, const char *prefix) 1464int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1330{ 1465{
1331 symbol__init(); 1466 symbol__init();
1332 1467