diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 102 |
1 files changed, 67 insertions, 35 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3f5d8ea05ff0..197793051fa5 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -794,8 +794,15 @@ callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples) | |||
794 | ret += callchain__fprintf(fp, self->parent, total_samples); | 794 | ret += callchain__fprintf(fp, self->parent, total_samples); |
795 | 795 | ||
796 | 796 | ||
797 | list_for_each_entry(chain, &self->val, list) | 797 | list_for_each_entry(chain, &self->val, list) { |
798 | ret += fprintf(fp, " %p\n", (void *)chain->ip); | 798 | if (chain->ip >= PERF_CONTEXT_MAX) |
799 | continue; | ||
800 | if (chain->sym) | ||
801 | ret += fprintf(fp, " %s\n", chain->sym->name); | ||
802 | else | ||
803 | ret += fprintf(fp, " %p\n", | ||
804 | (void *)chain->ip); | ||
805 | } | ||
799 | 806 | ||
800 | return ret; | 807 | return ret; |
801 | } | 808 | } |
@@ -930,6 +937,55 @@ static int call__match(struct symbol *sym) | |||
930 | return 0; | 937 | return 0; |
931 | } | 938 | } |
932 | 939 | ||
940 | static struct symbol ** | ||
941 | resolve_callchain(struct thread *thread, struct map *map, | ||
942 | struct ip_callchain *chain, struct hist_entry *entry) | ||
943 | { | ||
944 | int i; | ||
945 | struct symbol **syms; | ||
946 | u64 context = PERF_CONTEXT_MAX; | ||
947 | |||
948 | if (callchain) { | ||
949 | syms = calloc(chain->nr, sizeof(*syms)); | ||
950 | if (!syms) { | ||
951 | fprintf(stderr, "Can't allocate memory for symbols\n"); | ||
952 | exit(-1); | ||
953 | } | ||
954 | } | ||
955 | |||
956 | for (i = 0; i < chain->nr; i++) { | ||
957 | u64 ip = chain->ips[i]; | ||
958 | struct dso *dso = NULL; | ||
959 | struct symbol *sym; | ||
960 | |||
961 | if (ip >= PERF_CONTEXT_MAX) { | ||
962 | context = ip; | ||
963 | continue; | ||
964 | } | ||
965 | |||
966 | switch (context) { | ||
967 | case PERF_CONTEXT_KERNEL: | ||
968 | dso = kernel_dso; | ||
969 | break; | ||
970 | default: | ||
971 | break; | ||
972 | } | ||
973 | |||
974 | sym = resolve_symbol(thread, NULL, &dso, &ip); | ||
975 | |||
976 | if (sym) { | ||
977 | if (sort__has_parent && call__match(sym) && | ||
978 | !entry->parent) | ||
979 | entry->parent = sym; | ||
980 | if (!callchain) | ||
981 | break; | ||
982 | syms[i] = sym; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | return syms; | ||
987 | } | ||
988 | |||
933 | /* | 989 | /* |
934 | * collect histogram counts | 990 | * collect histogram counts |
935 | */ | 991 | */ |
@@ -942,6 +998,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | |||
942 | struct rb_node **p = &hist.rb_node; | 998 | struct rb_node **p = &hist.rb_node; |
943 | struct rb_node *parent = NULL; | 999 | struct rb_node *parent = NULL; |
944 | struct hist_entry *he; | 1000 | struct hist_entry *he; |
1001 | struct symbol **syms = NULL; | ||
945 | struct hist_entry entry = { | 1002 | struct hist_entry entry = { |
946 | .thread = thread, | 1003 | .thread = thread, |
947 | .map = map, | 1004 | .map = map, |
@@ -955,39 +1012,11 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | |||
955 | }; | 1012 | }; |
956 | int cmp; | 1013 | int cmp; |
957 | 1014 | ||
958 | if (sort__has_parent && chain) { | ||
959 | u64 context = PERF_CONTEXT_MAX; | ||
960 | int i; | ||
961 | |||
962 | for (i = 0; i < chain->nr; i++) { | ||
963 | u64 ip = chain->ips[i]; | ||
964 | struct dso *dso = NULL; | ||
965 | struct symbol *sym; | ||
966 | |||
967 | if (ip >= PERF_CONTEXT_MAX) { | ||
968 | context = ip; | ||
969 | continue; | ||
970 | } | ||
971 | |||
972 | switch (context) { | ||
973 | case PERF_CONTEXT_HV: | 1015 | case PERF_CONTEXT_HV: |
974 | dso = hypervisor_dso; | 1016 | dso = hypervisor_dso; |
975 | break; | 1017 | break; |
976 | case PERF_CONTEXT_KERNEL: | 1018 | if ((sort__has_parent || callchain) && chain) |
977 | dso = kernel_dso; | 1019 | syms = resolve_callchain(thread, map, chain, &entry); |
978 | break; | ||
979 | default: | ||
980 | break; | ||
981 | } | ||
982 | |||
983 | sym = resolve_symbol(thread, NULL, &dso, &ip); | ||
984 | |||
985 | if (sym && call__match(sym)) { | ||
986 | entry.parent = sym; | ||
987 | break; | ||
988 | } | ||
989 | } | ||
990 | } | ||
991 | 1020 | ||
992 | while (*p != NULL) { | 1021 | while (*p != NULL) { |
993 | parent = *p; | 1022 | parent = *p; |
@@ -997,8 +1026,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | |||
997 | 1026 | ||
998 | if (!cmp) { | 1027 | if (!cmp) { |
999 | he->count += count; | 1028 | he->count += count; |
1000 | if (callchain) | 1029 | if (callchain) { |
1001 | append_chain(&he->callchain, chain); | 1030 | append_chain(&he->callchain, chain, syms); |
1031 | free(syms); | ||
1032 | } | ||
1002 | return 0; | 1033 | return 0; |
1003 | } | 1034 | } |
1004 | 1035 | ||
@@ -1014,7 +1045,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | |||
1014 | *he = entry; | 1045 | *he = entry; |
1015 | if (callchain) { | 1046 | if (callchain) { |
1016 | callchain_init(&he->callchain); | 1047 | callchain_init(&he->callchain); |
1017 | append_chain(&he->callchain, chain); | 1048 | append_chain(&he->callchain, chain, syms); |
1049 | free(syms); | ||
1018 | } | 1050 | } |
1019 | rb_link_node(&he->rb_node, parent, p); | 1051 | rb_link_node(&he->rb_node, parent, p); |
1020 | rb_insert_color(&he->rb_node, &hist); | 1052 | rb_insert_color(&he->rb_node, &hist); |