aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-07-02 11:58:21 -0400
committerIngo Molnar <mingo@elte.hu>2009-07-02 14:47:15 -0400
commit4eb3e4788b8a5e220a0aeb590f88c28850726ebe (patch)
tree537392177078684b87197d358cf2104e90ec6d66 /tools/perf/builtin-report.c
parent5a4b181721375700124513cdd9f97056e1c66675 (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/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c141
1 files changed, 134 insertions, 7 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b44476ca2398..0ca46386d936 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -59,6 +59,7 @@ static regex_t parent_regex;
59 59
60static int exclude_other = 1; 60static int exclude_other = 1;
61static int callchain; 61static int callchain;
62static enum chain_mode callchain_mode;
62 63
63static u64 sample_type; 64static u64 sample_type;
64 65
@@ -787,8 +788,103 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
787 return cmp; 788 return cmp;
788} 789}
789 790
791static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
792{
793 int i;
794 size_t ret = 0;
795
796 ret += fprintf(fp, "%s", " ");
797
798 for (i = 0; i < depth; i++)
799 if (depth_mask & (1 << i))
800 ret += fprintf(fp, "| ");
801 else
802 ret += fprintf(fp, " ");
803
804 ret += fprintf(fp, "\n");
805
806 return ret;
807}
790static size_t 808static size_t
791callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples) 809ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
810 int depth_mask, int count, u64 total_samples,
811 int hits)
812{
813 int i;
814 size_t ret = 0;
815
816 ret += fprintf(fp, "%s", " ");
817 for (i = 0; i < depth; i++) {
818 if (depth_mask & (1 << i))
819 ret += fprintf(fp, "|");
820 else
821 ret += fprintf(fp, " ");
822 if (!count && i == depth - 1) {
823 double percent;
824
825 percent = hits * 100.0 / total_samples;
826 ret += fprintf(fp, "--%2.2f%%-- ", percent);
827 } else
828 ret += fprintf(fp, "%s", " ");
829 }
830 if (chain->sym)
831 ret += fprintf(fp, "%s\n", chain->sym->name);
832 else
833 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
834
835 return ret;
836}
837
838static size_t
839callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
840 u64 total_samples, int depth, int depth_mask)
841{
842 struct rb_node *node, *next;
843 struct callchain_node *child;
844 struct callchain_list *chain;
845 int new_depth_mask = depth_mask;
846 size_t ret = 0;
847 int i;
848
849 node = rb_first(&self->rb_root);
850 while (node) {
851 child = rb_entry(node, struct callchain_node, rb_node);
852
853 /*
854 * The depth mask manages the output of pipes that show
855 * the depth. We don't want to keep the pipes of the current
856 * level for the last child of this depth
857 */
858 next = rb_next(node);
859 if (!next)
860 new_depth_mask &= ~(1 << (depth - 1));
861
862 /*
863 * But we keep the older depth mask for the line seperator
864 * to keep the level link until we reach the last child
865 */
866 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
867 i = 0;
868 list_for_each_entry(chain, &child->val, list) {
869 if (chain->ip >= PERF_CONTEXT_MAX)
870 continue;
871 ret += ipchain__fprintf_graph(fp, chain, depth,
872 new_depth_mask, i++,
873 total_samples,
874 child->cumul_hit);
875 }
876 ret += callchain__fprintf_graph(fp, child, total_samples,
877 depth + 1,
878 new_depth_mask | (1 << depth));
879 node = next;
880 }
881
882 return ret;
883}
884
885static size_t
886callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
887 u64 total_samples)
792{ 888{
793 struct callchain_list *chain; 889 struct callchain_list *chain;
794 size_t ret = 0; 890 size_t ret = 0;
@@ -796,7 +892,7 @@ callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
796 if (!self) 892 if (!self)
797 return 0; 893 return 0;
798 894
799 ret += callchain__fprintf(fp, self->parent, total_samples); 895 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
800 896
801 897
802 list_for_each_entry(chain, &self->val, list) { 898 list_for_each_entry(chain, &self->val, list) {
@@ -826,8 +922,13 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
826 922
827 chain = rb_entry(rb_node, struct callchain_node, rb_node); 923 chain = rb_entry(rb_node, struct callchain_node, rb_node);
828 percent = chain->hit * 100.0 / total_samples; 924 percent = chain->hit * 100.0 / total_samples;
829 ret += fprintf(fp, " %6.2f%%\n", percent); 925 if (callchain_mode == FLAT) {
830 ret += callchain__fprintf(fp, chain, total_samples); 926 ret += fprintf(fp, " %6.2f%%\n", percent);
927 ret += callchain__fprintf_flat(fp, chain, total_samples);
928 } else if (callchain_mode == GRAPH) {
929 ret += callchain__fprintf_graph(fp, chain,
930 total_samples, 1, 1);
931 }
831 ret += fprintf(fp, "\n"); 932 ret += fprintf(fp, "\n");
832 rb_node = rb_next(rb_node); 933 rb_node = rb_next(rb_node);
833 } 934 }
@@ -1129,8 +1230,12 @@ static void output__insert_entry(struct hist_entry *he)
1129 struct rb_node *parent = NULL; 1230 struct rb_node *parent = NULL;
1130 struct hist_entry *iter; 1231 struct hist_entry *iter;
1131 1232
1132 if (callchain) 1233 if (callchain) {
1133 sort_chain_to_rbtree(&he->sorted_chain, &he->callchain); 1234 if (callchain_mode == FLAT)
1235 sort_chain_flat(&he->sorted_chain, &he->callchain);
1236 else if (callchain_mode == GRAPH)
1237 sort_chain_graph(&he->sorted_chain, &he->callchain);
1238 }
1134 1239
1135 while (*p != NULL) { 1240 while (*p != NULL) {
1136 parent = *p; 1241 parent = *p;
@@ -1702,6 +1807,26 @@ done:
1702 return rc; 1807 return rc;
1703} 1808}
1704 1809
1810static int
1811parse_callchain_opt(const struct option *opt __used, const char *arg,
1812 int unset __used)
1813{
1814 callchain = 1;
1815
1816 if (!arg)
1817 return 0;
1818
1819 if (!strncmp(arg, "graph", strlen(arg)))
1820 callchain_mode = GRAPH;
1821
1822 else if (!strncmp(arg, "flat", strlen(arg)))
1823 callchain_mode = FLAT;
1824 else
1825 return -1;
1826
1827 return 0;
1828}
1829
1705static const char * const report_usage[] = { 1830static const char * const report_usage[] = {
1706 "perf report [<options>] <command>", 1831 "perf report [<options>] <command>",
1707 NULL 1832 NULL
@@ -1725,7 +1850,9 @@ static const struct option options[] = {
1725 "regex filter to identify parent, see: '--sort parent'"), 1850 "regex filter to identify parent, see: '--sort parent'"),
1726 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 1851 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1727 "Only display entries with parent-match"), 1852 "Only display entries with parent-match"),
1728 OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"), 1853 OPT_CALLBACK_DEFAULT('c', "callchain", NULL, "output_type",
1854 "Display callchains with output_type: flat, graph. "
1855 "Default to flat", &parse_callchain_opt, "flat"),
1729 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 1856 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1730 "only consider symbols in these dsos"), 1857 "only consider symbols in these dsos"),
1731 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 1858 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",