aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-06-12 18:11:21 -0400
committerIngo Molnar <mingo@elte.hu>2009-06-13 06:58:23 -0400
commit301406b9c69e4914cf45ae9d5f929e7bcf0d93cd (patch)
tree42b8d04c4aac5dc1526bbeae9b3a1efa392ba9f4 /tools/perf
parentf3ad116588151b3371ae4e092290e4f48e62b8bb (diff)
perf annotate: Print the filename:line for annotated colored lines
When we have a colored line in perf annotate, ie a middle/high overhead one, it's sometimes useful to get the matching line and filename from the source file, especially this path prepares to another subsequent one which will print a sorted summary of midle/high overhead lines in the beginning of the output. Filename:Lines have the same color than the concerned ip lines. It can be slow because it relies on addr2line. We could also use objdump with -l but that implies we would have to bufferize objdump output and parse it to filter the relevant lines since we want to print a sorted summary in the beginning. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1244844682-12928-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/builtin-annotate.c98
-rw-r--r--tools/perf/util/symbol.h1
2 files changed, 98 insertions, 1 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index b1ed5f766cb3..6a08da41f76b 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -39,6 +39,8 @@ static int dump_trace = 0;
39 39
40static int verbose; 40static int verbose;
41 41
42static int print_line;
43
42static unsigned long page_size; 44static unsigned long page_size;
43static unsigned long mmap_window = 32; 45static unsigned long mmap_window = 32;
44 46
@@ -84,6 +86,12 @@ typedef union event_union {
84 struct period_event period; 86 struct period_event period;
85} event_t; 87} event_t;
86 88
89
90struct sym_ext {
91 double percent;
92 char *path;
93};
94
87static LIST_HEAD(dsos); 95static LIST_HEAD(dsos);
88static struct dso *kernel_dso; 96static struct dso *kernel_dso;
89static struct dso *vdso; 97static struct dso *vdso;
@@ -1034,6 +1042,8 @@ static int
1034parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) 1042parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1035{ 1043{
1036 char *line = NULL, *tmp, *tmp2; 1044 char *line = NULL, *tmp, *tmp2;
1045 static const char *prev_line;
1046 static const char *prev_color;
1037 unsigned int offset; 1047 unsigned int offset;
1038 size_t line_len; 1048 size_t line_len;
1039 __u64 line_ip; 1049 __u64 line_ip;
@@ -1073,15 +1083,20 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1073 } 1083 }
1074 1084
1075 if (line_ip != -1) { 1085 if (line_ip != -1) {
1086 const char *path = NULL;
1076 unsigned int hits = 0; 1087 unsigned int hits = 0;
1077 double percent = 0.0; 1088 double percent = 0.0;
1078 char *color = PERF_COLOR_NORMAL; 1089 char *color = PERF_COLOR_NORMAL;
1090 struct sym_ext *sym_ext = sym->priv;
1079 1091
1080 offset = line_ip - start; 1092 offset = line_ip - start;
1081 if (offset < len) 1093 if (offset < len)
1082 hits = sym->hist[offset]; 1094 hits = sym->hist[offset];
1083 1095
1084 if (sym->hist_sum) 1096 if (sym_ext) {
1097 path = sym_ext[offset].path;
1098 percent = sym_ext[offset].percent;
1099 } else if (sym->hist_sum)
1085 percent = 100.0 * hits / sym->hist_sum; 1100 percent = 100.0 * hits / sym->hist_sum;
1086 1101
1087 /* 1102 /*
@@ -1096,6 +1111,20 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1096 color = PERF_COLOR_GREEN; 1111 color = PERF_COLOR_GREEN;
1097 } 1112 }
1098 1113
1114 /*
1115 * Also color the filename and line if needed, with
1116 * the same color than the percentage. Don't print it
1117 * twice for close colored ip with the same filename:line
1118 */
1119 if (path) {
1120 if (!prev_line || strcmp(prev_line, path)
1121 || color != prev_color) {
1122 color_fprintf(stdout, color, " %s", path);
1123 prev_line = path;
1124 prev_color = color;
1125 }
1126 }
1127
1099 color_fprintf(stdout, color, " %7.2f", percent); 1128 color_fprintf(stdout, color, " %7.2f", percent);
1100 printf(" : "); 1129 printf(" : ");
1101 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); 1130 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
@@ -1109,6 +1138,67 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1109 return 0; 1138 return 0;
1110} 1139}
1111 1140
1141static void free_source_line(struct symbol *sym, int len)
1142{
1143 struct sym_ext *sym_ext = sym->priv;
1144 int i;
1145
1146 if (!sym_ext)
1147 return;
1148
1149 for (i = 0; i < len; i++)
1150 free(sym_ext[i].path);
1151 free(sym_ext);
1152
1153 sym->priv = NULL;
1154}
1155
1156/* Get the filename:line for the colored entries */
1157static void get_source_line(struct symbol *sym, __u64 start, int len)
1158{
1159 int i;
1160 char cmd[PATH_MAX * 2];
1161 struct sym_ext *sym_ext;
1162
1163 if (!sym->hist_sum)
1164 return;
1165
1166 sym->priv = calloc(len, sizeof(struct sym_ext));
1167 if (!sym->priv)
1168 return;
1169
1170 sym_ext = sym->priv;
1171
1172 for (i = 0; i < len; i++) {
1173 char *path = NULL;
1174 size_t line_len;
1175 __u64 offset;
1176 FILE *fp;
1177
1178 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
1179 if (sym_ext[i].percent <= 0.5)
1180 continue;
1181
1182 offset = start + i;
1183 sprintf(cmd, "addr2line -e %s %016llx", vmlinux, offset);
1184 fp = popen(cmd, "r");
1185 if (!fp)
1186 continue;
1187
1188 if (getline(&path, &line_len, fp) < 0 || !line_len)
1189 goto next;
1190
1191 sym_ext[i].path = malloc(sizeof(char) * line_len);
1192 if (!sym_ext[i].path)
1193 goto next;
1194
1195 strcpy(sym_ext[i].path, path);
1196
1197 next:
1198 pclose(fp);
1199 }
1200}
1201
1112static void annotate_sym(struct dso *dso, struct symbol *sym) 1202static void annotate_sym(struct dso *dso, struct symbol *sym)
1113{ 1203{
1114 char *filename = dso->name; 1204 char *filename = dso->name;
@@ -1135,6 +1225,9 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1135 end = start + sym->end - sym->start + 1; 1225 end = start + sym->end - sym->start + 1;
1136 len = sym->end - sym->start; 1226 len = sym->end - sym->start;
1137 1227
1228 if (print_line)
1229 get_source_line(sym, start, len);
1230
1138 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); 1231 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename);
1139 1232
1140 if (verbose >= 3) 1233 if (verbose >= 3)
@@ -1150,6 +1243,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1150 } 1243 }
1151 1244
1152 pclose(file); 1245 pclose(file);
1246 free_source_line(sym, len);
1153} 1247}
1154 1248
1155static void find_annotations(void) 1249static void find_annotations(void)
@@ -1308,6 +1402,8 @@ static const struct option options[] = {
1308 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1402 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1309 "dump raw trace in ASCII"), 1403 "dump raw trace in ASCII"),
1310 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1404 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1405 OPT_BOOLEAN('l', "print-line", &print_line,
1406 "print matching source lines (may be slow)"),
1311 OPT_END() 1407 OPT_END()
1312}; 1408};
1313 1409
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 0d1292bd8270..5ad9b06c3f6f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -12,6 +12,7 @@ struct symbol {
12 __u64 obj_start; 12 __u64 obj_start;
13 __u64 hist_sum; 13 __u64 hist_sum;
14 __u64 *hist; 14 __u64 *hist;
15 void *priv;
15 char name[0]; 16 char name[0];
16}; 17};
17 18