diff options
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r-- | tools/perf/util/machine.c | 155 |
1 files changed, 108 insertions, 47 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index b2ecad6ec46b..1dca61f0512d 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 | } |
@@ -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; |
@@ -969,7 +1016,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event | |||
969 | return 0; | 1016 | return 0; |
970 | } | 1017 | } |
971 | 1018 | ||
972 | thread = machine__findnew_thread(machine, event->mmap.pid); | 1019 | thread = machine__findnew_thread(machine, event->mmap.pid, |
1020 | event->mmap.pid); | ||
973 | if (thread == NULL) | 1021 | if (thread == NULL) |
974 | goto out_problem; | 1022 | goto out_problem; |
975 | 1023 | ||
@@ -994,11 +1042,30 @@ out_problem: | |||
994 | return 0; | 1042 | return 0; |
995 | } | 1043 | } |
996 | 1044 | ||
1045 | static void machine__remove_thread(struct machine *machine, struct thread *th) | ||
1046 | { | ||
1047 | machine->last_match = NULL; | ||
1048 | rb_erase(&th->rb_node, &machine->threads); | ||
1049 | /* | ||
1050 | * We may have references to this thread, for instance in some hist_entry | ||
1051 | * instances, so just move them to a separate list. | ||
1052 | */ | ||
1053 | list_add_tail(&th->node, &machine->dead_threads); | ||
1054 | } | ||
1055 | |||
997 | int machine__process_fork_event(struct machine *machine, union perf_event *event) | 1056 | int machine__process_fork_event(struct machine *machine, union perf_event *event) |
998 | { | 1057 | { |
999 | struct thread *thread = machine__findnew_thread(machine, event->fork.tid); | 1058 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
1000 | struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); | 1059 | struct thread *parent = machine__findnew_thread(machine, |
1060 | event->fork.ppid, | ||
1061 | event->fork.ptid); | ||
1001 | 1062 | ||
1063 | /* if a thread currently exists for the thread id remove it */ | ||
1064 | if (thread != NULL) | ||
1065 | machine__remove_thread(machine, thread); | ||
1066 | |||
1067 | thread = machine__findnew_thread(machine, event->fork.pid, | ||
1068 | event->fork.tid); | ||
1002 | if (dump_trace) | 1069 | if (dump_trace) |
1003 | perf_event__fprintf_task(event, stdout); | 1070 | perf_event__fprintf_task(event, stdout); |
1004 | 1071 | ||
@@ -1011,18 +1078,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1011 | return 0; | 1078 | return 0; |
1012 | } | 1079 | } |
1013 | 1080 | ||
1014 | static void machine__remove_thread(struct machine *machine, struct thread *th) | 1081 | int machine__process_exit_event(struct machine *machine __maybe_unused, |
1015 | { | 1082 | 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 | { | 1083 | { |
1027 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | 1084 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
1028 | 1085 | ||
@@ -1030,7 +1087,7 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event | |||
1030 | perf_event__fprintf_task(event, stdout); | 1087 | perf_event__fprintf_task(event, stdout); |
1031 | 1088 | ||
1032 | if (thread != NULL) | 1089 | if (thread != NULL) |
1033 | machine__remove_thread(machine, thread); | 1090 | thread__exited(thread); |
1034 | 1091 | ||
1035 | return 0; | 1092 | return 0; |
1036 | } | 1093 | } |
@@ -1058,11 +1115,10 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
1058 | return ret; | 1115 | return ret; |
1059 | } | 1116 | } |
1060 | 1117 | ||
1061 | static bool symbol__match_parent_regex(struct symbol *sym) | 1118 | static bool symbol__match_regex(struct symbol *sym, regex_t *regex) |
1062 | { | 1119 | { |
1063 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | 1120 | if (sym->name && !regexec(regex, sym->name, 0, NULL, 0)) |
1064 | return 1; | 1121 | return 1; |
1065 | |||
1066 | return 0; | 1122 | return 0; |
1067 | } | 1123 | } |
1068 | 1124 | ||
@@ -1094,7 +1150,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread, | |||
1094 | * or else, the symbol is unknown | 1150 | * or else, the symbol is unknown |
1095 | */ | 1151 | */ |
1096 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, | 1152 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, |
1097 | ip, &al, NULL); | 1153 | ip, &al); |
1098 | if (al.sym) | 1154 | if (al.sym) |
1099 | goto found; | 1155 | goto found; |
1100 | } | 1156 | } |
@@ -1112,8 +1168,8 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread, | |||
1112 | 1168 | ||
1113 | memset(&al, 0, sizeof(al)); | 1169 | memset(&al, 0, sizeof(al)); |
1114 | 1170 | ||
1115 | thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al, | 1171 | thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, |
1116 | NULL); | 1172 | &al); |
1117 | ams->addr = addr; | 1173 | ams->addr = addr; |
1118 | ams->al_addr = al.addr; | 1174 | ams->al_addr = al.addr; |
1119 | ams->sym = al.sym; | 1175 | ams->sym = al.sym; |
@@ -1159,8 +1215,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine, | |||
1159 | static int machine__resolve_callchain_sample(struct machine *machine, | 1215 | static int machine__resolve_callchain_sample(struct machine *machine, |
1160 | struct thread *thread, | 1216 | struct thread *thread, |
1161 | struct ip_callchain *chain, | 1217 | struct ip_callchain *chain, |
1162 | struct symbol **parent) | 1218 | struct symbol **parent, |
1163 | 1219 | struct addr_location *root_al) | |
1164 | { | 1220 | { |
1165 | u8 cpumode = PERF_RECORD_MISC_USER; | 1221 | u8 cpumode = PERF_RECORD_MISC_USER; |
1166 | unsigned int i; | 1222 | unsigned int i; |
@@ -1208,11 +1264,18 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1208 | 1264 | ||
1209 | al.filtered = false; | 1265 | al.filtered = false; |
1210 | thread__find_addr_location(thread, machine, cpumode, | 1266 | thread__find_addr_location(thread, machine, cpumode, |
1211 | MAP__FUNCTION, ip, &al, NULL); | 1267 | MAP__FUNCTION, ip, &al); |
1212 | if (al.sym != NULL) { | 1268 | if (al.sym != NULL) { |
1213 | if (sort__has_parent && !*parent && | 1269 | if (sort__has_parent && !*parent && |
1214 | symbol__match_parent_regex(al.sym)) | 1270 | symbol__match_regex(al.sym, &parent_regex)) |
1215 | *parent = al.sym; | 1271 | *parent = al.sym; |
1272 | else if (have_ignore_callees && root_al && | ||
1273 | symbol__match_regex(al.sym, &ignore_callees_regex)) { | ||
1274 | /* Treat this symbol as the root, | ||
1275 | forgetting its callees. */ | ||
1276 | *root_al = al; | ||
1277 | callchain_cursor_reset(&callchain_cursor); | ||
1278 | } | ||
1216 | if (!symbol_conf.use_callchain) | 1279 | if (!symbol_conf.use_callchain) |
1217 | break; | 1280 | break; |
1218 | } | 1281 | } |
@@ -1237,15 +1300,13 @@ int machine__resolve_callchain(struct machine *machine, | |||
1237 | struct perf_evsel *evsel, | 1300 | struct perf_evsel *evsel, |
1238 | struct thread *thread, | 1301 | struct thread *thread, |
1239 | struct perf_sample *sample, | 1302 | struct perf_sample *sample, |
1240 | struct symbol **parent) | 1303 | struct symbol **parent, |
1241 | 1304 | struct addr_location *root_al) | |
1242 | { | 1305 | { |
1243 | int ret; | 1306 | int ret; |
1244 | 1307 | ||
1245 | callchain_cursor_reset(&callchain_cursor); | ||
1246 | |||
1247 | ret = machine__resolve_callchain_sample(machine, thread, | 1308 | ret = machine__resolve_callchain_sample(machine, thread, |
1248 | sample->callchain, parent); | 1309 | sample->callchain, parent, root_al); |
1249 | if (ret) | 1310 | if (ret) |
1250 | return ret; | 1311 | return ret; |
1251 | 1312 | ||