perf tools: Add inverted call graph report support.
authorSam Liao <phyomh@gmail.com>
Tue, 7 Jun 2011 15:49:46 +0000 (23:49 +0800)
committerFrederic Weisbecker <fweisbec@gmail.com>
Wed, 29 Jun 2011 22:24:30 +0000 (00:24 +0200)
Add "caller/callee" option to support inverted butterfly report,
in the inverted report (with caller option), the call graph start
from the callee's ancestor. Users can use such view to catch system's
performance bottleneck from a sysprof like view. Using this option
with specified sort order like pid gives us high level view of call
graph statistics.

Also add "-G" alias for inverted call graph.

Signed-off-by: Sam Liao <phyomh@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
tools/perf/Documentation/perf-report.txt
tools/perf/builtin-report.c
tools/perf/util/callchain.h
tools/perf/util/hist.c
tools/perf/util/session.c

index 8ba03d6e5398d8387b11f9caf183bed81a0eb5a2..cfa8e513d0fb2fda8a123bba4451dc3d90e46754 100644 (file)
@@ -80,15 +80,24 @@ OPTIONS
 --dump-raw-trace::
         Dump raw trace in ASCII.
 
--g [type,min]::
+-g [type,min,order]::
 --call-graph::
-        Display call chains using type and min percent threshold.
+        Display call chains using type, min percent threshold and order.
        type can be either:
        - flat: single column, linear exposure of call chains.
        - graph: use a graph tree, displaying absolute overhead rates.
        - fractal: like graph, but displays relative rates. Each branch of
                 the tree is considered as a new profiled object. +
-       Default: fractal,0.5.
+
+       order can be either:
+       - callee: callee based call graph.
+       - caller: inverted caller based call graph.
+
+       Default: fractal,0.5,callee.
+
+-G::
+--inverted::
+        alias for inverted caller based call graph.
 
 --pretty=<key>::
         Pretty printing style.  key: normal, raw
index 287a173523a7fa4d39c0c6635cbbaf94a0ac181a..271e252dc651961823a4a8b76aa489ff984e7801 100644 (file)
@@ -45,7 +45,8 @@ static struct perf_read_values        show_threads_values;
 static const char      default_pretty_printing_style[] = "normal";
 static const char      *pretty_printing_style = default_pretty_printing_style;
 
-static char            callchain_default_opt[] = "fractal,0.5";
+static char            callchain_default_opt[] = "fractal,0.5,callee";
+static bool            inverted_callchain;
 static symbol_filter_t annotate_init;
 
 static int perf_session__add_hist_entry(struct perf_session *session,
@@ -386,13 +387,29 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
        if (!tok)
                goto setup;
 
-       tok2 = strtok(NULL, ",");
        callchain_param.min_percent = strtod(tok, &endptr);
        if (tok == endptr)
                return -1;
 
-       if (tok2)
+       /* get the print limit */
+       tok2 = strtok(NULL, ",");
+       if (!tok2)
+               goto setup;
+
+       if (tok2[0] != 'c') {
                callchain_param.print_limit = strtod(tok2, &endptr);
+               tok2 = strtok(NULL, ",");
+               if (!tok2)
+                       goto setup;
+       }
+
+       /* get the call chain order */
+       if (!strcmp(tok2, "caller"))
+               callchain_param.order = ORDER_CALLER;
+       else if (!strcmp(tok2, "callee"))
+               callchain_param.order = ORDER_CALLEE;
+       else
+               return -1;
 setup:
        if (callchain_register_param(&callchain_param) < 0) {
                fprintf(stderr, "Can't register callchain params\n");
@@ -436,9 +453,10 @@ static const struct option options[] = {
                   "regex filter to identify parent, see: '--sort parent'"),
        OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
                    "Only display entries with parent-match"),
-       OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
-                    "Display callchains using output_type (graph, flat, fractal, or none) and min percent threshold. "
-                    "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
+       OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order",
+                    "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. "
+                    "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
+       OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"),
        OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
                   "only consider symbols in these dsos"),
        OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -467,6 +485,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
        else if (use_tui)
                use_browser = 1;
 
+       if (inverted_callchain)
+               callchain_param.order = ORDER_CALLER;
+
        if (strcmp(input_name, "-") != 0)
                setup_browser(true);
        else
index 1a79df9f739f8425ce2991dcc0cc7a2eeac982dc..9b4ff16cac96dd924ec37c7fb4ab3226ded1f377 100644 (file)
@@ -14,6 +14,11 @@ enum chain_mode {
        CHAIN_GRAPH_REL
 };
 
+enum chain_order {
+       ORDER_CALLER,
+       ORDER_CALLEE
+};
+
 struct callchain_node {
        struct callchain_node   *parent;
        struct list_head        siblings;
@@ -41,6 +46,7 @@ struct callchain_param {
        u32                     print_limit;
        double                  min_percent;
        sort_chain_func_t       sort;
+       enum chain_order        order;
 };
 
 struct callchain_list {
index 627a02e03c57ab381d97cf2be9756997851d752d..dae4202fa65ae7bcfc6ae600c09dcf849611e316 100644 (file)
@@ -14,7 +14,8 @@ enum hist_filter {
 
 struct callchain_param callchain_param = {
        .mode   = CHAIN_GRAPH_REL,
-       .min_percent = 0.5
+       .min_percent = 0.5,
+       .order  = ORDER_CALLEE
 };
 
 u16 hists__col_len(struct hists *self, enum hist_column col)
index b723f211881cdcc4e124afc26b29d07d20977d36..558bcf99694935a706fd2d0e4dde914880918c7f 100644 (file)
@@ -247,9 +247,14 @@ int perf_session__resolve_callchain(struct perf_session *self,
        callchain_cursor_reset(&self->callchain_cursor);
 
        for (i = 0; i < chain->nr; i++) {
-               u64 ip = chain->ips[i];
+               u64 ip;
                struct addr_location al;
 
+               if (callchain_param.order == ORDER_CALLEE)
+                       ip = chain->ips[i];
+               else
+                       ip = chain->ips[chain->nr - i - 1];
+
                if (ip >= PERF_CONTEXT_MAX) {
                        switch (ip) {
                        case PERF_CONTEXT_HV: