diff options
Diffstat (limited to 'tools/perf/util/machine.c')
| -rw-r--r-- | tools/perf/util/machine.c | 166 |
1 files changed, 92 insertions, 74 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 6188d2876a71..ce034c183a7e 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 | ||
| @@ -1376,3 +1371,26 @@ int machine__resolve_callchain(struct machine *machine, | |||
| 1376 | sample); | 1371 | sample); |
| 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 | } | ||
