diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/builtin-report.c | 86 |
1 files changed, 39 insertions, 47 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 86981bd08f65..7a6577bf9a41 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -59,6 +59,11 @@ struct ip_event { | |||
59 | unsigned char __more_data[]; | 59 | unsigned char __more_data[]; |
60 | }; | 60 | }; |
61 | 61 | ||
62 | struct ip_callchain { | ||
63 | __u64 nr; | ||
64 | __u64 ips[0]; | ||
65 | }; | ||
66 | |||
62 | struct mmap_event { | 67 | struct mmap_event { |
63 | struct perf_event_header header; | 68 | struct perf_event_header header; |
64 | __u32 pid, tid; | 69 | __u32 pid, tid; |
@@ -833,15 +838,12 @@ got_dso: | |||
833 | return dso->find_symbol(dso, ip); | 838 | return dso->find_symbol(dso, ip); |
834 | } | 839 | } |
835 | 840 | ||
836 | static struct symbol *call__match(struct symbol *sym) | 841 | static int call__match(struct symbol *sym) |
837 | { | 842 | { |
838 | if (!sym) | ||
839 | return NULL; | ||
840 | |||
841 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | 843 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) |
842 | return sym; | 844 | return 1; |
843 | 845 | ||
844 | return NULL; | 846 | return 0; |
845 | } | 847 | } |
846 | 848 | ||
847 | /* | 849 | /* |
@@ -850,7 +852,7 @@ static struct symbol *call__match(struct symbol *sym) | |||
850 | 852 | ||
851 | static int | 853 | static int |
852 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | 854 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, |
853 | struct symbol *sym, __u64 ip, struct perf_callchain_entry *chain, | 855 | struct symbol *sym, __u64 ip, struct ip_callchain *chain, |
854 | char level, __u64 count) | 856 | char level, __u64 count) |
855 | { | 857 | { |
856 | struct rb_node **p = &hist.rb_node; | 858 | struct rb_node **p = &hist.rb_node; |
@@ -869,31 +871,35 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | |||
869 | int cmp; | 871 | int cmp; |
870 | 872 | ||
871 | if (sort__has_parent && chain) { | 873 | if (sort__has_parent && chain) { |
872 | int i, nr = chain->hv; | 874 | __u64 context = PERF_CONTEXT_MAX; |
873 | struct symbol *sym; | 875 | int i; |
874 | struct dso *dso; | 876 | |
875 | __u64 ip; | 877 | for (i = 0; i < chain->nr; i++) { |
876 | 878 | __u64 ip = chain->ips[i]; | |
877 | for (i = 0; i < chain->kernel; i++) { | 879 | struct dso *dso = NULL; |
878 | ip = chain->ip[nr + i]; | 880 | struct symbol *sym; |
879 | dso = kernel_dso; | 881 | |
882 | if (ip >= PERF_CONTEXT_MAX) { | ||
883 | context = ip; | ||
884 | continue; | ||
885 | } | ||
886 | |||
887 | switch (context) { | ||
888 | case PERF_CONTEXT_KERNEL: | ||
889 | dso = kernel_dso; | ||
890 | break; | ||
891 | default: | ||
892 | break; | ||
893 | } | ||
894 | |||
880 | sym = resolve_symbol(thread, NULL, &dso, &ip); | 895 | sym = resolve_symbol(thread, NULL, &dso, &ip); |
881 | entry.parent = call__match(sym); | 896 | |
882 | if (entry.parent) | 897 | if (sym && call__match(sym)) { |
883 | goto got_parent; | 898 | entry.parent = sym; |
884 | } | 899 | break; |
885 | nr += i; | 900 | } |
886 | |||
887 | for (i = 0; i < chain->user; i++) { | ||
888 | ip = chain->ip[nr + i]; | ||
889 | sym = resolve_symbol(thread, NULL, NULL, &ip); | ||
890 | entry.parent = call__match(sym); | ||
891 | if (entry.parent) | ||
892 | goto got_parent; | ||
893 | } | 901 | } |
894 | nr += i; | ||
895 | } | 902 | } |
896 | got_parent: | ||
897 | 903 | ||
898 | while (*p != NULL) { | 904 | while (*p != NULL) { |
899 | parent = *p; | 905 | parent = *p; |
@@ -1095,21 +1101,10 @@ static unsigned long total = 0, | |||
1095 | total_unknown = 0, | 1101 | total_unknown = 0, |
1096 | total_lost = 0; | 1102 | total_lost = 0; |
1097 | 1103 | ||
1098 | static int validate_chain(struct perf_callchain_entry *chain, event_t *event) | 1104 | static int validate_chain(struct ip_callchain *chain, event_t *event) |
1099 | { | 1105 | { |
1100 | unsigned int chain_size; | 1106 | unsigned int chain_size; |
1101 | 1107 | ||
1102 | if (chain->nr > MAX_STACK_DEPTH) | ||
1103 | return -1; | ||
1104 | if (chain->hv > MAX_STACK_DEPTH) | ||
1105 | return -1; | ||
1106 | if (chain->kernel > MAX_STACK_DEPTH) | ||
1107 | return -1; | ||
1108 | if (chain->user > MAX_STACK_DEPTH) | ||
1109 | return -1; | ||
1110 | if (chain->hv + chain->kernel + chain->user != chain->nr) | ||
1111 | return -1; | ||
1112 | |||
1113 | chain_size = event->header.size; | 1108 | chain_size = event->header.size; |
1114 | chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; | 1109 | chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; |
1115 | 1110 | ||
@@ -1130,7 +1125,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
1130 | __u64 period = 1; | 1125 | __u64 period = 1; |
1131 | struct map *map = NULL; | 1126 | struct map *map = NULL; |
1132 | void *more_data = event->ip.__more_data; | 1127 | void *more_data = event->ip.__more_data; |
1133 | struct perf_callchain_entry *chain = NULL; | 1128 | struct ip_callchain *chain = NULL; |
1134 | 1129 | ||
1135 | if (event->header.type & PERF_SAMPLE_PERIOD) { | 1130 | if (event->header.type & PERF_SAMPLE_PERIOD) { |
1136 | period = *(__u64 *)more_data; | 1131 | period = *(__u64 *)more_data; |
@@ -1150,10 +1145,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
1150 | 1145 | ||
1151 | chain = (void *)more_data; | 1146 | chain = (void *)more_data; |
1152 | 1147 | ||
1153 | dprintf("... chain: u:%d, k:%d, nr:%d\n", | 1148 | dprintf("... chain: nr:%Lu\n", chain->nr); |
1154 | chain->user, | ||
1155 | chain->kernel, | ||
1156 | chain->nr); | ||
1157 | 1149 | ||
1158 | if (validate_chain(chain, event) < 0) { | 1150 | if (validate_chain(chain, event) < 0) { |
1159 | eprintf("call-chain problem with event, skipping it.\n"); | 1151 | eprintf("call-chain problem with event, skipping it.\n"); |
@@ -1162,7 +1154,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
1162 | 1154 | ||
1163 | if (dump_trace) { | 1155 | if (dump_trace) { |
1164 | for (i = 0; i < chain->nr; i++) | 1156 | for (i = 0; i < chain->nr; i++) |
1165 | dprintf("..... %2d: %016Lx\n", i, chain->ip[i]); | 1157 | dprintf("..... %2d: %016Lx\n", i, chain->ips[i]); |
1166 | } | 1158 | } |
1167 | } | 1159 | } |
1168 | 1160 | ||