diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-10-19 15:17:57 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-10-20 01:55:51 -0400 |
commit | ed52ce2e3c33dc7626a40fa2da766d1a6460e543 (patch) | |
tree | 037f7791b8f493b1adc27d9f9692922ed886844e /tools/perf/builtin-annotate.c | |
parent | bbe2987bea26a684ff11d887dfc4cf39b22c27a2 (diff) |
perf tools: Add ->unmap_ip operation to struct map
We need this because we get section relative addresses when
reading the symtabs, but when a tool like 'perf annotate' needs
to match these address to what 'objdump -dS' produces we need
the address + section back again.
So in annotate now we look at the 'struct hist_entry' instances
(that weren't really being used) so that we iterate only over
the symbols that had some hit and get the map where that
particular hit happened so that we can get the right address to
match with annotate.
Verified that at least:
perf annotate mmap_read_counter # Uses the ~/bin/perf binary
perf annotate --vmlinux /home/acme/git/build/perf/vmlinux intel_pmu_enable_all
on a 'perf record perf top' session seems to work.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1255979877-12533-1-git-send-email-acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 62 |
1 files changed, 42 insertions, 20 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 56ba71658d70..06f10278b28e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -58,9 +58,12 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
58 | return; | 58 | return; |
59 | 59 | ||
60 | sym_size = sym->end - sym->start; | 60 | sym_size = sym->end - sym->start; |
61 | ip = he->map->map_ip(he->map, ip); | ||
62 | offset = ip - sym->start; | 61 | offset = ip - sym->start; |
63 | 62 | ||
63 | if (verbose) | ||
64 | fprintf(stderr, "%s: ip=%Lx\n", __func__, | ||
65 | he->map->unmap_ip(he->map, ip)); | ||
66 | |||
64 | if (offset >= sym_size) | 67 | if (offset >= sym_size) |
65 | return; | 68 | return; |
66 | 69 | ||
@@ -83,8 +86,7 @@ static int hist_entry__add(struct thread *thread, struct map *map, | |||
83 | count, level, &hit); | 86 | count, level, &hit); |
84 | if (he == NULL) | 87 | if (he == NULL) |
85 | return -ENOMEM; | 88 | return -ENOMEM; |
86 | if (hit) | 89 | hist_hit(he, ip); |
87 | hist_hit(he, ip); | ||
88 | return 0; | 90 | return 0; |
89 | } | 91 | } |
90 | 92 | ||
@@ -260,14 +262,15 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
260 | return 0; | 262 | return 0; |
261 | } | 263 | } |
262 | 264 | ||
263 | static int | 265 | static int parse_line(FILE *file, struct hist_entry *he, u64 len) |
264 | parse_line(FILE *file, struct symbol *sym, u64 len) | ||
265 | { | 266 | { |
267 | struct symbol *sym = he->sym; | ||
266 | char *line = NULL, *tmp, *tmp2; | 268 | char *line = NULL, *tmp, *tmp2; |
267 | static const char *prev_line; | 269 | static const char *prev_line; |
268 | static const char *prev_color; | 270 | static const char *prev_color; |
269 | unsigned int offset; | 271 | unsigned int offset; |
270 | size_t line_len; | 272 | size_t line_len; |
273 | u64 start; | ||
271 | s64 line_ip; | 274 | s64 line_ip; |
272 | int ret; | 275 | int ret; |
273 | char *c; | 276 | char *c; |
@@ -304,6 +307,8 @@ parse_line(FILE *file, struct symbol *sym, u64 len) | |||
304 | line_ip = -1; | 307 | line_ip = -1; |
305 | } | 308 | } |
306 | 309 | ||
310 | start = he->map->unmap_ip(he->map, sym->start); | ||
311 | |||
307 | if (line_ip != -1) { | 312 | if (line_ip != -1) { |
308 | const char *path = NULL; | 313 | const char *path = NULL; |
309 | unsigned int hits = 0; | 314 | unsigned int hits = 0; |
@@ -311,7 +316,7 @@ parse_line(FILE *file, struct symbol *sym, u64 len) | |||
311 | const char *color; | 316 | const char *color; |
312 | struct sym_ext *sym_ext = sym->priv; | 317 | struct sym_ext *sym_ext = sym->priv; |
313 | 318 | ||
314 | offset = line_ip - sym->start; | 319 | offset = line_ip - start; |
315 | if (offset < len) | 320 | if (offset < len) |
316 | hits = sym->hist[offset]; | 321 | hits = sym->hist[offset]; |
317 | 322 | ||
@@ -390,8 +395,10 @@ static void free_source_line(struct symbol *sym, int len) | |||
390 | 395 | ||
391 | /* Get the filename:line for the colored entries */ | 396 | /* Get the filename:line for the colored entries */ |
392 | static void | 397 | static void |
393 | get_source_line(struct symbol *sym, int len, const char *filename) | 398 | get_source_line(struct hist_entry *he, int len, const char *filename) |
394 | { | 399 | { |
400 | struct symbol *sym = he->sym; | ||
401 | u64 start; | ||
395 | int i; | 402 | int i; |
396 | char cmd[PATH_MAX * 2]; | 403 | char cmd[PATH_MAX * 2]; |
397 | struct sym_ext *sym_ext; | 404 | struct sym_ext *sym_ext; |
@@ -404,6 +411,7 @@ get_source_line(struct symbol *sym, int len, const char *filename) | |||
404 | return; | 411 | return; |
405 | 412 | ||
406 | sym_ext = sym->priv; | 413 | sym_ext = sym->priv; |
414 | start = he->map->unmap_ip(he->map, sym->start); | ||
407 | 415 | ||
408 | for (i = 0; i < len; i++) { | 416 | for (i = 0; i < len; i++) { |
409 | char *path = NULL; | 417 | char *path = NULL; |
@@ -415,7 +423,7 @@ get_source_line(struct symbol *sym, int len, const char *filename) | |||
415 | if (sym_ext[i].percent <= 0.5) | 423 | if (sym_ext[i].percent <= 0.5) |
416 | continue; | 424 | continue; |
417 | 425 | ||
418 | offset = sym->start + i; | 426 | offset = start + i; |
419 | sprintf(cmd, "addr2line -e %s %016llx", filename, offset); | 427 | sprintf(cmd, "addr2line -e %s %016llx", filename, offset); |
420 | fp = popen(cmd, "r"); | 428 | fp = popen(cmd, "r"); |
421 | if (!fp) | 429 | if (!fp) |
@@ -465,8 +473,11 @@ static void print_summary(const char *filename) | |||
465 | } | 473 | } |
466 | } | 474 | } |
467 | 475 | ||
468 | static void annotate_sym(struct dso *dso, struct symbol *sym) | 476 | static void annotate_sym(struct hist_entry *he) |
469 | { | 477 | { |
478 | struct map *map = he->map; | ||
479 | struct dso *dso = map->dso; | ||
480 | struct symbol *sym = he->sym; | ||
470 | const char *filename = dso->long_name, *d_filename; | 481 | const char *filename = dso->long_name, *d_filename; |
471 | u64 len; | 482 | u64 len; |
472 | char command[PATH_MAX*2]; | 483 | char command[PATH_MAX*2]; |
@@ -475,6 +486,12 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
475 | if (!filename) | 486 | if (!filename) |
476 | return; | 487 | return; |
477 | 488 | ||
489 | if (verbose) | ||
490 | fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n", | ||
491 | __func__, filename, sym->name, | ||
492 | map->unmap_ip(map, sym->start), | ||
493 | map->unmap_ip(map, sym->end)); | ||
494 | |||
478 | if (full_paths) | 495 | if (full_paths) |
479 | d_filename = filename; | 496 | d_filename = filename; |
480 | else | 497 | else |
@@ -483,7 +500,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
483 | len = sym->end - sym->start; | 500 | len = sym->end - sym->start; |
484 | 501 | ||
485 | if (print_line) { | 502 | if (print_line) { |
486 | get_source_line(sym, len, filename); | 503 | get_source_line(he, len, filename); |
487 | print_summary(filename); | 504 | print_summary(filename); |
488 | } | 505 | } |
489 | 506 | ||
@@ -496,7 +513,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
496 | dso, dso->long_name, sym, sym->name); | 513 | dso, dso->long_name, sym, sym->name); |
497 | 514 | ||
498 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", | 515 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", |
499 | sym->start, sym->end, filename, filename); | 516 | map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end), |
517 | filename, filename); | ||
500 | 518 | ||
501 | if (verbose >= 3) | 519 | if (verbose >= 3) |
502 | printf("doing: %s\n", command); | 520 | printf("doing: %s\n", command); |
@@ -506,7 +524,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
506 | return; | 524 | return; |
507 | 525 | ||
508 | while (!feof(file)) { | 526 | while (!feof(file)) { |
509 | if (parse_line(file, sym, len) < 0) | 527 | if (parse_line(file, he, len) < 0) |
510 | break; | 528 | break; |
511 | } | 529 | } |
512 | 530 | ||
@@ -518,18 +536,22 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
518 | static void find_annotations(void) | 536 | static void find_annotations(void) |
519 | { | 537 | { |
520 | struct rb_node *nd; | 538 | struct rb_node *nd; |
521 | struct dso *dso; | ||
522 | int count = 0; | 539 | int count = 0; |
523 | 540 | ||
524 | list_for_each_entry(dso, &dsos, node) { | 541 | for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { |
542 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | ||
525 | 543 | ||
526 | for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) { | 544 | if (he->sym && he->sym->hist) { |
527 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); | 545 | annotate_sym(he); |
546 | count++; | ||
547 | /* | ||
548 | * Since we have a hist_entry per IP for the same | ||
549 | * symbol, free he->sym->hist to signal we already | ||
550 | * processed this symbol. | ||
551 | */ | ||
552 | free(he->sym->hist); | ||
553 | he->sym->hist = NULL; | ||
528 | 554 | ||
529 | if (sym->hist) { | ||
530 | annotate_sym(dso, sym); | ||
531 | count++; | ||
532 | } | ||
533 | } | 555 | } |
534 | } | 556 | } |
535 | 557 | ||