diff options
| -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) |
