aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r--tools/perf/util/machine.c210
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
100void machines__exit(struct machines *machines) 104void 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
142void 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
136struct machine *machines__find(struct machines *machines, pid_t pid) 157struct 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
236static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, 257static 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
279struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) 306struct 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
284struct thread *machine__find_thread(struct machine *machine, pid_t pid) 312struct 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
289int machine__process_comm_event(struct machine *machine, union perf_event *event) 317int 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
813out_delete_line: 844out_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
892static 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
861static int machine__process_kernel_mmap_event(struct machine *machine, 904static 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
1000int 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
1043out_problem:
1044 dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
1045 return 0;
1046}
1047
953int machine__process_mmap_event(struct machine *machine, union perf_event *event) 1048int 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
1094static 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
997int machine__process_fork_event(struct machine *machine, union perf_event *event) 1105int 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
1014static void machine__remove_thread(struct machine *machine, struct thread *th) 1130int 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
1025int 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
1061static bool symbol__match_parent_regex(struct symbol *sym) 1169static 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,
1159static int machine__resolve_callchain_sample(struct machine *machine, 1266static 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