diff options
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r-- | tools/perf/util/machine.c | 180 |
1 files changed, 105 insertions, 75 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 6188d2876a71..84cdb072ac83 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -40,12 +40,29 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
40 | return -ENOMEM; | 40 | return -ENOMEM; |
41 | 41 | ||
42 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); | 42 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); |
43 | thread__set_comm(thread, comm); | 43 | thread__set_comm(thread, comm, 0); |
44 | } | 44 | } |
45 | 45 | ||
46 | return 0; | 46 | return 0; |
47 | } | 47 | } |
48 | 48 | ||
49 | struct machine *machine__new_host(void) | ||
50 | { | ||
51 | struct machine *machine = malloc(sizeof(*machine)); | ||
52 | |||
53 | if (machine != NULL) { | ||
54 | machine__init(machine, "", HOST_KERNEL_ID); | ||
55 | |||
56 | if (machine__create_kernel_maps(machine) < 0) | ||
57 | goto out_delete; | ||
58 | } | ||
59 | |||
60 | return machine; | ||
61 | out_delete: | ||
62 | free(machine); | ||
63 | return NULL; | ||
64 | } | ||
65 | |||
49 | static void dsos__delete(struct list_head *dsos) | 66 | static void dsos__delete(struct list_head *dsos) |
50 | { | 67 | { |
51 | struct dso *pos, *n; | 68 | struct dso *pos, *n; |
@@ -314,7 +331,8 @@ struct thread *machine__find_thread(struct machine *machine, pid_t tid) | |||
314 | return __machine__findnew_thread(machine, 0, tid, false); | 331 | return __machine__findnew_thread(machine, 0, tid, false); |
315 | } | 332 | } |
316 | 333 | ||
317 | int machine__process_comm_event(struct machine *machine, union perf_event *event) | 334 | int machine__process_comm_event(struct machine *machine, union perf_event *event, |
335 | struct perf_sample *sample) | ||
318 | { | 336 | { |
319 | struct thread *thread = machine__findnew_thread(machine, | 337 | struct thread *thread = machine__findnew_thread(machine, |
320 | event->comm.pid, | 338 | event->comm.pid, |
@@ -323,7 +341,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event | |||
323 | if (dump_trace) | 341 | if (dump_trace) |
324 | perf_event__fprintf_comm(event, stdout); | 342 | perf_event__fprintf_comm(event, stdout); |
325 | 343 | ||
326 | if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { | 344 | if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) { |
327 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); | 345 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); |
328 | return -1; | 346 | return -1; |
329 | } | 347 | } |
@@ -332,7 +350,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event | |||
332 | } | 350 | } |
333 | 351 | ||
334 | int machine__process_lost_event(struct machine *machine __maybe_unused, | 352 | int machine__process_lost_event(struct machine *machine __maybe_unused, |
335 | union perf_event *event) | 353 | union perf_event *event, struct perf_sample *sample __maybe_unused) |
336 | { | 354 | { |
337 | dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", | 355 | dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", |
338 | event->lost.id, event->lost.lost); | 356 | event->lost.id, event->lost.lost); |
@@ -776,75 +794,44 @@ static int machine__set_modules_path(struct machine *machine) | |||
776 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); | 794 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); |
777 | } | 795 | } |
778 | 796 | ||
779 | static int machine__create_modules(struct machine *machine) | 797 | static int machine__create_module(void *arg, const char *name, u64 start) |
780 | { | 798 | { |
781 | char *line = NULL; | 799 | struct machine *machine = arg; |
782 | size_t n; | ||
783 | FILE *file; | ||
784 | struct map *map; | 800 | struct map *map; |
801 | |||
802 | map = machine__new_module(machine, start, name); | ||
803 | if (map == NULL) | ||
804 | return -1; | ||
805 | |||
806 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); | ||
807 | |||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | static int machine__create_modules(struct machine *machine) | ||
812 | { | ||
785 | const char *modules; | 813 | const char *modules; |
786 | char path[PATH_MAX]; | 814 | char path[PATH_MAX]; |
787 | 815 | ||
788 | if (machine__is_default_guest(machine)) | 816 | if (machine__is_default_guest(machine)) { |
789 | modules = symbol_conf.default_guest_modules; | 817 | modules = symbol_conf.default_guest_modules; |
790 | else { | 818 | } else { |
791 | sprintf(path, "%s/proc/modules", machine->root_dir); | 819 | snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir); |
792 | modules = path; | 820 | modules = path; |
793 | } | 821 | } |
794 | 822 | ||
795 | if (symbol__restricted_filename(modules, "/proc/modules")) | 823 | if (symbol__restricted_filename(modules, "/proc/modules")) |
796 | return -1; | 824 | return -1; |
797 | 825 | ||
798 | file = fopen(modules, "r"); | 826 | if (modules__parse(modules, machine, machine__create_module)) |
799 | if (file == NULL) | ||
800 | return -1; | 827 | return -1; |
801 | 828 | ||
802 | while (!feof(file)) { | 829 | if (!machine__set_modules_path(machine)) |
803 | char name[PATH_MAX]; | 830 | return 0; |
804 | u64 start; | ||
805 | char *sep; | ||
806 | int line_len; | ||
807 | |||
808 | line_len = getline(&line, &n, file); | ||
809 | if (line_len < 0) | ||
810 | break; | ||
811 | |||
812 | if (!line) | ||
813 | goto out_failure; | ||
814 | |||
815 | line[--line_len] = '\0'; /* \n */ | ||
816 | |||
817 | sep = strrchr(line, 'x'); | ||
818 | if (sep == NULL) | ||
819 | continue; | ||
820 | |||
821 | hex2u64(sep + 1, &start); | ||
822 | |||
823 | sep = strchr(line, ' '); | ||
824 | if (sep == NULL) | ||
825 | continue; | ||
826 | |||
827 | *sep = '\0'; | ||
828 | |||
829 | snprintf(name, sizeof(name), "[%s]", line); | ||
830 | map = machine__new_module(machine, start, name); | ||
831 | if (map == NULL) | ||
832 | goto out_delete_line; | ||
833 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); | ||
834 | } | ||
835 | 831 | ||
836 | free(line); | 832 | pr_debug("Problems setting modules path maps, continuing anyway...\n"); |
837 | fclose(file); | ||
838 | 833 | ||
839 | if (machine__set_modules_path(machine) < 0) { | ||
840 | pr_debug("Problems setting modules path maps, continuing anyway...\n"); | ||
841 | } | ||
842 | return 0; | 834 | return 0; |
843 | |||
844 | out_delete_line: | ||
845 | free(line); | ||
846 | out_failure: | ||
847 | return -1; | ||
848 | } | 835 | } |
849 | 836 | ||
850 | int machine__create_kernel_maps(struct machine *machine) | 837 | int machine__create_kernel_maps(struct machine *machine) |
@@ -998,7 +985,8 @@ out_problem: | |||
998 | } | 985 | } |
999 | 986 | ||
1000 | int machine__process_mmap2_event(struct machine *machine, | 987 | int machine__process_mmap2_event(struct machine *machine, |
1001 | union perf_event *event) | 988 | union perf_event *event, |
989 | struct perf_sample *sample __maybe_unused) | ||
1002 | { | 990 | { |
1003 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 991 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
1004 | struct thread *thread; | 992 | struct thread *thread; |
@@ -1045,7 +1033,8 @@ out_problem: | |||
1045 | return 0; | 1033 | return 0; |
1046 | } | 1034 | } |
1047 | 1035 | ||
1048 | int machine__process_mmap_event(struct machine *machine, union perf_event *event) | 1036 | int machine__process_mmap_event(struct machine *machine, union perf_event *event, |
1037 | struct perf_sample *sample __maybe_unused) | ||
1049 | { | 1038 | { |
1050 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 1039 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
1051 | struct thread *thread; | 1040 | struct thread *thread; |
@@ -1102,7 +1091,8 @@ static void machine__remove_thread(struct machine *machine, struct thread *th) | |||
1102 | list_add_tail(&th->node, &machine->dead_threads); | 1091 | list_add_tail(&th->node, &machine->dead_threads); |
1103 | } | 1092 | } |
1104 | 1093 | ||
1105 | int machine__process_fork_event(struct machine *machine, union perf_event *event) | 1094 | int machine__process_fork_event(struct machine *machine, union perf_event *event, |
1095 | struct perf_sample *sample) | ||
1106 | { | 1096 | { |
1107 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | 1097 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
1108 | struct thread *parent = machine__findnew_thread(machine, | 1098 | struct thread *parent = machine__findnew_thread(machine, |
@@ -1119,7 +1109,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1119 | perf_event__fprintf_task(event, stdout); | 1109 | perf_event__fprintf_task(event, stdout); |
1120 | 1110 | ||
1121 | if (thread == NULL || parent == NULL || | 1111 | if (thread == NULL || parent == NULL || |
1122 | thread__fork(thread, parent) < 0) { | 1112 | thread__fork(thread, parent, sample->time) < 0) { |
1123 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); | 1113 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); |
1124 | return -1; | 1114 | return -1; |
1125 | } | 1115 | } |
@@ -1127,8 +1117,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1127 | return 0; | 1117 | return 0; |
1128 | } | 1118 | } |
1129 | 1119 | ||
1130 | int machine__process_exit_event(struct machine *machine __maybe_unused, | 1120 | int machine__process_exit_event(struct machine *machine, union perf_event *event, |
1131 | union perf_event *event) | 1121 | struct perf_sample *sample __maybe_unused) |
1132 | { | 1122 | { |
1133 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | 1123 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
1134 | 1124 | ||
@@ -1141,23 +1131,24 @@ int machine__process_exit_event(struct machine *machine __maybe_unused, | |||
1141 | return 0; | 1131 | return 0; |
1142 | } | 1132 | } |
1143 | 1133 | ||
1144 | int machine__process_event(struct machine *machine, union perf_event *event) | 1134 | int machine__process_event(struct machine *machine, union perf_event *event, |
1135 | struct perf_sample *sample) | ||
1145 | { | 1136 | { |
1146 | int ret; | 1137 | int ret; |
1147 | 1138 | ||
1148 | switch (event->header.type) { | 1139 | switch (event->header.type) { |
1149 | case PERF_RECORD_COMM: | 1140 | case PERF_RECORD_COMM: |
1150 | ret = machine__process_comm_event(machine, event); break; | 1141 | ret = machine__process_comm_event(machine, event, sample); break; |
1151 | case PERF_RECORD_MMAP: | 1142 | case PERF_RECORD_MMAP: |
1152 | ret = machine__process_mmap_event(machine, event); break; | 1143 | ret = machine__process_mmap_event(machine, event, sample); break; |
1153 | case PERF_RECORD_MMAP2: | 1144 | case PERF_RECORD_MMAP2: |
1154 | ret = machine__process_mmap2_event(machine, event); break; | 1145 | ret = machine__process_mmap2_event(machine, event, sample); break; |
1155 | case PERF_RECORD_FORK: | 1146 | case PERF_RECORD_FORK: |
1156 | ret = machine__process_fork_event(machine, event); break; | 1147 | ret = machine__process_fork_event(machine, event, sample); break; |
1157 | case PERF_RECORD_EXIT: | 1148 | case PERF_RECORD_EXIT: |
1158 | ret = machine__process_exit_event(machine, event); break; | 1149 | ret = machine__process_exit_event(machine, event, sample); break; |
1159 | case PERF_RECORD_LOST: | 1150 | case PERF_RECORD_LOST: |
1160 | ret = machine__process_lost_event(machine, event); break; | 1151 | ret = machine__process_lost_event(machine, event, sample); break; |
1161 | default: | 1152 | default: |
1162 | ret = -1; | 1153 | ret = -1; |
1163 | break; | 1154 | break; |
@@ -1267,10 +1258,12 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1267 | struct thread *thread, | 1258 | struct thread *thread, |
1268 | struct ip_callchain *chain, | 1259 | struct ip_callchain *chain, |
1269 | struct symbol **parent, | 1260 | struct symbol **parent, |
1270 | struct addr_location *root_al) | 1261 | struct addr_location *root_al, |
1262 | int max_stack) | ||
1271 | { | 1263 | { |
1272 | u8 cpumode = PERF_RECORD_MISC_USER; | 1264 | u8 cpumode = PERF_RECORD_MISC_USER; |
1273 | unsigned int i; | 1265 | int chain_nr = min(max_stack, (int)chain->nr); |
1266 | int i; | ||
1274 | int err; | 1267 | int err; |
1275 | 1268 | ||
1276 | callchain_cursor_reset(&callchain_cursor); | 1269 | callchain_cursor_reset(&callchain_cursor); |
@@ -1280,7 +1273,7 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1280 | return 0; | 1273 | return 0; |
1281 | } | 1274 | } |
1282 | 1275 | ||
1283 | for (i = 0; i < chain->nr; i++) { | 1276 | for (i = 0; i < chain_nr; i++) { |
1284 | u64 ip; | 1277 | u64 ip; |
1285 | struct addr_location al; | 1278 | struct addr_location al; |
1286 | 1279 | ||
@@ -1352,12 +1345,14 @@ int machine__resolve_callchain(struct machine *machine, | |||
1352 | struct thread *thread, | 1345 | struct thread *thread, |
1353 | struct perf_sample *sample, | 1346 | struct perf_sample *sample, |
1354 | struct symbol **parent, | 1347 | struct symbol **parent, |
1355 | struct addr_location *root_al) | 1348 | struct addr_location *root_al, |
1349 | int max_stack) | ||
1356 | { | 1350 | { |
1357 | int ret; | 1351 | int ret; |
1358 | 1352 | ||
1359 | ret = machine__resolve_callchain_sample(machine, thread, | 1353 | ret = machine__resolve_callchain_sample(machine, thread, |
1360 | sample->callchain, parent, root_al); | 1354 | sample->callchain, parent, |
1355 | root_al, max_stack); | ||
1361 | if (ret) | 1356 | if (ret) |
1362 | return ret; | 1357 | return ret; |
1363 | 1358 | ||
@@ -1373,6 +1368,41 @@ int machine__resolve_callchain(struct machine *machine, | |||
1373 | 1368 | ||
1374 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | 1369 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, |
1375 | thread, evsel->attr.sample_regs_user, | 1370 | thread, evsel->attr.sample_regs_user, |
1376 | sample); | 1371 | sample, max_stack); |
1377 | 1372 | ||
1378 | } | 1373 | } |
1374 | |||
1375 | int machine__for_each_thread(struct machine *machine, | ||
1376 | int (*fn)(struct thread *thread, void *p), | ||
1377 | void *priv) | ||
1378 | { | ||
1379 | struct rb_node *nd; | ||
1380 | struct thread *thread; | ||
1381 | int rc = 0; | ||
1382 | |||
1383 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | ||
1384 | thread = rb_entry(nd, struct thread, rb_node); | ||
1385 | rc = fn(thread, priv); | ||
1386 | if (rc != 0) | ||
1387 | return rc; | ||
1388 | } | ||
1389 | |||
1390 | list_for_each_entry(thread, &machine->dead_threads, node) { | ||
1391 | rc = fn(thread, priv); | ||
1392 | if (rc != 0) | ||
1393 | return rc; | ||
1394 | } | ||
1395 | return rc; | ||
1396 | } | ||
1397 | |||
1398 | int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, | ||
1399 | struct target *target, struct thread_map *threads, | ||
1400 | perf_event__handler_t process, bool data_mmap) | ||
1401 | { | ||
1402 | if (target__has_task(target)) | ||
1403 | return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); | ||
1404 | else if (target__has_cpu(target)) | ||
1405 | return perf_event__synthesize_threads(tool, process, machine, data_mmap); | ||
1406 | /* command specified */ | ||
1407 | return 0; | ||
1408 | } | ||