diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c index a58be7fee4256f753d8a022c2fae92fde74ef57d..a4c6ffa96505e688f20cadf50e075d1155756698 100644 --- a/Documentation/perf_counter/builtin-report.c +++ b/Documentation/perf_counter/builtin-report.c @@ -447,26 +447,33 @@ static size_t map__fprintf(struct map *self, FILE *fp) self->start, self->end, self->pgoff, self->dso->name); } +struct thread; + +static const char *thread__name(struct thread *self, char *bf, size_t size); + struct symhist { struct rb_node rb_node; struct dso *dso; struct symbol *sym; + struct thread *thread; uint64_t ip; uint32_t count; char level; }; static struct symhist *symhist__new(struct symbol *sym, uint64_t ip, - struct dso *dso, char level) + struct thread *thread, struct dso *dso, + char level) { struct symhist *self = malloc(sizeof(*self)); if (self != NULL) { - self->sym = sym; - self->ip = ip; - self->dso = dso; - self->level = level; - self->count = 1; + self->sym = sym; + self->thread = thread; + self->ip = ip; + self->dso = dso; + self->level = level; + self->count = 1; } return self; @@ -482,17 +489,29 @@ static void symhist__inc(struct symhist *self) ++self->count; } -static size_t symhist__fprintf(struct symhist *self, FILE *fp) +static size_t +symhist__fprintf(struct symhist *self, uint64_t total_samples, FILE *fp) { - size_t ret = fprintf(fp, "%#llx [%c] ", (unsigned long long)self->ip, self->level); + char bf[32]; + size_t ret; + + if (total_samples) + ret = fprintf(fp, "%5.2f", (self->count * 100.0) / total_samples); + else + ret = fprintf(fp, "%12d", self->count); + + ret += fprintf(fp, "%14s [%c] %#018llx ", + thread__name(self->thread, bf, sizeof(bf)), + self->level, (unsigned long long)self->ip); if (self->level != '.') - ret += fprintf(fp, "%s", self->sym ? self->sym->name: ""); + ret += fprintf(fp, "%s\n", + self->sym ? self->sym->name : ""); else - ret += fprintf(fp, "%s: %s", + ret += fprintf(fp, "%s: %s\n", self->dso ? self->dso->name : "", self->sym ? self->sym->name : ""); - return ret + fprintf(fp, ": %u\n", self->count); + return ret; } struct thread { @@ -503,6 +522,15 @@ struct thread { char *comm; }; +static const char *thread__name(struct thread *self, char *bf, size_t size) +{ + if (self->comm) + return self->comm; + + snprintf(bf, sizeof(bf), ":%u", self->pid); + return bf; +} + static struct thread *thread__new(pid_t pid) { struct thread *self = malloc(sizeof(*self)); @@ -542,7 +570,7 @@ static int thread__symbol_incnew(struct thread *self, struct symbol *sym, p = &(*p)->rb_right; } - sh = symhist__new(sym, ip, dso, level); + sh = symhist__new(sym, ip, self, dso, level); if (sh == NULL) return -ENOMEM; rb_link_node(&sh->rb_node, parent, p); @@ -574,7 +602,7 @@ static size_t thread__fprintf(struct thread *self, FILE *fp) for (nd = rb_first(&self->symhists); nd; nd = rb_next(nd)) { struct symhist *pos = rb_entry(nd, struct symhist, rb_node); - ret += symhist__fprintf(pos, fp); + ret += symhist__fprintf(pos, 0, fp); } return ret; @@ -628,7 +656,7 @@ static struct map *thread__find_map(struct thread *self, uint64_t ip) return NULL; } -static void threads__fprintf(FILE *fp) +void threads__fprintf(FILE *fp) { struct rb_node *nd; for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { @@ -637,6 +665,61 @@ static void threads__fprintf(FILE *fp) } } +static struct rb_root global_symhists = RB_ROOT; + +static void threads__insert_symhist(struct symhist *sh) +{ + struct rb_node **p = &global_symhists.rb_node; + struct rb_node *parent = NULL; + struct symhist *iter; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct symhist, rb_node); + + /* Reverse order */ + if (sh->count > iter->count) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&sh->rb_node, parent, p); + rb_insert_color(&sh->rb_node, &global_symhists); +} + +static void threads__sort_symhists(void) +{ + struct rb_node *nd; + + for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { + struct thread *thread = rb_entry(nd, struct thread, rb_node); + struct rb_node *next = rb_first(&thread->symhists); + + while (next) { + struct symhist *n = rb_entry(next, struct symhist, + rb_node); + next = rb_next(&n->rb_node); + rb_erase(&n->rb_node, &thread->symhists); + threads__insert_symhist(n); + } + + } +} + +static size_t threads__symhists_fprintf(uint64_t total_samples, FILE *fp) +{ + struct rb_node *nd; + size_t ret = 0; + + for (nd = rb_first(&global_symhists); nd; nd = rb_next(nd)) { + struct symhist *pos = rb_entry(nd, struct symhist, rb_node); + ret += symhist__fprintf(pos, total_samples, fp); + } + + return ret; +} + static int __cmd_report(void) { unsigned long offset = 0; @@ -826,23 +909,9 @@ static int __cmd_report(void) return 0; } - //dsos__fprintf(stdout); - threads__fprintf(stdout); -#if 0 - std::map::iterator hi = hist.begin(); - - while (hi != hist.end()) { - rev_hist.insert(std::pair(hi->second, hi->first)); - hist.erase(hi++); - } - - std::multimap::const_iterator ri = rev_hist.begin(); + threads__sort_symhists(); + threads__symhists_fprintf(total, stdout); - while (ri != rev_hist.end()) { - printf(" %5.2f %s\n", (100.0 * ri->first)/total, ri->second.c_str()); - ri++; - } -#endif return rc; }