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.c262
1 files changed, 214 insertions, 48 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index b1ed5f766cb3..7e58e3ad1508 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -25,6 +25,10 @@
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
28static char const *input_name = "perf.data"; 32static char const *input_name = "perf.data";
29static char *vmlinux = "vmlinux"; 33static char *vmlinux = "vmlinux";
30 34
@@ -39,40 +43,42 @@ static int dump_trace = 0;
39 43
40static int verbose; 44static int verbose;
41 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,7 +158,7 @@ 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(kernel_dso, ip);
151} 164}
@@ -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, 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;
@@ -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;
@@ -848,7 +861,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
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",
@@ -1030,13 +1043,33 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1030 return 0; 1043 return 0;
1031} 1044}
1032 1045
1046static 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
1033static int 1064static int
1034parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) 1065parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1035{ 1066{
1036 char *line = NULL, *tmp, *tmp2; 1067 char *line = NULL, *tmp, *tmp2;
1068 static const char *prev_line;
1069 static const char *prev_color;
1037 unsigned int offset; 1070 unsigned int offset;
1038 size_t line_len; 1071 size_t line_len;
1039 __u64 line_ip; 1072 u64 line_ip;
1040 int ret; 1073 int ret;
1041 char *c; 1074 char *c;
1042 1075
@@ -1073,27 +1106,36 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1073 } 1106 }
1074 1107
1075 if (line_ip != -1) { 1108 if (line_ip != -1) {
1109 const char *path = NULL;
1076 unsigned int hits = 0; 1110 unsigned int hits = 0;
1077 double percent = 0.0; 1111 double percent = 0.0;
1078 char *color = PERF_COLOR_NORMAL; 1112 char *color;
1113 struct sym_ext *sym_ext = sym->priv;
1079 1114
1080 offset = line_ip - start; 1115 offset = line_ip - start;
1081 if (offset < len) 1116 if (offset < len)
1082 hits = sym->hist[offset]; 1117 hits = sym->hist[offset];
1083 1118
1084 if (sym->hist_sum) 1119 if (offset < len && sym_ext) {
1120 path = sym_ext[offset].path;
1121 percent = sym_ext[offset].percent;
1122 } else if (sym->hist_sum)
1085 percent = 100.0 * hits / sym->hist_sum; 1123 percent = 100.0 * hits / sym->hist_sum;
1086 1124
1125 color = get_color(percent);
1126
1087 /* 1127 /*
1088 * We color high-overhead entries in red, mid-overhead 1128 * Also color the filename and line if needed, with
1089 * entries in green - and keep the low overhead places 1129 * the same color than the percentage. Don't print it
1090 * normal: 1130 * twice for close colored ip with the same filename:line
1091 */ 1131 */
1092 if (percent >= 5.0) 1132 if (path) {
1093 color = PERF_COLOR_RED; 1133 if (!prev_line || strcmp(prev_line, path)
1094 else { 1134 || color != prev_color) {
1095 if (percent > 0.5) 1135 color_fprintf(stdout, color, " %s", path);
1096 color = PERF_COLOR_GREEN; 1136 prev_line = path;
1137 prev_color = color;
1138 }
1097 } 1139 }
1098 1140
1099 color_fprintf(stdout, color, " %7.2f", percent); 1141 color_fprintf(stdout, color, " %7.2f", percent);
@@ -1109,10 +1151,125 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1109 return 0; 1151 return 0;
1110} 1152}
1111 1153
1154static struct rb_root root_sym_ext;
1155
1156static void insert_source_line(struct sym_ext *sym_ext)
1157{
1158 struct sym_ext *iter;
1159 struct rb_node **p = &root_sym_ext.rb_node;
1160 struct rb_node *parent = NULL;
1161
1162 while (*p != NULL) {
1163 parent = *p;
1164 iter = rb_entry(parent, struct sym_ext, node);
1165
1166 if (sym_ext->percent > iter->percent)
1167 p = &(*p)->rb_left;
1168 else
1169 p = &(*p)->rb_right;
1170 }
1171
1172 rb_link_node(&sym_ext->node, parent, p);
1173 rb_insert_color(&sym_ext->node, &root_sym_ext);
1174}
1175
1176static void free_source_line(struct symbol *sym, int len)
1177{
1178 struct sym_ext *sym_ext = sym->priv;
1179 int i;
1180
1181 if (!sym_ext)
1182 return;
1183
1184 for (i = 0; i < len; i++)
1185 free(sym_ext[i].path);
1186 free(sym_ext);
1187
1188 sym->priv = NULL;
1189 root_sym_ext = RB_ROOT;
1190}
1191
1192/* Get the filename:line for the colored entries */
1193static void
1194get_source_line(struct symbol *sym, u64 start, int len, char *filename)
1195{
1196 int i;
1197 char cmd[PATH_MAX * 2];
1198 struct sym_ext *sym_ext;
1199
1200 if (!sym->hist_sum)
1201 return;
1202
1203 sym->priv = calloc(len, sizeof(struct sym_ext));
1204 if (!sym->priv)
1205 return;
1206
1207 sym_ext = sym->priv;
1208
1209 for (i = 0; i < len; i++) {
1210 char *path = NULL;
1211 size_t line_len;
1212 u64 offset;
1213 FILE *fp;
1214
1215 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
1216 if (sym_ext[i].percent <= 0.5)
1217 continue;
1218
1219 offset = start + i;
1220 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
1221 fp = popen(cmd, "r");
1222 if (!fp)
1223 continue;
1224
1225 if (getline(&path, &line_len, fp) < 0 || !line_len)
1226 goto next;
1227
1228 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
1229 if (!sym_ext[i].path)
1230 goto next;
1231
1232 strcpy(sym_ext[i].path, path);
1233 insert_source_line(&sym_ext[i]);
1234
1235 next:
1236 pclose(fp);
1237 }
1238}
1239
1240static void print_summary(char *filename)
1241{
1242 struct sym_ext *sym_ext;
1243 struct rb_node *node;
1244
1245 printf("\nSorted summary for file %s\n", filename);
1246 printf("----------------------------------------------\n\n");
1247
1248 if (RB_EMPTY_ROOT(&root_sym_ext)) {
1249 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
1250 return;
1251 }
1252
1253 node = rb_first(&root_sym_ext);
1254 while (node) {
1255 double percent;
1256 char *color;
1257 char *path;
1258
1259 sym_ext = rb_entry(node, struct sym_ext, node);
1260 percent = sym_ext->percent;
1261 color = get_color(percent);
1262 path = sym_ext->path;
1263
1264 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1265 node = rb_next(node);
1266 }
1267}
1268
1112static void annotate_sym(struct dso *dso, struct symbol *sym) 1269static void annotate_sym(struct dso *dso, struct symbol *sym)
1113{ 1270{
1114 char *filename = dso->name; 1271 char *filename = dso->name;
1115 __u64 start, end, len; 1272 u64 start, end, len;
1116 char command[PATH_MAX*2]; 1273 char command[PATH_MAX*2];
1117 FILE *file; 1274 FILE *file;
1118 1275
@@ -1121,13 +1278,6 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1121 if (dso == kernel_dso) 1278 if (dso == kernel_dso)
1122 filename = vmlinux; 1279 filename = vmlinux;
1123 1280
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; 1281 start = sym->obj_start;
1132 if (!start) 1282 if (!start)
1133 start = sym->start; 1283 start = sym->start;
@@ -1135,7 +1285,19 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1135 end = start + sym->end - sym->start + 1; 1285 end = start + sym->end - sym->start + 1;
1136 len = sym->end - sym->start; 1286 len = sym->end - sym->start;
1137 1287
1138 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); 1288 if (print_line) {
1289 get_source_line(sym, start, len, filename);
1290 print_summary(filename);
1291 }
1292
1293 printf("\n\n------------------------------------------------\n");
1294 printf(" Percent | Source code & Disassembly of %s\n", filename);
1295 printf("------------------------------------------------\n");
1296
1297 if (verbose >= 2)
1298 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1299
1300 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename);
1139 1301
1140 if (verbose >= 3) 1302 if (verbose >= 3)
1141 printf("doing: %s\n", command); 1303 printf("doing: %s\n", command);
@@ -1150,6 +1312,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1150 } 1312 }
1151 1313
1152 pclose(file); 1314 pclose(file);
1315 if (print_line)
1316 free_source_line(sym, len);
1153} 1317}
1154 1318
1155static void find_annotations(void) 1319static void find_annotations(void)
@@ -1308,6 +1472,8 @@ static const struct option options[] = {
1308 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1472 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1309 "dump raw trace in ASCII"), 1473 "dump raw trace in ASCII"),
1310 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1474 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1475 OPT_BOOLEAN('l', "print-line", &print_line,
1476 "print matching source lines (may be slow)"),
1311 OPT_END() 1477 OPT_END()
1312}; 1478};
1313 1479