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.c262
1 files changed, 199 insertions, 63 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index d33fe937e6f1..d102716c43a1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -14,6 +14,7 @@
14#include "symbol.h" 14#include "symbol.h"
15#include "debug.h" 15#include "debug.h"
16#include "annotate.h" 16#include "annotate.h"
17#include "evsel.h"
17#include <pthread.h> 18#include <pthread.h>
18#include <linux/bitops.h> 19#include <linux/bitops.h>
19 20
@@ -602,8 +603,42 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa
602 return NULL; 603 return NULL;
603} 604}
604 605
606double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
607 s64 end, const char **path)
608{
609 struct source_line *src_line = notes->src->lines;
610 double percent = 0.0;
611
612 if (src_line) {
613 size_t sizeof_src_line = sizeof(*src_line) +
614 sizeof(src_line->p) * (src_line->nr_pcnt - 1);
615
616 while (offset < end) {
617 src_line = (void *)notes->src->lines +
618 (sizeof_src_line * offset);
619
620 if (*path == NULL)
621 *path = src_line->path;
622
623 percent += src_line->p[evidx].percent;
624 offset++;
625 }
626 } else {
627 struct sym_hist *h = annotation__histogram(notes, evidx);
628 unsigned int hits = 0;
629
630 while (offset < end)
631 hits += h->addr[offset++];
632
633 if (h->sum)
634 percent = 100.0 * hits / h->sum;
635 }
636
637 return percent;
638}
639
605static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 640static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
606 int evidx, u64 len, int min_pcnt, int printed, 641 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
607 int max_lines, struct disasm_line *queue) 642 int max_lines, struct disasm_line *queue)
608{ 643{
609 static const char *prev_line; 644 static const char *prev_line;
@@ -611,34 +646,37 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
611 646
612 if (dl->offset != -1) { 647 if (dl->offset != -1) {
613 const char *path = NULL; 648 const char *path = NULL;
614 unsigned int hits = 0; 649 double percent, max_percent = 0.0;
615 double percent = 0.0; 650 double *ppercents = &percent;
651 int i, nr_percent = 1;
616 const char *color; 652 const char *color;
617 struct annotation *notes = symbol__annotation(sym); 653 struct annotation *notes = symbol__annotation(sym);
618 struct source_line *src_line = notes->src->lines;
619 struct sym_hist *h = annotation__histogram(notes, evidx);
620 s64 offset = dl->offset; 654 s64 offset = dl->offset;
621 const u64 addr = start + offset; 655 const u64 addr = start + offset;
622 struct disasm_line *next; 656 struct disasm_line *next;
623 657
624 next = disasm__get_next_ip_line(&notes->src->source, dl); 658 next = disasm__get_next_ip_line(&notes->src->source, dl);
625 659
626 while (offset < (s64)len && 660 if (perf_evsel__is_group_event(evsel)) {
627 (next == NULL || offset < next->offset)) { 661 nr_percent = evsel->nr_members;
628 if (src_line) { 662 ppercents = calloc(nr_percent, sizeof(double));
629 if (path == NULL) 663 if (ppercents == NULL)
630 path = src_line[offset].path; 664 return -1;
631 percent += src_line[offset].percent;
632 } else
633 hits += h->addr[offset];
634
635 ++offset;
636 } 665 }
637 666
638 if (src_line == NULL && h->sum) 667 for (i = 0; i < nr_percent; i++) {
639 percent = 100.0 * hits / h->sum; 668 percent = disasm__calc_percent(notes,
669 notes->src->lines ? i : evsel->idx + i,
670 offset,
671 next ? next->offset : (s64) len,
672 &path);
673
674 ppercents[i] = percent;
675 if (percent > max_percent)
676 max_percent = percent;
677 }
640 678
641 if (percent < min_pcnt) 679 if (max_percent < min_pcnt)
642 return -1; 680 return -1;
643 681
644 if (max_lines && printed >= max_lines) 682 if (max_lines && printed >= max_lines)
@@ -648,12 +686,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
648 list_for_each_entry_from(queue, &notes->src->source, node) { 686 list_for_each_entry_from(queue, &notes->src->source, node) {
649 if (queue == dl) 687 if (queue == dl)
650 break; 688 break;
651 disasm_line__print(queue, sym, start, evidx, len, 689 disasm_line__print(queue, sym, start, evsel, len,
652 0, 0, 1, NULL); 690 0, 0, 1, NULL);
653 } 691 }
654 } 692 }
655 693
656 color = get_percent_color(percent); 694 color = get_percent_color(max_percent);
657 695
658 /* 696 /*
659 * Also color the filename and line if needed, with 697 * Also color the filename and line if needed, with
@@ -669,25 +707,59 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
669 } 707 }
670 } 708 }
671 709
672 color_fprintf(stdout, color, " %7.2f", percent); 710 for (i = 0; i < nr_percent; i++) {
711 percent = ppercents[i];
712 color = get_percent_color(percent);
713 color_fprintf(stdout, color, " %7.2f", percent);
714 }
715
673 printf(" : "); 716 printf(" : ");
674 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); 717 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
675 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); 718 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
719
720 if (ppercents != &percent)
721 free(ppercents);
722
676 } else if (max_lines && printed >= max_lines) 723 } else if (max_lines && printed >= max_lines)
677 return 1; 724 return 1;
678 else { 725 else {
726 int width = 8;
727
679 if (queue) 728 if (queue)
680 return -1; 729 return -1;
681 730
731 if (perf_evsel__is_group_event(evsel))
732 width *= evsel->nr_members;
733
682 if (!*dl->line) 734 if (!*dl->line)
683 printf(" :\n"); 735 printf(" %*s:\n", width, " ");
684 else 736 else
685 printf(" : %s\n", dl->line); 737 printf(" %*s: %s\n", width, " ", dl->line);
686 } 738 }
687 739
688 return 0; 740 return 0;
689} 741}
690 742
743/*
744 * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
745 * which looks like following
746 *
747 * 0000000000415500 <_init>:
748 * 415500: sub $0x8,%rsp
749 * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8>
750 * 41550b: test %rax,%rax
751 * 41550e: je 415515 <_init+0x15>
752 * 415510: callq 416e70 <__gmon_start__@plt>
753 * 415515: add $0x8,%rsp
754 * 415519: retq
755 *
756 * it will be parsed and saved into struct disasm_line as
757 * <offset> <name> <ops.raw>
758 *
759 * The offset will be a relative offset from the start of the symbol and -1
760 * means that it's not a disassembly line so should be treated differently.
761 * The ops.raw part will be parsed further according to type of the instruction.
762 */
691static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 763static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
692 FILE *file, size_t privsize) 764 FILE *file, size_t privsize)
693{ 765{
@@ -858,7 +930,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
858 struct source_line *iter; 930 struct source_line *iter;
859 struct rb_node **p = &root->rb_node; 931 struct rb_node **p = &root->rb_node;
860 struct rb_node *parent = NULL; 932 struct rb_node *parent = NULL;
861 int ret; 933 int i, ret;
862 934
863 while (*p != NULL) { 935 while (*p != NULL) {
864 parent = *p; 936 parent = *p;
@@ -866,7 +938,8 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
866 938
867 ret = strcmp(iter->path, src_line->path); 939 ret = strcmp(iter->path, src_line->path);
868 if (ret == 0) { 940 if (ret == 0) {
869 iter->percent_sum += src_line->percent; 941 for (i = 0; i < src_line->nr_pcnt; i++)
942 iter->p[i].percent_sum += src_line->p[i].percent;
870 return; 943 return;
871 } 944 }
872 945
@@ -876,12 +949,26 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
876 p = &(*p)->rb_right; 949 p = &(*p)->rb_right;
877 } 950 }
878 951
879 src_line->percent_sum = src_line->percent; 952 for (i = 0; i < src_line->nr_pcnt; i++)
953 src_line->p[i].percent_sum = src_line->p[i].percent;
880 954
881 rb_link_node(&src_line->node, parent, p); 955 rb_link_node(&src_line->node, parent, p);
882 rb_insert_color(&src_line->node, root); 956 rb_insert_color(&src_line->node, root);
883} 957}
884 958
959static int cmp_source_line(struct source_line *a, struct source_line *b)
960{
961 int i;
962
963 for (i = 0; i < a->nr_pcnt; i++) {
964 if (a->p[i].percent_sum == b->p[i].percent_sum)
965 continue;
966 return a->p[i].percent_sum > b->p[i].percent_sum;
967 }
968
969 return 0;
970}
971
885static void __resort_source_line(struct rb_root *root, struct source_line *src_line) 972static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
886{ 973{
887 struct source_line *iter; 974 struct source_line *iter;
@@ -892,7 +979,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l
892 parent = *p; 979 parent = *p;
893 iter = rb_entry(parent, struct source_line, node); 980 iter = rb_entry(parent, struct source_line, node);
894 981
895 if (src_line->percent_sum > iter->percent_sum) 982 if (cmp_source_line(src_line, iter))
896 p = &(*p)->rb_left; 983 p = &(*p)->rb_left;
897 else 984 else
898 p = &(*p)->rb_right; 985 p = &(*p)->rb_right;
@@ -924,32 +1011,52 @@ static void symbol__free_source_line(struct symbol *sym, int len)
924{ 1011{
925 struct annotation *notes = symbol__annotation(sym); 1012 struct annotation *notes = symbol__annotation(sym);
926 struct source_line *src_line = notes->src->lines; 1013 struct source_line *src_line = notes->src->lines;
1014 size_t sizeof_src_line;
927 int i; 1015 int i;
928 1016
929 for (i = 0; i < len; i++) 1017 sizeof_src_line = sizeof(*src_line) +
930 free(src_line[i].path); 1018 (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
1019
1020 for (i = 0; i < len; i++) {
1021 free(src_line->path);
1022 src_line = (void *)src_line + sizeof_src_line;
1023 }
931 1024
932 free(src_line); 1025 free(notes->src->lines);
933 notes->src->lines = NULL; 1026 notes->src->lines = NULL;
934} 1027}
935 1028
936/* Get the filename:line for the colored entries */ 1029/* Get the filename:line for the colored entries */
937static int symbol__get_source_line(struct symbol *sym, struct map *map, 1030static int symbol__get_source_line(struct symbol *sym, struct map *map,
938 int evidx, struct rb_root *root, int len, 1031 struct perf_evsel *evsel,
1032 struct rb_root *root, int len,
939 const char *filename) 1033 const char *filename)
940{ 1034{
941 u64 start; 1035 u64 start;
942 int i; 1036 int i, k;
1037 int evidx = evsel->idx;
943 char cmd[PATH_MAX * 2]; 1038 char cmd[PATH_MAX * 2];
944 struct source_line *src_line; 1039 struct source_line *src_line;
945 struct annotation *notes = symbol__annotation(sym); 1040 struct annotation *notes = symbol__annotation(sym);
946 struct sym_hist *h = annotation__histogram(notes, evidx); 1041 struct sym_hist *h = annotation__histogram(notes, evidx);
947 struct rb_root tmp_root = RB_ROOT; 1042 struct rb_root tmp_root = RB_ROOT;
1043 int nr_pcnt = 1;
1044 u64 h_sum = h->sum;
1045 size_t sizeof_src_line = sizeof(struct source_line);
1046
1047 if (perf_evsel__is_group_event(evsel)) {
1048 for (i = 1; i < evsel->nr_members; i++) {
1049 h = annotation__histogram(notes, evidx + i);
1050 h_sum += h->sum;
1051 }
1052 nr_pcnt = evsel->nr_members;
1053 sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p);
1054 }
948 1055
949 if (!h->sum) 1056 if (!h_sum)
950 return 0; 1057 return 0;
951 1058
952 src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); 1059 src_line = notes->src->lines = calloc(len, sizeof_src_line);
953 if (!notes->src->lines) 1060 if (!notes->src->lines)
954 return -1; 1061 return -1;
955 1062
@@ -960,29 +1067,41 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
960 size_t line_len; 1067 size_t line_len;
961 u64 offset; 1068 u64 offset;
962 FILE *fp; 1069 FILE *fp;
1070 double percent_max = 0.0;
963 1071
964 src_line[i].percent = 100.0 * h->addr[i] / h->sum; 1072 src_line->nr_pcnt = nr_pcnt;
965 if (src_line[i].percent <= 0.5) 1073
966 continue; 1074 for (k = 0; k < nr_pcnt; k++) {
1075 h = annotation__histogram(notes, evidx + k);
1076 src_line->p[k].percent = 100.0 * h->addr[i] / h->sum;
1077
1078 if (src_line->p[k].percent > percent_max)
1079 percent_max = src_line->p[k].percent;
1080 }
1081
1082 if (percent_max <= 0.5)
1083 goto next;
967 1084
968 offset = start + i; 1085 offset = start + i;
969 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); 1086 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
970 fp = popen(cmd, "r"); 1087 fp = popen(cmd, "r");
971 if (!fp) 1088 if (!fp)
972 continue; 1089 goto next;
973 1090
974 if (getline(&path, &line_len, fp) < 0 || !line_len) 1091 if (getline(&path, &line_len, fp) < 0 || !line_len)
975 goto next; 1092 goto next_close;
976 1093
977 src_line[i].path = malloc(sizeof(char) * line_len + 1); 1094 src_line->path = malloc(sizeof(char) * line_len + 1);
978 if (!src_line[i].path) 1095 if (!src_line->path)
979 goto next; 1096 goto next_close;
980 1097
981 strcpy(src_line[i].path, path); 1098 strcpy(src_line->path, path);
982 insert_source_line(&tmp_root, &src_line[i]); 1099 insert_source_line(&tmp_root, src_line);
983 1100
984 next: 1101 next_close:
985 pclose(fp); 1102 pclose(fp);
1103 next:
1104 src_line = (void *)src_line + sizeof_src_line;
986 } 1105 }
987 1106
988 resort_source_line(root, &tmp_root); 1107 resort_source_line(root, &tmp_root);
@@ -1004,24 +1123,33 @@ static void print_summary(struct rb_root *root, const char *filename)
1004 1123
1005 node = rb_first(root); 1124 node = rb_first(root);
1006 while (node) { 1125 while (node) {
1007 double percent; 1126 double percent, percent_max = 0.0;
1008 const char *color; 1127 const char *color;
1009 char *path; 1128 char *path;
1129 int i;
1010 1130
1011 src_line = rb_entry(node, struct source_line, node); 1131 src_line = rb_entry(node, struct source_line, node);
1012 percent = src_line->percent_sum; 1132 for (i = 0; i < src_line->nr_pcnt; i++) {
1013 color = get_percent_color(percent); 1133 percent = src_line->p[i].percent_sum;
1134 color = get_percent_color(percent);
1135 color_fprintf(stdout, color, " %7.2f", percent);
1136
1137 if (percent > percent_max)
1138 percent_max = percent;
1139 }
1140
1014 path = src_line->path; 1141 path = src_line->path;
1142 color = get_percent_color(percent_max);
1143 color_fprintf(stdout, color, " %s", path);
1015 1144
1016 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1017 node = rb_next(node); 1145 node = rb_next(node);
1018 } 1146 }
1019} 1147}
1020 1148
1021static void symbol__annotate_hits(struct symbol *sym, int evidx) 1149static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
1022{ 1150{
1023 struct annotation *notes = symbol__annotation(sym); 1151 struct annotation *notes = symbol__annotation(sym);
1024 struct sym_hist *h = annotation__histogram(notes, evidx); 1152 struct sym_hist *h = annotation__histogram(notes, evsel->idx);
1025 u64 len = symbol__size(sym), offset; 1153 u64 len = symbol__size(sym), offset;
1026 1154
1027 for (offset = 0; offset < len; ++offset) 1155 for (offset = 0; offset < len; ++offset)
@@ -1031,9 +1159,9 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
1031 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); 1159 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
1032} 1160}
1033 1161
1034int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 1162int symbol__annotate_printf(struct symbol *sym, struct map *map,
1035 bool full_paths, int min_pcnt, int max_lines, 1163 struct perf_evsel *evsel, bool full_paths,
1036 int context) 1164 int min_pcnt, int max_lines, int context)
1037{ 1165{
1038 struct dso *dso = map->dso; 1166 struct dso *dso = map->dso;
1039 char *filename; 1167 char *filename;
@@ -1044,6 +1172,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1044 int printed = 2, queue_len = 0; 1172 int printed = 2, queue_len = 0;
1045 int more = 0; 1173 int more = 0;
1046 u64 len; 1174 u64 len;
1175 int width = 8;
1176 int namelen;
1047 1177
1048 filename = strdup(dso->long_name); 1178 filename = strdup(dso->long_name);
1049 if (!filename) 1179 if (!filename)
@@ -1055,12 +1185,18 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1055 d_filename = basename(filename); 1185 d_filename = basename(filename);
1056 1186
1057 len = symbol__size(sym); 1187 len = symbol__size(sym);
1188 namelen = strlen(d_filename);
1189
1190 if (perf_evsel__is_group_event(evsel))
1191 width *= evsel->nr_members;
1058 1192
1059 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 1193 printf(" %-*.*s| Source code & Disassembly of %s\n",
1060 printf("------------------------------------------------\n"); 1194 width, width, "Percent", d_filename);
1195 printf("-%-*.*s-------------------------------------\n",
1196 width+namelen, width+namelen, graph_dotted_line);
1061 1197
1062 if (verbose) 1198 if (verbose)
1063 symbol__annotate_hits(sym, evidx); 1199 symbol__annotate_hits(sym, evsel);
1064 1200
1065 list_for_each_entry(pos, &notes->src->source, node) { 1201 list_for_each_entry(pos, &notes->src->source, node) {
1066 if (context && queue == NULL) { 1202 if (context && queue == NULL) {
@@ -1068,7 +1204,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1068 queue_len = 0; 1204 queue_len = 0;
1069 } 1205 }
1070 1206
1071 switch (disasm_line__print(pos, sym, start, evidx, len, 1207 switch (disasm_line__print(pos, sym, start, evsel, len,
1072 min_pcnt, printed, max_lines, 1208 min_pcnt, printed, max_lines,
1073 queue)) { 1209 queue)) {
1074 case 0: 1210 case 0:
@@ -1163,9 +1299,9 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp)
1163 return printed; 1299 return printed;
1164} 1300}
1165 1301
1166int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 1302int symbol__tty_annotate(struct symbol *sym, struct map *map,
1167 bool print_lines, bool full_paths, int min_pcnt, 1303 struct perf_evsel *evsel, bool print_lines,
1168 int max_lines) 1304 bool full_paths, int min_pcnt, int max_lines)
1169{ 1305{
1170 struct dso *dso = map->dso; 1306 struct dso *dso = map->dso;
1171 const char *filename = dso->long_name; 1307 const char *filename = dso->long_name;
@@ -1178,12 +1314,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
1178 len = symbol__size(sym); 1314 len = symbol__size(sym);
1179 1315
1180 if (print_lines) { 1316 if (print_lines) {
1181 symbol__get_source_line(sym, map, evidx, &source_line, 1317 symbol__get_source_line(sym, map, evsel, &source_line,
1182 len, filename); 1318 len, filename);
1183 print_summary(&source_line, filename); 1319 print_summary(&source_line, filename);
1184 } 1320 }
1185 1321
1186 symbol__annotate_printf(sym, map, evidx, full_paths, 1322 symbol__annotate_printf(sym, map, evsel, full_paths,
1187 min_pcnt, max_lines, 0); 1323 min_pcnt, max_lines, 0);
1188 if (print_lines) 1324 if (print_lines)
1189 symbol__free_source_line(sym, len); 1325 symbol__free_source_line(sym, len);