diff options
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r-- | tools/perf/util/annotate.c | 652 |
1 files changed, 340 insertions, 312 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3369c7830260..28b233c3dcbe 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <pthread.h> | 26 | #include <pthread.h> |
27 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
29 | #include <sys/utsname.h> | ||
30 | 29 | ||
31 | #include "sane_ctype.h" | 30 | #include "sane_ctype.h" |
32 | 31 | ||
@@ -322,6 +321,8 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) | |||
322 | return 0; | 321 | return 0; |
323 | 322 | ||
324 | *addrp = strtoull(comment, &endptr, 16); | 323 | *addrp = strtoull(comment, &endptr, 16); |
324 | if (endptr == comment) | ||
325 | return 0; | ||
325 | name = strchr(endptr, '<'); | 326 | name = strchr(endptr, '<'); |
326 | if (name == NULL) | 327 | if (name == NULL) |
327 | return -1; | 328 | return -1; |
@@ -435,8 +436,8 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *m | |||
435 | return 0; | 436 | return 0; |
436 | 437 | ||
437 | comment = ltrim(comment); | 438 | comment = ltrim(comment); |
438 | comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); | 439 | comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name); |
439 | comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); | 440 | comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); |
440 | 441 | ||
441 | return 0; | 442 | return 0; |
442 | 443 | ||
@@ -480,7 +481,7 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops | |||
480 | return 0; | 481 | return 0; |
481 | 482 | ||
482 | comment = ltrim(comment); | 483 | comment = ltrim(comment); |
483 | comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); | 484 | comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); |
484 | 485 | ||
485 | return 0; | 486 | return 0; |
486 | } | 487 | } |
@@ -878,32 +879,99 @@ out_free_name: | |||
878 | return -1; | 879 | return -1; |
879 | } | 880 | } |
880 | 881 | ||
881 | static struct disasm_line *disasm_line__new(s64 offset, char *line, | 882 | struct annotate_args { |
882 | size_t privsize, int line_nr, | 883 | size_t privsize; |
883 | struct arch *arch, | 884 | struct arch *arch; |
884 | struct map *map) | 885 | struct map *map; |
886 | struct perf_evsel *evsel; | ||
887 | s64 offset; | ||
888 | char *line; | ||
889 | int line_nr; | ||
890 | }; | ||
891 | |||
892 | static void annotation_line__delete(struct annotation_line *al) | ||
885 | { | 893 | { |
886 | struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); | 894 | void *ptr = (void *) al - al->privsize; |
895 | |||
896 | free_srcline(al->path); | ||
897 | zfree(&al->line); | ||
898 | free(ptr); | ||
899 | } | ||
900 | |||
901 | /* | ||
902 | * Allocating the annotation line data with following | ||
903 | * structure: | ||
904 | * | ||
905 | * -------------------------------------- | ||
906 | * private space | struct annotation_line | ||
907 | * -------------------------------------- | ||
908 | * | ||
909 | * Size of the private space is stored in 'struct annotation_line'. | ||
910 | * | ||
911 | */ | ||
912 | static struct annotation_line * | ||
913 | annotation_line__new(struct annotate_args *args, size_t privsize) | ||
914 | { | ||
915 | struct annotation_line *al; | ||
916 | struct perf_evsel *evsel = args->evsel; | ||
917 | size_t size = privsize + sizeof(*al); | ||
918 | int nr = 1; | ||
919 | |||
920 | if (perf_evsel__is_group_event(evsel)) | ||
921 | nr = evsel->nr_members; | ||
922 | |||
923 | size += sizeof(al->samples[0]) * nr; | ||
924 | |||
925 | al = zalloc(size); | ||
926 | if (al) { | ||
927 | al = (void *) al + privsize; | ||
928 | al->privsize = privsize; | ||
929 | al->offset = args->offset; | ||
930 | al->line = strdup(args->line); | ||
931 | al->line_nr = args->line_nr; | ||
932 | al->samples_nr = nr; | ||
933 | } | ||
934 | |||
935 | return al; | ||
936 | } | ||
937 | |||
938 | /* | ||
939 | * Allocating the disasm annotation line data with | ||
940 | * following structure: | ||
941 | * | ||
942 | * ------------------------------------------------------------ | ||
943 | * privsize space | struct disasm_line | struct annotation_line | ||
944 | * ------------------------------------------------------------ | ||
945 | * | ||
946 | * We have 'struct annotation_line' member as last member | ||
947 | * of 'struct disasm_line' to have an easy access. | ||
948 | * | ||
949 | */ | ||
950 | static struct disasm_line *disasm_line__new(struct annotate_args *args) | ||
951 | { | ||
952 | struct disasm_line *dl = NULL; | ||
953 | struct annotation_line *al; | ||
954 | size_t privsize = args->privsize + offsetof(struct disasm_line, al); | ||
955 | |||
956 | al = annotation_line__new(args, privsize); | ||
957 | if (al != NULL) { | ||
958 | dl = disasm_line(al); | ||
887 | 959 | ||
888 | if (dl != NULL) { | 960 | if (dl->al.line == NULL) |
889 | dl->offset = offset; | ||
890 | dl->line = strdup(line); | ||
891 | dl->line_nr = line_nr; | ||
892 | if (dl->line == NULL) | ||
893 | goto out_delete; | 961 | goto out_delete; |
894 | 962 | ||
895 | if (offset != -1) { | 963 | if (args->offset != -1) { |
896 | if (disasm_line__parse(dl->line, &dl->ins.name, &dl->ops.raw) < 0) | 964 | if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) |
897 | goto out_free_line; | 965 | goto out_free_line; |
898 | 966 | ||
899 | disasm_line__init_ins(dl, arch, map); | 967 | disasm_line__init_ins(dl, args->arch, args->map); |
900 | } | 968 | } |
901 | } | 969 | } |
902 | 970 | ||
903 | return dl; | 971 | return dl; |
904 | 972 | ||
905 | out_free_line: | 973 | out_free_line: |
906 | zfree(&dl->line); | 974 | zfree(&dl->al.line); |
907 | out_delete: | 975 | out_delete: |
908 | free(dl); | 976 | free(dl); |
909 | return NULL; | 977 | return NULL; |
@@ -911,14 +979,13 @@ out_delete: | |||
911 | 979 | ||
912 | void disasm_line__free(struct disasm_line *dl) | 980 | void disasm_line__free(struct disasm_line *dl) |
913 | { | 981 | { |
914 | zfree(&dl->line); | ||
915 | if (dl->ins.ops && dl->ins.ops->free) | 982 | if (dl->ins.ops && dl->ins.ops->free) |
916 | dl->ins.ops->free(&dl->ops); | 983 | dl->ins.ops->free(&dl->ops); |
917 | else | 984 | else |
918 | ins__delete(&dl->ops); | 985 | ins__delete(&dl->ops); |
919 | free((void *)dl->ins.name); | 986 | free((void *)dl->ins.name); |
920 | dl->ins.name = NULL; | 987 | dl->ins.name = NULL; |
921 | free(dl); | 988 | annotation_line__delete(&dl->al); |
922 | } | 989 | } |
923 | 990 | ||
924 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) | 991 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) |
@@ -929,12 +996,13 @@ int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool r | |||
929 | return ins__scnprintf(&dl->ins, bf, size, &dl->ops); | 996 | return ins__scnprintf(&dl->ins, bf, size, &dl->ops); |
930 | } | 997 | } |
931 | 998 | ||
932 | static void disasm__add(struct list_head *head, struct disasm_line *line) | 999 | static void annotation_line__add(struct annotation_line *al, struct list_head *head) |
933 | { | 1000 | { |
934 | list_add_tail(&line->node, head); | 1001 | list_add_tail(&al->node, head); |
935 | } | 1002 | } |
936 | 1003 | ||
937 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) | 1004 | struct annotation_line * |
1005 | annotation_line__next(struct annotation_line *pos, struct list_head *head) | ||
938 | { | 1006 | { |
939 | list_for_each_entry_continue(pos, head, node) | 1007 | list_for_each_entry_continue(pos, head, node) |
940 | if (pos->offset >= 0) | 1008 | if (pos->offset >= 0) |
@@ -943,50 +1011,6 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa | |||
943 | return NULL; | 1011 | return NULL; |
944 | } | 1012 | } |
945 | 1013 | ||
946 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | ||
947 | s64 end, const char **path, struct sym_hist_entry *sample) | ||
948 | { | ||
949 | struct source_line *src_line = notes->src->lines; | ||
950 | double percent = 0.0; | ||
951 | |||
952 | sample->nr_samples = sample->period = 0; | ||
953 | |||
954 | if (src_line) { | ||
955 | size_t sizeof_src_line = sizeof(*src_line) + | ||
956 | sizeof(src_line->samples) * (src_line->nr_pcnt - 1); | ||
957 | |||
958 | while (offset < end) { | ||
959 | src_line = (void *)notes->src->lines + | ||
960 | (sizeof_src_line * offset); | ||
961 | |||
962 | if (*path == NULL) | ||
963 | *path = src_line->path; | ||
964 | |||
965 | percent += src_line->samples[evidx].percent; | ||
966 | sample->nr_samples += src_line->samples[evidx].nr; | ||
967 | offset++; | ||
968 | } | ||
969 | } else { | ||
970 | struct sym_hist *h = annotation__histogram(notes, evidx); | ||
971 | unsigned int hits = 0; | ||
972 | u64 period = 0; | ||
973 | |||
974 | while (offset < end) { | ||
975 | hits += h->addr[offset].nr_samples; | ||
976 | period += h->addr[offset].period; | ||
977 | ++offset; | ||
978 | } | ||
979 | |||
980 | if (h->nr_samples) { | ||
981 | sample->period = period; | ||
982 | sample->nr_samples = hits; | ||
983 | percent = 100.0 * hits / h->nr_samples; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | return percent; | ||
988 | } | ||
989 | |||
990 | static const char *annotate__address_color(struct block_range *br) | 1014 | static const char *annotate__address_color(struct block_range *br) |
991 | { | 1015 | { |
992 | double cov = block_range__coverage(br); | 1016 | double cov = block_range__coverage(br); |
@@ -1069,50 +1093,39 @@ static void annotate__branch_printf(struct block_range *br, u64 addr) | |||
1069 | } | 1093 | } |
1070 | } | 1094 | } |
1071 | 1095 | ||
1096 | static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_width) | ||
1097 | { | ||
1098 | s64 offset = dl->al.offset; | ||
1099 | const u64 addr = start + offset; | ||
1100 | struct block_range *br; | ||
1101 | |||
1102 | br = block_range__find(addr); | ||
1103 | color_fprintf(stdout, annotate__address_color(br), " %*" PRIx64 ":", addr_fmt_width, addr); | ||
1104 | color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line); | ||
1105 | annotate__branch_printf(br, addr); | ||
1106 | return 0; | ||
1107 | } | ||
1072 | 1108 | ||
1073 | static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, | 1109 | static int |
1074 | struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, | 1110 | annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, |
1075 | int max_lines, struct disasm_line *queue) | 1111 | struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, |
1112 | int max_lines, struct annotation_line *queue, int addr_fmt_width) | ||
1076 | { | 1113 | { |
1114 | struct disasm_line *dl = container_of(al, struct disasm_line, al); | ||
1077 | static const char *prev_line; | 1115 | static const char *prev_line; |
1078 | static const char *prev_color; | 1116 | static const char *prev_color; |
1079 | 1117 | ||
1080 | if (dl->offset != -1) { | 1118 | if (al->offset != -1) { |
1081 | const char *path = NULL; | 1119 | double max_percent = 0.0; |
1082 | double percent, max_percent = 0.0; | ||
1083 | double *ppercents = &percent; | ||
1084 | struct sym_hist_entry sample; | ||
1085 | struct sym_hist_entry *psamples = &sample; | ||
1086 | int i, nr_percent = 1; | 1120 | int i, nr_percent = 1; |
1087 | const char *color; | 1121 | const char *color; |
1088 | struct annotation *notes = symbol__annotation(sym); | 1122 | struct annotation *notes = symbol__annotation(sym); |
1089 | s64 offset = dl->offset; | ||
1090 | const u64 addr = start + offset; | ||
1091 | struct disasm_line *next; | ||
1092 | struct block_range *br; | ||
1093 | |||
1094 | next = disasm__get_next_ip_line(¬es->src->source, dl); | ||
1095 | |||
1096 | if (perf_evsel__is_group_event(evsel)) { | ||
1097 | nr_percent = evsel->nr_members; | ||
1098 | ppercents = calloc(nr_percent, sizeof(double)); | ||
1099 | psamples = calloc(nr_percent, sizeof(struct sym_hist_entry)); | ||
1100 | if (ppercents == NULL || psamples == NULL) { | ||
1101 | return -1; | ||
1102 | } | ||
1103 | } | ||
1104 | 1123 | ||
1105 | for (i = 0; i < nr_percent; i++) { | 1124 | for (i = 0; i < al->samples_nr; i++) { |
1106 | percent = disasm__calc_percent(notes, | 1125 | struct annotation_data *sample = &al->samples[i]; |
1107 | notes->src->lines ? i : evsel->idx + i, | 1126 | |
1108 | offset, | 1127 | if (sample->percent > max_percent) |
1109 | next ? next->offset : (s64) len, | 1128 | max_percent = sample->percent; |
1110 | &path, &sample); | ||
1111 | |||
1112 | ppercents[i] = percent; | ||
1113 | psamples[i] = sample; | ||
1114 | if (percent > max_percent) | ||
1115 | max_percent = percent; | ||
1116 | } | 1129 | } |
1117 | 1130 | ||
1118 | if (max_percent < min_pcnt) | 1131 | if (max_percent < min_pcnt) |
@@ -1123,10 +1136,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1123 | 1136 | ||
1124 | if (queue != NULL) { | 1137 | if (queue != NULL) { |
1125 | list_for_each_entry_from(queue, ¬es->src->source, node) { | 1138 | list_for_each_entry_from(queue, ¬es->src->source, node) { |
1126 | if (queue == dl) | 1139 | if (queue == al) |
1127 | break; | 1140 | break; |
1128 | disasm_line__print(queue, sym, start, evsel, len, | 1141 | annotation_line__print(queue, sym, start, evsel, len, |
1129 | 0, 0, 1, NULL); | 1142 | 0, 0, 1, NULL, addr_fmt_width); |
1130 | } | 1143 | } |
1131 | } | 1144 | } |
1132 | 1145 | ||
@@ -1137,44 +1150,34 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1137 | * the same color than the percentage. Don't print it | 1150 | * the same color than the percentage. Don't print it |
1138 | * twice for close colored addr with the same filename:line | 1151 | * twice for close colored addr with the same filename:line |
1139 | */ | 1152 | */ |
1140 | if (path) { | 1153 | if (al->path) { |
1141 | if (!prev_line || strcmp(prev_line, path) | 1154 | if (!prev_line || strcmp(prev_line, al->path) |
1142 | || color != prev_color) { | 1155 | || color != prev_color) { |
1143 | color_fprintf(stdout, color, " %s", path); | 1156 | color_fprintf(stdout, color, " %s", al->path); |
1144 | prev_line = path; | 1157 | prev_line = al->path; |
1145 | prev_color = color; | 1158 | prev_color = color; |
1146 | } | 1159 | } |
1147 | } | 1160 | } |
1148 | 1161 | ||
1149 | for (i = 0; i < nr_percent; i++) { | 1162 | for (i = 0; i < nr_percent; i++) { |
1150 | percent = ppercents[i]; | 1163 | struct annotation_data *sample = &al->samples[i]; |
1151 | sample = psamples[i]; | 1164 | |
1152 | color = get_percent_color(percent); | 1165 | color = get_percent_color(sample->percent); |
1153 | 1166 | ||
1154 | if (symbol_conf.show_total_period) | 1167 | if (symbol_conf.show_total_period) |
1155 | color_fprintf(stdout, color, " %11" PRIu64, | 1168 | color_fprintf(stdout, color, " %11" PRIu64, |
1156 | sample.period); | 1169 | sample->he.period); |
1157 | else if (symbol_conf.show_nr_samples) | 1170 | else if (symbol_conf.show_nr_samples) |
1158 | color_fprintf(stdout, color, " %7" PRIu64, | 1171 | color_fprintf(stdout, color, " %7" PRIu64, |
1159 | sample.nr_samples); | 1172 | sample->he.nr_samples); |
1160 | else | 1173 | else |
1161 | color_fprintf(stdout, color, " %7.2f", percent); | 1174 | color_fprintf(stdout, color, " %7.2f", sample->percent); |
1162 | } | 1175 | } |
1163 | 1176 | ||
1164 | printf(" : "); | 1177 | printf(" : "); |
1165 | 1178 | ||
1166 | br = block_range__find(addr); | 1179 | disasm_line__print(dl, start, addr_fmt_width); |
1167 | color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr); | ||
1168 | color_fprintf(stdout, annotate__asm_color(br), "%s", dl->line); | ||
1169 | annotate__branch_printf(br, addr); | ||
1170 | printf("\n"); | 1180 | printf("\n"); |
1171 | |||
1172 | if (ppercents != &percent) | ||
1173 | free(ppercents); | ||
1174 | |||
1175 | if (psamples != &sample) | ||
1176 | free(psamples); | ||
1177 | |||
1178 | } else if (max_lines && printed >= max_lines) | 1181 | } else if (max_lines && printed >= max_lines) |
1179 | return 1; | 1182 | return 1; |
1180 | else { | 1183 | else { |
@@ -1186,10 +1189,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1186 | if (perf_evsel__is_group_event(evsel)) | 1189 | if (perf_evsel__is_group_event(evsel)) |
1187 | width *= evsel->nr_members; | 1190 | width *= evsel->nr_members; |
1188 | 1191 | ||
1189 | if (!*dl->line) | 1192 | if (!*al->line) |
1190 | printf(" %*s:\n", width, " "); | 1193 | printf(" %*s:\n", width, " "); |
1191 | else | 1194 | else |
1192 | printf(" %*s: %s\n", width, " ", dl->line); | 1195 | printf(" %*s: %*s %s\n", width, " ", addr_fmt_width, " ", al->line); |
1193 | } | 1196 | } |
1194 | 1197 | ||
1195 | return 0; | 1198 | return 0; |
@@ -1215,11 +1218,11 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1215 | * means that it's not a disassembly line so should be treated differently. | 1218 | * means that it's not a disassembly line so should be treated differently. |
1216 | * The ops.raw part will be parsed further according to type of the instruction. | 1219 | * The ops.raw part will be parsed further according to type of the instruction. |
1217 | */ | 1220 | */ |
1218 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | 1221 | static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, |
1219 | struct arch *arch, | 1222 | struct annotate_args *args, |
1220 | FILE *file, size_t privsize, | ||
1221 | int *line_nr) | 1223 | int *line_nr) |
1222 | { | 1224 | { |
1225 | struct map *map = args->map; | ||
1223 | struct annotation *notes = symbol__annotation(sym); | 1226 | struct annotation *notes = symbol__annotation(sym); |
1224 | struct disasm_line *dl; | 1227 | struct disasm_line *dl; |
1225 | char *line = NULL, *parsed_line, *tmp, *tmp2; | 1228 | char *line = NULL, *parsed_line, *tmp, *tmp2; |
@@ -1263,7 +1266,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
1263 | parsed_line = tmp2 + 1; | 1266 | parsed_line = tmp2 + 1; |
1264 | } | 1267 | } |
1265 | 1268 | ||
1266 | dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, arch, map); | 1269 | args->offset = offset; |
1270 | args->line = parsed_line; | ||
1271 | args->line_nr = *line_nr; | ||
1272 | |||
1273 | dl = disasm_line__new(args); | ||
1267 | free(line); | 1274 | free(line); |
1268 | (*line_nr)++; | 1275 | (*line_nr)++; |
1269 | 1276 | ||
@@ -1288,7 +1295,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
1288 | dl->ops.target.name = strdup(target.sym->name); | 1295 | dl->ops.target.name = strdup(target.sym->name); |
1289 | } | 1296 | } |
1290 | 1297 | ||
1291 | disasm__add(¬es->src->source, dl); | 1298 | annotation_line__add(&dl->al, ¬es->src->source); |
1292 | 1299 | ||
1293 | return 0; | 1300 | return 0; |
1294 | } | 1301 | } |
@@ -1305,19 +1312,19 @@ static void delete_last_nop(struct symbol *sym) | |||
1305 | struct disasm_line *dl; | 1312 | struct disasm_line *dl; |
1306 | 1313 | ||
1307 | while (!list_empty(list)) { | 1314 | while (!list_empty(list)) { |
1308 | dl = list_entry(list->prev, struct disasm_line, node); | 1315 | dl = list_entry(list->prev, struct disasm_line, al.node); |
1309 | 1316 | ||
1310 | if (dl->ins.ops) { | 1317 | if (dl->ins.ops) { |
1311 | if (dl->ins.ops != &nop_ops) | 1318 | if (dl->ins.ops != &nop_ops) |
1312 | return; | 1319 | return; |
1313 | } else { | 1320 | } else { |
1314 | if (!strstr(dl->line, " nop ") && | 1321 | if (!strstr(dl->al.line, " nop ") && |
1315 | !strstr(dl->line, " nopl ") && | 1322 | !strstr(dl->al.line, " nopl ") && |
1316 | !strstr(dl->line, " nopw ")) | 1323 | !strstr(dl->al.line, " nopw ")) |
1317 | return; | 1324 | return; |
1318 | } | 1325 | } |
1319 | 1326 | ||
1320 | list_del(&dl->node); | 1327 | list_del(&dl->al.node); |
1321 | disasm_line__free(dl); | 1328 | disasm_line__free(dl); |
1322 | } | 1329 | } |
1323 | } | 1330 | } |
@@ -1412,25 +1419,11 @@ fallback: | |||
1412 | return 0; | 1419 | return 0; |
1413 | } | 1420 | } |
1414 | 1421 | ||
1415 | static const char *annotate__norm_arch(const char *arch_name) | 1422 | static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) |
1416 | { | ||
1417 | struct utsname uts; | ||
1418 | |||
1419 | if (!arch_name) { /* Assume we are annotating locally. */ | ||
1420 | if (uname(&uts) < 0) | ||
1421 | return NULL; | ||
1422 | arch_name = uts.machine; | ||
1423 | } | ||
1424 | return normalize_arch((char *)arch_name); | ||
1425 | } | ||
1426 | |||
1427 | int symbol__disassemble(struct symbol *sym, struct map *map, | ||
1428 | const char *arch_name, size_t privsize, | ||
1429 | struct arch **parch, char *cpuid) | ||
1430 | { | 1423 | { |
1424 | struct map *map = args->map; | ||
1431 | struct dso *dso = map->dso; | 1425 | struct dso *dso = map->dso; |
1432 | char command[PATH_MAX * 2]; | 1426 | char command[PATH_MAX * 2]; |
1433 | struct arch *arch = NULL; | ||
1434 | FILE *file; | 1427 | FILE *file; |
1435 | char symfs_filename[PATH_MAX]; | 1428 | char symfs_filename[PATH_MAX]; |
1436 | struct kcore_extract kce; | 1429 | struct kcore_extract kce; |
@@ -1444,25 +1437,6 @@ int symbol__disassemble(struct symbol *sym, struct map *map, | |||
1444 | if (err) | 1437 | if (err) |
1445 | return err; | 1438 | return err; |
1446 | 1439 | ||
1447 | arch_name = annotate__norm_arch(arch_name); | ||
1448 | if (!arch_name) | ||
1449 | return -1; | ||
1450 | |||
1451 | arch = arch__find(arch_name); | ||
1452 | if (arch == NULL) | ||
1453 | return -ENOTSUP; | ||
1454 | |||
1455 | if (parch) | ||
1456 | *parch = arch; | ||
1457 | |||
1458 | if (arch->init) { | ||
1459 | err = arch->init(arch, cpuid); | ||
1460 | if (err) { | ||
1461 | pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name); | ||
1462 | return err; | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, | 1440 | pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, |
1467 | symfs_filename, sym->name, map->unmap_ip(map, sym->start), | 1441 | symfs_filename, sym->name, map->unmap_ip(map, sym->start), |
1468 | map->unmap_ip(map, sym->end)); | 1442 | map->unmap_ip(map, sym->end)); |
@@ -1546,8 +1520,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, | |||
1546 | * can associate it with the instructions till the next one. | 1520 | * can associate it with the instructions till the next one. |
1547 | * See disasm_line__new() and struct disasm_line::line_nr. | 1521 | * See disasm_line__new() and struct disasm_line::line_nr. |
1548 | */ | 1522 | */ |
1549 | if (symbol__parse_objdump_line(sym, map, arch, file, privsize, | 1523 | if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0) |
1550 | &lineno) < 0) | ||
1551 | break; | 1524 | break; |
1552 | nline++; | 1525 | nline++; |
1553 | } | 1526 | } |
@@ -1580,21 +1553,110 @@ out_close_stdout: | |||
1580 | goto out_remove_tmp; | 1553 | goto out_remove_tmp; |
1581 | } | 1554 | } |
1582 | 1555 | ||
1583 | static void insert_source_line(struct rb_root *root, struct source_line *src_line) | 1556 | static void calc_percent(struct sym_hist *hist, |
1557 | struct annotation_data *sample, | ||
1558 | s64 offset, s64 end) | ||
1559 | { | ||
1560 | unsigned int hits = 0; | ||
1561 | u64 period = 0; | ||
1562 | |||
1563 | while (offset < end) { | ||
1564 | hits += hist->addr[offset].nr_samples; | ||
1565 | period += hist->addr[offset].period; | ||
1566 | ++offset; | ||
1567 | } | ||
1568 | |||
1569 | if (hist->nr_samples) { | ||
1570 | sample->he.period = period; | ||
1571 | sample->he.nr_samples = hits; | ||
1572 | sample->percent = 100.0 * hits / hist->nr_samples; | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | static void annotation__calc_percent(struct annotation *notes, | ||
1577 | struct perf_evsel *evsel, s64 len) | ||
1578 | { | ||
1579 | struct annotation_line *al, *next; | ||
1580 | |||
1581 | list_for_each_entry(al, ¬es->src->source, node) { | ||
1582 | s64 end; | ||
1583 | int i; | ||
1584 | |||
1585 | if (al->offset == -1) | ||
1586 | continue; | ||
1587 | |||
1588 | next = annotation_line__next(al, ¬es->src->source); | ||
1589 | end = next ? next->offset : len; | ||
1590 | |||
1591 | for (i = 0; i < al->samples_nr; i++) { | ||
1592 | struct annotation_data *sample; | ||
1593 | struct sym_hist *hist; | ||
1594 | |||
1595 | hist = annotation__histogram(notes, evsel->idx + i); | ||
1596 | sample = &al->samples[i]; | ||
1597 | |||
1598 | calc_percent(hist, sample, al->offset, end); | ||
1599 | } | ||
1600 | } | ||
1601 | } | ||
1602 | |||
1603 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) | ||
1604 | { | ||
1605 | struct annotation *notes = symbol__annotation(sym); | ||
1606 | |||
1607 | annotation__calc_percent(notes, evsel, symbol__size(sym)); | ||
1608 | } | ||
1609 | |||
1610 | int symbol__annotate(struct symbol *sym, struct map *map, | ||
1611 | struct perf_evsel *evsel, size_t privsize, | ||
1612 | struct arch **parch) | ||
1584 | { | 1613 | { |
1585 | struct source_line *iter; | 1614 | struct annotate_args args = { |
1615 | .privsize = privsize, | ||
1616 | .map = map, | ||
1617 | .evsel = evsel, | ||
1618 | }; | ||
1619 | struct perf_env *env = perf_evsel__env(evsel); | ||
1620 | const char *arch_name = perf_env__arch(env); | ||
1621 | struct arch *arch; | ||
1622 | int err; | ||
1623 | |||
1624 | if (!arch_name) | ||
1625 | return -1; | ||
1626 | |||
1627 | args.arch = arch = arch__find(arch_name); | ||
1628 | if (arch == NULL) | ||
1629 | return -ENOTSUP; | ||
1630 | |||
1631 | if (parch) | ||
1632 | *parch = arch; | ||
1633 | |||
1634 | if (arch->init) { | ||
1635 | err = arch->init(arch, env ? env->cpuid : NULL); | ||
1636 | if (err) { | ||
1637 | pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name); | ||
1638 | return err; | ||
1639 | } | ||
1640 | } | ||
1641 | |||
1642 | return symbol__disassemble(sym, &args); | ||
1643 | } | ||
1644 | |||
1645 | static void insert_source_line(struct rb_root *root, struct annotation_line *al) | ||
1646 | { | ||
1647 | struct annotation_line *iter; | ||
1586 | struct rb_node **p = &root->rb_node; | 1648 | struct rb_node **p = &root->rb_node; |
1587 | struct rb_node *parent = NULL; | 1649 | struct rb_node *parent = NULL; |
1588 | int i, ret; | 1650 | int i, ret; |
1589 | 1651 | ||
1590 | while (*p != NULL) { | 1652 | while (*p != NULL) { |
1591 | parent = *p; | 1653 | parent = *p; |
1592 | iter = rb_entry(parent, struct source_line, node); | 1654 | iter = rb_entry(parent, struct annotation_line, rb_node); |
1593 | 1655 | ||
1594 | ret = strcmp(iter->path, src_line->path); | 1656 | ret = strcmp(iter->path, al->path); |
1595 | if (ret == 0) { | 1657 | if (ret == 0) { |
1596 | for (i = 0; i < src_line->nr_pcnt; i++) | 1658 | for (i = 0; i < al->samples_nr; i++) |
1597 | iter->samples[i].percent_sum += src_line->samples[i].percent; | 1659 | iter->samples[i].percent_sum += al->samples[i].percent; |
1598 | return; | 1660 | return; |
1599 | } | 1661 | } |
1600 | 1662 | ||
@@ -1604,18 +1666,18 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
1604 | p = &(*p)->rb_right; | 1666 | p = &(*p)->rb_right; |
1605 | } | 1667 | } |
1606 | 1668 | ||
1607 | for (i = 0; i < src_line->nr_pcnt; i++) | 1669 | for (i = 0; i < al->samples_nr; i++) |
1608 | src_line->samples[i].percent_sum = src_line->samples[i].percent; | 1670 | al->samples[i].percent_sum = al->samples[i].percent; |
1609 | 1671 | ||
1610 | rb_link_node(&src_line->node, parent, p); | 1672 | rb_link_node(&al->rb_node, parent, p); |
1611 | rb_insert_color(&src_line->node, root); | 1673 | rb_insert_color(&al->rb_node, root); |
1612 | } | 1674 | } |
1613 | 1675 | ||
1614 | static int cmp_source_line(struct source_line *a, struct source_line *b) | 1676 | static int cmp_source_line(struct annotation_line *a, struct annotation_line *b) |
1615 | { | 1677 | { |
1616 | int i; | 1678 | int i; |
1617 | 1679 | ||
1618 | for (i = 0; i < a->nr_pcnt; i++) { | 1680 | for (i = 0; i < a->samples_nr; i++) { |
1619 | if (a->samples[i].percent_sum == b->samples[i].percent_sum) | 1681 | if (a->samples[i].percent_sum == b->samples[i].percent_sum) |
1620 | continue; | 1682 | continue; |
1621 | return a->samples[i].percent_sum > b->samples[i].percent_sum; | 1683 | return a->samples[i].percent_sum > b->samples[i].percent_sum; |
@@ -1624,135 +1686,47 @@ static int cmp_source_line(struct source_line *a, struct source_line *b) | |||
1624 | return 0; | 1686 | return 0; |
1625 | } | 1687 | } |
1626 | 1688 | ||
1627 | static void __resort_source_line(struct rb_root *root, struct source_line *src_line) | 1689 | static void __resort_source_line(struct rb_root *root, struct annotation_line *al) |
1628 | { | 1690 | { |
1629 | struct source_line *iter; | 1691 | struct annotation_line *iter; |
1630 | struct rb_node **p = &root->rb_node; | 1692 | struct rb_node **p = &root->rb_node; |
1631 | struct rb_node *parent = NULL; | 1693 | struct rb_node *parent = NULL; |
1632 | 1694 | ||
1633 | while (*p != NULL) { | 1695 | while (*p != NULL) { |
1634 | parent = *p; | 1696 | parent = *p; |
1635 | iter = rb_entry(parent, struct source_line, node); | 1697 | iter = rb_entry(parent, struct annotation_line, rb_node); |
1636 | 1698 | ||
1637 | if (cmp_source_line(src_line, iter)) | 1699 | if (cmp_source_line(al, iter)) |
1638 | p = &(*p)->rb_left; | 1700 | p = &(*p)->rb_left; |
1639 | else | 1701 | else |
1640 | p = &(*p)->rb_right; | 1702 | p = &(*p)->rb_right; |
1641 | } | 1703 | } |
1642 | 1704 | ||
1643 | rb_link_node(&src_line->node, parent, p); | 1705 | rb_link_node(&al->rb_node, parent, p); |
1644 | rb_insert_color(&src_line->node, root); | 1706 | rb_insert_color(&al->rb_node, root); |
1645 | } | 1707 | } |
1646 | 1708 | ||
1647 | static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root) | 1709 | static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root) |
1648 | { | 1710 | { |
1649 | struct source_line *src_line; | 1711 | struct annotation_line *al; |
1650 | struct rb_node *node; | 1712 | struct rb_node *node; |
1651 | 1713 | ||
1652 | node = rb_first(src_root); | 1714 | node = rb_first(src_root); |
1653 | while (node) { | 1715 | while (node) { |
1654 | struct rb_node *next; | 1716 | struct rb_node *next; |
1655 | 1717 | ||
1656 | src_line = rb_entry(node, struct source_line, node); | 1718 | al = rb_entry(node, struct annotation_line, rb_node); |
1657 | next = rb_next(node); | 1719 | next = rb_next(node); |
1658 | rb_erase(node, src_root); | 1720 | rb_erase(node, src_root); |
1659 | 1721 | ||
1660 | __resort_source_line(dest_root, src_line); | 1722 | __resort_source_line(dest_root, al); |
1661 | node = next; | 1723 | node = next; |
1662 | } | 1724 | } |
1663 | } | 1725 | } |
1664 | 1726 | ||
1665 | static void symbol__free_source_line(struct symbol *sym, int len) | ||
1666 | { | ||
1667 | struct annotation *notes = symbol__annotation(sym); | ||
1668 | struct source_line *src_line = notes->src->lines; | ||
1669 | size_t sizeof_src_line; | ||
1670 | int i; | ||
1671 | |||
1672 | sizeof_src_line = sizeof(*src_line) + | ||
1673 | (sizeof(src_line->samples) * (src_line->nr_pcnt - 1)); | ||
1674 | |||
1675 | for (i = 0; i < len; i++) { | ||
1676 | free_srcline(src_line->path); | ||
1677 | src_line = (void *)src_line + sizeof_src_line; | ||
1678 | } | ||
1679 | |||
1680 | zfree(¬es->src->lines); | ||
1681 | } | ||
1682 | |||
1683 | /* Get the filename:line for the colored entries */ | ||
1684 | static int symbol__get_source_line(struct symbol *sym, struct map *map, | ||
1685 | struct perf_evsel *evsel, | ||
1686 | struct rb_root *root, int len) | ||
1687 | { | ||
1688 | u64 start; | ||
1689 | int i, k; | ||
1690 | int evidx = evsel->idx; | ||
1691 | struct source_line *src_line; | ||
1692 | struct annotation *notes = symbol__annotation(sym); | ||
1693 | struct sym_hist *h = annotation__histogram(notes, evidx); | ||
1694 | struct rb_root tmp_root = RB_ROOT; | ||
1695 | int nr_pcnt = 1; | ||
1696 | u64 nr_samples = h->nr_samples; | ||
1697 | size_t sizeof_src_line = sizeof(struct source_line); | ||
1698 | |||
1699 | if (perf_evsel__is_group_event(evsel)) { | ||
1700 | for (i = 1; i < evsel->nr_members; i++) { | ||
1701 | h = annotation__histogram(notes, evidx + i); | ||
1702 | nr_samples += h->nr_samples; | ||
1703 | } | ||
1704 | nr_pcnt = evsel->nr_members; | ||
1705 | sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples); | ||
1706 | } | ||
1707 | |||
1708 | if (!nr_samples) | ||
1709 | return 0; | ||
1710 | |||
1711 | src_line = notes->src->lines = calloc(len, sizeof_src_line); | ||
1712 | if (!notes->src->lines) | ||
1713 | return -1; | ||
1714 | |||
1715 | start = map__rip_2objdump(map, sym->start); | ||
1716 | |||
1717 | for (i = 0; i < len; i++) { | ||
1718 | u64 offset; | ||
1719 | double percent_max = 0.0; | ||
1720 | |||
1721 | src_line->nr_pcnt = nr_pcnt; | ||
1722 | |||
1723 | for (k = 0; k < nr_pcnt; k++) { | ||
1724 | double percent = 0.0; | ||
1725 | |||
1726 | h = annotation__histogram(notes, evidx + k); | ||
1727 | nr_samples = h->addr[i].nr_samples; | ||
1728 | if (h->nr_samples) | ||
1729 | percent = 100.0 * nr_samples / h->nr_samples; | ||
1730 | |||
1731 | if (percent > percent_max) | ||
1732 | percent_max = percent; | ||
1733 | src_line->samples[k].percent = percent; | ||
1734 | src_line->samples[k].nr = nr_samples; | ||
1735 | } | ||
1736 | |||
1737 | if (percent_max <= 0.5) | ||
1738 | goto next; | ||
1739 | |||
1740 | offset = start + i; | ||
1741 | src_line->path = get_srcline(map->dso, offset, NULL, | ||
1742 | false, true); | ||
1743 | insert_source_line(&tmp_root, src_line); | ||
1744 | |||
1745 | next: | ||
1746 | src_line = (void *)src_line + sizeof_src_line; | ||
1747 | } | ||
1748 | |||
1749 | resort_source_line(root, &tmp_root); | ||
1750 | return 0; | ||
1751 | } | ||
1752 | |||
1753 | static void print_summary(struct rb_root *root, const char *filename) | 1727 | static void print_summary(struct rb_root *root, const char *filename) |
1754 | { | 1728 | { |
1755 | struct source_line *src_line; | 1729 | struct annotation_line *al; |
1756 | struct rb_node *node; | 1730 | struct rb_node *node; |
1757 | 1731 | ||
1758 | printf("\nSorted summary for file %s\n", filename); | 1732 | printf("\nSorted summary for file %s\n", filename); |
@@ -1770,9 +1744,9 @@ static void print_summary(struct rb_root *root, const char *filename) | |||
1770 | char *path; | 1744 | char *path; |
1771 | int i; | 1745 | int i; |
1772 | 1746 | ||
1773 | src_line = rb_entry(node, struct source_line, node); | 1747 | al = rb_entry(node, struct annotation_line, rb_node); |
1774 | for (i = 0; i < src_line->nr_pcnt; i++) { | 1748 | for (i = 0; i < al->samples_nr; i++) { |
1775 | percent = src_line->samples[i].percent_sum; | 1749 | percent = al->samples[i].percent_sum; |
1776 | color = get_percent_color(percent); | 1750 | color = get_percent_color(percent); |
1777 | color_fprintf(stdout, color, " %7.2f", percent); | 1751 | color_fprintf(stdout, color, " %7.2f", percent); |
1778 | 1752 | ||
@@ -1780,7 +1754,7 @@ static void print_summary(struct rb_root *root, const char *filename) | |||
1780 | percent_max = percent; | 1754 | percent_max = percent; |
1781 | } | 1755 | } |
1782 | 1756 | ||
1783 | path = src_line->path; | 1757 | path = al->path; |
1784 | color = get_percent_color(percent_max); | 1758 | color = get_percent_color(percent_max); |
1785 | color_fprintf(stdout, color, " %s\n", path); | 1759 | color_fprintf(stdout, color, " %s\n", path); |
1786 | 1760 | ||
@@ -1801,6 +1775,19 @@ static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) | |||
1801 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples); | 1775 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples); |
1802 | } | 1776 | } |
1803 | 1777 | ||
1778 | static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) | ||
1779 | { | ||
1780 | char bf[32]; | ||
1781 | struct annotation_line *line; | ||
1782 | |||
1783 | list_for_each_entry_reverse(line, lines, node) { | ||
1784 | if (line->offset != -1) | ||
1785 | return scnprintf(bf, sizeof(bf), "%" PRIx64, start + line->offset); | ||
1786 | } | ||
1787 | |||
1788 | return 0; | ||
1789 | } | ||
1790 | |||
1804 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 1791 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
1805 | struct perf_evsel *evsel, bool full_paths, | 1792 | struct perf_evsel *evsel, bool full_paths, |
1806 | int min_pcnt, int max_lines, int context) | 1793 | int min_pcnt, int max_lines, int context) |
@@ -1811,9 +1798,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
1811 | const char *evsel_name = perf_evsel__name(evsel); | 1798 | const char *evsel_name = perf_evsel__name(evsel); |
1812 | struct annotation *notes = symbol__annotation(sym); | 1799 | struct annotation *notes = symbol__annotation(sym); |
1813 | struct sym_hist *h = annotation__histogram(notes, evsel->idx); | 1800 | struct sym_hist *h = annotation__histogram(notes, evsel->idx); |
1814 | struct disasm_line *pos, *queue = NULL; | 1801 | struct annotation_line *pos, *queue = NULL; |
1815 | u64 start = map__rip_2objdump(map, sym->start); | 1802 | u64 start = map__rip_2objdump(map, sym->start); |
1816 | int printed = 2, queue_len = 0; | 1803 | int printed = 2, queue_len = 0, addr_fmt_width; |
1817 | int more = 0; | 1804 | int more = 0; |
1818 | u64 len; | 1805 | u64 len; |
1819 | int width = symbol_conf.show_total_period ? 12 : 8; | 1806 | int width = symbol_conf.show_total_period ? 12 : 8; |
@@ -1844,15 +1831,21 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
1844 | if (verbose > 0) | 1831 | if (verbose > 0) |
1845 | symbol__annotate_hits(sym, evsel); | 1832 | symbol__annotate_hits(sym, evsel); |
1846 | 1833 | ||
1834 | addr_fmt_width = annotated_source__addr_fmt_width(¬es->src->source, start); | ||
1835 | |||
1847 | list_for_each_entry(pos, ¬es->src->source, node) { | 1836 | list_for_each_entry(pos, ¬es->src->source, node) { |
1837 | int err; | ||
1838 | |||
1848 | if (context && queue == NULL) { | 1839 | if (context && queue == NULL) { |
1849 | queue = pos; | 1840 | queue = pos; |
1850 | queue_len = 0; | 1841 | queue_len = 0; |
1851 | } | 1842 | } |
1852 | 1843 | ||
1853 | switch (disasm_line__print(pos, sym, start, evsel, len, | 1844 | err = annotation_line__print(pos, sym, start, evsel, len, |
1854 | min_pcnt, printed, max_lines, | 1845 | min_pcnt, printed, max_lines, |
1855 | queue)) { | 1846 | queue, addr_fmt_width); |
1847 | |||
1848 | switch (err) { | ||
1856 | case 0: | 1849 | case 0: |
1857 | ++printed; | 1850 | ++printed; |
1858 | if (context) { | 1851 | if (context) { |
@@ -1907,13 +1900,13 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) | |||
1907 | } | 1900 | } |
1908 | } | 1901 | } |
1909 | 1902 | ||
1910 | void disasm__purge(struct list_head *head) | 1903 | void annotated_source__purge(struct annotated_source *as) |
1911 | { | 1904 | { |
1912 | struct disasm_line *pos, *n; | 1905 | struct annotation_line *al, *n; |
1913 | 1906 | ||
1914 | list_for_each_entry_safe(pos, n, head, node) { | 1907 | list_for_each_entry_safe(al, n, &as->source, node) { |
1915 | list_del(&pos->node); | 1908 | list_del(&al->node); |
1916 | disasm_line__free(pos); | 1909 | disasm_line__free(disasm_line(al)); |
1917 | } | 1910 | } |
1918 | } | 1911 | } |
1919 | 1912 | ||
@@ -1921,10 +1914,10 @@ static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) | |||
1921 | { | 1914 | { |
1922 | size_t printed; | 1915 | size_t printed; |
1923 | 1916 | ||
1924 | if (dl->offset == -1) | 1917 | if (dl->al.offset == -1) |
1925 | return fprintf(fp, "%s\n", dl->line); | 1918 | return fprintf(fp, "%s\n", dl->al.line); |
1926 | 1919 | ||
1927 | printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->ins.name); | 1920 | printed = fprintf(fp, "%#" PRIx64 " %s", dl->al.offset, dl->ins.name); |
1928 | 1921 | ||
1929 | if (dl->ops.raw[0] != '\0') { | 1922 | if (dl->ops.raw[0] != '\0') { |
1930 | printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", | 1923 | printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", |
@@ -1939,38 +1932,73 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) | |||
1939 | struct disasm_line *pos; | 1932 | struct disasm_line *pos; |
1940 | size_t printed = 0; | 1933 | size_t printed = 0; |
1941 | 1934 | ||
1942 | list_for_each_entry(pos, head, node) | 1935 | list_for_each_entry(pos, head, al.node) |
1943 | printed += disasm_line__fprintf(pos, fp); | 1936 | printed += disasm_line__fprintf(pos, fp); |
1944 | 1937 | ||
1945 | return printed; | 1938 | return printed; |
1946 | } | 1939 | } |
1947 | 1940 | ||
1941 | static void annotation__calc_lines(struct annotation *notes, struct map *map, | ||
1942 | struct rb_root *root, u64 start) | ||
1943 | { | ||
1944 | struct annotation_line *al; | ||
1945 | struct rb_root tmp_root = RB_ROOT; | ||
1946 | |||
1947 | list_for_each_entry(al, ¬es->src->source, node) { | ||
1948 | double percent_max = 0.0; | ||
1949 | int i; | ||
1950 | |||
1951 | for (i = 0; i < al->samples_nr; i++) { | ||
1952 | struct annotation_data *sample; | ||
1953 | |||
1954 | sample = &al->samples[i]; | ||
1955 | |||
1956 | if (sample->percent > percent_max) | ||
1957 | percent_max = sample->percent; | ||
1958 | } | ||
1959 | |||
1960 | if (percent_max <= 0.5) | ||
1961 | continue; | ||
1962 | |||
1963 | al->path = get_srcline(map->dso, start + al->offset, NULL, | ||
1964 | false, true, start + al->offset); | ||
1965 | insert_source_line(&tmp_root, al); | ||
1966 | } | ||
1967 | |||
1968 | resort_source_line(root, &tmp_root); | ||
1969 | } | ||
1970 | |||
1971 | static void symbol__calc_lines(struct symbol *sym, struct map *map, | ||
1972 | struct rb_root *root) | ||
1973 | { | ||
1974 | struct annotation *notes = symbol__annotation(sym); | ||
1975 | u64 start = map__rip_2objdump(map, sym->start); | ||
1976 | |||
1977 | annotation__calc_lines(notes, map, root, start); | ||
1978 | } | ||
1979 | |||
1948 | int symbol__tty_annotate(struct symbol *sym, struct map *map, | 1980 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
1949 | struct perf_evsel *evsel, bool print_lines, | 1981 | struct perf_evsel *evsel, bool print_lines, |
1950 | bool full_paths, int min_pcnt, int max_lines) | 1982 | bool full_paths, int min_pcnt, int max_lines) |
1951 | { | 1983 | { |
1952 | struct dso *dso = map->dso; | 1984 | struct dso *dso = map->dso; |
1953 | struct rb_root source_line = RB_ROOT; | 1985 | struct rb_root source_line = RB_ROOT; |
1954 | u64 len; | ||
1955 | 1986 | ||
1956 | if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), | 1987 | if (symbol__annotate(sym, map, evsel, 0, NULL) < 0) |
1957 | 0, NULL, NULL) < 0) | ||
1958 | return -1; | 1988 | return -1; |
1959 | 1989 | ||
1960 | len = symbol__size(sym); | 1990 | symbol__calc_percent(sym, evsel); |
1961 | 1991 | ||
1962 | if (print_lines) { | 1992 | if (print_lines) { |
1963 | srcline_full_filename = full_paths; | 1993 | srcline_full_filename = full_paths; |
1964 | symbol__get_source_line(sym, map, evsel, &source_line, len); | 1994 | symbol__calc_lines(sym, map, &source_line); |
1965 | print_summary(&source_line, dso->long_name); | 1995 | print_summary(&source_line, dso->long_name); |
1966 | } | 1996 | } |
1967 | 1997 | ||
1968 | symbol__annotate_printf(sym, map, evsel, full_paths, | 1998 | symbol__annotate_printf(sym, map, evsel, full_paths, |
1969 | min_pcnt, max_lines, 0); | 1999 | min_pcnt, max_lines, 0); |
1970 | if (print_lines) | ||
1971 | symbol__free_source_line(sym, len); | ||
1972 | 2000 | ||
1973 | disasm__purge(&symbol__annotation(sym)->src->source); | 2001 | annotated_source__purge(symbol__annotation(sym)->src); |
1974 | 2002 | ||
1975 | return 0; | 2003 | return 0; |
1976 | } | 2004 | } |