aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c82
1 files changed, 71 insertions, 11 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 28d1cb2127e9..ed391db9e0f8 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -15,6 +15,7 @@
15#include "util/rbtree.h" 15#include "util/rbtree.h"
16#include "util/symbol.h" 16#include "util/symbol.h"
17#include "util/string.h" 17#include "util/string.h"
18#include "util/callchain.h"
18 19
19#include "perf.h" 20#include "perf.h"
20#include "util/header.h" 21#include "util/header.h"
@@ -52,6 +53,7 @@ static char *parent_pattern = default_parent_pattern;
52static regex_t parent_regex; 53static regex_t parent_regex;
53 54
54static int exclude_other = 1; 55static int exclude_other = 1;
56static int callchain;
55 57
56static u64 sample_type; 58static u64 sample_type;
57 59
@@ -488,17 +490,19 @@ static size_t threads__fprintf(FILE *fp)
488static struct rb_root hist; 490static struct rb_root hist;
489 491
490struct hist_entry { 492struct hist_entry {
491 struct rb_node rb_node; 493 struct rb_node rb_node;
492 494
493 struct thread *thread; 495 struct thread *thread;
494 struct map *map; 496 struct map *map;
495 struct dso *dso; 497 struct dso *dso;
496 struct symbol *sym; 498 struct symbol *sym;
497 struct symbol *parent; 499 struct symbol *parent;
498 u64 ip; 500 u64 ip;
499 char level; 501 char level;
500 502 struct callchain_node callchain;
501 u64 count; 503 struct rb_root sorted_chain;
504
505 u64 count;
502}; 506};
503 507
504/* 508/*
@@ -769,6 +773,48 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
769} 773}
770 774
771static size_t 775static size_t
776callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
777{
778 struct callchain_list *chain;
779 size_t ret = 0;
780
781 if (!self)
782 return 0;
783
784 ret += callchain__fprintf(fp, self->parent, total_samples);
785
786
787 list_for_each_entry(chain, &self->val, list)
788 ret += fprintf(fp, " %p\n", (void *)chain->ip);
789
790 return ret;
791}
792
793static size_t
794hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
795 u64 total_samples)
796{
797 struct rb_node *rb_node;
798 struct callchain_node *chain;
799 size_t ret = 0;
800
801 rb_node = rb_first(&self->sorted_chain);
802 while (rb_node) {
803 double percent;
804
805 chain = rb_entry(rb_node, struct callchain_node, rb_node);
806 percent = chain->hit * 100.0 / total_samples;
807 ret += fprintf(fp, " %6.2f%%\n", percent);
808 ret += callchain__fprintf(fp, chain, total_samples);
809 ret += fprintf(fp, "\n");
810 rb_node = rb_next(rb_node);
811 }
812
813 return ret;
814}
815
816
817static size_t
772hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) 818hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
773{ 819{
774 struct sort_entry *se; 820 struct sort_entry *se;
@@ -808,6 +854,9 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
808 854
809 ret += fprintf(fp, "\n"); 855 ret += fprintf(fp, "\n");
810 856
857 if (callchain)
858 hist_entry_callchain__fprintf(fp, self, total_samples);
859
811 return ret; 860 return ret;
812} 861}
813 862
@@ -892,6 +941,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
892 .level = level, 941 .level = level,
893 .count = count, 942 .count = count,
894 .parent = NULL, 943 .parent = NULL,
944 .sorted_chain = RB_ROOT
895 }; 945 };
896 int cmp; 946 int cmp;
897 947
@@ -934,6 +984,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
934 984
935 if (!cmp) { 985 if (!cmp) {
936 he->count += count; 986 he->count += count;
987 if (callchain)
988 append_chain(&he->callchain, chain);
937 return 0; 989 return 0;
938 } 990 }
939 991
@@ -947,6 +999,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
947 if (!he) 999 if (!he)
948 return -ENOMEM; 1000 return -ENOMEM;
949 *he = entry; 1001 *he = entry;
1002 if (callchain) {
1003 callchain_init(&he->callchain);
1004 append_chain(&he->callchain, chain);
1005 }
950 rb_link_node(&he->rb_node, parent, p); 1006 rb_link_node(&he->rb_node, parent, p);
951 rb_insert_color(&he->rb_node, &hist); 1007 rb_insert_color(&he->rb_node, &hist);
952 1008
@@ -1023,6 +1079,9 @@ static void output__insert_entry(struct hist_entry *he)
1023 struct rb_node *parent = NULL; 1079 struct rb_node *parent = NULL;
1024 struct hist_entry *iter; 1080 struct hist_entry *iter;
1025 1081
1082 if (callchain)
1083 sort_chain_to_rbtree(&he->sorted_chain, &he->callchain);
1084
1026 while (*p != NULL) { 1085 while (*p != NULL) {
1027 parent = *p; 1086 parent = *p;
1028 iter = rb_entry(parent, struct hist_entry, rb_node); 1087 iter = rb_entry(parent, struct hist_entry, rb_node);
@@ -1599,6 +1658,7 @@ static const struct option options[] = {
1599 "regex filter to identify parent, see: '--sort parent'"), 1658 "regex filter to identify parent, see: '--sort parent'"),
1600 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 1659 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1601 "Only display entries with parent-match"), 1660 "Only display entries with parent-match"),
1661 OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"),
1602 OPT_END() 1662 OPT_END()
1603}; 1663};
1604 1664