diff options
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r-- | tools/perf/util/machine.c | 210 |
1 files changed, 161 insertions, 49 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index b2ecad6ec46b..6188d2876a71 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -25,12 +25,15 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
25 | machine->kmaps.machine = machine; | 25 | machine->kmaps.machine = machine; |
26 | machine->pid = pid; | 26 | machine->pid = pid; |
27 | 27 | ||
28 | machine->symbol_filter = NULL; | ||
29 | |||
28 | machine->root_dir = strdup(root_dir); | 30 | machine->root_dir = strdup(root_dir); |
29 | if (machine->root_dir == NULL) | 31 | if (machine->root_dir == NULL) |
30 | return -ENOMEM; | 32 | return -ENOMEM; |
31 | 33 | ||
32 | if (pid != HOST_KERNEL_ID) { | 34 | if (pid != HOST_KERNEL_ID) { |
33 | struct thread *thread = machine__findnew_thread(machine, pid); | 35 | struct thread *thread = machine__findnew_thread(machine, 0, |
36 | pid); | ||
34 | char comm[64]; | 37 | char comm[64]; |
35 | 38 | ||
36 | if (thread == NULL) | 39 | if (thread == NULL) |
@@ -95,6 +98,7 @@ void machines__init(struct machines *machines) | |||
95 | { | 98 | { |
96 | machine__init(&machines->host, "", HOST_KERNEL_ID); | 99 | machine__init(&machines->host, "", HOST_KERNEL_ID); |
97 | machines->guests = RB_ROOT; | 100 | machines->guests = RB_ROOT; |
101 | machines->symbol_filter = NULL; | ||
98 | } | 102 | } |
99 | 103 | ||
100 | void machines__exit(struct machines *machines) | 104 | void machines__exit(struct machines *machines) |
@@ -118,6 +122,8 @@ struct machine *machines__add(struct machines *machines, pid_t pid, | |||
118 | return NULL; | 122 | return NULL; |
119 | } | 123 | } |
120 | 124 | ||
125 | machine->symbol_filter = machines->symbol_filter; | ||
126 | |||
121 | while (*p != NULL) { | 127 | while (*p != NULL) { |
122 | parent = *p; | 128 | parent = *p; |
123 | pos = rb_entry(parent, struct machine, rb_node); | 129 | pos = rb_entry(parent, struct machine, rb_node); |
@@ -133,6 +139,21 @@ struct machine *machines__add(struct machines *machines, pid_t pid, | |||
133 | return machine; | 139 | return machine; |
134 | } | 140 | } |
135 | 141 | ||
142 | void machines__set_symbol_filter(struct machines *machines, | ||
143 | symbol_filter_t symbol_filter) | ||
144 | { | ||
145 | struct rb_node *nd; | ||
146 | |||
147 | machines->symbol_filter = symbol_filter; | ||
148 | machines->host.symbol_filter = symbol_filter; | ||
149 | |||
150 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | ||
151 | struct machine *machine = rb_entry(nd, struct machine, rb_node); | ||
152 | |||
153 | machine->symbol_filter = symbol_filter; | ||
154 | } | ||
155 | } | ||
156 | |||
136 | struct machine *machines__find(struct machines *machines, pid_t pid) | 157 | struct machine *machines__find(struct machines *machines, pid_t pid) |
137 | { | 158 | { |
138 | struct rb_node **p = &machines->guests.rb_node; | 159 | struct rb_node **p = &machines->guests.rb_node; |
@@ -233,7 +254,8 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) | |||
233 | return; | 254 | return; |
234 | } | 255 | } |
235 | 256 | ||
236 | static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, | 257 | static struct thread *__machine__findnew_thread(struct machine *machine, |
258 | pid_t pid, pid_t tid, | ||
237 | bool create) | 259 | bool create) |
238 | { | 260 | { |
239 | struct rb_node **p = &machine->threads.rb_node; | 261 | struct rb_node **p = &machine->threads.rb_node; |
@@ -241,23 +263,28 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p | |||
241 | struct thread *th; | 263 | struct thread *th; |
242 | 264 | ||
243 | /* | 265 | /* |
244 | * Font-end cache - PID lookups come in blocks, | 266 | * Front-end cache - TID lookups come in blocks, |
245 | * so most of the time we dont have to look up | 267 | * so most of the time we dont have to look up |
246 | * the full rbtree: | 268 | * the full rbtree: |
247 | */ | 269 | */ |
248 | if (machine->last_match && machine->last_match->pid == pid) | 270 | if (machine->last_match && machine->last_match->tid == tid) { |
271 | if (pid && pid != machine->last_match->pid_) | ||
272 | machine->last_match->pid_ = pid; | ||
249 | return machine->last_match; | 273 | return machine->last_match; |
274 | } | ||
250 | 275 | ||
251 | while (*p != NULL) { | 276 | while (*p != NULL) { |
252 | parent = *p; | 277 | parent = *p; |
253 | th = rb_entry(parent, struct thread, rb_node); | 278 | th = rb_entry(parent, struct thread, rb_node); |
254 | 279 | ||
255 | if (th->pid == pid) { | 280 | if (th->tid == tid) { |
256 | machine->last_match = th; | 281 | machine->last_match = th; |
282 | if (pid && pid != th->pid_) | ||
283 | th->pid_ = pid; | ||
257 | return th; | 284 | return th; |
258 | } | 285 | } |
259 | 286 | ||
260 | if (pid < th->pid) | 287 | if (tid < th->tid) |
261 | p = &(*p)->rb_left; | 288 | p = &(*p)->rb_left; |
262 | else | 289 | else |
263 | p = &(*p)->rb_right; | 290 | p = &(*p)->rb_right; |
@@ -266,7 +293,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p | |||
266 | if (!create) | 293 | if (!create) |
267 | return NULL; | 294 | return NULL; |
268 | 295 | ||
269 | th = thread__new(pid); | 296 | th = thread__new(pid, tid); |
270 | if (th != NULL) { | 297 | if (th != NULL) { |
271 | rb_link_node(&th->rb_node, parent, p); | 298 | rb_link_node(&th->rb_node, parent, p); |
272 | rb_insert_color(&th->rb_node, &machine->threads); | 299 | rb_insert_color(&th->rb_node, &machine->threads); |
@@ -276,19 +303,22 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p | |||
276 | return th; | 303 | return th; |
277 | } | 304 | } |
278 | 305 | ||
279 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) | 306 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, |
307 | pid_t tid) | ||
280 | { | 308 | { |
281 | return __machine__findnew_thread(machine, pid, true); | 309 | return __machine__findnew_thread(machine, pid, tid, true); |
282 | } | 310 | } |
283 | 311 | ||
284 | struct thread *machine__find_thread(struct machine *machine, pid_t pid) | 312 | struct thread *machine__find_thread(struct machine *machine, pid_t tid) |
285 | { | 313 | { |
286 | return __machine__findnew_thread(machine, pid, false); | 314 | return __machine__findnew_thread(machine, 0, tid, false); |
287 | } | 315 | } |
288 | 316 | ||
289 | int machine__process_comm_event(struct machine *machine, union perf_event *event) | 317 | int machine__process_comm_event(struct machine *machine, union perf_event *event) |
290 | { | 318 | { |
291 | struct thread *thread = machine__findnew_thread(machine, event->comm.tid); | 319 | struct thread *thread = machine__findnew_thread(machine, |
320 | event->comm.pid, | ||
321 | event->comm.tid); | ||
292 | 322 | ||
293 | if (dump_trace) | 323 | if (dump_trace) |
294 | perf_event__fprintf_comm(event, stdout); | 324 | perf_event__fprintf_comm(event, stdout); |
@@ -628,10 +658,8 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | |||
628 | struct map *map = machine->vmlinux_maps[type]; | 658 | struct map *map = machine->vmlinux_maps[type]; |
629 | int ret = dso__load_vmlinux_path(map->dso, map, filter); | 659 | int ret = dso__load_vmlinux_path(map->dso, map, filter); |
630 | 660 | ||
631 | if (ret > 0) { | 661 | if (ret > 0) |
632 | dso__set_loaded(map->dso, type); | 662 | dso__set_loaded(map->dso, type); |
633 | map__reloc_vmlinux(map); | ||
634 | } | ||
635 | 663 | ||
636 | return ret; | 664 | return ret; |
637 | } | 665 | } |
@@ -764,7 +792,7 @@ static int machine__create_modules(struct machine *machine) | |||
764 | modules = path; | 792 | modules = path; |
765 | } | 793 | } |
766 | 794 | ||
767 | if (symbol__restricted_filename(path, "/proc/modules")) | 795 | if (symbol__restricted_filename(modules, "/proc/modules")) |
768 | return -1; | 796 | return -1; |
769 | 797 | ||
770 | file = fopen(modules, "r"); | 798 | file = fopen(modules, "r"); |
@@ -808,7 +836,10 @@ static int machine__create_modules(struct machine *machine) | |||
808 | free(line); | 836 | free(line); |
809 | fclose(file); | 837 | fclose(file); |
810 | 838 | ||
811 | return machine__set_modules_path(machine); | 839 | if (machine__set_modules_path(machine) < 0) { |
840 | pr_debug("Problems setting modules path maps, continuing anyway...\n"); | ||
841 | } | ||
842 | return 0; | ||
812 | 843 | ||
813 | out_delete_line: | 844 | out_delete_line: |
814 | free(line); | 845 | free(line); |
@@ -858,6 +889,18 @@ static void machine__set_kernel_mmap_len(struct machine *machine, | |||
858 | } | 889 | } |
859 | } | 890 | } |
860 | 891 | ||
892 | static bool machine__uses_kcore(struct machine *machine) | ||
893 | { | ||
894 | struct dso *dso; | ||
895 | |||
896 | list_for_each_entry(dso, &machine->kernel_dsos, node) { | ||
897 | if (dso__is_kcore(dso)) | ||
898 | return true; | ||
899 | } | ||
900 | |||
901 | return false; | ||
902 | } | ||
903 | |||
861 | static int machine__process_kernel_mmap_event(struct machine *machine, | 904 | static int machine__process_kernel_mmap_event(struct machine *machine, |
862 | union perf_event *event) | 905 | union perf_event *event) |
863 | { | 906 | { |
@@ -866,6 +909,10 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
866 | enum dso_kernel_type kernel_type; | 909 | enum dso_kernel_type kernel_type; |
867 | bool is_kernel_mmap; | 910 | bool is_kernel_mmap; |
868 | 911 | ||
912 | /* If we have maps from kcore then we do not need or want any others */ | ||
913 | if (machine__uses_kcore(machine)) | ||
914 | return 0; | ||
915 | |||
869 | machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); | 916 | machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); |
870 | if (machine__is_host(machine)) | 917 | if (machine__is_host(machine)) |
871 | kernel_type = DSO_TYPE_KERNEL; | 918 | kernel_type = DSO_TYPE_KERNEL; |
@@ -950,6 +997,54 @@ out_problem: | |||
950 | return -1; | 997 | return -1; |
951 | } | 998 | } |
952 | 999 | ||
1000 | int machine__process_mmap2_event(struct machine *machine, | ||
1001 | union perf_event *event) | ||
1002 | { | ||
1003 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
1004 | struct thread *thread; | ||
1005 | struct map *map; | ||
1006 | enum map_type type; | ||
1007 | int ret = 0; | ||
1008 | |||
1009 | if (dump_trace) | ||
1010 | perf_event__fprintf_mmap2(event, stdout); | ||
1011 | |||
1012 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || | ||
1013 | cpumode == PERF_RECORD_MISC_KERNEL) { | ||
1014 | ret = machine__process_kernel_mmap_event(machine, event); | ||
1015 | if (ret < 0) | ||
1016 | goto out_problem; | ||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | thread = machine__findnew_thread(machine, event->mmap2.pid, | ||
1021 | event->mmap2.pid); | ||
1022 | if (thread == NULL) | ||
1023 | goto out_problem; | ||
1024 | |||
1025 | if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) | ||
1026 | type = MAP__VARIABLE; | ||
1027 | else | ||
1028 | type = MAP__FUNCTION; | ||
1029 | |||
1030 | map = map__new(&machine->user_dsos, event->mmap2.start, | ||
1031 | event->mmap2.len, event->mmap2.pgoff, | ||
1032 | event->mmap2.pid, event->mmap2.maj, | ||
1033 | event->mmap2.min, event->mmap2.ino, | ||
1034 | event->mmap2.ino_generation, | ||
1035 | event->mmap2.filename, type); | ||
1036 | |||
1037 | if (map == NULL) | ||
1038 | goto out_problem; | ||
1039 | |||
1040 | thread__insert_map(thread, map); | ||
1041 | return 0; | ||
1042 | |||
1043 | out_problem: | ||
1044 | dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n"); | ||
1045 | return 0; | ||
1046 | } | ||
1047 | |||
953 | int machine__process_mmap_event(struct machine *machine, union perf_event *event) | 1048 | int machine__process_mmap_event(struct machine *machine, union perf_event *event) |
954 | { | 1049 | { |
955 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 1050 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
@@ -969,7 +1064,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event | |||
969 | return 0; | 1064 | return 0; |
970 | } | 1065 | } |
971 | 1066 | ||
972 | thread = machine__findnew_thread(machine, event->mmap.pid); | 1067 | thread = machine__findnew_thread(machine, event->mmap.pid, |
1068 | event->mmap.pid); | ||
973 | if (thread == NULL) | 1069 | if (thread == NULL) |
974 | goto out_problem; | 1070 | goto out_problem; |
975 | 1071 | ||
@@ -980,7 +1076,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event | |||
980 | 1076 | ||
981 | map = map__new(&machine->user_dsos, event->mmap.start, | 1077 | map = map__new(&machine->user_dsos, event->mmap.start, |
982 | event->mmap.len, event->mmap.pgoff, | 1078 | event->mmap.len, event->mmap.pgoff, |
983 | event->mmap.pid, event->mmap.filename, | 1079 | event->mmap.pid, 0, 0, 0, 0, |
1080 | event->mmap.filename, | ||
984 | type); | 1081 | type); |
985 | 1082 | ||
986 | if (map == NULL) | 1083 | if (map == NULL) |
@@ -994,11 +1091,30 @@ out_problem: | |||
994 | return 0; | 1091 | return 0; |
995 | } | 1092 | } |
996 | 1093 | ||
1094 | static void machine__remove_thread(struct machine *machine, struct thread *th) | ||
1095 | { | ||
1096 | machine->last_match = NULL; | ||
1097 | rb_erase(&th->rb_node, &machine->threads); | ||
1098 | /* | ||
1099 | * We may have references to this thread, for instance in some hist_entry | ||
1100 | * instances, so just move them to a separate list. | ||
1101 | */ | ||
1102 | list_add_tail(&th->node, &machine->dead_threads); | ||
1103 | } | ||
1104 | |||
997 | int machine__process_fork_event(struct machine *machine, union perf_event *event) | 1105 | int machine__process_fork_event(struct machine *machine, union perf_event *event) |
998 | { | 1106 | { |
999 | struct thread *thread = machine__findnew_thread(machine, event->fork.tid); | 1107 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
1000 | struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); | 1108 | struct thread *parent = machine__findnew_thread(machine, |
1109 | event->fork.ppid, | ||
1110 | event->fork.ptid); | ||
1001 | 1111 | ||
1112 | /* if a thread currently exists for the thread id remove it */ | ||
1113 | if (thread != NULL) | ||
1114 | machine__remove_thread(machine, thread); | ||
1115 | |||
1116 | thread = machine__findnew_thread(machine, event->fork.pid, | ||
1117 | event->fork.tid); | ||
1002 | if (dump_trace) | 1118 | if (dump_trace) |
1003 | perf_event__fprintf_task(event, stdout); | 1119 | perf_event__fprintf_task(event, stdout); |
1004 | 1120 | ||
@@ -1011,18 +1127,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1011 | return 0; | 1127 | return 0; |
1012 | } | 1128 | } |
1013 | 1129 | ||
1014 | static void machine__remove_thread(struct machine *machine, struct thread *th) | 1130 | int machine__process_exit_event(struct machine *machine __maybe_unused, |
1015 | { | 1131 | union perf_event *event) |
1016 | machine->last_match = NULL; | ||
1017 | rb_erase(&th->rb_node, &machine->threads); | ||
1018 | /* | ||
1019 | * We may have references to this thread, for instance in some hist_entry | ||
1020 | * instances, so just move them to a separate list. | ||
1021 | */ | ||
1022 | list_add_tail(&th->node, &machine->dead_threads); | ||
1023 | } | ||
1024 | |||
1025 | int machine__process_exit_event(struct machine *machine, union perf_event *event) | ||
1026 | { | 1132 | { |
1027 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | 1133 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
1028 | 1134 | ||
@@ -1030,7 +1136,7 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event | |||
1030 | perf_event__fprintf_task(event, stdout); | 1136 | perf_event__fprintf_task(event, stdout); |
1031 | 1137 | ||
1032 | if (thread != NULL) | 1138 | if (thread != NULL) |
1033 | machine__remove_thread(machine, thread); | 1139 | thread__exited(thread); |
1034 | 1140 | ||
1035 | return 0; | 1141 | return 0; |
1036 | } | 1142 | } |
@@ -1044,6 +1150,8 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
1044 | ret = machine__process_comm_event(machine, event); break; | 1150 | ret = machine__process_comm_event(machine, event); break; |
1045 | case PERF_RECORD_MMAP: | 1151 | case PERF_RECORD_MMAP: |
1046 | ret = machine__process_mmap_event(machine, event); break; | 1152 | ret = machine__process_mmap_event(machine, event); break; |
1153 | case PERF_RECORD_MMAP2: | ||
1154 | ret = machine__process_mmap2_event(machine, event); break; | ||
1047 | case PERF_RECORD_FORK: | 1155 | case PERF_RECORD_FORK: |
1048 | ret = machine__process_fork_event(machine, event); break; | 1156 | ret = machine__process_fork_event(machine, event); break; |
1049 | case PERF_RECORD_EXIT: | 1157 | case PERF_RECORD_EXIT: |
@@ -1058,11 +1166,10 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
1058 | return ret; | 1166 | return ret; |
1059 | } | 1167 | } |
1060 | 1168 | ||
1061 | static bool symbol__match_parent_regex(struct symbol *sym) | 1169 | static bool symbol__match_regex(struct symbol *sym, regex_t *regex) |
1062 | { | 1170 | { |
1063 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | 1171 | if (sym->name && !regexec(regex, sym->name, 0, NULL, 0)) |
1064 | return 1; | 1172 | return 1; |
1065 | |||
1066 | return 0; | 1173 | return 0; |
1067 | } | 1174 | } |
1068 | 1175 | ||
@@ -1094,7 +1201,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread, | |||
1094 | * or else, the symbol is unknown | 1201 | * or else, the symbol is unknown |
1095 | */ | 1202 | */ |
1096 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, | 1203 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, |
1097 | ip, &al, NULL); | 1204 | ip, &al); |
1098 | if (al.sym) | 1205 | if (al.sym) |
1099 | goto found; | 1206 | goto found; |
1100 | } | 1207 | } |
@@ -1112,8 +1219,8 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread, | |||
1112 | 1219 | ||
1113 | memset(&al, 0, sizeof(al)); | 1220 | memset(&al, 0, sizeof(al)); |
1114 | 1221 | ||
1115 | thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al, | 1222 | thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, |
1116 | NULL); | 1223 | &al); |
1117 | ams->addr = addr; | 1224 | ams->addr = addr; |
1118 | ams->al_addr = al.addr; | 1225 | ams->al_addr = al.addr; |
1119 | ams->sym = al.sym; | 1226 | ams->sym = al.sym; |
@@ -1159,8 +1266,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine, | |||
1159 | static int machine__resolve_callchain_sample(struct machine *machine, | 1266 | static int machine__resolve_callchain_sample(struct machine *machine, |
1160 | struct thread *thread, | 1267 | struct thread *thread, |
1161 | struct ip_callchain *chain, | 1268 | struct ip_callchain *chain, |
1162 | struct symbol **parent) | 1269 | struct symbol **parent, |
1163 | 1270 | struct addr_location *root_al) | |
1164 | { | 1271 | { |
1165 | u8 cpumode = PERF_RECORD_MISC_USER; | 1272 | u8 cpumode = PERF_RECORD_MISC_USER; |
1166 | unsigned int i; | 1273 | unsigned int i; |
@@ -1208,11 +1315,18 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1208 | 1315 | ||
1209 | al.filtered = false; | 1316 | al.filtered = false; |
1210 | thread__find_addr_location(thread, machine, cpumode, | 1317 | thread__find_addr_location(thread, machine, cpumode, |
1211 | MAP__FUNCTION, ip, &al, NULL); | 1318 | MAP__FUNCTION, ip, &al); |
1212 | if (al.sym != NULL) { | 1319 | if (al.sym != NULL) { |
1213 | if (sort__has_parent && !*parent && | 1320 | if (sort__has_parent && !*parent && |
1214 | symbol__match_parent_regex(al.sym)) | 1321 | symbol__match_regex(al.sym, &parent_regex)) |
1215 | *parent = al.sym; | 1322 | *parent = al.sym; |
1323 | else if (have_ignore_callees && root_al && | ||
1324 | symbol__match_regex(al.sym, &ignore_callees_regex)) { | ||
1325 | /* Treat this symbol as the root, | ||
1326 | forgetting its callees. */ | ||
1327 | *root_al = al; | ||
1328 | callchain_cursor_reset(&callchain_cursor); | ||
1329 | } | ||
1216 | if (!symbol_conf.use_callchain) | 1330 | if (!symbol_conf.use_callchain) |
1217 | break; | 1331 | break; |
1218 | } | 1332 | } |
@@ -1237,15 +1351,13 @@ int machine__resolve_callchain(struct machine *machine, | |||
1237 | struct perf_evsel *evsel, | 1351 | struct perf_evsel *evsel, |
1238 | struct thread *thread, | 1352 | struct thread *thread, |
1239 | struct perf_sample *sample, | 1353 | struct perf_sample *sample, |
1240 | struct symbol **parent) | 1354 | struct symbol **parent, |
1241 | 1355 | struct addr_location *root_al) | |
1242 | { | 1356 | { |
1243 | int ret; | 1357 | int ret; |
1244 | 1358 | ||
1245 | callchain_cursor_reset(&callchain_cursor); | ||
1246 | |||
1247 | ret = machine__resolve_callchain_sample(machine, thread, | 1359 | ret = machine__resolve_callchain_sample(machine, thread, |
1248 | sample->callchain, parent); | 1360 | sample->callchain, parent, root_al); |
1249 | if (ret) | 1361 | if (ret) |
1250 | return ret; | 1362 | return ret; |
1251 | 1363 | ||