diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-10-20 12:25:40 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-10-20 15:12:58 -0400 |
commit | e42049926ebdcae24fdfdc8f0e3ff8f05f24a60b (patch) | |
tree | be0a07b62070aef5edcd64d84e12e04950220590 /tools/perf/builtin-annotate.c | |
parent | ed52ce2e3c33dc7626a40fa2da766d1a6460e543 (diff) |
perf annotate: Use the sym_priv_size area for the histogram
We have this sym_priv_size mechanism for attaching private areas
to struct symbol entries but annotate wasn't using it, adding
private areas to struct symbol in addition to a ->priv pointer.
Scrap all that and use the sym_priv_size mechanism.
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: <1256055940-19511-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 | 109 |
1 files changed, 79 insertions, 30 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 06f10278b28e..245692530de1 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -37,12 +37,44 @@ static int print_line; | |||
37 | static unsigned long page_size; | 37 | static unsigned long page_size; |
38 | static unsigned long mmap_window = 32; | 38 | static unsigned long mmap_window = 32; |
39 | 39 | ||
40 | struct sym_hist { | ||
41 | u64 sum; | ||
42 | u64 ip[0]; | ||
43 | }; | ||
44 | |||
40 | struct sym_ext { | 45 | struct sym_ext { |
41 | struct rb_node node; | 46 | struct rb_node node; |
42 | double percent; | 47 | double percent; |
43 | char *path; | 48 | char *path; |
44 | }; | 49 | }; |
45 | 50 | ||
51 | struct sym_priv { | ||
52 | struct sym_hist *hist; | ||
53 | struct sym_ext *ext; | ||
54 | }; | ||
55 | |||
56 | static const char *sym_hist_filter; | ||
57 | |||
58 | static int symbol_filter(struct map *map, struct symbol *sym) | ||
59 | { | ||
60 | if (strcmp(sym->name, sym_hist_filter) == 0) { | ||
61 | struct sym_priv *priv = dso__sym_priv(map->dso, sym); | ||
62 | const int size = (sizeof(*priv->hist) + | ||
63 | (sym->end - sym->start) * sizeof(u64)); | ||
64 | |||
65 | priv->hist = malloc(size); | ||
66 | if (priv->hist) | ||
67 | memset(priv->hist, 0, size); | ||
68 | return 0; | ||
69 | } | ||
70 | /* | ||
71 | * FIXME: We should really filter it out, as we don't want to go thru symbols | ||
72 | * we're not interested, and if a DSO ends up with no symbols, delete it too, | ||
73 | * but right now the kernel loading routines in symbol.c bail out if no symbols | ||
74 | * are found, fix it later. | ||
75 | */ | ||
76 | return 0; | ||
77 | } | ||
46 | 78 | ||
47 | /* | 79 | /* |
48 | * collect histogram counts | 80 | * collect histogram counts |
@@ -51,10 +83,16 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
51 | { | 83 | { |
52 | unsigned int sym_size, offset; | 84 | unsigned int sym_size, offset; |
53 | struct symbol *sym = he->sym; | 85 | struct symbol *sym = he->sym; |
86 | struct sym_priv *priv; | ||
87 | struct sym_hist *h; | ||
54 | 88 | ||
55 | he->count++; | 89 | he->count++; |
56 | 90 | ||
57 | if (!sym || !sym->hist) | 91 | if (!sym || !he->map) |
92 | return; | ||
93 | |||
94 | priv = dso__sym_priv(he->map->dso, sym); | ||
95 | if (!priv->hist) | ||
58 | return; | 96 | return; |
59 | 97 | ||
60 | sym_size = sym->end - sym->start; | 98 | sym_size = sym->end - sym->start; |
@@ -67,15 +105,16 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
67 | if (offset >= sym_size) | 105 | if (offset >= sym_size) |
68 | return; | 106 | return; |
69 | 107 | ||
70 | sym->hist_sum++; | 108 | h = priv->hist; |
71 | sym->hist[offset]++; | 109 | h->sum++; |
110 | h->ip[offset]++; | ||
72 | 111 | ||
73 | if (verbose >= 3) | 112 | if (verbose >= 3) |
74 | printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", | 113 | printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", |
75 | (void *)(unsigned long)he->sym->start, | 114 | (void *)(unsigned long)he->sym->start, |
76 | he->sym->name, | 115 | he->sym->name, |
77 | (void *)(unsigned long)ip, ip - he->sym->start, | 116 | (void *)(unsigned long)ip, ip - he->sym->start, |
78 | sym->hist[offset]); | 117 | h->ip[offset]); |
79 | } | 118 | } |
80 | 119 | ||
81 | static int hist_entry__add(struct thread *thread, struct map *map, | 120 | static int hist_entry__add(struct thread *thread, struct map *map, |
@@ -162,7 +201,9 @@ got_map: | |||
162 | static int | 201 | static int |
163 | process_mmap_event(event_t *event, unsigned long offset, unsigned long head) | 202 | process_mmap_event(event_t *event, unsigned long offset, unsigned long head) |
164 | { | 203 | { |
165 | struct map *map = map__new(&event->mmap, NULL, 0); | 204 | struct map *map = map__new(&event->mmap, NULL, 0, |
205 | sizeof(struct sym_priv), symbol_filter, | ||
206 | verbose); | ||
166 | struct thread *thread = threads__findnew(event->mmap.pid); | 207 | struct thread *thread = threads__findnew(event->mmap.pid); |
167 | 208 | ||
168 | dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n", | 209 | dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n", |
@@ -314,17 +355,19 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
314 | unsigned int hits = 0; | 355 | unsigned int hits = 0; |
315 | double percent = 0.0; | 356 | double percent = 0.0; |
316 | const char *color; | 357 | const char *color; |
317 | struct sym_ext *sym_ext = sym->priv; | 358 | struct sym_priv *priv = dso__sym_priv(he->map->dso, sym); |
359 | struct sym_ext *sym_ext = priv->ext; | ||
360 | struct sym_hist *h = priv->hist; | ||
318 | 361 | ||
319 | offset = line_ip - start; | 362 | offset = line_ip - start; |
320 | if (offset < len) | 363 | if (offset < len) |
321 | hits = sym->hist[offset]; | 364 | hits = h->ip[offset]; |
322 | 365 | ||
323 | if (offset < len && sym_ext) { | 366 | if (offset < len && sym_ext) { |
324 | path = sym_ext[offset].path; | 367 | path = sym_ext[offset].path; |
325 | percent = sym_ext[offset].percent; | 368 | percent = sym_ext[offset].percent; |
326 | } else if (sym->hist_sum) | 369 | } else if (h->sum) |
327 | percent = 100.0 * hits / sym->hist_sum; | 370 | percent = 100.0 * hits / h->sum; |
328 | 371 | ||
329 | color = get_percent_color(percent); | 372 | color = get_percent_color(percent); |
330 | 373 | ||
@@ -377,9 +420,10 @@ static void insert_source_line(struct sym_ext *sym_ext) | |||
377 | rb_insert_color(&sym_ext->node, &root_sym_ext); | 420 | rb_insert_color(&sym_ext->node, &root_sym_ext); |
378 | } | 421 | } |
379 | 422 | ||
380 | static void free_source_line(struct symbol *sym, int len) | 423 | static void free_source_line(struct hist_entry *he, int len) |
381 | { | 424 | { |
382 | struct sym_ext *sym_ext = sym->priv; | 425 | struct sym_priv *priv = dso__sym_priv(he->map->dso, he->sym); |
426 | struct sym_ext *sym_ext = priv->ext; | ||
383 | int i; | 427 | int i; |
384 | 428 | ||
385 | if (!sym_ext) | 429 | if (!sym_ext) |
@@ -389,7 +433,7 @@ static void free_source_line(struct symbol *sym, int len) | |||
389 | free(sym_ext[i].path); | 433 | free(sym_ext[i].path); |
390 | free(sym_ext); | 434 | free(sym_ext); |
391 | 435 | ||
392 | sym->priv = NULL; | 436 | priv->ext = NULL; |
393 | root_sym_ext = RB_ROOT; | 437 | root_sym_ext = RB_ROOT; |
394 | } | 438 | } |
395 | 439 | ||
@@ -402,15 +446,16 @@ get_source_line(struct hist_entry *he, int len, const char *filename) | |||
402 | int i; | 446 | int i; |
403 | char cmd[PATH_MAX * 2]; | 447 | char cmd[PATH_MAX * 2]; |
404 | struct sym_ext *sym_ext; | 448 | struct sym_ext *sym_ext; |
449 | struct sym_priv *priv = dso__sym_priv(he->map->dso, sym); | ||
450 | struct sym_hist *h = priv->hist; | ||
405 | 451 | ||
406 | if (!sym->hist_sum) | 452 | if (!h->sum) |
407 | return; | 453 | return; |
408 | 454 | ||
409 | sym->priv = calloc(len, sizeof(struct sym_ext)); | 455 | sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext)); |
410 | if (!sym->priv) | 456 | if (!priv->ext) |
411 | return; | 457 | return; |
412 | 458 | ||
413 | sym_ext = sym->priv; | ||
414 | start = he->map->unmap_ip(he->map, sym->start); | 459 | start = he->map->unmap_ip(he->map, sym->start); |
415 | 460 | ||
416 | for (i = 0; i < len; i++) { | 461 | for (i = 0; i < len; i++) { |
@@ -419,7 +464,7 @@ get_source_line(struct hist_entry *he, int len, const char *filename) | |||
419 | u64 offset; | 464 | u64 offset; |
420 | FILE *fp; | 465 | FILE *fp; |
421 | 466 | ||
422 | sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; | 467 | sym_ext[i].percent = 100.0 * h->ip[i] / h->sum; |
423 | if (sym_ext[i].percent <= 0.5) | 468 | if (sym_ext[i].percent <= 0.5) |
424 | continue; | 469 | continue; |
425 | 470 | ||
@@ -530,7 +575,7 @@ static void annotate_sym(struct hist_entry *he) | |||
530 | 575 | ||
531 | pclose(file); | 576 | pclose(file); |
532 | if (print_line) | 577 | if (print_line) |
533 | free_source_line(sym, len); | 578 | free_source_line(he, len); |
534 | } | 579 | } |
535 | 580 | ||
536 | static void find_annotations(void) | 581 | static void find_annotations(void) |
@@ -540,19 +585,23 @@ static void find_annotations(void) | |||
540 | 585 | ||
541 | for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { | 586 | for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { |
542 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | 587 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); |
588 | struct sym_priv *priv; | ||
543 | 589 | ||
544 | if (he->sym && he->sym->hist) { | 590 | if (he->sym == NULL) |
545 | annotate_sym(he); | 591 | continue; |
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; | ||
554 | 592 | ||
555 | } | 593 | priv = dso__sym_priv(he->map->dso, he->sym); |
594 | if (priv->hist == NULL) | ||
595 | continue; | ||
596 | |||
597 | annotate_sym(he); | ||
598 | count++; | ||
599 | /* | ||
600 | * Since we have a hist_entry per IP for the same symbol, free | ||
601 | * he->sym->hist to signal we already processed this symbol. | ||
602 | */ | ||
603 | free(priv->hist); | ||
604 | priv->hist = NULL; | ||
556 | } | 605 | } |
557 | 606 | ||
558 | if (!count) | 607 | if (!count) |
@@ -593,7 +642,7 @@ static int __cmd_annotate(void) | |||
593 | exit(0); | 642 | exit(0); |
594 | } | 643 | } |
595 | 644 | ||
596 | if (load_kernel() < 0) { | 645 | if (load_kernel(sizeof(struct sym_priv), symbol_filter) < 0) { |
597 | perror("failed to load kernel symbols"); | 646 | perror("failed to load kernel symbols"); |
598 | return EXIT_FAILURE; | 647 | return EXIT_FAILURE; |
599 | } | 648 | } |