perf report: Print sorted callchains per histogram entries
authorFrederic Weisbecker <fweisbec@gmail.com>
Fri, 26 Jun 2009 14:28:01 +0000 (16:28 +0200)
committerIngo Molnar <mingo@elte.hu>
Fri, 26 Jun 2009 14:47:01 +0000 (16:47 +0200)
Use the newly created callchains radix tree to gather the chains stats
from the recorded events and then print the callchains for all of them,
sorted by hits, using the "-c" parameter with perf report.

Example:

 66.15%  [k] atm_clip_exit
            63.08%
                0xffffffffffffff80
                0xffffffff810196a8
                0xffffffff810c14c8
                0xffffffff8101a79c
                0xffffffff810194f3
                0xffffffff8106ab7f
                0xffffffff8106abe5
                0xffffffff8106acde
                0xffffffff8100d94b
                0xffffffff8153e7ea
                [...]

             1.54%
                0xffffffffffffff80
                0xffffffff810196a8
                0xffffffff810c14c8
                0xffffffff8101a79c
[...]

Symbols are not yet resolved.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1246026481-8314-3-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
tools/perf/builtin-report.c

index 28d1cb2127e9ed3cd48ceeb3de56c19cb9e1ddf7..ed391db9e0f8d78034c1ada0713f42f91e89a785 100644 (file)
@@ -15,6 +15,7 @@
 #include "util/rbtree.h"
 #include "util/symbol.h"
 #include "util/string.h"
+#include "util/callchain.h"
 
 #include "perf.h"
 #include "util/header.h"
@@ -52,6 +53,7 @@ static char           *parent_pattern = default_parent_pattern;
 static regex_t         parent_regex;
 
 static int             exclude_other = 1;
+static int             callchain;
 
 static u64             sample_type;
 
@@ -488,17 +490,19 @@ static size_t threads__fprintf(FILE *fp)
 static struct rb_root hist;
 
 struct hist_entry {
-       struct rb_node   rb_node;
-
-       struct thread    *thread;
-       struct map       *map;
-       struct dso       *dso;
-       struct symbol    *sym;
-       struct symbol    *parent;
-       u64              ip;
-       char             level;
-
-       u64              count;
+       struct rb_node          rb_node;
+
+       struct thread           *thread;
+       struct map              *map;
+       struct dso              *dso;
+       struct symbol           *sym;
+       struct symbol           *parent;
+       u64                     ip;
+       char                    level;
+       struct callchain_node   callchain;
+       struct rb_root          sorted_chain;
+
+       u64                     count;
 };
 
 /*
@@ -768,6 +772,48 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
        return cmp;
 }
 
+static size_t
+callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
+{
+       struct callchain_list *chain;
+       size_t ret = 0;
+
+       if (!self)
+               return 0;
+
+       ret += callchain__fprintf(fp, self->parent, total_samples);
+
+
+       list_for_each_entry(chain, &self->val, list)
+               ret += fprintf(fp, "                %p\n", (void *)chain->ip);
+
+       return ret;
+}
+
+static size_t
+hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
+                             u64 total_samples)
+{
+       struct rb_node *rb_node;
+       struct callchain_node *chain;
+       size_t ret = 0;
+
+       rb_node = rb_first(&self->sorted_chain);
+       while (rb_node) {
+               double percent;
+
+               chain = rb_entry(rb_node, struct callchain_node, rb_node);
+               percent = chain->hit * 100.0 / total_samples;
+               ret += fprintf(fp, "           %6.2f%%\n", percent);
+               ret += callchain__fprintf(fp, chain, total_samples);
+               ret += fprintf(fp, "\n");
+               rb_node = rb_next(rb_node);
+       }
+
+       return ret;
+}
+
+
 static size_t
 hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 {
@@ -808,6 +854,9 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 
        ret += fprintf(fp, "\n");
 
+       if (callchain)
+               hist_entry_callchain__fprintf(fp, self, total_samples);
+
        return ret;
 }
 
@@ -892,6 +941,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
                .level  = level,
                .count  = count,
                .parent = NULL,
+               .sorted_chain = RB_ROOT
        };
        int cmp;
 
@@ -934,6 +984,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
 
                if (!cmp) {
                        he->count += count;
+                       if (callchain)
+                               append_chain(&he->callchain, chain);
                        return 0;
                }
 
@@ -947,6 +999,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
        if (!he)
                return -ENOMEM;
        *he = entry;
+       if (callchain) {
+               callchain_init(&he->callchain);
+               append_chain(&he->callchain, chain);
+       }
        rb_link_node(&he->rb_node, parent, p);
        rb_insert_color(&he->rb_node, &hist);
 
@@ -1023,6 +1079,9 @@ static void output__insert_entry(struct hist_entry *he)
        struct rb_node *parent = NULL;
        struct hist_entry *iter;
 
+       if (callchain)
+               sort_chain_to_rbtree(&he->sorted_chain, &he->callchain);
+
        while (*p != NULL) {
                parent = *p;
                iter = rb_entry(parent, struct hist_entry, rb_node);
@@ -1599,6 +1658,7 @@ static const struct option options[] = {
                   "regex filter to identify parent, see: '--sort parent'"),
        OPT_BOOLEAN('x', "exclude-other", &exclude_other,
                    "Only display entries with parent-match"),
+       OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"),
        OPT_END()
 };