diff options
| -rw-r--r-- | tools/perf/builtin-annotate.c | 50 | ||||
| -rw-r--r-- | tools/perf/builtin-report.c | 63 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 46 | ||||
| -rw-r--r-- | tools/perf/util/hist.h | 3 |
4 files changed, 74 insertions, 88 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 7d5a3b1bcda9..855094234f2d 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -80,48 +80,16 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
| 80 | sym->hist[offset]); | 80 | sym->hist[offset]); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | static int | 83 | static int hist_entry__add(struct thread *thread, struct map *map, |
| 84 | hist_entry__add(struct thread *thread, struct map *map, | 84 | struct symbol *sym, u64 ip, u64 count, char level) |
| 85 | struct symbol *sym, u64 ip, char level) | ||
| 86 | { | 85 | { |
| 87 | struct rb_node **p = &hist.rb_node; | 86 | bool hit; |
| 88 | struct rb_node *parent = NULL; | 87 | struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip, |
| 89 | struct hist_entry *he; | 88 | count, level, &hit); |
| 90 | struct hist_entry entry = { | 89 | if (he == NULL) |
| 91 | .thread = thread, | ||
| 92 | .map = map, | ||
| 93 | .sym = sym, | ||
| 94 | .ip = ip, | ||
| 95 | .level = level, | ||
| 96 | .count = 1, | ||
| 97 | }; | ||
| 98 | int cmp; | ||
| 99 | |||
| 100 | while (*p != NULL) { | ||
| 101 | parent = *p; | ||
| 102 | he = rb_entry(parent, struct hist_entry, rb_node); | ||
| 103 | |||
| 104 | cmp = hist_entry__cmp(&entry, he); | ||
| 105 | |||
| 106 | if (!cmp) { | ||
| 107 | hist_hit(he, ip); | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | if (cmp < 0) | ||
| 113 | p = &(*p)->rb_left; | ||
| 114 | else | ||
| 115 | p = &(*p)->rb_right; | ||
| 116 | } | ||
| 117 | |||
| 118 | he = malloc(sizeof(*he)); | ||
| 119 | if (!he) | ||
| 120 | return -ENOMEM; | 90 | return -ENOMEM; |
| 121 | *he = entry; | 91 | if (hit) |
| 122 | rb_link_node(&he->rb_node, parent, p); | 92 | hist_hit(he, ip); |
| 123 | rb_insert_color(&he->rb_node, &hist); | ||
| 124 | |||
| 125 | return 0; | 93 | return 0; |
| 126 | } | 94 | } |
| 127 | 95 | ||
| @@ -191,7 +159,7 @@ got_map: | |||
| 191 | } | 159 | } |
| 192 | 160 | ||
| 193 | if (show & show_mask) { | 161 | if (show & show_mask) { |
| 194 | if (hist_entry__add(thread, map, sym, ip, level)) { | 162 | if (hist_entry__add(thread, map, sym, ip, 1, level)) { |
| 195 | fprintf(stderr, | 163 | fprintf(stderr, |
| 196 | "problem incrementing symbol count, skipping event\n"); | 164 | "problem incrementing symbol count, skipping event\n"); |
| 197 | return -1; | 165 | return -1; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3ed3baf96ffb..0e83ffcbe55a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -407,9 +407,9 @@ static int call__match(struct symbol *sym) | |||
| 407 | return 0; | 407 | return 0; |
| 408 | } | 408 | } |
| 409 | 409 | ||
| 410 | static struct symbol ** | 410 | static struct symbol **resolve_callchain(struct thread *thread, struct map *map, |
| 411 | resolve_callchain(struct thread *thread, struct map *map, | 411 | struct ip_callchain *chain, |
| 412 | struct ip_callchain *chain, struct hist_entry *entry) | 412 | struct symbol **parent) |
| 413 | { | 413 | { |
| 414 | u64 context = PERF_CONTEXT_MAX; | 414 | u64 context = PERF_CONTEXT_MAX; |
| 415 | struct symbol **syms = NULL; | 415 | struct symbol **syms = NULL; |
| @@ -444,9 +444,8 @@ resolve_callchain(struct thread *thread, struct map *map, | |||
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | if (sym) { | 446 | if (sym) { |
| 447 | if (sort__has_parent && call__match(sym) && | 447 | if (sort__has_parent && !*parent && call__match(sym)) |
| 448 | !entry->parent) | 448 | *parent = sym; |
| 449 | entry->parent = sym; | ||
| 450 | if (!callchain) | 449 | if (!callchain) |
| 451 | break; | 450 | break; |
| 452 | syms[i] = sym; | 451 | syms[i] = sym; |
| @@ -465,57 +464,27 @@ hist_entry__add(struct thread *thread, struct map *map, | |||
| 465 | struct symbol *sym, u64 ip, struct ip_callchain *chain, | 464 | struct symbol *sym, u64 ip, struct ip_callchain *chain, |
| 466 | char level, u64 count) | 465 | char level, u64 count) |
| 467 | { | 466 | { |
| 468 | struct rb_node **p = &hist.rb_node; | 467 | struct symbol **syms = NULL, *parent = NULL; |
| 469 | struct rb_node *parent = NULL; | 468 | bool hit; |
| 470 | struct hist_entry *he; | 469 | struct hist_entry *he; |
| 471 | struct symbol **syms = NULL; | ||
| 472 | struct hist_entry entry = { | ||
| 473 | .thread = thread, | ||
| 474 | .map = map, | ||
| 475 | .sym = sym, | ||
| 476 | .ip = ip, | ||
| 477 | .level = level, | ||
| 478 | .count = count, | ||
| 479 | .parent = NULL, | ||
| 480 | .sorted_chain = RB_ROOT | ||
| 481 | }; | ||
| 482 | int cmp; | ||
| 483 | 470 | ||
| 484 | if ((sort__has_parent || callchain) && chain) | 471 | if ((sort__has_parent || callchain) && chain) |
| 485 | syms = resolve_callchain(thread, map, chain, &entry); | 472 | syms = resolve_callchain(thread, map, chain, &parent); |
| 486 | |||
| 487 | while (*p != NULL) { | ||
| 488 | parent = *p; | ||
| 489 | he = rb_entry(parent, struct hist_entry, rb_node); | ||
| 490 | |||
| 491 | cmp = hist_entry__cmp(&entry, he); | ||
| 492 | 473 | ||
| 493 | if (!cmp) { | 474 | he = __hist_entry__add(thread, map, sym, parent, |
| 494 | he->count += count; | 475 | ip, count, level, &hit); |
| 495 | if (callchain) { | 476 | if (he == NULL) |
| 496 | append_chain(&he->callchain, chain, syms); | 477 | return -ENOMEM; |
| 497 | free(syms); | ||
| 498 | } | ||
| 499 | return 0; | ||
| 500 | } | ||
| 501 | 478 | ||
| 502 | if (cmp < 0) | 479 | if (hit) |
| 503 | p = &(*p)->rb_left; | 480 | he->count += count; |
| 504 | else | ||
| 505 | p = &(*p)->rb_right; | ||
| 506 | } | ||
| 507 | 481 | ||
| 508 | he = malloc(sizeof(*he)); | ||
| 509 | if (!he) | ||
| 510 | return -ENOMEM; | ||
| 511 | *he = entry; | ||
| 512 | if (callchain) { | 482 | if (callchain) { |
| 513 | callchain_init(&he->callchain); | 483 | if (!hit) |
| 484 | callchain_init(&he->callchain); | ||
| 514 | append_chain(&he->callchain, chain, syms); | 485 | append_chain(&he->callchain, chain, syms); |
| 515 | free(syms); | 486 | free(syms); |
| 516 | } | 487 | } |
| 517 | rb_link_node(&he->rb_node, parent, p); | ||
| 518 | rb_insert_color(&he->rb_node, &hist); | ||
| 519 | 488 | ||
| 520 | return 0; | 489 | return 0; |
| 521 | } | 490 | } |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 82808dc4f8e3..7393a02fd8d4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -21,6 +21,52 @@ unsigned long total_lost; | |||
| 21 | * histogram, sorted on item, collects counts | 21 | * histogram, sorted on item, collects counts |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, | ||
| 25 | struct symbol *sym, | ||
| 26 | struct symbol *sym_parent, | ||
| 27 | u64 ip, u64 count, char level, bool *hit) | ||
| 28 | { | ||
| 29 | struct rb_node **p = &hist.rb_node; | ||
| 30 | struct rb_node *parent = NULL; | ||
| 31 | struct hist_entry *he; | ||
| 32 | struct hist_entry entry = { | ||
| 33 | .thread = thread, | ||
| 34 | .map = map, | ||
| 35 | .sym = sym, | ||
| 36 | .ip = ip, | ||
| 37 | .level = level, | ||
| 38 | .count = count, | ||
| 39 | .parent = sym_parent, | ||
| 40 | }; | ||
| 41 | int cmp; | ||
| 42 | |||
| 43 | while (*p != NULL) { | ||
| 44 | parent = *p; | ||
| 45 | he = rb_entry(parent, struct hist_entry, rb_node); | ||
| 46 | |||
| 47 | cmp = hist_entry__cmp(&entry, he); | ||
| 48 | |||
| 49 | if (!cmp) { | ||
| 50 | *hit = true; | ||
| 51 | return he; | ||
| 52 | } | ||
| 53 | |||
| 54 | if (cmp < 0) | ||
| 55 | p = &(*p)->rb_left; | ||
| 56 | else | ||
| 57 | p = &(*p)->rb_right; | ||
| 58 | } | ||
| 59 | |||
| 60 | he = malloc(sizeof(*he)); | ||
| 61 | if (!he) | ||
| 62 | return NULL; | ||
| 63 | *he = entry; | ||
| 64 | rb_link_node(&he->rb_node, parent, p); | ||
| 65 | rb_insert_color(&he->rb_node, &hist); | ||
| 66 | *hit = false; | ||
| 67 | return he; | ||
| 68 | } | ||
| 69 | |||
| 24 | int64_t | 70 | int64_t |
| 25 | hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) | 71 | hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) |
| 26 | { | 72 | { |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 9a8daa12b43a..ac2149c559b0 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -36,6 +36,9 @@ extern unsigned long total_fork; | |||
| 36 | extern unsigned long total_unknown; | 36 | extern unsigned long total_unknown; |
| 37 | extern unsigned long total_lost; | 37 | extern unsigned long total_lost; |
| 38 | 38 | ||
| 39 | struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, | ||
| 40 | struct symbol *sym, struct symbol *parent, | ||
| 41 | u64 ip, u64 count, char level, bool *hit); | ||
| 39 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); | 42 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); |
| 40 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); | 43 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); |
| 41 | extern void hist_entry__free(struct hist_entry *); | 44 | extern void hist_entry__free(struct hist_entry *); |
