diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-05-26 16:19:04 -0300 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-26 21:26:30 +0200 |
commit | 3a4b8cc70b7473a0b9f26f5b4ddc6579b5e214be (patch) | |
tree | 6d7ece70ac2ce733673fd74c80c6a32bd8782717 | |
parent | 6142f9ec108a4ddbf0d5904c3daa5fdcaa618792 (diff) |
perf report: Sort output by symbol usage
[acme@emilia ~]$ perf record find / > /dev/null 2>&1
[acme@emilia ~]$ perf stat perf report | head -20
4.95 find [k] 0xffffffff81393d65 _spin_lock
3.89 find [.] 0x000000000000af89 /usr/bin/find: <unknown>
2.19 find [k] 0xffffffffa00518e0 ext3fs_dirhash
1.87 find [k] 0xffffffff810a6cea __rcu_read_lock
1.86 find [k] 0xffffffff811c7312 _atomic_dec_and_lock
1.86 find [.] 0x00000000000782ab /lib64/libc-2.5.so: __GI_strlen
1.85 find [k] 0xffffffff810fedfb __kmalloc
1.62 find [.] 0x00000000000430ff /lib64/libc-2.5.so: vfprintf
1.59 find [k] 0xffffffff810a6d6d __rcu_read_unlock
1.55 find [k] 0xffffffff81119395 __d_lookup
1.39 find [.] 0x0000000000071b40 /lib64/libc-2.5.so: _int_malloc
1.30 find [k] 0xffffffffa031c4fc nfs_do_filldir
1.21 find [k] 0xffffffff811876a5 avc_has_perm_noaudit
1.15 find [k] 0xffffffff810fef62 kmem_cache_alloc
1.07 find [k] 0xffffffff811d03fb copy_user_generic_string
1.03 find [k] 0xffffffffa0043882 ext3_htree_store_dirent
0.99 find [k] 0xffffffff81393ebb _spin_lock_bh
0.98 find [k] 0xffffffffa03319a2 nfs3_decode_dirent
0.97 find [k] 0xffffffff8100bf20 system_call
0.92 find [k] 0xffffffff8139437e _spin_unlock
Performance counter stats for 'perf':
244.278972 task clock ticks (msecs)
8 context switches (events)
9 CPU migrations (events)
2104 pagefaults (events)
35329669 CPU cycles (events) (scaled from 75.40%)
13740366 instructions (events) (scaled from 75.49%)
59073 cache references (events) (scaled from 24.60%)
196 cache misses (events) (scaled from 24.51%)
Wall-clock time elapsed: 246.060717 msecs
[acme@emilia ~]$
[acme@emilia ~]$ grep "model name" /proc/cpuinfo | head -1
model name : Intel(R) Xeon(R) CPU E5405 @ 2.00GHz
[acme@emilia ~]$ grep "model name" /proc/cpuinfo | wc -l
8
[acme@emilia ~]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20090526191904.GH4424@ghostprotocols.net>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | Documentation/perf_counter/builtin-report.c | 129 |
1 files changed, 99 insertions, 30 deletions
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c index a58be7fee42..a4c6ffa9650 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: "<unknown>"); + ret += fprintf(fp, "%s\n", + self->sym ? self->sym->name : "<unknown>"); else - ret += fprintf(fp, "%s: %s", + ret += fprintf(fp, "%s: %s\n", self->dso ? self->dso->name : "<unknown>", self->sym ? self->sym->name : "<unknown>"); - 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 @@ done: return 0; } - //dsos__fprintf(stdout); - threads__fprintf(stdout); -#if 0 - std::map<std::string, int>::iterator hi = hist.begin(); - - while (hi != hist.end()) { - rev_hist.insert(std::pair<int, std::string>(hi->second, hi->first)); - hist.erase(hi++); - } - - std::multimap<int, std::string>::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; } |