diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-07-02 11:58:21 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-07-02 14:47:15 -0400 |
commit | 4eb3e4788b8a5e220a0aeb590f88c28850726ebe (patch) | |
tree | 537392177078684b87197d358cf2104e90ec6d66 /tools/perf/util/callchain.c | |
parent | 5a4b181721375700124513cdd9f97056e1c66675 (diff) |
perf report: Add support for callchain graph output
Currently, the printing of callchains is done in a single
vertical level, this is the "flat" mode:
8.25% [k] copy_user_generic_string
4.19%
copy_user_generic_string
generic_file_aio_read
do_sync_read
vfs_read
sys_pread64
system_call_fastpath
pread64
This patch introduces a new "graph" mode which provides a
hierarchical output of factorized paths recursively sorted:
8.25% [k] copy_user_generic_string
|
|--4.31%-- generic_file_aio_read
| do_sync_read
| vfs_read
| |
| |--4.19%-- sys_pread64
| | system_call_fastpath
| | pread64
| |
| --0.12%-- sys_read
| system_call_fastpath
| __read
|
|--3.24%-- generic_file_buffered_write
| __generic_file_aio_write_nolock
| generic_file_aio_write
| do_sync_write
| reiserfs_file_write
| vfs_write
| |
| |--3.14%-- sys_pwrite64
| | system_call_fastpath
| | __pwrite64
| |
| --0.10%-- sys_write
[...]
The command line has then changed.
By providing the -c option, the callchain will output in the
flat mode by default.
But you can override it:
perf report -c graph
or
perf report -c flat
You can also pass the abreviated mode:
perf report -c g
or
perf report -c gra
will both make use of the graph mode.
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>
Cc: Anton Blanchard <anton@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <1246550301-8954-3-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/callchain.c')
-rw-r--r-- | tools/perf/util/callchain.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 3c4a91fea622..a9873aafcd92 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -19,9 +19,9 @@ | |||
19 | #define chain_for_each_child(child, parent) \ | 19 | #define chain_for_each_child(child, parent) \ |
20 | list_for_each_entry(child, &parent->children, brothers) | 20 | list_for_each_entry(child, &parent->children, brothers) |
21 | 21 | ||
22 | |||
23 | static void | 22 | static void |
24 | rb_insert_callchain(struct rb_root *root, struct callchain_node *chain) | 23 | rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, |
24 | enum chain_mode mode) | ||
25 | { | 25 | { |
26 | struct rb_node **p = &root->rb_node; | 26 | struct rb_node **p = &root->rb_node; |
27 | struct rb_node *parent = NULL; | 27 | struct rb_node *parent = NULL; |
@@ -31,10 +31,22 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain) | |||
31 | parent = *p; | 31 | parent = *p; |
32 | rnode = rb_entry(parent, struct callchain_node, rb_node); | 32 | rnode = rb_entry(parent, struct callchain_node, rb_node); |
33 | 33 | ||
34 | if (rnode->hit < chain->hit) | 34 | switch (mode) { |
35 | p = &(*p)->rb_left; | 35 | case FLAT: |
36 | else | 36 | if (rnode->hit < chain->hit) |
37 | p = &(*p)->rb_right; | 37 | p = &(*p)->rb_left; |
38 | else | ||
39 | p = &(*p)->rb_right; | ||
40 | break; | ||
41 | case GRAPH: | ||
42 | if (rnode->cumul_hit < chain->cumul_hit) | ||
43 | p = &(*p)->rb_left; | ||
44 | else | ||
45 | p = &(*p)->rb_right; | ||
46 | break; | ||
47 | default: | ||
48 | break; | ||
49 | } | ||
38 | } | 50 | } |
39 | 51 | ||
40 | rb_link_node(&chain->rb_node, parent, p); | 52 | rb_link_node(&chain->rb_node, parent, p); |
@@ -45,15 +57,36 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain) | |||
45 | * Once we get every callchains from the stream, we can now | 57 | * Once we get every callchains from the stream, we can now |
46 | * sort them by hit | 58 | * sort them by hit |
47 | */ | 59 | */ |
48 | void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node) | 60 | void sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node) |
49 | { | 61 | { |
50 | struct callchain_node *child; | 62 | struct callchain_node *child; |
51 | 63 | ||
52 | chain_for_each_child(child, node) | 64 | chain_for_each_child(child, node) |
53 | sort_chain_to_rbtree(rb_root, child); | 65 | sort_chain_flat(rb_root, child); |
54 | 66 | ||
55 | if (node->hit) | 67 | if (node->hit) |
56 | rb_insert_callchain(rb_root, node); | 68 | rb_insert_callchain(rb_root, node, FLAT); |
69 | } | ||
70 | |||
71 | static void __sort_chain_graph(struct callchain_node *node) | ||
72 | { | ||
73 | struct callchain_node *child; | ||
74 | |||
75 | node->rb_root = RB_ROOT; | ||
76 | node->cumul_hit = node->hit; | ||
77 | |||
78 | chain_for_each_child(child, node) { | ||
79 | __sort_chain_graph(child); | ||
80 | rb_insert_callchain(&node->rb_root, child, GRAPH); | ||
81 | node->cumul_hit += child->cumul_hit; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | void | ||
86 | sort_chain_graph(struct rb_root *rb_root, struct callchain_node *chain_root) | ||
87 | { | ||
88 | __sort_chain_graph(chain_root); | ||
89 | rb_root->rb_node = chain_root->rb_root.rb_node; | ||
57 | } | 90 | } |
58 | 91 | ||
59 | /* | 92 | /* |