diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-06-12 18:11:22 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-13 06:58:23 -0400 |
commit | 971738f3669092dd247eaf89658f2685180492a0 (patch) | |
tree | 3b338afa8ecac80564769e0d6881e87b4587a2d3 /tools/perf/builtin-annotate.c | |
parent | 301406b9c69e4914cf45ae9d5f929e7bcf0d93cd (diff) |
perf annotate: Print a sorted summary of annotated overhead lines
It's can be very annoying to scroll down perf annotated output
until we find relevant overhead.
Using the -l option, you can now have a small summary sorted per
overhead in the beginning of the output.
Example:
./perf annotate -l -k ../../vmlinux -s __lock_acquire
Sorted summary for file ../../vmlinux
----------------------------------------------
12.04 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1653
4.61 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1740
3.77 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1775
3.56 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1653
2.93 /home/fweisbec/linux/linux-2.6-tip/arch/x86/include/asm/irqflags.h:15
2.83 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2545
2.30 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2594
2.20 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2388
2.20 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:730
2.09 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:730
2.09 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:138
1.88 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2548
1.47 /home/fweisbec/linux/linux-2.6-tip/arch/x86/include/asm/irqflags.h:15
1.36 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2594
1.36 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:730
1.26 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1654
1.26 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1653
1.15 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2592
1.15 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1740
1.15 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1740
[...]
Only overhead over 0.5% are summarized.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1244844682-12928-2-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 111 |
1 files changed, 90 insertions, 21 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6a08da41f76b..7a5b27867a96 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 | |||
28 | static char const *input_name = "perf.data"; | 32 | static char const *input_name = "perf.data"; |
29 | static char *vmlinux = "vmlinux"; | 33 | static char *vmlinux = "vmlinux"; |
30 | 34 | ||
@@ -88,6 +92,7 @@ typedef union event_union { | |||
88 | 92 | ||
89 | 93 | ||
90 | struct sym_ext { | 94 | struct sym_ext { |
95 | struct rb_node node; | ||
91 | double percent; | 96 | double percent; |
92 | char *path; | 97 | char *path; |
93 | }; | 98 | }; |
@@ -1038,6 +1043,24 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1038 | return 0; | 1043 | return 0; |
1039 | } | 1044 | } |
1040 | 1045 | ||
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 | |||
1041 | static int | 1064 | static int |
1042 | parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | 1065 | parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) |
1043 | { | 1066 | { |
@@ -1086,7 +1109,7 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
1086 | const char *path = NULL; | 1109 | const char *path = NULL; |
1087 | unsigned int hits = 0; | 1110 | unsigned int hits = 0; |
1088 | double percent = 0.0; | 1111 | double percent = 0.0; |
1089 | char *color = PERF_COLOR_NORMAL; | 1112 | char *color; |
1090 | struct sym_ext *sym_ext = sym->priv; | 1113 | struct sym_ext *sym_ext = sym->priv; |
1091 | 1114 | ||
1092 | offset = line_ip - start; | 1115 | offset = line_ip - start; |
@@ -1099,17 +1122,7 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
1099 | } else if (sym->hist_sum) | 1122 | } else if (sym->hist_sum) |
1100 | percent = 100.0 * hits / sym->hist_sum; | 1123 | percent = 100.0 * hits / sym->hist_sum; |
1101 | 1124 | ||
1102 | /* | 1125 | color = get_color(percent); |
1103 | * We color high-overhead entries in red, mid-overhead | ||
1104 | * entries in green - and keep the low overhead places | ||
1105 | * normal: | ||
1106 | */ | ||
1107 | if (percent >= 5.0) | ||
1108 | color = PERF_COLOR_RED; | ||
1109 | else { | ||
1110 | if (percent > 0.5) | ||
1111 | color = PERF_COLOR_GREEN; | ||
1112 | } | ||
1113 | 1126 | ||
1114 | /* | 1127 | /* |
1115 | * Also color the filename and line if needed, with | 1128 | * Also color the filename and line if needed, with |
@@ -1138,6 +1151,28 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
1138 | return 0; | 1151 | return 0; |
1139 | } | 1152 | } |
1140 | 1153 | ||
1154 | static struct rb_root root_sym_ext; | ||
1155 | |||
1156 | static 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 | |||
1141 | static void free_source_line(struct symbol *sym, int len) | 1176 | static void free_source_line(struct symbol *sym, int len) |
1142 | { | 1177 | { |
1143 | struct sym_ext *sym_ext = sym->priv; | 1178 | struct sym_ext *sym_ext = sym->priv; |
@@ -1151,6 +1186,7 @@ static void free_source_line(struct symbol *sym, int len) | |||
1151 | free(sym_ext); | 1186 | free(sym_ext); |
1152 | 1187 | ||
1153 | sym->priv = NULL; | 1188 | sym->priv = NULL; |
1189 | root_sym_ext = RB_ROOT; | ||
1154 | } | 1190 | } |
1155 | 1191 | ||
1156 | /* Get the filename:line for the colored entries */ | 1192 | /* Get the filename:line for the colored entries */ |
@@ -1193,12 +1229,42 @@ static void get_source_line(struct symbol *sym, __u64 start, int len) | |||
1193 | goto next; | 1229 | goto next; |
1194 | 1230 | ||
1195 | strcpy(sym_ext[i].path, path); | 1231 | strcpy(sym_ext[i].path, path); |
1232 | insert_source_line(&sym_ext[i]); | ||
1196 | 1233 | ||
1197 | next: | 1234 | next: |
1198 | pclose(fp); | 1235 | pclose(fp); |
1199 | } | 1236 | } |
1200 | } | 1237 | } |
1201 | 1238 | ||
1239 | static void print_summary(char *filename) | ||
1240 | { | ||
1241 | struct sym_ext *sym_ext; | ||
1242 | struct rb_node *node; | ||
1243 | |||
1244 | printf("\nSorted summary for file %s\n", filename); | ||
1245 | printf("----------------------------------------------\n\n"); | ||
1246 | |||
1247 | if (RB_EMPTY_ROOT(&root_sym_ext)) { | ||
1248 | printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); | ||
1249 | return; | ||
1250 | } | ||
1251 | |||
1252 | node = rb_first(&root_sym_ext); | ||
1253 | while (node) { | ||
1254 | double percent; | ||
1255 | char *color; | ||
1256 | char *path; | ||
1257 | |||
1258 | sym_ext = rb_entry(node, struct sym_ext, node); | ||
1259 | percent = sym_ext->percent; | ||
1260 | color = get_color(percent); | ||
1261 | path = sym_ext->path; | ||
1262 | |||
1263 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | ||
1264 | node = rb_next(node); | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1202 | static void annotate_sym(struct dso *dso, struct symbol *sym) | 1268 | static void annotate_sym(struct dso *dso, struct symbol *sym) |
1203 | { | 1269 | { |
1204 | char *filename = dso->name; | 1270 | char *filename = dso->name; |
@@ -1211,13 +1277,6 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
1211 | if (dso == kernel_dso) | 1277 | if (dso == kernel_dso) |
1212 | filename = vmlinux; | 1278 | filename = vmlinux; |
1213 | 1279 | ||
1214 | printf("\n------------------------------------------------\n"); | ||
1215 | printf(" Percent | Source code & Disassembly of %s\n", filename); | ||
1216 | printf("------------------------------------------------\n"); | ||
1217 | |||
1218 | if (verbose >= 2) | ||
1219 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | ||
1220 | |||
1221 | start = sym->obj_start; | 1280 | start = sym->obj_start; |
1222 | if (!start) | 1281 | if (!start) |
1223 | start = sym->start; | 1282 | start = sym->start; |
@@ -1225,8 +1284,17 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
1225 | end = start + sym->end - sym->start + 1; | 1284 | end = start + sym->end - sym->start + 1; |
1226 | len = sym->end - sym->start; | 1285 | len = sym->end - sym->start; |
1227 | 1286 | ||
1228 | if (print_line) | 1287 | if (print_line) { |
1229 | get_source_line(sym, start, len); | 1288 | get_source_line(sym, start, len); |
1289 | print_summary(filename); | ||
1290 | } | ||
1291 | |||
1292 | printf("\n\n------------------------------------------------\n"); | ||
1293 | printf(" Percent | Source code & Disassembly of %s\n", filename); | ||
1294 | printf("------------------------------------------------\n"); | ||
1295 | |||
1296 | if (verbose >= 2) | ||
1297 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | ||
1230 | 1298 | ||
1231 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); | 1299 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); |
1232 | 1300 | ||
@@ -1243,7 +1311,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
1243 | } | 1311 | } |
1244 | 1312 | ||
1245 | pclose(file); | 1313 | pclose(file); |
1246 | free_source_line(sym, len); | 1314 | if (print_line) |
1315 | free_source_line(sym, len); | ||
1247 | } | 1316 | } |
1248 | 1317 | ||
1249 | static void find_annotations(void) | 1318 | static void find_annotations(void) |