aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/annotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r--tools/perf/util/annotate.c652
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
881static struct disasm_line *disasm_line__new(s64 offset, char *line, 882struct 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
892static 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 */
912static struct annotation_line *
913annotation_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 */
950static 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
905out_free_line: 973out_free_line:
906 zfree(&dl->line); 974 zfree(&dl->al.line);
907out_delete: 975out_delete:
908 free(dl); 976 free(dl);
909 return NULL; 977 return NULL;
@@ -911,14 +979,13 @@ out_delete:
911 979
912void disasm_line__free(struct disasm_line *dl) 980void 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
924int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) 991int 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
932static void disasm__add(struct list_head *head, struct disasm_line *line) 999static 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
937struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) 1004struct annotation_line *
1005annotation_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
946double 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
990static const char *annotate__address_color(struct block_range *br) 1014static 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
1096static 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
1073static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 1109static int
1074 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, 1110annotation_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(&notes->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, &notes->src->source, node) { 1138 list_for_each_entry_from(queue, &notes->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 */
1218static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 1221static 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(&notes->src->source, dl); 1298 annotation_line__add(&dl->al, &notes->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
1415static const char *annotate__norm_arch(const char *arch_name) 1422static 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
1427int 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
1583static void insert_source_line(struct rb_root *root, struct source_line *src_line) 1556static 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
1576static 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, &notes->src->source, node) {
1582 s64 end;
1583 int i;
1584
1585 if (al->offset == -1)
1586 continue;
1587
1588 next = annotation_line__next(al, &notes->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
1603void 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
1610int 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
1645static 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
1614static int cmp_source_line(struct source_line *a, struct source_line *b) 1676static 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
1627static void __resort_source_line(struct rb_root *root, struct source_line *src_line) 1689static 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
1647static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root) 1709static 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
1665static 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(&notes->src->lines);
1681}
1682
1683/* Get the filename:line for the colored entries */
1684static 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
1753static void print_summary(struct rb_root *root, const char *filename) 1727static 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
1778static 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
1804int symbol__annotate_printf(struct symbol *sym, struct map *map, 1791int 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(&notes->src->source, start);
1835
1847 list_for_each_entry(pos, &notes->src->source, node) { 1836 list_for_each_entry(pos, &notes->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
1910void disasm__purge(struct list_head *head) 1903void 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
1941static 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, &notes->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
1971static 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
1948int symbol__tty_annotate(struct symbol *sym, struct map *map, 1980int 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}