diff options
-rw-r--r-- | tools/perf/builtin-annotate.c | 135 |
1 files changed, 112 insertions, 23 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e47dd1587e39..5ec5de995872 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -145,21 +145,58 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
145 | return 0; | 145 | return 0; |
146 | } | 146 | } |
147 | 147 | ||
148 | static int parse_line(FILE *file, struct hist_entry *he, u64 len) | 148 | struct objdump_line { |
149 | struct list_head node; | ||
150 | s64 offset; | ||
151 | char *line; | ||
152 | }; | ||
153 | |||
154 | static struct objdump_line *objdump_line__new(s64 offset, char *line) | ||
155 | { | ||
156 | struct objdump_line *self = malloc(sizeof(*self)); | ||
157 | |||
158 | if (self != NULL) { | ||
159 | self->offset = offset; | ||
160 | self->line = line; | ||
161 | } | ||
162 | |||
163 | return self; | ||
164 | } | ||
165 | |||
166 | static void objdump_line__free(struct objdump_line *self) | ||
167 | { | ||
168 | free(self->line); | ||
169 | free(self); | ||
170 | } | ||
171 | |||
172 | static void objdump__add_line(struct list_head *head, struct objdump_line *line) | ||
173 | { | ||
174 | list_add_tail(&line->node, head); | ||
175 | } | ||
176 | |||
177 | static struct objdump_line *objdump__get_next_ip_line(struct list_head *head, | ||
178 | struct objdump_line *pos) | ||
179 | { | ||
180 | list_for_each_entry_continue(pos, head, node) | ||
181 | if (pos->offset >= 0) | ||
182 | return pos; | ||
183 | |||
184 | return NULL; | ||
185 | } | ||
186 | |||
187 | static int parse_line(FILE *file, struct hist_entry *he, | ||
188 | struct list_head *head) | ||
149 | { | 189 | { |
150 | struct symbol *sym = he->sym; | 190 | struct symbol *sym = he->sym; |
191 | struct objdump_line *objdump_line; | ||
151 | char *line = NULL, *tmp, *tmp2; | 192 | char *line = NULL, *tmp, *tmp2; |
152 | static const char *prev_line; | ||
153 | static const char *prev_color; | ||
154 | unsigned int offset; | ||
155 | size_t line_len; | 193 | size_t line_len; |
156 | u64 start; | 194 | s64 line_ip, offset = -1; |
157 | s64 line_ip; | ||
158 | int ret; | ||
159 | char *c; | 195 | char *c; |
160 | 196 | ||
161 | if (getline(&line, &line_len, file) < 0) | 197 | if (getline(&line, &line_len, file) < 0) |
162 | return -1; | 198 | return -1; |
199 | |||
163 | if (!line) | 200 | if (!line) |
164 | return -1; | 201 | return -1; |
165 | 202 | ||
@@ -168,8 +205,6 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
168 | *c = 0; | 205 | *c = 0; |
169 | 206 | ||
170 | line_ip = -1; | 207 | line_ip = -1; |
171 | offset = 0; | ||
172 | ret = -2; | ||
173 | 208 | ||
174 | /* | 209 | /* |
175 | * Strip leading spaces: | 210 | * Strip leading spaces: |
@@ -190,9 +225,30 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
190 | line_ip = -1; | 225 | line_ip = -1; |
191 | } | 226 | } |
192 | 227 | ||
193 | start = map__rip_2objdump(he->map, sym->start); | ||
194 | |||
195 | if (line_ip != -1) { | 228 | if (line_ip != -1) { |
229 | u64 start = map__rip_2objdump(he->map, sym->start); | ||
230 | offset = line_ip - start; | ||
231 | } | ||
232 | |||
233 | objdump_line = objdump_line__new(offset, line); | ||
234 | if (objdump_line == NULL) { | ||
235 | free(line); | ||
236 | return -1; | ||
237 | } | ||
238 | objdump__add_line(head, objdump_line); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int objdump_line__print(struct objdump_line *self, | ||
244 | struct list_head *head, | ||
245 | struct hist_entry *he, u64 len) | ||
246 | { | ||
247 | struct symbol *sym = he->sym; | ||
248 | static const char *prev_line; | ||
249 | static const char *prev_color; | ||
250 | |||
251 | if (self->offset != -1) { | ||
196 | const char *path = NULL; | 252 | const char *path = NULL; |
197 | unsigned int hits = 0; | 253 | unsigned int hits = 0; |
198 | double percent = 0.0; | 254 | double percent = 0.0; |
@@ -200,15 +256,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
200 | struct sym_priv *priv = symbol__priv(sym); | 256 | struct sym_priv *priv = symbol__priv(sym); |
201 | struct sym_ext *sym_ext = priv->ext; | 257 | struct sym_ext *sym_ext = priv->ext; |
202 | struct sym_hist *h = priv->hist; | 258 | struct sym_hist *h = priv->hist; |
259 | s64 offset = self->offset; | ||
260 | struct objdump_line *next = objdump__get_next_ip_line(head, self); | ||
261 | |||
262 | while (offset < (s64)len && | ||
263 | (next == NULL || offset < next->offset)) { | ||
264 | if (sym_ext) { | ||
265 | if (path == NULL) | ||
266 | path = sym_ext[offset].path; | ||
267 | percent += sym_ext[offset].percent; | ||
268 | } else | ||
269 | hits += h->ip[offset]; | ||
270 | |||
271 | ++offset; | ||
272 | } | ||
203 | 273 | ||
204 | offset = line_ip - start; | 274 | if (sym_ext == NULL && h->sum) |
205 | if (offset < len) | ||
206 | hits = h->ip[offset]; | ||
207 | |||
208 | if (offset < len && sym_ext) { | ||
209 | path = sym_ext[offset].path; | ||
210 | percent = sym_ext[offset].percent; | ||
211 | } else if (h->sum) | ||
212 | percent = 100.0 * hits / h->sum; | 275 | percent = 100.0 * hits / h->sum; |
213 | 276 | ||
214 | color = get_percent_color(percent); | 277 | color = get_percent_color(percent); |
@@ -229,12 +292,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
229 | 292 | ||
230 | color_fprintf(stdout, color, " %7.2f", percent); | 293 | color_fprintf(stdout, color, " %7.2f", percent); |
231 | printf(" : "); | 294 | printf(" : "); |
232 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); | 295 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line); |
233 | } else { | 296 | } else { |
234 | if (!*line) | 297 | if (!*self->line) |
235 | printf(" :\n"); | 298 | printf(" :\n"); |
236 | else | 299 | else |
237 | printf(" : %s\n", line); | 300 | printf(" : %s\n", self->line); |
238 | } | 301 | } |
239 | 302 | ||
240 | return 0; | 303 | return 0; |
@@ -360,6 +423,20 @@ static void print_summary(const char *filename) | |||
360 | } | 423 | } |
361 | } | 424 | } |
362 | 425 | ||
426 | static void hist_entry__print_hits(struct hist_entry *self) | ||
427 | { | ||
428 | struct symbol *sym = self->sym; | ||
429 | struct sym_priv *priv = symbol__priv(sym); | ||
430 | struct sym_hist *h = priv->hist; | ||
431 | u64 len = sym->end - sym->start, offset; | ||
432 | |||
433 | for (offset = 0; offset < len; ++offset) | ||
434 | if (h->ip[offset] != 0) | ||
435 | printf("%*Lx: %Lu\n", BITS_PER_LONG / 2, | ||
436 | sym->start + offset, h->ip[offset]); | ||
437 | printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); | ||
438 | } | ||
439 | |||
363 | static void annotate_sym(struct hist_entry *he) | 440 | static void annotate_sym(struct hist_entry *he) |
364 | { | 441 | { |
365 | struct map *map = he->map; | 442 | struct map *map = he->map; |
@@ -369,6 +446,8 @@ static void annotate_sym(struct hist_entry *he) | |||
369 | u64 len; | 446 | u64 len; |
370 | char command[PATH_MAX*2]; | 447 | char command[PATH_MAX*2]; |
371 | FILE *file; | 448 | FILE *file; |
449 | LIST_HEAD(head); | ||
450 | struct objdump_line *pos, *n; | ||
372 | 451 | ||
373 | if (!filename) | 452 | if (!filename) |
374 | return; | 453 | return; |
@@ -410,11 +489,21 @@ static void annotate_sym(struct hist_entry *he) | |||
410 | return; | 489 | return; |
411 | 490 | ||
412 | while (!feof(file)) { | 491 | while (!feof(file)) { |
413 | if (parse_line(file, he, len) < 0) | 492 | if (parse_line(file, he, &head) < 0) |
414 | break; | 493 | break; |
415 | } | 494 | } |
416 | 495 | ||
417 | pclose(file); | 496 | pclose(file); |
497 | |||
498 | if (verbose) | ||
499 | hist_entry__print_hits(he); | ||
500 | |||
501 | list_for_each_entry_safe(pos, n, &head, node) { | ||
502 | objdump_line__print(pos, &head, he, len); | ||
503 | list_del(&pos->node); | ||
504 | objdump_line__free(pos); | ||
505 | } | ||
506 | |||
418 | if (print_line) | 507 | if (print_line) |
419 | free_source_line(he, len); | 508 | free_source_line(he, len); |
420 | } | 509 | } |