diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-07-05 01:39:21 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-07-05 04:30:23 -0400 |
commit | 805d127d62472f17c7d79baa001a7651afe2fa47 (patch) | |
tree | 59dfdd2337190e168a007ba65cc25c7e5d8c0fda /tools/perf/builtin-report.c | |
parent | e05b876c222178bc6abcfa9f23d8311731691046 (diff) |
perf report: Add "Fractal" mode output - support callchains with relative overhead rate
The current callchain displays the overhead rates as absolute:
relative to the total overhead.
This patch provides relative overhead percentage, in which each
branch of the callchain tree is a independant instrumentated object.
This provides a 'fractal' view of the call-chain profile: each
sub-graph looks like a profile in itself - relative to its parent.
You can produce such output by using the "fractal" mode
that you can abbreviate via f, fr, fra, frac, etc...
./perf report -s sym -c fractal
Example:
8.46% [k] copy_user_generic_string
|
|--52.01%-- generic_file_aio_read
| do_sync_read
| vfs_read
| |
| |--97.20%-- sys_pread64
| | system_call_fastpath
| | pread64
| |
| --2.81%-- sys_read
| system_call_fastpath
| __read
|
|--39.85%-- generic_file_buffered_write
| __generic_file_aio_write_nolock
| generic_file_aio_write
| do_sync_write
| reiserfs_file_write
| vfs_write
| |
| |--97.05%-- sys_pwrite64
| | system_call_fastpath
| | __pwrite64
| |
| --2.95%-- sys_write
| system_call_fastpath
| __write_nocancel
[...]
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: Jens Axboe <jens.axboe@oracle.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <1246772361-9960-5-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 60 |
1 files changed, 40 insertions, 20 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8bd58651128c..4e5cc266311e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -59,10 +59,15 @@ static regex_t parent_regex; | |||
59 | 59 | ||
60 | static int exclude_other = 1; | 60 | static int exclude_other = 1; |
61 | 61 | ||
62 | static char callchain_default_opt[] = "graph,0.5"; | 62 | static char callchain_default_opt[] = "fractal,0.5"; |
63 | |||
63 | static int callchain; | 64 | static int callchain; |
64 | static enum chain_mode callchain_mode; | 65 | |
65 | static double callchain_min_percent = 0.5; | 66 | static |
67 | struct callchain_param callchain_param = { | ||
68 | .mode = CHAIN_GRAPH_ABS, | ||
69 | .min_percent = 0.5 | ||
70 | }; | ||
66 | 71 | ||
67 | static u64 sample_type; | 72 | static u64 sample_type; |
68 | 73 | ||
@@ -846,9 +851,15 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | |||
846 | struct callchain_node *child; | 851 | struct callchain_node *child; |
847 | struct callchain_list *chain; | 852 | struct callchain_list *chain; |
848 | int new_depth_mask = depth_mask; | 853 | int new_depth_mask = depth_mask; |
854 | u64 new_total; | ||
849 | size_t ret = 0; | 855 | size_t ret = 0; |
850 | int i; | 856 | int i; |
851 | 857 | ||
858 | if (callchain_param.mode == CHAIN_GRAPH_REL) | ||
859 | new_total = self->cumul_hit; | ||
860 | else | ||
861 | new_total = total_samples; | ||
862 | |||
852 | node = rb_first(&self->rb_root); | 863 | node = rb_first(&self->rb_root); |
853 | while (node) { | 864 | while (node) { |
854 | child = rb_entry(node, struct callchain_node, rb_node); | 865 | child = rb_entry(node, struct callchain_node, rb_node); |
@@ -873,10 +884,10 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | |||
873 | continue; | 884 | continue; |
874 | ret += ipchain__fprintf_graph(fp, chain, depth, | 885 | ret += ipchain__fprintf_graph(fp, chain, depth, |
875 | new_depth_mask, i++, | 886 | new_depth_mask, i++, |
876 | total_samples, | 887 | new_total, |
877 | child->cumul_hit); | 888 | child->cumul_hit); |
878 | } | 889 | } |
879 | ret += callchain__fprintf_graph(fp, child, total_samples, | 890 | ret += callchain__fprintf_graph(fp, child, new_total, |
880 | depth + 1, | 891 | depth + 1, |
881 | new_depth_mask | (1 << depth)); | 892 | new_depth_mask | (1 << depth)); |
882 | node = next; | 893 | node = next; |
@@ -925,13 +936,18 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, | |||
925 | 936 | ||
926 | chain = rb_entry(rb_node, struct callchain_node, rb_node); | 937 | chain = rb_entry(rb_node, struct callchain_node, rb_node); |
927 | percent = chain->hit * 100.0 / total_samples; | 938 | percent = chain->hit * 100.0 / total_samples; |
928 | if (callchain_mode == FLAT) { | 939 | switch (callchain_param.mode) { |
940 | case CHAIN_FLAT: | ||
929 | ret += percent_color_fprintf(fp, " %6.2f%%\n", | 941 | ret += percent_color_fprintf(fp, " %6.2f%%\n", |
930 | percent); | 942 | percent); |
931 | ret += callchain__fprintf_flat(fp, chain, total_samples); | 943 | ret += callchain__fprintf_flat(fp, chain, total_samples); |
932 | } else if (callchain_mode == GRAPH) { | 944 | break; |
945 | case CHAIN_GRAPH_ABS: /* Falldown */ | ||
946 | case CHAIN_GRAPH_REL: | ||
933 | ret += callchain__fprintf_graph(fp, chain, | 947 | ret += callchain__fprintf_graph(fp, chain, |
934 | total_samples, 1, 1); | 948 | total_samples, 1, 1); |
949 | default: | ||
950 | break; | ||
935 | } | 951 | } |
936 | ret += fprintf(fp, "\n"); | 952 | ret += fprintf(fp, "\n"); |
937 | rb_node = rb_next(rb_node); | 953 | rb_node = rb_next(rb_node); |
@@ -1219,14 +1235,9 @@ static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits) | |||
1219 | struct rb_node *parent = NULL; | 1235 | struct rb_node *parent = NULL; |
1220 | struct hist_entry *iter; | 1236 | struct hist_entry *iter; |
1221 | 1237 | ||
1222 | if (callchain) { | 1238 | if (callchain) |
1223 | if (callchain_mode == FLAT) | 1239 | callchain_param.sort(&he->sorted_chain, &he->callchain, |
1224 | sort_chain_flat(&he->sorted_chain, &he->callchain, | 1240 | min_callchain_hits, &callchain_param); |
1225 | min_callchain_hits); | ||
1226 | else if (callchain_mode == GRAPH) | ||
1227 | sort_chain_graph(&he->sorted_chain, &he->callchain, | ||
1228 | min_callchain_hits); | ||
1229 | } | ||
1230 | 1241 | ||
1231 | while (*p != NULL) { | 1242 | while (*p != NULL) { |
1232 | parent = *p; | 1243 | parent = *p; |
@@ -1249,7 +1260,7 @@ static void output__resort(u64 total_samples) | |||
1249 | struct rb_root *tree = &hist; | 1260 | struct rb_root *tree = &hist; |
1250 | u64 min_callchain_hits; | 1261 | u64 min_callchain_hits; |
1251 | 1262 | ||
1252 | min_callchain_hits = total_samples * (callchain_min_percent / 100); | 1263 | min_callchain_hits = total_samples * (callchain_param.min_percent / 100); |
1253 | 1264 | ||
1254 | if (sort__need_collapse) | 1265 | if (sort__need_collapse) |
1255 | tree = &collapse_hists; | 1266 | tree = &collapse_hists; |
@@ -1829,22 +1840,31 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, | |||
1829 | 1840 | ||
1830 | /* get the output mode */ | 1841 | /* get the output mode */ |
1831 | if (!strncmp(tok, "graph", strlen(arg))) | 1842 | if (!strncmp(tok, "graph", strlen(arg))) |
1832 | callchain_mode = GRAPH; | 1843 | callchain_param.mode = CHAIN_GRAPH_ABS; |
1833 | 1844 | ||
1834 | else if (!strncmp(tok, "flat", strlen(arg))) | 1845 | else if (!strncmp(tok, "flat", strlen(arg))) |
1835 | callchain_mode = FLAT; | 1846 | callchain_param.mode = CHAIN_FLAT; |
1847 | |||
1848 | else if (!strncmp(tok, "fractal", strlen(arg))) | ||
1849 | callchain_param.mode = CHAIN_GRAPH_REL; | ||
1850 | |||
1836 | else | 1851 | else |
1837 | return -1; | 1852 | return -1; |
1838 | 1853 | ||
1839 | /* get the min percentage */ | 1854 | /* get the min percentage */ |
1840 | tok = strtok(NULL, ","); | 1855 | tok = strtok(NULL, ","); |
1841 | if (!tok) | 1856 | if (!tok) |
1842 | return 0; | 1857 | goto setup; |
1843 | 1858 | ||
1844 | callchain_min_percent = strtod(tok, &endptr); | 1859 | callchain_param.min_percent = strtod(tok, &endptr); |
1845 | if (tok == endptr) | 1860 | if (tok == endptr) |
1846 | return -1; | 1861 | return -1; |
1847 | 1862 | ||
1863 | setup: | ||
1864 | if (register_callchain_param(&callchain_param) < 0) { | ||
1865 | fprintf(stderr, "Can't register callchain params\n"); | ||
1866 | return -1; | ||
1867 | } | ||
1848 | return 0; | 1868 | return 0; |
1849 | } | 1869 | } |
1850 | 1870 | ||