diff options
| author | Zhang, Yanmin <yanmin_zhang@linux.intel.com> | 2010-04-19 01:32:50 -0400 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2010-04-19 05:37:24 -0400 |
| commit | a1645ce12adb6c9cc9e19d7695466204e3f017fe (patch) | |
| tree | 5d31aaaf534997e6e9cebc07f38eca35f76986cf /tools/perf | |
| parent | ff9d07a0e7ce756a183e7c2e483aec452ee6b574 (diff) | |
perf: 'perf kvm' tool for monitoring guest performance from host
Here is the patch of userspace perf tool.
Signed-off-by: Zhang Yanmin <yanmin_zhang@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'tools/perf')
30 files changed, 1407 insertions, 316 deletions
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt new file mode 100644 index 000000000000..93400a0f17f0 --- /dev/null +++ b/tools/perf/Documentation/perf-kvm.txt | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | perf-kvm(1) | ||
| 2 | ============== | ||
| 3 | |||
| 4 | NAME | ||
| 5 | ---- | ||
| 6 | perf-kvm - Tool to trace/measure kvm guest os | ||
| 7 | |||
| 8 | SYNOPSIS | ||
| 9 | -------- | ||
| 10 | [verse] | ||
| 11 | 'perf kvm' [--host] [--guest] [--guestmount=<path> | ||
| 12 | [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] | ||
| 13 | {top|record|report|diff|buildid-list} | ||
| 14 | 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> | ||
| 15 | | --guestvmlinux=<path>] {top|record|report|diff|buildid-list} | ||
| 16 | |||
| 17 | DESCRIPTION | ||
| 18 | ----------- | ||
| 19 | There are a couple of variants of perf kvm: | ||
| 20 | |||
| 21 | 'perf kvm [options] top <command>' to generates and displays | ||
| 22 | a performance counter profile of guest os in realtime | ||
| 23 | of an arbitrary workload. | ||
| 24 | |||
| 25 | 'perf kvm record <command>' to record the performance couinter profile | ||
| 26 | of an arbitrary workload and save it into a perf data file. If both | ||
| 27 | --host and --guest are input, the perf data file name is perf.data.kvm. | ||
| 28 | If there is no --host but --guest, the file name is perf.data.guest. | ||
| 29 | If there is no --guest but --host, the file name is perf.data.host. | ||
| 30 | |||
| 31 | 'perf kvm report' to display the performance counter profile information | ||
| 32 | recorded via perf kvm record. | ||
| 33 | |||
| 34 | 'perf kvm diff' to displays the performance difference amongst two perf.data | ||
| 35 | files captured via perf record. | ||
| 36 | |||
| 37 | 'perf kvm buildid-list' to display the buildids found in a perf data file, | ||
| 38 | so that other tools can be used to fetch packages with matching symbol tables | ||
| 39 | for use by perf report. | ||
| 40 | |||
| 41 | OPTIONS | ||
| 42 | ------- | ||
| 43 | --host=:: | ||
| 44 | Collect host side perforamnce profile. | ||
| 45 | --guest=:: | ||
| 46 | Collect guest side perforamnce profile. | ||
| 47 | --guestmount=<path>:: | ||
| 48 | Guest os root file system mount directory. Users mounts guest os | ||
| 49 | root directories under <path> by a specific filesystem access method, | ||
| 50 | typically, sshfs. For example, start 2 guest os. The one's pid is 8888 | ||
| 51 | and the other's is 9999. | ||
| 52 | #mkdir ~/guestmount; cd ~/guestmount | ||
| 53 | #sshfs -o allow_other,direct_io -p 5551 localhost:/ 8888/ | ||
| 54 | #sshfs -o allow_other,direct_io -p 5552 localhost:/ 9999/ | ||
| 55 | #perf kvm --host --guest --guestmount=~/guestmount top | ||
| 56 | --guestkallsyms=<path>:: | ||
| 57 | Guest os /proc/kallsyms file copy. 'perf' kvm' reads it to get guest | ||
| 58 | kernel symbols. Users copy it out from guest os. | ||
| 59 | --guestmodules=<path>:: | ||
| 60 | Guest os /proc/modules file copy. 'perf' kvm' reads it to get guest | ||
| 61 | kernel module information. Users copy it out from guest os. | ||
| 62 | --guestvmlinux=<path>:: | ||
| 63 | Guest os kernel vmlinux. | ||
| 64 | |||
| 65 | SEE ALSO | ||
| 66 | -------- | ||
| 67 | linkperf:perf-top[1] perf-record[1] perf-report[1] perf-diff[1] perf-buildid-list[1] | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 57b3569716dd..3cb3449a9645 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -472,6 +472,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-trace.o | |||
| 472 | BUILTIN_OBJS += $(OUTPUT)builtin-probe.o | 472 | BUILTIN_OBJS += $(OUTPUT)builtin-probe.o |
| 473 | BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o | 473 | BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o |
| 474 | BUILTIN_OBJS += $(OUTPUT)builtin-lock.o | 474 | BUILTIN_OBJS += $(OUTPUT)builtin-lock.o |
| 475 | BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o | ||
| 475 | 476 | ||
| 476 | PERFLIBS = $(LIB_FILE) | 477 | PERFLIBS = $(LIB_FILE) |
| 477 | 478 | ||
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 06eaebe10d04..f924b4332be6 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -571,7 +571,7 @@ static int __cmd_annotate(void) | |||
| 571 | perf_session__fprintf(session, stdout); | 571 | perf_session__fprintf(session, stdout); |
| 572 | 572 | ||
| 573 | if (verbose > 2) | 573 | if (verbose > 2) |
| 574 | dsos__fprintf(stdout); | 574 | dsos__fprintf(&session->kerninfo_root, stdout); |
| 575 | 575 | ||
| 576 | perf_session__collapse_resort(&session->hists); | 576 | perf_session__collapse_resort(&session->hists); |
| 577 | perf_session__output_resort(&session->hists, session->event_total[0]); | 577 | perf_session__output_resort(&session->hists, session->event_total[0]); |
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index af2ad8b92f76..623afe3fdcb8 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
| @@ -46,7 +46,7 @@ static int __cmd_buildid_list(void) | |||
| 46 | if (with_hits) | 46 | if (with_hits) |
| 47 | perf_session__process_events(session, &build_id__mark_dso_hit_ops); | 47 | perf_session__process_events(session, &build_id__mark_dso_hit_ops); |
| 48 | 48 | ||
| 49 | dsos__fprintf_buildid(stdout, with_hits); | 49 | dsos__fprintf_buildid(&session->kerninfo_root, stdout, with_hits); |
| 50 | 50 | ||
| 51 | perf_session__delete(session); | 51 | perf_session__delete(session); |
| 52 | return err; | 52 | return err; |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 3a1d94d75dce..207e860591e2 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
| @@ -33,7 +33,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, | |||
| 33 | return -ENOMEM; | 33 | return -ENOMEM; |
| 34 | 34 | ||
| 35 | if (hit) | 35 | if (hit) |
| 36 | he->count += count; | 36 | __perf_session__add_count(he, al, count); |
| 37 | 37 | ||
| 38 | return 0; | 38 | return 0; |
| 39 | } | 39 | } |
| @@ -225,6 +225,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix __used) | |||
| 225 | input_new = argv[1]; | 225 | input_new = argv[1]; |
| 226 | } else | 226 | } else |
| 227 | input_new = argv[0]; | 227 | input_new = argv[0]; |
| 228 | } else if (symbol_conf.default_guest_vmlinux_name || | ||
| 229 | symbol_conf.default_guest_kallsyms) { | ||
| 230 | input_old = "perf.data.host"; | ||
| 231 | input_new = "perf.data.guest"; | ||
| 228 | } | 232 | } |
| 229 | 233 | ||
| 230 | symbol_conf.exclude_other = false; | 234 | symbol_conf.exclude_other = false; |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 513aa8a55db6..db474bbf3322 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -351,6 +351,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session, | |||
| 351 | int n_lines, int is_caller) | 351 | int n_lines, int is_caller) |
| 352 | { | 352 | { |
| 353 | struct rb_node *next; | 353 | struct rb_node *next; |
| 354 | struct kernel_info *kerninfo; | ||
| 354 | 355 | ||
| 355 | printf("%.102s\n", graph_dotted_line); | 356 | printf("%.102s\n", graph_dotted_line); |
| 356 | printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); | 357 | printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); |
| @@ -359,10 +360,16 @@ static void __print_result(struct rb_root *root, struct perf_session *session, | |||
| 359 | 360 | ||
| 360 | next = rb_first(root); | 361 | next = rb_first(root); |
| 361 | 362 | ||
| 363 | kerninfo = kerninfo__findhost(&session->kerninfo_root); | ||
| 364 | if (!kerninfo) { | ||
| 365 | pr_err("__print_result: couldn't find kernel information\n"); | ||
| 366 | return; | ||
| 367 | } | ||
| 362 | while (next && n_lines--) { | 368 | while (next && n_lines--) { |
| 363 | struct alloc_stat *data = rb_entry(next, struct alloc_stat, | 369 | struct alloc_stat *data = rb_entry(next, struct alloc_stat, |
| 364 | node); | 370 | node); |
| 365 | struct symbol *sym = NULL; | 371 | struct symbol *sym = NULL; |
| 372 | struct map_groups *kmaps = &kerninfo->kmaps; | ||
| 366 | struct map *map; | 373 | struct map *map; |
| 367 | char buf[BUFSIZ]; | 374 | char buf[BUFSIZ]; |
| 368 | u64 addr; | 375 | u64 addr; |
| @@ -370,8 +377,8 @@ static void __print_result(struct rb_root *root, struct perf_session *session, | |||
| 370 | if (is_caller) { | 377 | if (is_caller) { |
| 371 | addr = data->call_site; | 378 | addr = data->call_site; |
| 372 | if (!raw_ip) | 379 | if (!raw_ip) |
| 373 | sym = map_groups__find_function(&session->kmaps, | 380 | sym = map_groups__find_function(kmaps, addr, |
| 374 | addr, &map, NULL); | 381 | &map, NULL); |
| 375 | } else | 382 | } else |
| 376 | addr = data->ptr; | 383 | addr = data->ptr; |
| 377 | 384 | ||
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c new file mode 100644 index 000000000000..a4c7cae45024 --- /dev/null +++ b/tools/perf/builtin-kvm.c | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | #include "builtin.h" | ||
| 2 | #include "perf.h" | ||
| 3 | |||
| 4 | #include "util/util.h" | ||
| 5 | #include "util/cache.h" | ||
| 6 | #include "util/symbol.h" | ||
| 7 | #include "util/thread.h" | ||
| 8 | #include "util/header.h" | ||
| 9 | #include "util/session.h" | ||
| 10 | |||
| 11 | #include "util/parse-options.h" | ||
| 12 | #include "util/trace-event.h" | ||
| 13 | |||
| 14 | #include "util/debug.h" | ||
| 15 | |||
| 16 | #include <sys/prctl.h> | ||
| 17 | |||
| 18 | #include <semaphore.h> | ||
| 19 | #include <pthread.h> | ||
| 20 | #include <math.h> | ||
| 21 | |||
| 22 | static char *file_name; | ||
| 23 | static char name_buffer[256]; | ||
| 24 | |||
| 25 | int perf_host = 1; | ||
| 26 | int perf_guest; | ||
| 27 | |||
| 28 | static const char * const kvm_usage[] = { | ||
| 29 | "perf kvm [<options>] {top|record|report|diff|buildid-list}", | ||
| 30 | NULL | ||
| 31 | }; | ||
| 32 | |||
| 33 | static const struct option kvm_options[] = { | ||
| 34 | OPT_STRING('i', "input", &file_name, "file", | ||
| 35 | "Input file name"), | ||
| 36 | OPT_STRING('o', "output", &file_name, "file", | ||
| 37 | "Output file name"), | ||
| 38 | OPT_BOOLEAN(0, "guest", &perf_guest, | ||
| 39 | "Collect guest os data"), | ||
| 40 | OPT_BOOLEAN(0, "host", &perf_host, | ||
| 41 | "Collect guest os data"), | ||
| 42 | OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", | ||
| 43 | "guest mount directory under which every guest os" | ||
| 44 | " instance has a subdir"), | ||
| 45 | OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, | ||
| 46 | "file", "file saving guest os vmlinux"), | ||
| 47 | OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, | ||
| 48 | "file", "file saving guest os /proc/kallsyms"), | ||
| 49 | OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, | ||
| 50 | "file", "file saving guest os /proc/modules"), | ||
| 51 | OPT_END() | ||
| 52 | }; | ||
| 53 | |||
| 54 | static int __cmd_record(int argc, const char **argv) | ||
| 55 | { | ||
| 56 | int rec_argc, i = 0, j; | ||
| 57 | const char **rec_argv; | ||
| 58 | |||
| 59 | rec_argc = argc + 2; | ||
| 60 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | ||
| 61 | rec_argv[i++] = strdup("record"); | ||
| 62 | rec_argv[i++] = strdup("-o"); | ||
| 63 | rec_argv[i++] = strdup(file_name); | ||
| 64 | for (j = 1; j < argc; j++, i++) | ||
| 65 | rec_argv[i] = argv[j]; | ||
| 66 | |||
| 67 | BUG_ON(i != rec_argc); | ||
| 68 | |||
| 69 | return cmd_record(i, rec_argv, NULL); | ||
| 70 | } | ||
| 71 | |||
| 72 | static int __cmd_report(int argc, const char **argv) | ||
| 73 | { | ||
| 74 | int rec_argc, i = 0, j; | ||
| 75 | const char **rec_argv; | ||
| 76 | |||
| 77 | rec_argc = argc + 2; | ||
| 78 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | ||
| 79 | rec_argv[i++] = strdup("report"); | ||
| 80 | rec_argv[i++] = strdup("-i"); | ||
| 81 | rec_argv[i++] = strdup(file_name); | ||
| 82 | for (j = 1; j < argc; j++, i++) | ||
| 83 | rec_argv[i] = argv[j]; | ||
| 84 | |||
| 85 | BUG_ON(i != rec_argc); | ||
| 86 | |||
| 87 | return cmd_report(i, rec_argv, NULL); | ||
| 88 | } | ||
| 89 | |||
| 90 | static int __cmd_buildid_list(int argc, const char **argv) | ||
| 91 | { | ||
| 92 | int rec_argc, i = 0, j; | ||
| 93 | const char **rec_argv; | ||
| 94 | |||
| 95 | rec_argc = argc + 2; | ||
| 96 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | ||
| 97 | rec_argv[i++] = strdup("buildid-list"); | ||
| 98 | rec_argv[i++] = strdup("-i"); | ||
| 99 | rec_argv[i++] = strdup(file_name); | ||
| 100 | for (j = 1; j < argc; j++, i++) | ||
| 101 | rec_argv[i] = argv[j]; | ||
| 102 | |||
| 103 | BUG_ON(i != rec_argc); | ||
| 104 | |||
| 105 | return cmd_buildid_list(i, rec_argv, NULL); | ||
| 106 | } | ||
| 107 | |||
| 108 | int cmd_kvm(int argc, const char **argv, const char *prefix __used) | ||
| 109 | { | ||
| 110 | perf_host = perf_guest = 0; | ||
| 111 | |||
| 112 | argc = parse_options(argc, argv, kvm_options, kvm_usage, | ||
| 113 | PARSE_OPT_STOP_AT_NON_OPTION); | ||
| 114 | if (!argc) | ||
| 115 | usage_with_options(kvm_usage, kvm_options); | ||
| 116 | |||
| 117 | if (!perf_host) | ||
| 118 | perf_guest = 1; | ||
| 119 | |||
| 120 | if (!file_name) { | ||
| 121 | if (perf_host && !perf_guest) | ||
| 122 | sprintf(name_buffer, "perf.data.host"); | ||
| 123 | else if (!perf_host && perf_guest) | ||
| 124 | sprintf(name_buffer, "perf.data.guest"); | ||
| 125 | else | ||
| 126 | sprintf(name_buffer, "perf.data.kvm"); | ||
| 127 | file_name = name_buffer; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (!strncmp(argv[0], "rec", 3)) | ||
| 131 | return __cmd_record(argc, argv); | ||
| 132 | else if (!strncmp(argv[0], "rep", 3)) | ||
| 133 | return __cmd_report(argc, argv); | ||
| 134 | else if (!strncmp(argv[0], "diff", 4)) | ||
| 135 | return cmd_diff(argc, argv, NULL); | ||
| 136 | else if (!strncmp(argv[0], "top", 3)) | ||
| 137 | return cmd_top(argc, argv, NULL); | ||
| 138 | else if (!strncmp(argv[0], "buildid-list", 12)) | ||
| 139 | return __cmd_buildid_list(argc, argv); | ||
| 140 | else | ||
| 141 | usage_with_options(kvm_usage, kvm_options); | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | } | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a1b99eeac3c0..27f992aca8b5 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -456,6 +456,52 @@ static void atexit_header(void) | |||
| 456 | } | 456 | } |
| 457 | } | 457 | } |
| 458 | 458 | ||
| 459 | static void event__synthesize_guest_os(struct kernel_info *kerninfo, | ||
| 460 | void *data __attribute__((unused))) | ||
| 461 | { | ||
| 462 | int err; | ||
| 463 | char *guest_kallsyms; | ||
| 464 | char path[PATH_MAX]; | ||
| 465 | |||
| 466 | if (is_host_kernel(kerninfo)) | ||
| 467 | return; | ||
| 468 | |||
| 469 | /* | ||
| 470 | *As for guest kernel when processing subcommand record&report, | ||
| 471 | *we arrange module mmap prior to guest kernel mmap and trigger | ||
| 472 | *a preload dso because default guest module symbols are loaded | ||
| 473 | *from guest kallsyms instead of /lib/modules/XXX/XXX. This | ||
| 474 | *method is used to avoid symbol missing when the first addr is | ||
| 475 | *in module instead of in guest kernel. | ||
| 476 | */ | ||
| 477 | err = event__synthesize_modules(process_synthesized_event, | ||
| 478 | session, | ||
| 479 | kerninfo); | ||
| 480 | if (err < 0) | ||
| 481 | pr_err("Couldn't record guest kernel [%d]'s reference" | ||
| 482 | " relocation symbol.\n", kerninfo->pid); | ||
| 483 | |||
| 484 | if (is_default_guest(kerninfo)) | ||
| 485 | guest_kallsyms = (char *) symbol_conf.default_guest_kallsyms; | ||
| 486 | else { | ||
| 487 | sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir); | ||
| 488 | guest_kallsyms = path; | ||
| 489 | } | ||
| 490 | |||
| 491 | /* | ||
| 492 | * We use _stext for guest kernel because guest kernel's /proc/kallsyms | ||
| 493 | * have no _text sometimes. | ||
| 494 | */ | ||
| 495 | err = event__synthesize_kernel_mmap(process_synthesized_event, | ||
| 496 | session, kerninfo, "_text"); | ||
| 497 | if (err < 0) | ||
| 498 | err = event__synthesize_kernel_mmap(process_synthesized_event, | ||
| 499 | session, kerninfo, "_stext"); | ||
| 500 | if (err < 0) | ||
| 501 | pr_err("Couldn't record guest kernel [%d]'s reference" | ||
| 502 | " relocation symbol.\n", kerninfo->pid); | ||
| 503 | } | ||
| 504 | |||
| 459 | static int __cmd_record(int argc, const char **argv) | 505 | static int __cmd_record(int argc, const char **argv) |
| 460 | { | 506 | { |
| 461 | int i, counter; | 507 | int i, counter; |
| @@ -467,6 +513,7 @@ static int __cmd_record(int argc, const char **argv) | |||
| 467 | int child_ready_pipe[2], go_pipe[2]; | 513 | int child_ready_pipe[2], go_pipe[2]; |
| 468 | const bool forks = argc > 0; | 514 | const bool forks = argc > 0; |
| 469 | char buf; | 515 | char buf; |
| 516 | struct kernel_info *kerninfo; | ||
| 470 | 517 | ||
| 471 | page_size = sysconf(_SC_PAGE_SIZE); | 518 | page_size = sysconf(_SC_PAGE_SIZE); |
| 472 | 519 | ||
| @@ -635,21 +682,31 @@ static int __cmd_record(int argc, const char **argv) | |||
| 635 | advance_output(err); | 682 | advance_output(err); |
| 636 | } | 683 | } |
| 637 | 684 | ||
| 685 | kerninfo = kerninfo__findhost(&session->kerninfo_root); | ||
| 686 | if (!kerninfo) { | ||
| 687 | pr_err("Couldn't find native kernel information.\n"); | ||
| 688 | return -1; | ||
| 689 | } | ||
| 690 | |||
| 638 | err = event__synthesize_kernel_mmap(process_synthesized_event, | 691 | err = event__synthesize_kernel_mmap(process_synthesized_event, |
| 639 | session, "_text"); | 692 | session, kerninfo, "_text"); |
| 640 | if (err < 0) | 693 | if (err < 0) |
| 641 | err = event__synthesize_kernel_mmap(process_synthesized_event, | 694 | err = event__synthesize_kernel_mmap(process_synthesized_event, |
| 642 | session, "_stext"); | 695 | session, kerninfo, "_stext"); |
| 643 | if (err < 0) { | 696 | if (err < 0) { |
| 644 | pr_err("Couldn't record kernel reference relocation symbol.\n"); | 697 | pr_err("Couldn't record kernel reference relocation symbol.\n"); |
| 645 | return err; | 698 | return err; |
| 646 | } | 699 | } |
| 647 | 700 | ||
| 648 | err = event__synthesize_modules(process_synthesized_event, session); | 701 | err = event__synthesize_modules(process_synthesized_event, |
| 702 | session, kerninfo); | ||
| 649 | if (err < 0) { | 703 | if (err < 0) { |
| 650 | pr_err("Couldn't record kernel reference relocation symbol.\n"); | 704 | pr_err("Couldn't record kernel reference relocation symbol.\n"); |
| 651 | return err; | 705 | return err; |
| 652 | } | 706 | } |
| 707 | if (perf_guest) | ||
| 708 | kerninfo__process_allkernels(&session->kerninfo_root, | ||
| 709 | event__synthesize_guest_os, session); | ||
| 653 | 710 | ||
| 654 | if (!system_wide && profile_cpu == -1) | 711 | if (!system_wide && profile_cpu == -1) |
| 655 | event__synthesize_thread(target_tid, process_synthesized_event, | 712 | event__synthesize_thread(target_tid, process_synthesized_event, |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 7da5fb365264..816edae7c5b2 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -108,7 +108,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, | |||
| 108 | return -ENOMEM; | 108 | return -ENOMEM; |
| 109 | 109 | ||
| 110 | if (hit) | 110 | if (hit) |
| 111 | he->count += data->period; | 111 | __perf_session__add_count(he, al, data->period); |
| 112 | 112 | ||
| 113 | if (symbol_conf.use_callchain) { | 113 | if (symbol_conf.use_callchain) { |
| 114 | if (!hit) | 114 | if (!hit) |
| @@ -313,7 +313,7 @@ static int __cmd_report(void) | |||
| 313 | perf_session__fprintf(session, stdout); | 313 | perf_session__fprintf(session, stdout); |
| 314 | 314 | ||
| 315 | if (verbose > 2) | 315 | if (verbose > 2) |
| 316 | dsos__fprintf(stdout); | 316 | dsos__fprintf(&session->kerninfo_root, stdout); |
| 317 | 317 | ||
| 318 | next = rb_first(&session->stats_by_id); | 318 | next = rb_first(&session->stats_by_id); |
| 319 | while (next) { | 319 | while (next) { |
| @@ -450,6 +450,8 @@ static const struct option options[] = { | |||
| 450 | "sort by key(s): pid, comm, dso, symbol, parent"), | 450 | "sort by key(s): pid, comm, dso, symbol, parent"), |
| 451 | OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, | 451 | OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, |
| 452 | "Don't shorten the pathnames taking into account the cwd"), | 452 | "Don't shorten the pathnames taking into account the cwd"), |
| 453 | OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, | ||
| 454 | "Show sample percentage for different cpu modes"), | ||
| 453 | OPT_STRING('p', "parent", &parent_pattern, "regex", | 455 | OPT_STRING('p', "parent", &parent_pattern, "regex", |
| 454 | "regex filter to identify parent, see: '--sort parent'"), | 456 | "regex filter to identify parent, see: '--sort parent'"), |
| 455 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, | 457 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 40f24dd46ef4..dfd7ea7dabdd 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -420,8 +420,9 @@ static double sym_weight(const struct sym_entry *sym) | |||
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | static long samples; | 422 | static long samples; |
| 423 | static long userspace_samples; | 423 | static long kernel_samples, us_samples; |
| 424 | static long exact_samples; | 424 | static long exact_samples; |
| 425 | static long guest_us_samples, guest_kernel_samples; | ||
| 425 | static const char CONSOLE_CLEAR[] = "[H[2J"; | 426 | static const char CONSOLE_CLEAR[] = "[H[2J"; |
| 426 | 427 | ||
| 427 | static void __list_insert_active_sym(struct sym_entry *syme) | 428 | static void __list_insert_active_sym(struct sym_entry *syme) |
| @@ -461,7 +462,10 @@ static void print_sym_table(void) | |||
| 461 | int printed = 0, j; | 462 | int printed = 0, j; |
| 462 | int counter, snap = !display_weighted ? sym_counter : 0; | 463 | int counter, snap = !display_weighted ? sym_counter : 0; |
| 463 | float samples_per_sec = samples/delay_secs; | 464 | float samples_per_sec = samples/delay_secs; |
| 464 | float ksamples_per_sec = (samples-userspace_samples)/delay_secs; | 465 | float ksamples_per_sec = kernel_samples/delay_secs; |
| 466 | float us_samples_per_sec = (us_samples)/delay_secs; | ||
| 467 | float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs; | ||
| 468 | float guest_us_samples_per_sec = (guest_us_samples)/delay_secs; | ||
| 465 | float esamples_percent = (100.0*exact_samples)/samples; | 469 | float esamples_percent = (100.0*exact_samples)/samples; |
| 466 | float sum_ksamples = 0.0; | 470 | float sum_ksamples = 0.0; |
| 467 | struct sym_entry *syme, *n; | 471 | struct sym_entry *syme, *n; |
| @@ -470,7 +474,8 @@ static void print_sym_table(void) | |||
| 470 | int sym_width = 0, dso_width = 0, dso_short_width = 0; | 474 | int sym_width = 0, dso_width = 0, dso_short_width = 0; |
| 471 | const int win_width = winsize.ws_col - 1; | 475 | const int win_width = winsize.ws_col - 1; |
| 472 | 476 | ||
| 473 | samples = userspace_samples = exact_samples = 0; | 477 | samples = us_samples = kernel_samples = exact_samples = 0; |
| 478 | guest_kernel_samples = guest_us_samples = 0; | ||
| 474 | 479 | ||
| 475 | /* Sort the active symbols */ | 480 | /* Sort the active symbols */ |
| 476 | pthread_mutex_lock(&active_symbols_lock); | 481 | pthread_mutex_lock(&active_symbols_lock); |
| @@ -501,10 +506,30 @@ static void print_sym_table(void) | |||
| 501 | puts(CONSOLE_CLEAR); | 506 | puts(CONSOLE_CLEAR); |
| 502 | 507 | ||
| 503 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 508 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
| 504 | printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% exact: %4.1f%% [", | 509 | if (!perf_guest) { |
| 505 | samples_per_sec, | 510 | printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%" |
| 506 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)), | 511 | " exact: %4.1f%% [", |
| 507 | esamples_percent); | 512 | samples_per_sec, |
| 513 | 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / | ||
| 514 | samples_per_sec)), | ||
| 515 | esamples_percent); | ||
| 516 | } else { | ||
| 517 | printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%" | ||
| 518 | " guest kernel:%4.1f%% guest us:%4.1f%%" | ||
| 519 | " exact: %4.1f%% [", | ||
| 520 | samples_per_sec, | ||
| 521 | 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) / | ||
| 522 | samples_per_sec)), | ||
| 523 | 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) / | ||
| 524 | samples_per_sec)), | ||
| 525 | 100.0 - (100.0 * ((samples_per_sec - | ||
| 526 | guest_kernel_samples_per_sec) / | ||
| 527 | samples_per_sec)), | ||
| 528 | 100.0 - (100.0 * ((samples_per_sec - | ||
| 529 | guest_us_samples_per_sec) / | ||
| 530 | samples_per_sec)), | ||
| 531 | esamples_percent); | ||
| 532 | } | ||
| 508 | 533 | ||
| 509 | if (nr_counters == 1 || !display_weighted) { | 534 | if (nr_counters == 1 || !display_weighted) { |
| 510 | printf("%Ld", (u64)attrs[0].sample_period); | 535 | printf("%Ld", (u64)attrs[0].sample_period); |
| @@ -597,7 +622,6 @@ static void print_sym_table(void) | |||
| 597 | 622 | ||
| 598 | syme = rb_entry(nd, struct sym_entry, rb_node); | 623 | syme = rb_entry(nd, struct sym_entry, rb_node); |
| 599 | sym = sym_entry__symbol(syme); | 624 | sym = sym_entry__symbol(syme); |
| 600 | |||
| 601 | if (++printed > print_entries || (int)syme->snap_count < count_filter) | 625 | if (++printed > print_entries || (int)syme->snap_count < count_filter) |
| 602 | continue; | 626 | continue; |
| 603 | 627 | ||
| @@ -761,7 +785,7 @@ static int key_mapped(int c) | |||
| 761 | return 0; | 785 | return 0; |
| 762 | } | 786 | } |
| 763 | 787 | ||
| 764 | static void handle_keypress(int c) | 788 | static void handle_keypress(struct perf_session *session, int c) |
| 765 | { | 789 | { |
| 766 | if (!key_mapped(c)) { | 790 | if (!key_mapped(c)) { |
| 767 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 791 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
| @@ -830,7 +854,7 @@ static void handle_keypress(int c) | |||
| 830 | case 'Q': | 854 | case 'Q': |
| 831 | printf("exiting.\n"); | 855 | printf("exiting.\n"); |
| 832 | if (dump_symtab) | 856 | if (dump_symtab) |
| 833 | dsos__fprintf(stderr); | 857 | dsos__fprintf(&session->kerninfo_root, stderr); |
| 834 | exit(0); | 858 | exit(0); |
| 835 | case 's': | 859 | case 's': |
| 836 | prompt_symbol(&sym_filter_entry, "Enter details symbol"); | 860 | prompt_symbol(&sym_filter_entry, "Enter details symbol"); |
| @@ -866,6 +890,7 @@ static void *display_thread(void *arg __used) | |||
| 866 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 890 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
| 867 | struct termios tc, save; | 891 | struct termios tc, save; |
| 868 | int delay_msecs, c; | 892 | int delay_msecs, c; |
| 893 | struct perf_session *session = (struct perf_session *) arg; | ||
| 869 | 894 | ||
| 870 | tcgetattr(0, &save); | 895 | tcgetattr(0, &save); |
| 871 | tc = save; | 896 | tc = save; |
| @@ -886,7 +911,7 @@ repeat: | |||
| 886 | c = getc(stdin); | 911 | c = getc(stdin); |
| 887 | tcsetattr(0, TCSAFLUSH, &save); | 912 | tcsetattr(0, TCSAFLUSH, &save); |
| 888 | 913 | ||
| 889 | handle_keypress(c); | 914 | handle_keypress(session, c); |
| 890 | goto repeat; | 915 | goto repeat; |
| 891 | 916 | ||
| 892 | return NULL; | 917 | return NULL; |
| @@ -957,24 +982,46 @@ static void event__process_sample(const event_t *self, | |||
| 957 | u64 ip = self->ip.ip; | 982 | u64 ip = self->ip.ip; |
| 958 | struct sym_entry *syme; | 983 | struct sym_entry *syme; |
| 959 | struct addr_location al; | 984 | struct addr_location al; |
| 985 | struct kernel_info *kerninfo; | ||
| 960 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 986 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
| 961 | 987 | ||
| 962 | ++samples; | 988 | ++samples; |
| 963 | 989 | ||
| 964 | switch (origin) { | 990 | switch (origin) { |
| 965 | case PERF_RECORD_MISC_USER: | 991 | case PERF_RECORD_MISC_USER: |
| 966 | ++userspace_samples; | 992 | ++us_samples; |
| 967 | if (hide_user_symbols) | 993 | if (hide_user_symbols) |
| 968 | return; | 994 | return; |
| 995 | kerninfo = kerninfo__findhost(&session->kerninfo_root); | ||
| 969 | break; | 996 | break; |
| 970 | case PERF_RECORD_MISC_KERNEL: | 997 | case PERF_RECORD_MISC_KERNEL: |
| 998 | ++kernel_samples; | ||
| 971 | if (hide_kernel_symbols) | 999 | if (hide_kernel_symbols) |
| 972 | return; | 1000 | return; |
| 1001 | kerninfo = kerninfo__findhost(&session->kerninfo_root); | ||
| 973 | break; | 1002 | break; |
| 1003 | case PERF_RECORD_MISC_GUEST_KERNEL: | ||
| 1004 | ++guest_kernel_samples; | ||
| 1005 | kerninfo = kerninfo__find(&session->kerninfo_root, | ||
| 1006 | self->ip.pid); | ||
| 1007 | break; | ||
| 1008 | case PERF_RECORD_MISC_GUEST_USER: | ||
| 1009 | ++guest_us_samples; | ||
| 1010 | /* | ||
| 1011 | * TODO: we don't process guest user from host side | ||
| 1012 | * except simple counting. | ||
| 1013 | */ | ||
| 1014 | return; | ||
| 974 | default: | 1015 | default: |
| 975 | return; | 1016 | return; |
| 976 | } | 1017 | } |
| 977 | 1018 | ||
| 1019 | if (!kerninfo && perf_guest) { | ||
| 1020 | pr_err("Can't find guest [%d]'s kernel information\n", | ||
| 1021 | self->ip.pid); | ||
| 1022 | return; | ||
| 1023 | } | ||
| 1024 | |||
| 978 | if (self->header.misc & PERF_RECORD_MISC_EXACT) | 1025 | if (self->header.misc & PERF_RECORD_MISC_EXACT) |
| 979 | exact_samples++; | 1026 | exact_samples++; |
| 980 | 1027 | ||
| @@ -994,7 +1041,7 @@ static void event__process_sample(const event_t *self, | |||
| 994 | * --hide-kernel-symbols, even if the user specifies an | 1041 | * --hide-kernel-symbols, even if the user specifies an |
| 995 | * invalid --vmlinux ;-) | 1042 | * invalid --vmlinux ;-) |
| 996 | */ | 1043 | */ |
| 997 | if (al.map == session->vmlinux_maps[MAP__FUNCTION] && | 1044 | if (al.map == kerninfo->vmlinux_maps[MAP__FUNCTION] && |
| 998 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { | 1045 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { |
| 999 | pr_err("The %s file can't be used\n", | 1046 | pr_err("The %s file can't be used\n", |
| 1000 | symbol_conf.vmlinux_name); | 1047 | symbol_conf.vmlinux_name); |
| @@ -1261,7 +1308,7 @@ static int __cmd_top(void) | |||
| 1261 | 1308 | ||
| 1262 | perf_session__mmap_read(session); | 1309 | perf_session__mmap_read(session); |
| 1263 | 1310 | ||
| 1264 | if (pthread_create(&thread, NULL, display_thread, NULL)) { | 1311 | if (pthread_create(&thread, NULL, display_thread, session)) { |
| 1265 | printf("Could not create display thread.\n"); | 1312 | printf("Could not create display thread.\n"); |
| 1266 | exit(-1); | 1313 | exit(-1); |
| 1267 | } | 1314 | } |
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 10fe49e7048a..ab28bca92e52 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h | |||
| @@ -32,5 +32,6 @@ extern int cmd_version(int argc, const char **argv, const char *prefix); | |||
| 32 | extern int cmd_probe(int argc, const char **argv, const char *prefix); | 32 | extern int cmd_probe(int argc, const char **argv, const char *prefix); |
| 33 | extern int cmd_kmem(int argc, const char **argv, const char *prefix); | 33 | extern int cmd_kmem(int argc, const char **argv, const char *prefix); |
| 34 | extern int cmd_lock(int argc, const char **argv, const char *prefix); | 34 | extern int cmd_lock(int argc, const char **argv, const char *prefix); |
| 35 | extern int cmd_kvm(int argc, const char **argv, const char *prefix); | ||
| 35 | 36 | ||
| 36 | #endif | 37 | #endif |
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index db6ee94d4a8e..2a1162d413a8 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt | |||
| @@ -19,3 +19,4 @@ perf-trace mainporcelain common | |||
| 19 | perf-probe mainporcelain common | 19 | perf-probe mainporcelain common |
| 20 | perf-kmem mainporcelain common | 20 | perf-kmem mainporcelain common |
| 21 | perf-lock mainporcelain common | 21 | perf-lock mainporcelain common |
| 22 | perf-kvm mainporcelain common | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index d4be55b6cd34..985cdb4bd005 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -307,6 +307,7 @@ static void handle_internal_command(int argc, const char **argv) | |||
| 307 | { "probe", cmd_probe, 0 }, | 307 | { "probe", cmd_probe, 0 }, |
| 308 | { "kmem", cmd_kmem, 0 }, | 308 | { "kmem", cmd_kmem, 0 }, |
| 309 | { "lock", cmd_lock, 0 }, | 309 | { "lock", cmd_lock, 0 }, |
| 310 | { "kvm", cmd_kvm, 0 }, | ||
| 310 | }; | 311 | }; |
| 311 | unsigned int i; | 312 | unsigned int i; |
| 312 | static const char ext[] = STRIP_EXTENSION; | 313 | static const char ext[] = STRIP_EXTENSION; |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index ec212748d651..02821febb704 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
| @@ -131,4 +131,6 @@ struct ip_callchain { | |||
| 131 | u64 ips[0]; | 131 | u64 ips[0]; |
| 132 | }; | 132 | }; |
| 133 | 133 | ||
| 134 | extern int perf_host, perf_guest; | ||
| 135 | |||
| 134 | #endif | 136 | #endif |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 04904b35ba81..0f60a3906808 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
| @@ -24,7 +24,7 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) | |||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, | 26 | thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, |
| 27 | event->ip.ip, &al); | 27 | event->ip.pid, event->ip.ip, &al); |
| 28 | 28 | ||
| 29 | if (al.map != NULL) | 29 | if (al.map != NULL) |
| 30 | al.map->dso->hit = 1; | 30 | al.map->dso->hit = 1; |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 571fb25f7eb9..e3fa8d3d11b4 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -112,7 +112,11 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | |||
| 112 | event_t ev = { | 112 | event_t ev = { |
| 113 | .header = { | 113 | .header = { |
| 114 | .type = PERF_RECORD_MMAP, | 114 | .type = PERF_RECORD_MMAP, |
| 115 | .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */ | 115 | /* |
| 116 | * Just like the kernel, see __perf_event_mmap | ||
| 117 | * in kernel/perf_event.c | ||
| 118 | */ | ||
| 119 | .misc = PERF_RECORD_MISC_USER, | ||
| 116 | }, | 120 | }, |
| 117 | }; | 121 | }; |
| 118 | int n; | 122 | int n; |
| @@ -167,11 +171,23 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | |||
| 167 | } | 171 | } |
| 168 | 172 | ||
| 169 | int event__synthesize_modules(event__handler_t process, | 173 | int event__synthesize_modules(event__handler_t process, |
| 170 | struct perf_session *session) | 174 | struct perf_session *session, |
| 175 | struct kernel_info *kerninfo) | ||
| 171 | { | 176 | { |
| 172 | struct rb_node *nd; | 177 | struct rb_node *nd; |
| 178 | struct map_groups *kmaps = &kerninfo->kmaps; | ||
| 179 | u16 misc; | ||
| 173 | 180 | ||
| 174 | for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]); | 181 | /* |
| 182 | * kernel uses 0 for user space maps, see kernel/perf_event.c | ||
| 183 | * __perf_event_mmap | ||
| 184 | */ | ||
| 185 | if (is_host_kernel(kerninfo)) | ||
| 186 | misc = PERF_RECORD_MISC_KERNEL; | ||
| 187 | else | ||
| 188 | misc = PERF_RECORD_MISC_GUEST_KERNEL; | ||
| 189 | |||
| 190 | for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); | ||
| 175 | nd; nd = rb_next(nd)) { | 191 | nd; nd = rb_next(nd)) { |
| 176 | event_t ev; | 192 | event_t ev; |
| 177 | size_t size; | 193 | size_t size; |
| @@ -182,12 +198,13 @@ int event__synthesize_modules(event__handler_t process, | |||
| 182 | 198 | ||
| 183 | size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); | 199 | size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); |
| 184 | memset(&ev, 0, sizeof(ev)); | 200 | memset(&ev, 0, sizeof(ev)); |
| 185 | ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */ | 201 | ev.mmap.header.misc = misc; |
| 186 | ev.mmap.header.type = PERF_RECORD_MMAP; | 202 | ev.mmap.header.type = PERF_RECORD_MMAP; |
| 187 | ev.mmap.header.size = (sizeof(ev.mmap) - | 203 | ev.mmap.header.size = (sizeof(ev.mmap) - |
| 188 | (sizeof(ev.mmap.filename) - size)); | 204 | (sizeof(ev.mmap.filename) - size)); |
| 189 | ev.mmap.start = pos->start; | 205 | ev.mmap.start = pos->start; |
| 190 | ev.mmap.len = pos->end - pos->start; | 206 | ev.mmap.len = pos->end - pos->start; |
| 207 | ev.mmap.pid = kerninfo->pid; | ||
| 191 | 208 | ||
| 192 | memcpy(ev.mmap.filename, pos->dso->long_name, | 209 | memcpy(ev.mmap.filename, pos->dso->long_name, |
| 193 | pos->dso->long_name_len + 1); | 210 | pos->dso->long_name_len + 1); |
| @@ -250,13 +267,18 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start) | |||
| 250 | 267 | ||
| 251 | int event__synthesize_kernel_mmap(event__handler_t process, | 268 | int event__synthesize_kernel_mmap(event__handler_t process, |
| 252 | struct perf_session *session, | 269 | struct perf_session *session, |
| 270 | struct kernel_info *kerninfo, | ||
| 253 | const char *symbol_name) | 271 | const char *symbol_name) |
| 254 | { | 272 | { |
| 255 | size_t size; | 273 | size_t size; |
| 274 | const char *filename, *mmap_name; | ||
| 275 | char path[PATH_MAX]; | ||
| 276 | char name_buff[PATH_MAX]; | ||
| 277 | struct map *map; | ||
| 278 | |||
| 256 | event_t ev = { | 279 | event_t ev = { |
| 257 | .header = { | 280 | .header = { |
| 258 | .type = PERF_RECORD_MMAP, | 281 | .type = PERF_RECORD_MMAP, |
| 259 | .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */ | ||
| 260 | }, | 282 | }, |
| 261 | }; | 283 | }; |
| 262 | /* | 284 | /* |
| @@ -266,16 +288,37 @@ int event__synthesize_kernel_mmap(event__handler_t process, | |||
| 266 | */ | 288 | */ |
| 267 | struct process_symbol_args args = { .name = symbol_name, }; | 289 | struct process_symbol_args args = { .name = symbol_name, }; |
| 268 | 290 | ||
| 269 | if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0) | 291 | mmap_name = kern_mmap_name(kerninfo, name_buff); |
| 292 | if (is_host_kernel(kerninfo)) { | ||
| 293 | /* | ||
| 294 | * kernel uses PERF_RECORD_MISC_USER for user space maps, | ||
| 295 | * see kernel/perf_event.c __perf_event_mmap | ||
| 296 | */ | ||
| 297 | ev.header.misc = PERF_RECORD_MISC_KERNEL; | ||
| 298 | filename = "/proc/kallsyms"; | ||
| 299 | } else { | ||
| 300 | ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL; | ||
| 301 | if (is_default_guest(kerninfo)) | ||
| 302 | filename = (char *) symbol_conf.default_guest_kallsyms; | ||
| 303 | else { | ||
| 304 | sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir); | ||
| 305 | filename = path; | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) | ||
| 270 | return -ENOENT; | 310 | return -ENOENT; |
| 271 | 311 | ||
| 312 | map = kerninfo->vmlinux_maps[MAP__FUNCTION]; | ||
| 272 | size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), | 313 | size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), |
| 273 | "[kernel.kallsyms.%s]", symbol_name) + 1; | 314 | "%s%s", mmap_name, symbol_name) + 1; |
| 274 | size = ALIGN(size, sizeof(u64)); | 315 | size = ALIGN(size, sizeof(u64)); |
| 275 | ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size)); | 316 | ev.mmap.header.size = (sizeof(ev.mmap) - |
| 317 | (sizeof(ev.mmap.filename) - size)); | ||
| 276 | ev.mmap.pgoff = args.start; | 318 | ev.mmap.pgoff = args.start; |
| 277 | ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start; | 319 | ev.mmap.start = map->start; |
| 278 | ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ; | 320 | ev.mmap.len = map->end - ev.mmap.start; |
| 321 | ev.mmap.pid = kerninfo->pid; | ||
| 279 | 322 | ||
| 280 | return process(&ev, session); | 323 | return process(&ev, session); |
| 281 | } | 324 | } |
| @@ -329,22 +372,50 @@ int event__process_lost(event_t *self, struct perf_session *session) | |||
| 329 | return 0; | 372 | return 0; |
| 330 | } | 373 | } |
| 331 | 374 | ||
| 332 | int event__process_mmap(event_t *self, struct perf_session *session) | 375 | static void event_set_kernel_mmap_len(struct map **maps, event_t *self) |
| 376 | { | ||
| 377 | maps[MAP__FUNCTION]->start = self->mmap.start; | ||
| 378 | maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; | ||
| 379 | /* | ||
| 380 | * Be a bit paranoid here, some perf.data file came with | ||
| 381 | * a zero sized synthesized MMAP event for the kernel. | ||
| 382 | */ | ||
| 383 | if (maps[MAP__FUNCTION]->end == 0) | ||
| 384 | maps[MAP__FUNCTION]->end = ~0UL; | ||
| 385 | } | ||
| 386 | |||
| 387 | static int event__process_kernel_mmap(event_t *self, | ||
| 388 | struct perf_session *session) | ||
| 333 | { | 389 | { |
| 334 | struct thread *thread; | ||
| 335 | struct map *map; | 390 | struct map *map; |
| 391 | char kmmap_prefix[PATH_MAX]; | ||
| 392 | struct kernel_info *kerninfo; | ||
| 393 | enum dso_kernel_type kernel_type; | ||
| 394 | bool is_kernel_mmap; | ||
| 395 | |||
| 396 | kerninfo = kerninfo__findnew(&session->kerninfo_root, self->mmap.pid); | ||
| 397 | if (!kerninfo) { | ||
| 398 | pr_err("Can't find id %d's kerninfo\n", self->mmap.pid); | ||
| 399 | goto out_problem; | ||
| 400 | } | ||
| 336 | 401 | ||
| 337 | dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n", | 402 | kern_mmap_name(kerninfo, kmmap_prefix); |
| 338 | self->mmap.pid, self->mmap.tid, self->mmap.start, | 403 | if (is_host_kernel(kerninfo)) |
| 339 | self->mmap.len, self->mmap.pgoff, self->mmap.filename); | 404 | kernel_type = DSO_TYPE_KERNEL; |
| 405 | else | ||
| 406 | kernel_type = DSO_TYPE_GUEST_KERNEL; | ||
| 340 | 407 | ||
| 341 | if (self->mmap.pid == 0) { | 408 | is_kernel_mmap = memcmp(self->mmap.filename, |
| 342 | static const char kmmap_prefix[] = "[kernel.kallsyms."; | 409 | kmmap_prefix, |
| 410 | strlen(kmmap_prefix)) == 0; | ||
| 411 | if (self->mmap.filename[0] == '/' || | ||
| 412 | (!is_kernel_mmap && self->mmap.filename[0] == '[')) { | ||
| 343 | 413 | ||
| 344 | if (self->mmap.filename[0] == '/') { | 414 | char short_module_name[1024]; |
| 345 | char short_module_name[1024]; | 415 | char *name, *dot; |
| 346 | char *name = strrchr(self->mmap.filename, '/'), *dot; | ||
| 347 | 416 | ||
| 417 | if (self->mmap.filename[0] == '/') { | ||
| 418 | name = strrchr(self->mmap.filename, '/'); | ||
| 348 | if (name == NULL) | 419 | if (name == NULL) |
| 349 | goto out_problem; | 420 | goto out_problem; |
| 350 | 421 | ||
| @@ -352,59 +423,86 @@ int event__process_mmap(event_t *self, struct perf_session *session) | |||
| 352 | dot = strrchr(name, '.'); | 423 | dot = strrchr(name, '.'); |
| 353 | if (dot == NULL) | 424 | if (dot == NULL) |
| 354 | goto out_problem; | 425 | goto out_problem; |
| 355 | |||
| 356 | snprintf(short_module_name, sizeof(short_module_name), | 426 | snprintf(short_module_name, sizeof(short_module_name), |
| 357 | "[%.*s]", (int)(dot - name), name); | 427 | "[%.*s]", (int)(dot - name), name); |
| 358 | strxfrchar(short_module_name, '-', '_'); | 428 | strxfrchar(short_module_name, '-', '_'); |
| 359 | 429 | } else | |
| 360 | map = perf_session__new_module_map(session, | 430 | strcpy(short_module_name, self->mmap.filename); |
| 361 | self->mmap.start, | 431 | |
| 362 | self->mmap.filename); | 432 | map = map_groups__new_module(&kerninfo->kmaps, |
| 363 | if (map == NULL) | 433 | self->mmap.start, |
| 364 | goto out_problem; | 434 | self->mmap.filename, |
| 365 | 435 | kerninfo); | |
| 366 | name = strdup(short_module_name); | 436 | if (map == NULL) |
| 367 | if (name == NULL) | 437 | goto out_problem; |
| 368 | goto out_problem; | 438 | |
| 369 | 439 | name = strdup(short_module_name); | |
| 370 | map->dso->short_name = name; | 440 | if (name == NULL) |
| 371 | map->end = map->start + self->mmap.len; | 441 | goto out_problem; |
| 372 | } else if (memcmp(self->mmap.filename, kmmap_prefix, | 442 | |
| 373 | sizeof(kmmap_prefix) - 1) == 0) { | 443 | map->dso->short_name = name; |
| 374 | const char *symbol_name = (self->mmap.filename + | 444 | map->end = map->start + self->mmap.len; |
| 375 | sizeof(kmmap_prefix) - 1); | 445 | } else if (is_kernel_mmap) { |
| 446 | const char *symbol_name = (self->mmap.filename + | ||
| 447 | strlen(kmmap_prefix)); | ||
| 448 | /* | ||
| 449 | * Should be there already, from the build-id table in | ||
| 450 | * the header. | ||
| 451 | */ | ||
| 452 | struct dso *kernel = __dsos__findnew(&kerninfo->dsos__kernel, | ||
| 453 | kmmap_prefix); | ||
| 454 | if (kernel == NULL) | ||
| 455 | goto out_problem; | ||
| 456 | |||
| 457 | kernel->kernel = kernel_type; | ||
| 458 | if (__map_groups__create_kernel_maps(&kerninfo->kmaps, | ||
| 459 | kerninfo->vmlinux_maps, kernel) < 0) | ||
| 460 | goto out_problem; | ||
| 461 | |||
| 462 | event_set_kernel_mmap_len(kerninfo->vmlinux_maps, self); | ||
| 463 | perf_session__set_kallsyms_ref_reloc_sym(kerninfo->vmlinux_maps, | ||
| 464 | symbol_name, | ||
| 465 | self->mmap.pgoff); | ||
| 466 | if (is_default_guest(kerninfo)) { | ||
| 376 | /* | 467 | /* |
| 377 | * Should be there already, from the build-id table in | 468 | * preload dso of guest kernel and modules |
| 378 | * the header. | ||
| 379 | */ | 469 | */ |
| 380 | struct dso *kernel = __dsos__findnew(&dsos__kernel, | 470 | dso__load(kernel, |
| 381 | "[kernel.kallsyms]"); | 471 | kerninfo->vmlinux_maps[MAP__FUNCTION], |
| 382 | if (kernel == NULL) | 472 | NULL); |
| 383 | goto out_problem; | 473 | } |
| 384 | 474 | } | |
| 385 | kernel->kernel = 1; | 475 | return 0; |
| 386 | if (__perf_session__create_kernel_maps(session, kernel) < 0) | 476 | out_problem: |
| 387 | goto out_problem; | 477 | return -1; |
| 478 | } | ||
| 388 | 479 | ||
| 389 | session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start; | 480 | int event__process_mmap(event_t *self, struct perf_session *session) |
| 390 | session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; | 481 | { |
| 391 | /* | 482 | struct kernel_info *kerninfo; |
| 392 | * Be a bit paranoid here, some perf.data file came with | 483 | struct thread *thread; |
| 393 | * a zero sized synthesized MMAP event for the kernel. | 484 | struct map *map; |
| 394 | */ | 485 | u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
| 395 | if (session->vmlinux_maps[MAP__FUNCTION]->end == 0) | 486 | int ret = 0; |
| 396 | session->vmlinux_maps[MAP__FUNCTION]->end = ~0UL; | ||
| 397 | 487 | ||
| 398 | perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name, | 488 | dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n", |
| 399 | self->mmap.pgoff); | 489 | self->mmap.pid, self->mmap.tid, self->mmap.start, |
| 400 | } | 490 | self->mmap.len, self->mmap.pgoff, self->mmap.filename); |
| 491 | |||
| 492 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || | ||
| 493 | cpumode == PERF_RECORD_MISC_KERNEL) { | ||
| 494 | ret = event__process_kernel_mmap(self, session); | ||
| 495 | if (ret < 0) | ||
| 496 | goto out_problem; | ||
| 401 | return 0; | 497 | return 0; |
| 402 | } | 498 | } |
| 403 | 499 | ||
| 404 | thread = perf_session__findnew(session, self->mmap.pid); | 500 | thread = perf_session__findnew(session, self->mmap.pid); |
| 405 | map = map__new(self->mmap.start, self->mmap.len, self->mmap.pgoff, | 501 | kerninfo = kerninfo__findhost(&session->kerninfo_root); |
| 406 | self->mmap.pid, self->mmap.filename, MAP__FUNCTION, | 502 | map = map__new(&kerninfo->dsos__user, self->mmap.start, |
| 407 | session->cwd, session->cwdlen); | 503 | self->mmap.len, self->mmap.pgoff, |
| 504 | self->mmap.pid, self->mmap.filename, | ||
| 505 | MAP__FUNCTION, session->cwd, session->cwdlen); | ||
| 408 | 506 | ||
| 409 | if (thread == NULL || map == NULL) | 507 | if (thread == NULL || map == NULL) |
| 410 | goto out_problem; | 508 | goto out_problem; |
| @@ -444,22 +542,52 @@ int event__process_task(event_t *self, struct perf_session *session) | |||
| 444 | 542 | ||
| 445 | void thread__find_addr_map(struct thread *self, | 543 | void thread__find_addr_map(struct thread *self, |
| 446 | struct perf_session *session, u8 cpumode, | 544 | struct perf_session *session, u8 cpumode, |
| 447 | enum map_type type, u64 addr, | 545 | enum map_type type, pid_t pid, u64 addr, |
| 448 | struct addr_location *al) | 546 | struct addr_location *al) |
| 449 | { | 547 | { |
| 450 | struct map_groups *mg = &self->mg; | 548 | struct map_groups *mg = &self->mg; |
| 549 | struct kernel_info *kerninfo = NULL; | ||
| 451 | 550 | ||
| 452 | al->thread = self; | 551 | al->thread = self; |
| 453 | al->addr = addr; | 552 | al->addr = addr; |
| 553 | al->cpumode = cpumode; | ||
| 554 | al->filtered = false; | ||
| 454 | 555 | ||
| 455 | if (cpumode == PERF_RECORD_MISC_KERNEL) { | 556 | if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { |
| 456 | al->level = 'k'; | 557 | al->level = 'k'; |
| 457 | mg = &session->kmaps; | 558 | kerninfo = kerninfo__findhost(&session->kerninfo_root); |
| 458 | } else if (cpumode == PERF_RECORD_MISC_USER) | 559 | mg = &kerninfo->kmaps; |
| 560 | } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { | ||
| 459 | al->level = '.'; | 561 | al->level = '.'; |
| 460 | else { | 562 | kerninfo = kerninfo__findhost(&session->kerninfo_root); |
| 461 | al->level = 'H'; | 563 | } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { |
| 564 | al->level = 'g'; | ||
| 565 | kerninfo = kerninfo__find(&session->kerninfo_root, pid); | ||
| 566 | if (!kerninfo) { | ||
| 567 | al->map = NULL; | ||
| 568 | return; | ||
| 569 | } | ||
| 570 | mg = &kerninfo->kmaps; | ||
| 571 | } else { | ||
| 572 | /* | ||
| 573 | * 'u' means guest os user space. | ||
| 574 | * TODO: We don't support guest user space. Might support late. | ||
| 575 | */ | ||
| 576 | if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) | ||
| 577 | al->level = 'u'; | ||
| 578 | else | ||
| 579 | al->level = 'H'; | ||
| 462 | al->map = NULL; | 580 | al->map = NULL; |
| 581 | |||
| 582 | if ((cpumode == PERF_RECORD_MISC_GUEST_USER || | ||
| 583 | cpumode == PERF_RECORD_MISC_GUEST_KERNEL) && | ||
| 584 | !perf_guest) | ||
| 585 | al->filtered = true; | ||
| 586 | if ((cpumode == PERF_RECORD_MISC_USER || | ||
| 587 | cpumode == PERF_RECORD_MISC_KERNEL) && | ||
| 588 | !perf_host) | ||
| 589 | al->filtered = true; | ||
| 590 | |||
| 463 | return; | 591 | return; |
| 464 | } | 592 | } |
| 465 | try_again: | 593 | try_again: |
| @@ -474,8 +602,11 @@ try_again: | |||
| 474 | * "[vdso]" dso, but for now lets use the old trick of looking | 602 | * "[vdso]" dso, but for now lets use the old trick of looking |
| 475 | * in the whole kernel symbol list. | 603 | * in the whole kernel symbol list. |
| 476 | */ | 604 | */ |
| 477 | if ((long long)al->addr < 0 && mg != &session->kmaps) { | 605 | if ((long long)al->addr < 0 && |
| 478 | mg = &session->kmaps; | 606 | cpumode == PERF_RECORD_MISC_KERNEL && |
| 607 | kerninfo && | ||
| 608 | mg != &kerninfo->kmaps) { | ||
| 609 | mg = &kerninfo->kmaps; | ||
| 479 | goto try_again; | 610 | goto try_again; |
| 480 | } | 611 | } |
| 481 | } else | 612 | } else |
| @@ -484,11 +615,11 @@ try_again: | |||
| 484 | 615 | ||
| 485 | void thread__find_addr_location(struct thread *self, | 616 | void thread__find_addr_location(struct thread *self, |
| 486 | struct perf_session *session, u8 cpumode, | 617 | struct perf_session *session, u8 cpumode, |
| 487 | enum map_type type, u64 addr, | 618 | enum map_type type, pid_t pid, u64 addr, |
| 488 | struct addr_location *al, | 619 | struct addr_location *al, |
| 489 | symbol_filter_t filter) | 620 | symbol_filter_t filter) |
| 490 | { | 621 | { |
| 491 | thread__find_addr_map(self, session, cpumode, type, addr, al); | 622 | thread__find_addr_map(self, session, cpumode, type, pid, addr, al); |
| 492 | if (al->map != NULL) | 623 | if (al->map != NULL) |
| 493 | al->sym = map__find_symbol(al->map, al->addr, filter); | 624 | al->sym = map__find_symbol(al->map, al->addr, filter); |
| 494 | else | 625 | else |
| @@ -524,7 +655,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, | |||
| 524 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 655 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
| 525 | 656 | ||
| 526 | thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, | 657 | thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, |
| 527 | self->ip.ip, al); | 658 | self->ip.pid, self->ip.ip, al); |
| 528 | dump_printf(" ...... dso: %s\n", | 659 | dump_printf(" ...... dso: %s\n", |
| 529 | al->map ? al->map->dso->long_name : | 660 | al->map ? al->map->dso->long_name : |
| 530 | al->level == 'H' ? "[hypervisor]" : "<not found>"); | 661 | al->level == 'H' ? "[hypervisor]" : "<not found>"); |
| @@ -554,7 +685,6 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, | |||
| 554 | !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) | 685 | !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) |
| 555 | goto out_filtered; | 686 | goto out_filtered; |
| 556 | 687 | ||
| 557 | al->filtered = false; | ||
| 558 | return 0; | 688 | return 0; |
| 559 | 689 | ||
| 560 | out_filtered: | 690 | out_filtered: |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index e5740ea140ab..4af2ed5d48ad 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -79,6 +79,7 @@ struct sample_data { | |||
| 79 | 79 | ||
| 80 | struct build_id_event { | 80 | struct build_id_event { |
| 81 | struct perf_event_header header; | 81 | struct perf_event_header header; |
| 82 | pid_t pid; | ||
| 82 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | 83 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; |
| 83 | char filename[]; | 84 | char filename[]; |
| 84 | }; | 85 | }; |
| @@ -154,10 +155,13 @@ int event__synthesize_thread(pid_t pid, event__handler_t process, | |||
| 154 | void event__synthesize_threads(event__handler_t process, | 155 | void event__synthesize_threads(event__handler_t process, |
| 155 | struct perf_session *session); | 156 | struct perf_session *session); |
| 156 | int event__synthesize_kernel_mmap(event__handler_t process, | 157 | int event__synthesize_kernel_mmap(event__handler_t process, |
| 157 | struct perf_session *session, | 158 | struct perf_session *session, |
| 158 | const char *symbol_name); | 159 | struct kernel_info *kerninfo, |
| 160 | const char *symbol_name); | ||
| 161 | |||
| 159 | int event__synthesize_modules(event__handler_t process, | 162 | int event__synthesize_modules(event__handler_t process, |
| 160 | struct perf_session *session); | 163 | struct perf_session *session, |
| 164 | struct kernel_info *kerninfo); | ||
| 161 | 165 | ||
| 162 | int event__process_comm(event_t *self, struct perf_session *session); | 166 | int event__process_comm(event_t *self, struct perf_session *session); |
| 163 | int event__process_lost(event_t *self, struct perf_session *session); | 167 | int event__process_lost(event_t *self, struct perf_session *session); |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 628173ba689e..75d016768021 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -190,7 +190,8 @@ static int write_padded(int fd, const void *bf, size_t count, | |||
| 190 | continue; \ | 190 | continue; \ |
| 191 | else | 191 | else |
| 192 | 192 | ||
| 193 | static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) | 193 | static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, |
| 194 | u16 misc, int fd) | ||
| 194 | { | 195 | { |
| 195 | struct dso *pos; | 196 | struct dso *pos; |
| 196 | 197 | ||
| @@ -205,6 +206,7 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) | |||
| 205 | len = ALIGN(len, NAME_ALIGN); | 206 | len = ALIGN(len, NAME_ALIGN); |
| 206 | memset(&b, 0, sizeof(b)); | 207 | memset(&b, 0, sizeof(b)); |
| 207 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); | 208 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); |
| 209 | b.pid = pid; | ||
| 208 | b.header.misc = misc; | 210 | b.header.misc = misc; |
| 209 | b.header.size = sizeof(b) + len; | 211 | b.header.size = sizeof(b) + len; |
| 210 | err = do_write(fd, &b, sizeof(b)); | 212 | err = do_write(fd, &b, sizeof(b)); |
| @@ -219,13 +221,33 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) | |||
| 219 | return 0; | 221 | return 0; |
| 220 | } | 222 | } |
| 221 | 223 | ||
| 222 | static int dsos__write_buildid_table(int fd) | 224 | static int dsos__write_buildid_table(struct perf_header *header, int fd) |
| 223 | { | 225 | { |
| 224 | int err = __dsos__write_buildid_table(&dsos__kernel, | 226 | struct perf_session *session = container_of(header, |
| 225 | PERF_RECORD_MISC_KERNEL, fd); | 227 | struct perf_session, header); |
| 226 | if (err == 0) | 228 | struct rb_node *nd; |
| 227 | err = __dsos__write_buildid_table(&dsos__user, | 229 | int err = 0; |
| 228 | PERF_RECORD_MISC_USER, fd); | 230 | u16 kmisc, umisc; |
| 231 | |||
| 232 | for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) { | ||
| 233 | struct kernel_info *pos = rb_entry(nd, struct kernel_info, | ||
| 234 | rb_node); | ||
| 235 | if (is_host_kernel(pos)) { | ||
| 236 | kmisc = PERF_RECORD_MISC_KERNEL; | ||
| 237 | umisc = PERF_RECORD_MISC_USER; | ||
| 238 | } else { | ||
| 239 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; | ||
| 240 | umisc = PERF_RECORD_MISC_GUEST_USER; | ||
| 241 | } | ||
| 242 | |||
| 243 | err = __dsos__write_buildid_table(&pos->dsos__kernel, pos->pid, | ||
| 244 | kmisc, fd); | ||
| 245 | if (err == 0) | ||
| 246 | err = __dsos__write_buildid_table(&pos->dsos__user, | ||
| 247 | pos->pid, umisc, fd); | ||
| 248 | if (err) | ||
| 249 | break; | ||
| 250 | } | ||
| 229 | return err; | 251 | return err; |
| 230 | } | 252 | } |
| 231 | 253 | ||
| @@ -342,9 +364,12 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | |||
| 342 | return err; | 364 | return err; |
| 343 | } | 365 | } |
| 344 | 366 | ||
| 345 | static int dsos__cache_build_ids(void) | 367 | static int dsos__cache_build_ids(struct perf_header *self) |
| 346 | { | 368 | { |
| 347 | int err_kernel, err_user; | 369 | struct perf_session *session = container_of(self, |
| 370 | struct perf_session, header); | ||
| 371 | struct rb_node *nd; | ||
| 372 | int ret = 0; | ||
| 348 | char debugdir[PATH_MAX]; | 373 | char debugdir[PATH_MAX]; |
| 349 | 374 | ||
| 350 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), | 375 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), |
| @@ -353,9 +378,30 @@ static int dsos__cache_build_ids(void) | |||
| 353 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | 378 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) |
| 354 | return -1; | 379 | return -1; |
| 355 | 380 | ||
| 356 | err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir); | 381 | for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) { |
| 357 | err_user = __dsos__cache_build_ids(&dsos__user, debugdir); | 382 | struct kernel_info *pos = rb_entry(nd, struct kernel_info, |
| 358 | return err_kernel || err_user ? -1 : 0; | 383 | rb_node); |
| 384 | ret |= __dsos__cache_build_ids(&pos->dsos__kernel, debugdir); | ||
| 385 | ret |= __dsos__cache_build_ids(&pos->dsos__user, debugdir); | ||
| 386 | } | ||
| 387 | return ret ? -1 : 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | static bool dsos__read_build_ids(struct perf_header *self, bool with_hits) | ||
| 391 | { | ||
| 392 | bool ret = false; | ||
| 393 | struct perf_session *session = container_of(self, | ||
| 394 | struct perf_session, header); | ||
| 395 | struct rb_node *nd; | ||
| 396 | |||
| 397 | for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) { | ||
| 398 | struct kernel_info *pos = rb_entry(nd, struct kernel_info, | ||
| 399 | rb_node); | ||
| 400 | ret |= __dsos__read_build_ids(&pos->dsos__kernel, with_hits); | ||
| 401 | ret |= __dsos__read_build_ids(&pos->dsos__user, with_hits); | ||
| 402 | } | ||
| 403 | |||
| 404 | return ret; | ||
| 359 | } | 405 | } |
| 360 | 406 | ||
| 361 | static int perf_header__adds_write(struct perf_header *self, int fd) | 407 | static int perf_header__adds_write(struct perf_header *self, int fd) |
| @@ -366,7 +412,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
| 366 | u64 sec_start; | 412 | u64 sec_start; |
| 367 | int idx = 0, err; | 413 | int idx = 0, err; |
| 368 | 414 | ||
| 369 | if (dsos__read_build_ids(true)) | 415 | if (dsos__read_build_ids(self, true)) |
| 370 | perf_header__set_feat(self, HEADER_BUILD_ID); | 416 | perf_header__set_feat(self, HEADER_BUILD_ID); |
| 371 | 417 | ||
| 372 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 418 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); |
| @@ -401,14 +447,14 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
| 401 | 447 | ||
| 402 | /* Write build-ids */ | 448 | /* Write build-ids */ |
| 403 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); | 449 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); |
| 404 | err = dsos__write_buildid_table(fd); | 450 | err = dsos__write_buildid_table(self, fd); |
| 405 | if (err < 0) { | 451 | if (err < 0) { |
| 406 | pr_debug("failed to write buildid table\n"); | 452 | pr_debug("failed to write buildid table\n"); |
| 407 | goto out_free; | 453 | goto out_free; |
| 408 | } | 454 | } |
| 409 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - | 455 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - |
| 410 | buildid_sec->offset; | 456 | buildid_sec->offset; |
| 411 | dsos__cache_build_ids(); | 457 | dsos__cache_build_ids(self); |
| 412 | } | 458 | } |
| 413 | 459 | ||
| 414 | lseek(fd, sec_start, SEEK_SET); | 460 | lseek(fd, sec_start, SEEK_SET); |
| @@ -633,6 +679,85 @@ int perf_file_header__read(struct perf_file_header *self, | |||
| 633 | return 0; | 679 | return 0; |
| 634 | } | 680 | } |
| 635 | 681 | ||
| 682 | static int __event_process_build_id(struct build_id_event *bev, | ||
| 683 | char *filename, | ||
| 684 | struct perf_session *session) | ||
| 685 | { | ||
| 686 | int err = -1; | ||
| 687 | struct list_head *head; | ||
| 688 | struct kernel_info *kerninfo; | ||
| 689 | u16 misc; | ||
| 690 | struct dso *dso; | ||
| 691 | enum dso_kernel_type dso_type; | ||
| 692 | |||
| 693 | kerninfo = kerninfo__findnew(&session->kerninfo_root, bev->pid); | ||
| 694 | if (!kerninfo) | ||
| 695 | goto out; | ||
| 696 | |||
| 697 | misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
| 698 | |||
| 699 | switch (misc) { | ||
| 700 | case PERF_RECORD_MISC_KERNEL: | ||
| 701 | dso_type = DSO_TYPE_KERNEL; | ||
| 702 | head = &kerninfo->dsos__kernel; | ||
| 703 | break; | ||
| 704 | case PERF_RECORD_MISC_GUEST_KERNEL: | ||
| 705 | dso_type = DSO_TYPE_GUEST_KERNEL; | ||
| 706 | head = &kerninfo->dsos__kernel; | ||
| 707 | break; | ||
| 708 | case PERF_RECORD_MISC_USER: | ||
| 709 | case PERF_RECORD_MISC_GUEST_USER: | ||
| 710 | dso_type = DSO_TYPE_USER; | ||
| 711 | head = &kerninfo->dsos__user; | ||
| 712 | break; | ||
| 713 | default: | ||
| 714 | goto out; | ||
| 715 | } | ||
| 716 | |||
| 717 | dso = __dsos__findnew(head, filename); | ||
| 718 | if (dso != NULL) { | ||
| 719 | dso__set_build_id(dso, &bev->build_id); | ||
| 720 | if (filename[0] == '[') | ||
| 721 | dso->kernel = dso_type; | ||
| 722 | } | ||
| 723 | |||
| 724 | err = 0; | ||
| 725 | out: | ||
| 726 | return err; | ||
| 727 | } | ||
| 728 | |||
| 729 | static int perf_header__read_build_ids(struct perf_header *self, | ||
| 730 | int input, u64 offset, u64 size) | ||
| 731 | { | ||
| 732 | struct perf_session *session = container_of(self, | ||
| 733 | struct perf_session, header); | ||
| 734 | struct build_id_event bev; | ||
| 735 | char filename[PATH_MAX]; | ||
| 736 | u64 limit = offset + size; | ||
| 737 | int err = -1; | ||
| 738 | |||
| 739 | while (offset < limit) { | ||
| 740 | ssize_t len; | ||
| 741 | |||
| 742 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | ||
| 743 | goto out; | ||
| 744 | |||
| 745 | if (self->needs_swap) | ||
| 746 | perf_event_header__bswap(&bev.header); | ||
| 747 | |||
| 748 | len = bev.header.size - sizeof(bev); | ||
| 749 | if (read(input, filename, len) != len) | ||
| 750 | goto out; | ||
| 751 | |||
| 752 | __event_process_build_id(&bev, filename, session); | ||
| 753 | |||
| 754 | offset += bev.header.size; | ||
| 755 | } | ||
| 756 | err = 0; | ||
| 757 | out: | ||
| 758 | return err; | ||
| 759 | } | ||
| 760 | |||
| 636 | static int perf_file_section__process(struct perf_file_section *self, | 761 | static int perf_file_section__process(struct perf_file_section *self, |
| 637 | struct perf_header *ph, | 762 | struct perf_header *ph, |
| 638 | int feat, int fd) | 763 | int feat, int fd) |
| @@ -989,6 +1114,7 @@ int event__process_tracing_data(event_t *self, | |||
| 989 | 1114 | ||
| 990 | int event__synthesize_build_id(struct dso *pos, u16 misc, | 1115 | int event__synthesize_build_id(struct dso *pos, u16 misc, |
| 991 | event__handler_t process, | 1116 | event__handler_t process, |
| 1117 | struct kernel_info *kerninfo, | ||
| 992 | struct perf_session *session) | 1118 | struct perf_session *session) |
| 993 | { | 1119 | { |
| 994 | event_t ev; | 1120 | event_t ev; |
| @@ -1005,6 +1131,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc, | |||
| 1005 | memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); | 1131 | memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); |
| 1006 | ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; | 1132 | ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; |
| 1007 | ev.build_id.header.misc = misc; | 1133 | ev.build_id.header.misc = misc; |
| 1134 | ev.build_id.pid = kerninfo->pid; | ||
| 1008 | ev.build_id.header.size = sizeof(ev.build_id) + len; | 1135 | ev.build_id.header.size = sizeof(ev.build_id) + len; |
| 1009 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); | 1136 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); |
| 1010 | 1137 | ||
| @@ -1015,6 +1142,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc, | |||
| 1015 | 1142 | ||
| 1016 | static int __event_synthesize_build_ids(struct list_head *head, u16 misc, | 1143 | static int __event_synthesize_build_ids(struct list_head *head, u16 misc, |
| 1017 | event__handler_t process, | 1144 | event__handler_t process, |
| 1145 | struct kernel_info *kerninfo, | ||
| 1018 | struct perf_session *session) | 1146 | struct perf_session *session) |
| 1019 | { | 1147 | { |
| 1020 | struct dso *pos; | 1148 | struct dso *pos; |
| @@ -1024,7 +1152,8 @@ static int __event_synthesize_build_ids(struct list_head *head, u16 misc, | |||
| 1024 | if (!pos->hit) | 1152 | if (!pos->hit) |
| 1025 | continue; | 1153 | continue; |
| 1026 | 1154 | ||
| 1027 | err = event__synthesize_build_id(pos, misc, process, session); | 1155 | err = event__synthesize_build_id(pos, misc, process, |
| 1156 | kerninfo, session); | ||
| 1028 | if (err < 0) | 1157 | if (err < 0) |
| 1029 | return err; | 1158 | return err; |
| 1030 | } | 1159 | } |
| @@ -1035,44 +1164,48 @@ static int __event_synthesize_build_ids(struct list_head *head, u16 misc, | |||
| 1035 | int event__synthesize_build_ids(event__handler_t process, | 1164 | int event__synthesize_build_ids(event__handler_t process, |
| 1036 | struct perf_session *session) | 1165 | struct perf_session *session) |
| 1037 | { | 1166 | { |
| 1038 | int err; | 1167 | int err = 0; |
| 1168 | u16 kmisc, umisc; | ||
| 1169 | struct kernel_info *pos; | ||
| 1170 | struct rb_node *nd; | ||
| 1039 | 1171 | ||
| 1040 | if (!dsos__read_build_ids(true)) | 1172 | if (!dsos__read_build_ids(&session->header, true)) |
| 1041 | return 0; | 1173 | return 0; |
| 1042 | 1174 | ||
| 1043 | err = __event_synthesize_build_ids(&dsos__kernel, | 1175 | for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) { |
| 1044 | PERF_RECORD_MISC_KERNEL, | 1176 | pos = rb_entry(nd, struct kernel_info, rb_node); |
| 1045 | process, session); | 1177 | if (is_host_kernel(pos)) { |
| 1046 | if (err == 0) | 1178 | kmisc = PERF_RECORD_MISC_KERNEL; |
| 1047 | err = __event_synthesize_build_ids(&dsos__user, | 1179 | umisc = PERF_RECORD_MISC_USER; |
| 1048 | PERF_RECORD_MISC_USER, | 1180 | } else { |
| 1049 | process, session); | 1181 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; |
| 1182 | umisc = PERF_RECORD_MISC_GUEST_USER; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | err = __event_synthesize_build_ids(&pos->dsos__kernel, | ||
| 1186 | kmisc, process, pos, session); | ||
| 1187 | if (err == 0) | ||
| 1188 | err = __event_synthesize_build_ids(&pos->dsos__user, | ||
| 1189 | umisc, process, pos, session); | ||
| 1190 | if (err) | ||
| 1191 | break; | ||
| 1192 | } | ||
| 1050 | 1193 | ||
| 1051 | if (err < 0) { | 1194 | if (err < 0) { |
| 1052 | pr_debug("failed to synthesize build ids\n"); | 1195 | pr_debug("failed to synthesize build ids\n"); |
| 1053 | return err; | 1196 | return err; |
| 1054 | } | 1197 | } |
| 1055 | 1198 | ||
| 1056 | dsos__cache_build_ids(); | 1199 | dsos__cache_build_ids(&session->header); |
| 1057 | 1200 | ||
| 1058 | return 0; | 1201 | return 0; |
| 1059 | } | 1202 | } |
| 1060 | 1203 | ||
| 1061 | int event__process_build_id(event_t *self, | 1204 | int event__process_build_id(event_t *self, |
| 1062 | struct perf_session *session __unused) | 1205 | struct perf_session *session) |
| 1063 | { | 1206 | { |
| 1064 | struct list_head *head = &dsos__user; | 1207 | __event_process_build_id(&self->build_id, |
| 1065 | struct dso *dso; | 1208 | self->build_id.filename, |
| 1066 | 1209 | session); | |
| 1067 | if (self->build_id.header.misc & PERF_RECORD_MISC_KERNEL) | ||
| 1068 | head = &dsos__kernel; | ||
| 1069 | |||
| 1070 | dso = __dsos__findnew(head, self->build_id.filename); | ||
| 1071 | if (dso != NULL) { | ||
| 1072 | dso__set_build_id(dso, &self->build_id.build_id); | ||
| 1073 | if (head == &dsos__kernel && self->build_id.filename[0] == '[') | ||
| 1074 | dso->kernel = 1; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | return 0; | 1210 | return 0; |
| 1078 | } | 1211 | } |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 4214e2375650..275915458148 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
| @@ -120,6 +120,7 @@ int event__process_tracing_data(event_t *self, | |||
| 120 | 120 | ||
| 121 | int event__synthesize_build_id(struct dso *pos, u16 misc, | 121 | int event__synthesize_build_id(struct dso *pos, u16 misc, |
| 122 | event__handler_t process, | 122 | event__handler_t process, |
| 123 | struct kernel_info *kerninfo, | ||
| 123 | struct perf_session *session); | 124 | struct perf_session *session); |
| 124 | int event__synthesize_build_ids(event__handler_t process, | 125 | int event__synthesize_build_ids(event__handler_t process, |
| 125 | struct perf_session *session); | 126 | struct perf_session *session); |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 9c2b8743cef6..ad6b22dde27f 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -8,6 +8,30 @@ struct callchain_param callchain_param = { | |||
| 8 | .min_percent = 0.5 | 8 | .min_percent = 0.5 |
| 9 | }; | 9 | }; |
| 10 | 10 | ||
| 11 | void __perf_session__add_count(struct hist_entry *he, | ||
| 12 | struct addr_location *al, | ||
| 13 | u64 count) | ||
| 14 | { | ||
| 15 | he->count += count; | ||
| 16 | |||
| 17 | switch (al->cpumode) { | ||
| 18 | case PERF_RECORD_MISC_KERNEL: | ||
| 19 | he->count_sys += count; | ||
| 20 | break; | ||
| 21 | case PERF_RECORD_MISC_USER: | ||
| 22 | he->count_us += count; | ||
| 23 | break; | ||
| 24 | case PERF_RECORD_MISC_GUEST_KERNEL: | ||
| 25 | he->count_guest_sys += count; | ||
| 26 | break; | ||
| 27 | case PERF_RECORD_MISC_GUEST_USER: | ||
| 28 | he->count_guest_us += count; | ||
| 29 | break; | ||
| 30 | default: | ||
| 31 | break; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 11 | /* | 35 | /* |
| 12 | * histogram, sorted on item, collects counts | 36 | * histogram, sorted on item, collects counts |
| 13 | */ | 37 | */ |
| @@ -464,7 +488,7 @@ int hist_entry__snprintf(struct hist_entry *self, | |||
| 464 | u64 session_total) | 488 | u64 session_total) |
| 465 | { | 489 | { |
| 466 | struct sort_entry *se; | 490 | struct sort_entry *se; |
| 467 | u64 count, total; | 491 | u64 count, total, count_sys, count_us, count_guest_sys, count_guest_us; |
| 468 | const char *sep = symbol_conf.field_sep; | 492 | const char *sep = symbol_conf.field_sep; |
| 469 | int ret; | 493 | int ret; |
| 470 | 494 | ||
| @@ -474,9 +498,17 @@ int hist_entry__snprintf(struct hist_entry *self, | |||
| 474 | if (pair_session) { | 498 | if (pair_session) { |
| 475 | count = self->pair ? self->pair->count : 0; | 499 | count = self->pair ? self->pair->count : 0; |
| 476 | total = pair_session->events_stats.total; | 500 | total = pair_session->events_stats.total; |
| 501 | count_sys = self->pair ? self->pair->count_sys : 0; | ||
| 502 | count_us = self->pair ? self->pair->count_us : 0; | ||
| 503 | count_guest_sys = self->pair ? self->pair->count_guest_sys : 0; | ||
| 504 | count_guest_us = self->pair ? self->pair->count_guest_us : 0; | ||
| 477 | } else { | 505 | } else { |
| 478 | count = self->count; | 506 | count = self->count; |
| 479 | total = session_total; | 507 | total = session_total; |
| 508 | count_sys = self->count_sys; | ||
| 509 | count_us = self->count_us; | ||
| 510 | count_guest_sys = self->count_guest_sys; | ||
| 511 | count_guest_us = self->count_guest_us; | ||
| 480 | } | 512 | } |
| 481 | 513 | ||
| 482 | if (total) { | 514 | if (total) { |
| @@ -487,6 +519,26 @@ int hist_entry__snprintf(struct hist_entry *self, | |||
| 487 | else | 519 | else |
| 488 | ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%", | 520 | ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%", |
| 489 | (count * 100.0) / total); | 521 | (count * 100.0) / total); |
| 522 | if (symbol_conf.show_cpu_utilization) { | ||
| 523 | ret += percent_color_snprintf(s + ret, size - ret, | ||
| 524 | sep ? "%.2f" : " %6.2f%%", | ||
| 525 | (count_sys * 100.0) / total); | ||
| 526 | ret += percent_color_snprintf(s + ret, size - ret, | ||
| 527 | sep ? "%.2f" : " %6.2f%%", | ||
| 528 | (count_us * 100.0) / total); | ||
| 529 | if (perf_guest) { | ||
| 530 | ret += percent_color_snprintf(s + ret, | ||
| 531 | size - ret, | ||
| 532 | sep ? "%.2f" : " %6.2f%%", | ||
| 533 | (count_guest_sys * 100.0) / | ||
| 534 | total); | ||
| 535 | ret += percent_color_snprintf(s + ret, | ||
| 536 | size - ret, | ||
| 537 | sep ? "%.2f" : " %6.2f%%", | ||
| 538 | (count_guest_us * 100.0) / | ||
| 539 | total); | ||
| 540 | } | ||
| 541 | } | ||
| 490 | } else | 542 | } else |
| 491 | ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count); | 543 | ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count); |
| 492 | 544 | ||
| @@ -597,6 +649,24 @@ size_t perf_session__fprintf_hists(struct rb_root *hists, | |||
| 597 | fputs(" Samples ", fp); | 649 | fputs(" Samples ", fp); |
| 598 | } | 650 | } |
| 599 | 651 | ||
| 652 | if (symbol_conf.show_cpu_utilization) { | ||
| 653 | if (sep) { | ||
| 654 | ret += fprintf(fp, "%csys", *sep); | ||
| 655 | ret += fprintf(fp, "%cus", *sep); | ||
| 656 | if (perf_guest) { | ||
| 657 | ret += fprintf(fp, "%cguest sys", *sep); | ||
| 658 | ret += fprintf(fp, "%cguest us", *sep); | ||
| 659 | } | ||
| 660 | } else { | ||
| 661 | ret += fprintf(fp, " sys "); | ||
| 662 | ret += fprintf(fp, " us "); | ||
| 663 | if (perf_guest) { | ||
| 664 | ret += fprintf(fp, " guest sys "); | ||
| 665 | ret += fprintf(fp, " guest us "); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 600 | if (pair) { | 670 | if (pair) { |
| 601 | if (sep) | 671 | if (sep) |
| 602 | ret += fprintf(fp, "%cDelta", *sep); | 672 | ret += fprintf(fp, "%cDelta", *sep); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ad17f0ad798b..9df1c340ec92 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -12,6 +12,9 @@ struct addr_location; | |||
| 12 | struct symbol; | 12 | struct symbol; |
| 13 | struct rb_root; | 13 | struct rb_root; |
| 14 | 14 | ||
| 15 | void __perf_session__add_count(struct hist_entry *he, | ||
| 16 | struct addr_location *al, | ||
| 17 | u64 count); | ||
| 15 | struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, | 18 | struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, |
| 16 | struct addr_location *al, | 19 | struct addr_location *al, |
| 17 | struct symbol *parent, | 20 | struct symbol *parent, |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 37913b241bdf..7facd016ec97 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
| 5 | #include <string.h> | 5 | #include <string.h> |
| 6 | #include <stdio.h> | 6 | #include <stdio.h> |
| 7 | #include <unistd.h> | ||
| 7 | #include "map.h" | 8 | #include "map.h" |
| 8 | 9 | ||
| 9 | const char *map_type__name[MAP__NR_TYPES] = { | 10 | const char *map_type__name[MAP__NR_TYPES] = { |
| @@ -37,9 +38,11 @@ void map__init(struct map *self, enum map_type type, | |||
| 37 | self->map_ip = map__map_ip; | 38 | self->map_ip = map__map_ip; |
| 38 | self->unmap_ip = map__unmap_ip; | 39 | self->unmap_ip = map__unmap_ip; |
| 39 | RB_CLEAR_NODE(&self->rb_node); | 40 | RB_CLEAR_NODE(&self->rb_node); |
| 41 | self->groups = NULL; | ||
| 40 | } | 42 | } |
| 41 | 43 | ||
| 42 | struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename, | 44 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, |
| 45 | u64 pgoff, u32 pid, char *filename, | ||
| 43 | enum map_type type, char *cwd, int cwdlen) | 46 | enum map_type type, char *cwd, int cwdlen) |
| 44 | { | 47 | { |
| 45 | struct map *self = malloc(sizeof(*self)); | 48 | struct map *self = malloc(sizeof(*self)); |
| @@ -66,7 +69,7 @@ struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename, | |||
| 66 | filename = newfilename; | 69 | filename = newfilename; |
| 67 | } | 70 | } |
| 68 | 71 | ||
| 69 | dso = dsos__findnew(filename); | 72 | dso = __dsos__findnew(dsos__list, filename); |
| 70 | if (dso == NULL) | 73 | if (dso == NULL) |
| 71 | goto out_delete; | 74 | goto out_delete; |
| 72 | 75 | ||
| @@ -242,6 +245,7 @@ void map_groups__init(struct map_groups *self) | |||
| 242 | self->maps[i] = RB_ROOT; | 245 | self->maps[i] = RB_ROOT; |
| 243 | INIT_LIST_HEAD(&self->removed_maps[i]); | 246 | INIT_LIST_HEAD(&self->removed_maps[i]); |
| 244 | } | 247 | } |
| 248 | self->this_kerninfo = NULL; | ||
| 245 | } | 249 | } |
| 246 | 250 | ||
| 247 | void map_groups__flush(struct map_groups *self) | 251 | void map_groups__flush(struct map_groups *self) |
| @@ -508,3 +512,134 @@ struct map *maps__find(struct rb_root *maps, u64 ip) | |||
| 508 | 512 | ||
| 509 | return NULL; | 513 | return NULL; |
| 510 | } | 514 | } |
| 515 | |||
| 516 | struct kernel_info *add_new_kernel_info(struct rb_root *kerninfo_root, | ||
| 517 | pid_t pid, const char *root_dir) | ||
| 518 | { | ||
| 519 | struct rb_node **p = &kerninfo_root->rb_node; | ||
| 520 | struct rb_node *parent = NULL; | ||
| 521 | struct kernel_info *kerninfo, *pos; | ||
| 522 | |||
| 523 | kerninfo = malloc(sizeof(struct kernel_info)); | ||
| 524 | if (!kerninfo) | ||
| 525 | return NULL; | ||
| 526 | |||
| 527 | kerninfo->pid = pid; | ||
| 528 | map_groups__init(&kerninfo->kmaps); | ||
| 529 | kerninfo->root_dir = strdup(root_dir); | ||
| 530 | RB_CLEAR_NODE(&kerninfo->rb_node); | ||
| 531 | INIT_LIST_HEAD(&kerninfo->dsos__user); | ||
| 532 | INIT_LIST_HEAD(&kerninfo->dsos__kernel); | ||
| 533 | kerninfo->kmaps.this_kerninfo = kerninfo; | ||
| 534 | |||
| 535 | while (*p != NULL) { | ||
| 536 | parent = *p; | ||
| 537 | pos = rb_entry(parent, struct kernel_info, rb_node); | ||
| 538 | if (pid < pos->pid) | ||
| 539 | p = &(*p)->rb_left; | ||
| 540 | else | ||
| 541 | p = &(*p)->rb_right; | ||
| 542 | } | ||
| 543 | |||
| 544 | rb_link_node(&kerninfo->rb_node, parent, p); | ||
| 545 | rb_insert_color(&kerninfo->rb_node, kerninfo_root); | ||
| 546 | |||
| 547 | return kerninfo; | ||
| 548 | } | ||
| 549 | |||
| 550 | struct kernel_info *kerninfo__find(struct rb_root *kerninfo_root, pid_t pid) | ||
| 551 | { | ||
| 552 | struct rb_node **p = &kerninfo_root->rb_node; | ||
| 553 | struct rb_node *parent = NULL; | ||
| 554 | struct kernel_info *kerninfo; | ||
| 555 | struct kernel_info *default_kerninfo = NULL; | ||
| 556 | |||
| 557 | while (*p != NULL) { | ||
| 558 | parent = *p; | ||
| 559 | kerninfo = rb_entry(parent, struct kernel_info, rb_node); | ||
| 560 | if (pid < kerninfo->pid) | ||
| 561 | p = &(*p)->rb_left; | ||
| 562 | else if (pid > kerninfo->pid) | ||
| 563 | p = &(*p)->rb_right; | ||
| 564 | else | ||
| 565 | return kerninfo; | ||
| 566 | if (!kerninfo->pid) | ||
| 567 | default_kerninfo = kerninfo; | ||
| 568 | } | ||
| 569 | |||
| 570 | return default_kerninfo; | ||
| 571 | } | ||
| 572 | |||
| 573 | struct kernel_info *kerninfo__findhost(struct rb_root *kerninfo_root) | ||
| 574 | { | ||
| 575 | struct rb_node **p = &kerninfo_root->rb_node; | ||
| 576 | struct rb_node *parent = NULL; | ||
| 577 | struct kernel_info *kerninfo; | ||
| 578 | pid_t pid = HOST_KERNEL_ID; | ||
| 579 | |||
| 580 | while (*p != NULL) { | ||
| 581 | parent = *p; | ||
| 582 | kerninfo = rb_entry(parent, struct kernel_info, rb_node); | ||
| 583 | if (pid < kerninfo->pid) | ||
| 584 | p = &(*p)->rb_left; | ||
| 585 | else if (pid > kerninfo->pid) | ||
| 586 | p = &(*p)->rb_right; | ||
| 587 | else | ||
| 588 | return kerninfo; | ||
| 589 | } | ||
| 590 | |||
| 591 | return NULL; | ||
| 592 | } | ||
| 593 | |||
| 594 | struct kernel_info *kerninfo__findnew(struct rb_root *kerninfo_root, pid_t pid) | ||
| 595 | { | ||
| 596 | char path[PATH_MAX]; | ||
| 597 | const char *root_dir; | ||
| 598 | int ret; | ||
| 599 | struct kernel_info *kerninfo = kerninfo__find(kerninfo_root, pid); | ||
| 600 | |||
| 601 | if (!kerninfo || kerninfo->pid != pid) { | ||
| 602 | if (pid == HOST_KERNEL_ID || pid == DEFAULT_GUEST_KERNEL_ID) | ||
| 603 | root_dir = ""; | ||
| 604 | else { | ||
| 605 | if (!symbol_conf.guestmount) | ||
| 606 | goto out; | ||
| 607 | sprintf(path, "%s/%d", symbol_conf.guestmount, pid); | ||
| 608 | ret = access(path, R_OK); | ||
| 609 | if (ret) { | ||
| 610 | pr_err("Can't access file %s\n", path); | ||
| 611 | goto out; | ||
| 612 | } | ||
| 613 | root_dir = path; | ||
| 614 | } | ||
| 615 | kerninfo = add_new_kernel_info(kerninfo_root, pid, root_dir); | ||
| 616 | } | ||
| 617 | |||
| 618 | out: | ||
| 619 | return kerninfo; | ||
| 620 | } | ||
| 621 | |||
| 622 | void kerninfo__process_allkernels(struct rb_root *kerninfo_root, | ||
| 623 | process_kernel_info process, | ||
| 624 | void *data) | ||
| 625 | { | ||
| 626 | struct rb_node *nd; | ||
| 627 | |||
| 628 | for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) { | ||
| 629 | struct kernel_info *pos = rb_entry(nd, struct kernel_info, | ||
| 630 | rb_node); | ||
| 631 | process(pos, data); | ||
| 632 | } | ||
| 633 | } | ||
| 634 | |||
| 635 | char *kern_mmap_name(struct kernel_info *kerninfo, char *buff) | ||
| 636 | { | ||
| 637 | if (is_host_kernel(kerninfo)) | ||
| 638 | sprintf(buff, "[%s]", "kernel.kallsyms"); | ||
| 639 | else if (is_default_guest(kerninfo)) | ||
| 640 | sprintf(buff, "[%s]", "guest.kernel.kallsyms"); | ||
| 641 | else | ||
| 642 | sprintf(buff, "[%s.%d]", "guest.kernel.kallsyms", kerninfo->pid); | ||
| 643 | |||
| 644 | return buff; | ||
| 645 | } | ||
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 2031278cc06a..30d38d634e09 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
| @@ -19,6 +19,7 @@ extern const char *map_type__name[MAP__NR_TYPES]; | |||
| 19 | struct dso; | 19 | struct dso; |
| 20 | struct ref_reloc_sym; | 20 | struct ref_reloc_sym; |
| 21 | struct map_groups; | 21 | struct map_groups; |
| 22 | struct kernel_info; | ||
| 22 | 23 | ||
| 23 | struct map { | 24 | struct map { |
| 24 | union { | 25 | union { |
| @@ -36,6 +37,7 @@ struct map { | |||
| 36 | u64 (*unmap_ip)(struct map *, u64); | 37 | u64 (*unmap_ip)(struct map *, u64); |
| 37 | 38 | ||
| 38 | struct dso *dso; | 39 | struct dso *dso; |
| 40 | struct map_groups *groups; | ||
| 39 | }; | 41 | }; |
| 40 | 42 | ||
| 41 | struct kmap { | 43 | struct kmap { |
| @@ -43,6 +45,26 @@ struct kmap { | |||
| 43 | struct map_groups *kmaps; | 45 | struct map_groups *kmaps; |
| 44 | }; | 46 | }; |
| 45 | 47 | ||
| 48 | struct map_groups { | ||
| 49 | struct rb_root maps[MAP__NR_TYPES]; | ||
| 50 | struct list_head removed_maps[MAP__NR_TYPES]; | ||
| 51 | struct kernel_info *this_kerninfo; | ||
| 52 | }; | ||
| 53 | |||
| 54 | /* Native host kernel uses -1 as pid index in kernel_info */ | ||
| 55 | #define HOST_KERNEL_ID (-1) | ||
| 56 | #define DEFAULT_GUEST_KERNEL_ID (0) | ||
| 57 | |||
| 58 | struct kernel_info { | ||
| 59 | struct rb_node rb_node; | ||
| 60 | pid_t pid; | ||
| 61 | char *root_dir; | ||
| 62 | struct list_head dsos__user; | ||
| 63 | struct list_head dsos__kernel; | ||
| 64 | struct map_groups kmaps; | ||
| 65 | struct map *vmlinux_maps[MAP__NR_TYPES]; | ||
| 66 | }; | ||
| 67 | |||
| 46 | static inline struct kmap *map__kmap(struct map *self) | 68 | static inline struct kmap *map__kmap(struct map *self) |
| 47 | { | 69 | { |
| 48 | return (struct kmap *)(self + 1); | 70 | return (struct kmap *)(self + 1); |
| @@ -74,7 +96,8 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); | |||
| 74 | 96 | ||
| 75 | void map__init(struct map *self, enum map_type type, | 97 | void map__init(struct map *self, enum map_type type, |
| 76 | u64 start, u64 end, u64 pgoff, struct dso *dso); | 98 | u64 start, u64 end, u64 pgoff, struct dso *dso); |
| 77 | struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename, | 99 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, |
| 100 | u64 pgoff, u32 pid, char *filename, | ||
| 78 | enum map_type type, char *cwd, int cwdlen); | 101 | enum map_type type, char *cwd, int cwdlen); |
| 79 | void map__delete(struct map *self); | 102 | void map__delete(struct map *self); |
| 80 | struct map *map__clone(struct map *self); | 103 | struct map *map__clone(struct map *self); |
| @@ -91,11 +114,6 @@ void map__fixup_end(struct map *self); | |||
| 91 | 114 | ||
| 92 | void map__reloc_vmlinux(struct map *self); | 115 | void map__reloc_vmlinux(struct map *self); |
| 93 | 116 | ||
| 94 | struct map_groups { | ||
| 95 | struct rb_root maps[MAP__NR_TYPES]; | ||
| 96 | struct list_head removed_maps[MAP__NR_TYPES]; | ||
| 97 | }; | ||
| 98 | |||
| 99 | size_t __map_groups__fprintf_maps(struct map_groups *self, | 117 | size_t __map_groups__fprintf_maps(struct map_groups *self, |
| 100 | enum map_type type, int verbose, FILE *fp); | 118 | enum map_type type, int verbose, FILE *fp); |
| 101 | void maps__insert(struct rb_root *maps, struct map *map); | 119 | void maps__insert(struct rb_root *maps, struct map *map); |
| @@ -106,9 +124,40 @@ int map_groups__clone(struct map_groups *self, | |||
| 106 | size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); | 124 | size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); |
| 107 | size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); | 125 | size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); |
| 108 | 126 | ||
| 127 | struct kernel_info *add_new_kernel_info(struct rb_root *kerninfo_root, | ||
| 128 | pid_t pid, const char *root_dir); | ||
| 129 | struct kernel_info *kerninfo__find(struct rb_root *kerninfo_root, pid_t pid); | ||
| 130 | struct kernel_info *kerninfo__findnew(struct rb_root *kerninfo_root, pid_t pid); | ||
| 131 | struct kernel_info *kerninfo__findhost(struct rb_root *kerninfo_root); | ||
| 132 | char *kern_mmap_name(struct kernel_info *kerninfo, char *buff); | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Default guest kernel is defined by parameter --guestkallsyms | ||
| 136 | * and --guestmodules | ||
| 137 | */ | ||
| 138 | static inline int is_default_guest(struct kernel_info *kerninfo) | ||
| 139 | { | ||
| 140 | if (!kerninfo) | ||
| 141 | return 0; | ||
| 142 | return kerninfo->pid == DEFAULT_GUEST_KERNEL_ID; | ||
| 143 | } | ||
| 144 | |||
| 145 | static inline int is_host_kernel(struct kernel_info *kerninfo) | ||
| 146 | { | ||
| 147 | if (!kerninfo) | ||
| 148 | return 0; | ||
| 149 | return kerninfo->pid == HOST_KERNEL_ID; | ||
| 150 | } | ||
| 151 | |||
| 152 | typedef void (*process_kernel_info)(struct kernel_info *kerninfo, void *data); | ||
| 153 | void kerninfo__process_allkernels(struct rb_root *kerninfo_root, | ||
| 154 | process_kernel_info process, | ||
| 155 | void *data); | ||
| 156 | |||
| 109 | static inline void map_groups__insert(struct map_groups *self, struct map *map) | 157 | static inline void map_groups__insert(struct map_groups *self, struct map *map) |
| 110 | { | 158 | { |
| 111 | maps__insert(&self->maps[map->type], map); | 159 | maps__insert(&self->maps[map->type], map); |
| 160 | map->groups = self; | ||
| 112 | } | 161 | } |
| 113 | 162 | ||
| 114 | static inline struct map *map_groups__find(struct map_groups *self, | 163 | static inline struct map *map_groups__find(struct map_groups *self, |
| @@ -148,13 +197,11 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | |||
| 148 | 197 | ||
| 149 | struct map *map_groups__find_by_name(struct map_groups *self, | 198 | struct map *map_groups__find_by_name(struct map_groups *self, |
| 150 | enum map_type type, const char *name); | 199 | enum map_type type, const char *name); |
| 151 | int __map_groups__create_kernel_maps(struct map_groups *self, | 200 | struct map *map_groups__new_module(struct map_groups *self, |
| 152 | struct map *vmlinux_maps[MAP__NR_TYPES], | 201 | u64 start, |
| 153 | struct dso *kernel); | 202 | const char *filename, |
| 154 | int map_groups__create_kernel_maps(struct map_groups *self, | 203 | struct kernel_info *kerninfo); |
| 155 | struct map *vmlinux_maps[MAP__NR_TYPES]); | 204 | |
| 156 | struct map *map_groups__new_module(struct map_groups *self, u64 start, | ||
| 157 | const char *filename); | ||
| 158 | void map_groups__flush(struct map_groups *self); | 205 | void map_groups__flush(struct map_groups *self); |
| 159 | 206 | ||
| 160 | #endif /* __PERF_MAP_H */ | 207 | #endif /* __PERF_MAP_H */ |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 5bf8ab034466..3967f8f63d0d 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -78,6 +78,7 @@ static struct map *kmaps[MAP__NR_TYPES]; | |||
| 78 | /* Initialize symbol maps and path of vmlinux */ | 78 | /* Initialize symbol maps and path of vmlinux */ |
| 79 | static int init_vmlinux(void) | 79 | static int init_vmlinux(void) |
| 80 | { | 80 | { |
| 81 | struct dso *kernel; | ||
| 81 | int ret; | 82 | int ret; |
| 82 | 83 | ||
| 83 | symbol_conf.sort_by_name = true; | 84 | symbol_conf.sort_by_name = true; |
| @@ -91,8 +92,12 @@ static int init_vmlinux(void) | |||
| 91 | goto out; | 92 | goto out; |
| 92 | } | 93 | } |
| 93 | 94 | ||
| 95 | kernel = dso__new_kernel(symbol_conf.vmlinux_name); | ||
| 96 | if (kernel == NULL) | ||
| 97 | die("Failed to create kernel dso."); | ||
| 98 | |||
| 94 | map_groups__init(&kmap_groups); | 99 | map_groups__init(&kmap_groups); |
| 95 | ret = map_groups__create_kernel_maps(&kmap_groups, kmaps); | 100 | ret = __map_groups__create_kernel_maps(&kmap_groups, kmaps, kernel); |
| 96 | if (ret < 0) | 101 | if (ret < 0) |
| 97 | pr_debug("Failed to create kernel maps.\n"); | 102 | pr_debug("Failed to create kernel maps.\n"); |
| 98 | 103 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0fdf3ebef1e9..7d88ae5c270f 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -67,6 +67,17 @@ void perf_session__update_sample_type(struct perf_session *self) | |||
| 67 | self->sample_type = perf_header__sample_type(&self->header); | 67 | self->sample_type = perf_header__sample_type(&self->header); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | int perf_session__create_kernel_maps(struct perf_session *self) | ||
| 71 | { | ||
| 72 | int ret; | ||
| 73 | struct rb_root *root = &self->kerninfo_root; | ||
| 74 | |||
| 75 | ret = map_groups__create_kernel_maps(root, HOST_KERNEL_ID); | ||
| 76 | if (ret >= 0) | ||
| 77 | ret = map_groups__create_guest_kernel_maps(root); | ||
| 78 | return ret; | ||
| 79 | } | ||
| 80 | |||
| 70 | struct perf_session *perf_session__new(const char *filename, int mode, bool force) | 81 | struct perf_session *perf_session__new(const char *filename, int mode, bool force) |
| 71 | { | 82 | { |
| 72 | size_t len = filename ? strlen(filename) + 1 : 0; | 83 | size_t len = filename ? strlen(filename) + 1 : 0; |
| @@ -86,7 +97,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc | |||
| 86 | self->cwd = NULL; | 97 | self->cwd = NULL; |
| 87 | self->cwdlen = 0; | 98 | self->cwdlen = 0; |
| 88 | self->unknown_events = 0; | 99 | self->unknown_events = 0; |
| 89 | map_groups__init(&self->kmaps); | 100 | self->kerninfo_root = RB_ROOT; |
| 90 | 101 | ||
| 91 | if (mode == O_RDONLY) { | 102 | if (mode == O_RDONLY) { |
| 92 | if (perf_session__open(self, force) < 0) | 103 | if (perf_session__open(self, force) < 0) |
| @@ -157,8 +168,9 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, | |||
| 157 | continue; | 168 | continue; |
| 158 | } | 169 | } |
| 159 | 170 | ||
| 171 | al.filtered = false; | ||
| 160 | thread__find_addr_location(thread, self, cpumode, | 172 | thread__find_addr_location(thread, self, cpumode, |
| 161 | MAP__FUNCTION, ip, &al, NULL); | 173 | MAP__FUNCTION, thread->pid, ip, &al, NULL); |
| 162 | if (al.sym != NULL) { | 174 | if (al.sym != NULL) { |
| 163 | if (sort__has_parent && !*parent && | 175 | if (sort__has_parent && !*parent && |
| 164 | symbol__match_parent_regex(al.sym)) | 176 | symbol__match_parent_regex(al.sym)) |
| @@ -399,46 +411,6 @@ void perf_event_header__bswap(struct perf_event_header *self) | |||
| 399 | self->size = bswap_16(self->size); | 411 | self->size = bswap_16(self->size); |
| 400 | } | 412 | } |
| 401 | 413 | ||
| 402 | int perf_header__read_build_ids(struct perf_header *self, | ||
| 403 | int input, u64 offset, u64 size) | ||
| 404 | { | ||
| 405 | struct build_id_event bev; | ||
| 406 | char filename[PATH_MAX]; | ||
| 407 | u64 limit = offset + size; | ||
| 408 | int err = -1; | ||
| 409 | |||
| 410 | while (offset < limit) { | ||
| 411 | struct dso *dso; | ||
| 412 | ssize_t len; | ||
| 413 | struct list_head *head = &dsos__user; | ||
| 414 | |||
| 415 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | ||
| 416 | goto out; | ||
| 417 | |||
| 418 | if (self->needs_swap) | ||
| 419 | perf_event_header__bswap(&bev.header); | ||
| 420 | |||
| 421 | len = bev.header.size - sizeof(bev); | ||
| 422 | if (read(input, filename, len) != len) | ||
| 423 | goto out; | ||
| 424 | |||
| 425 | if (bev.header.misc & PERF_RECORD_MISC_KERNEL) | ||
| 426 | head = &dsos__kernel; | ||
| 427 | |||
| 428 | dso = __dsos__findnew(head, filename); | ||
| 429 | if (dso != NULL) { | ||
| 430 | dso__set_build_id(dso, &bev.build_id); | ||
| 431 | if (head == &dsos__kernel && filename[0] == '[') | ||
| 432 | dso->kernel = 1; | ||
| 433 | } | ||
| 434 | |||
| 435 | offset += bev.header.size; | ||
| 436 | } | ||
| 437 | err = 0; | ||
| 438 | out: | ||
| 439 | return err; | ||
| 440 | } | ||
| 441 | |||
| 442 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) | 414 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) |
| 443 | { | 415 | { |
| 444 | struct thread *thread = perf_session__findnew(self, 0); | 416 | struct thread *thread = perf_session__findnew(self, 0); |
| @@ -690,26 +662,33 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg) | |||
| 690 | return true; | 662 | return true; |
| 691 | } | 663 | } |
| 692 | 664 | ||
| 693 | int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, | 665 | int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, |
| 694 | const char *symbol_name, | 666 | const char *symbol_name, |
| 695 | u64 addr) | 667 | u64 addr) |
| 696 | { | 668 | { |
| 697 | char *bracket; | 669 | char *bracket; |
| 698 | enum map_type i; | 670 | enum map_type i; |
| 671 | struct ref_reloc_sym *ref; | ||
| 672 | |||
| 673 | ref = zalloc(sizeof(struct ref_reloc_sym)); | ||
| 674 | if (ref == NULL) | ||
| 675 | return -ENOMEM; | ||
| 699 | 676 | ||
| 700 | self->ref_reloc_sym.name = strdup(symbol_name); | 677 | ref->name = strdup(symbol_name); |
| 701 | if (self->ref_reloc_sym.name == NULL) | 678 | if (ref->name == NULL) { |
| 679 | free(ref); | ||
| 702 | return -ENOMEM; | 680 | return -ENOMEM; |
| 681 | } | ||
| 703 | 682 | ||
| 704 | bracket = strchr(self->ref_reloc_sym.name, ']'); | 683 | bracket = strchr(ref->name, ']'); |
| 705 | if (bracket) | 684 | if (bracket) |
| 706 | *bracket = '\0'; | 685 | *bracket = '\0'; |
| 707 | 686 | ||
| 708 | self->ref_reloc_sym.addr = addr; | 687 | ref->addr = addr; |
| 709 | 688 | ||
| 710 | for (i = 0; i < MAP__NR_TYPES; ++i) { | 689 | for (i = 0; i < MAP__NR_TYPES; ++i) { |
| 711 | struct kmap *kmap = map__kmap(self->vmlinux_maps[i]); | 690 | struct kmap *kmap = map__kmap(maps[i]); |
| 712 | kmap->ref_reloc_sym = &self->ref_reloc_sym; | 691 | kmap->ref_reloc_sym = ref; |
| 713 | } | 692 | } |
| 714 | 693 | ||
| 715 | return 0; | 694 | return 0; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 0ac14d42dc28..5e47c87b9266 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
| @@ -15,17 +15,15 @@ struct perf_session { | |||
| 15 | struct perf_header header; | 15 | struct perf_header header; |
| 16 | unsigned long size; | 16 | unsigned long size; |
| 17 | unsigned long mmap_window; | 17 | unsigned long mmap_window; |
| 18 | struct map_groups kmaps; | ||
| 19 | struct rb_root threads; | 18 | struct rb_root threads; |
| 20 | struct thread *last_match; | 19 | struct thread *last_match; |
| 21 | struct map *vmlinux_maps[MAP__NR_TYPES]; | 20 | struct rb_root kerninfo_root; |
| 22 | struct events_stats events_stats; | 21 | struct events_stats events_stats; |
| 23 | struct rb_root stats_by_id; | 22 | struct rb_root stats_by_id; |
| 24 | unsigned long event_total[PERF_RECORD_MAX]; | 23 | unsigned long event_total[PERF_RECORD_MAX]; |
| 25 | unsigned long unknown_events; | 24 | unsigned long unknown_events; |
| 26 | struct rb_root hists; | 25 | struct rb_root hists; |
| 27 | u64 sample_type; | 26 | u64 sample_type; |
| 28 | struct ref_reloc_sym ref_reloc_sym; | ||
| 29 | int fd; | 27 | int fd; |
| 30 | bool fd_pipe; | 28 | bool fd_pipe; |
| 31 | int cwdlen; | 29 | int cwdlen; |
| @@ -69,33 +67,13 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, | |||
| 69 | 67 | ||
| 70 | bool perf_session__has_traces(struct perf_session *self, const char *msg); | 68 | bool perf_session__has_traces(struct perf_session *self, const char *msg); |
| 71 | 69 | ||
| 72 | int perf_header__read_build_ids(struct perf_header *self, int input, | 70 | int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, |
| 73 | u64 offset, u64 file_size); | ||
| 74 | |||
| 75 | int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, | ||
| 76 | const char *symbol_name, | 71 | const char *symbol_name, |
| 77 | u64 addr); | 72 | u64 addr); |
| 78 | 73 | ||
| 79 | void mem_bswap_64(void *src, int byte_size); | 74 | void mem_bswap_64(void *src, int byte_size); |
| 80 | 75 | ||
| 81 | static inline int __perf_session__create_kernel_maps(struct perf_session *self, | 76 | int perf_session__create_kernel_maps(struct perf_session *self); |
| 82 | struct dso *kernel) | ||
| 83 | { | ||
| 84 | return __map_groups__create_kernel_maps(&self->kmaps, | ||
| 85 | self->vmlinux_maps, kernel); | ||
| 86 | } | ||
| 87 | |||
| 88 | static inline int perf_session__create_kernel_maps(struct perf_session *self) | ||
| 89 | { | ||
| 90 | return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps); | ||
| 91 | } | ||
| 92 | |||
| 93 | static inline struct map * | ||
| 94 | perf_session__new_module_map(struct perf_session *self, | ||
| 95 | u64 start, const char *filename) | ||
| 96 | { | ||
| 97 | return map_groups__new_module(&self->kmaps, start, filename); | ||
| 98 | } | ||
| 99 | 77 | ||
| 100 | int do_read(int fd, void *buf, size_t size); | 78 | int do_read(int fd, void *buf, size_t size); |
| 101 | void perf_session__update_sample_type(struct perf_session *self); | 79 | void perf_session__update_sample_type(struct perf_session *self); |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 1d857aa2c01f..b7c54eeed9c9 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
| @@ -44,6 +44,11 @@ extern enum sort_type sort__first_dimension; | |||
| 44 | struct hist_entry { | 44 | struct hist_entry { |
| 45 | struct rb_node rb_node; | 45 | struct rb_node rb_node; |
| 46 | u64 count; | 46 | u64 count; |
| 47 | u64 count_sys; | ||
| 48 | u64 count_us; | ||
| 49 | u64 count_guest_sys; | ||
| 50 | u64 count_guest_us; | ||
| 51 | |||
| 47 | /* | 52 | /* |
| 48 | * XXX WARNING! | 53 | * XXX WARNING! |
| 49 | * thread _has_ to come after ms, see | 54 | * thread _has_ to come after ms, see |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f3d4151e46a1..e782e7db16c5 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -28,6 +28,8 @@ static void dsos__add(struct list_head *head, struct dso *dso); | |||
| 28 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 28 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
| 29 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 29 | static int dso__load_kernel_sym(struct dso *self, struct map *map, |
| 30 | symbol_filter_t filter); | 30 | symbol_filter_t filter); |
| 31 | static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, | ||
| 32 | symbol_filter_t filter); | ||
| 31 | static int vmlinux_path__nr_entries; | 33 | static int vmlinux_path__nr_entries; |
| 32 | static char **vmlinux_path; | 34 | static char **vmlinux_path; |
| 33 | 35 | ||
| @@ -186,6 +188,7 @@ struct dso *dso__new(const char *name) | |||
| 186 | self->loaded = 0; | 188 | self->loaded = 0; |
| 187 | self->sorted_by_name = 0; | 189 | self->sorted_by_name = 0; |
| 188 | self->has_build_id = 0; | 190 | self->has_build_id = 0; |
| 191 | self->kernel = DSO_TYPE_USER; | ||
| 189 | } | 192 | } |
| 190 | 193 | ||
| 191 | return self; | 194 | return self; |
| @@ -402,12 +405,9 @@ int kallsyms__parse(const char *filename, void *arg, | |||
| 402 | char *symbol_name; | 405 | char *symbol_name; |
| 403 | 406 | ||
| 404 | line_len = getline(&line, &n, file); | 407 | line_len = getline(&line, &n, file); |
| 405 | if (line_len < 0) | 408 | if (line_len < 0 || !line) |
| 406 | break; | 409 | break; |
| 407 | 410 | ||
| 408 | if (!line) | ||
| 409 | goto out_failure; | ||
| 410 | |||
| 411 | line[--line_len] = '\0'; /* \n */ | 411 | line[--line_len] = '\0'; /* \n */ |
| 412 | 412 | ||
| 413 | len = hex2u64(line, &start); | 413 | len = hex2u64(line, &start); |
| @@ -459,6 +459,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name, | |||
| 459 | * map__split_kallsyms, when we have split the maps per module | 459 | * map__split_kallsyms, when we have split the maps per module |
| 460 | */ | 460 | */ |
| 461 | symbols__insert(root, sym); | 461 | symbols__insert(root, sym); |
| 462 | |||
| 462 | return 0; | 463 | return 0; |
| 463 | } | 464 | } |
| 464 | 465 | ||
| @@ -483,6 +484,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
| 483 | symbol_filter_t filter) | 484 | symbol_filter_t filter) |
| 484 | { | 485 | { |
| 485 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 486 | struct map_groups *kmaps = map__kmap(map)->kmaps; |
| 487 | struct kernel_info *kerninfo = kmaps->this_kerninfo; | ||
| 486 | struct map *curr_map = map; | 488 | struct map *curr_map = map; |
| 487 | struct symbol *pos; | 489 | struct symbol *pos; |
| 488 | int count = 0; | 490 | int count = 0; |
| @@ -504,15 +506,33 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
| 504 | *module++ = '\0'; | 506 | *module++ = '\0'; |
| 505 | 507 | ||
| 506 | if (strcmp(curr_map->dso->short_name, module)) { | 508 | if (strcmp(curr_map->dso->short_name, module)) { |
| 507 | curr_map = map_groups__find_by_name(kmaps, map->type, module); | 509 | if (curr_map != map && |
| 510 | self->kernel == DSO_TYPE_GUEST_KERNEL && | ||
| 511 | is_default_guest(kerninfo)) { | ||
| 512 | /* | ||
| 513 | * We assume all symbols of a module are | ||
| 514 | * continuous in * kallsyms, so curr_map | ||
| 515 | * points to a module and all its | ||
| 516 | * symbols are in its kmap. Mark it as | ||
| 517 | * loaded. | ||
| 518 | */ | ||
| 519 | dso__set_loaded(curr_map->dso, | ||
| 520 | curr_map->type); | ||
| 521 | } | ||
| 522 | |||
| 523 | curr_map = map_groups__find_by_name(kmaps, | ||
| 524 | map->type, module); | ||
| 508 | if (curr_map == NULL) { | 525 | if (curr_map == NULL) { |
| 509 | pr_debug("/proc/{kallsyms,modules} " | 526 | pr_err("%s/proc/{kallsyms,modules} " |
| 510 | "inconsistency while looking " | 527 | "inconsistency while looking " |
| 511 | "for \"%s\" module!\n", module); | 528 | "for \"%s\" module!\n", |
| 512 | return -1; | 529 | kerninfo->root_dir, module); |
| 530 | curr_map = map; | ||
| 531 | goto discard_symbol; | ||
| 513 | } | 532 | } |
| 514 | 533 | ||
| 515 | if (curr_map->dso->loaded) | 534 | if (curr_map->dso->loaded && |
| 535 | !is_default_guest(kmaps->this_kerninfo)) | ||
| 516 | goto discard_symbol; | 536 | goto discard_symbol; |
| 517 | } | 537 | } |
| 518 | /* | 538 | /* |
| @@ -525,13 +545,21 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
| 525 | char dso_name[PATH_MAX]; | 545 | char dso_name[PATH_MAX]; |
| 526 | struct dso *dso; | 546 | struct dso *dso; |
| 527 | 547 | ||
| 528 | snprintf(dso_name, sizeof(dso_name), "[kernel].%d", | 548 | if (self->kernel == DSO_TYPE_GUEST_KERNEL) |
| 529 | kernel_range++); | 549 | snprintf(dso_name, sizeof(dso_name), |
| 550 | "[guest.kernel].%d", | ||
| 551 | kernel_range++); | ||
| 552 | else | ||
| 553 | snprintf(dso_name, sizeof(dso_name), | ||
| 554 | "[kernel].%d", | ||
| 555 | kernel_range++); | ||
| 530 | 556 | ||
| 531 | dso = dso__new(dso_name); | 557 | dso = dso__new(dso_name); |
| 532 | if (dso == NULL) | 558 | if (dso == NULL) |
| 533 | return -1; | 559 | return -1; |
| 534 | 560 | ||
| 561 | dso->kernel = self->kernel; | ||
| 562 | |||
| 535 | curr_map = map__new2(pos->start, dso, map->type); | 563 | curr_map = map__new2(pos->start, dso, map->type); |
| 536 | if (curr_map == NULL) { | 564 | if (curr_map == NULL) { |
| 537 | dso__delete(dso); | 565 | dso__delete(dso); |
| @@ -555,6 +583,12 @@ discard_symbol: rb_erase(&pos->rb_node, root); | |||
| 555 | } | 583 | } |
| 556 | } | 584 | } |
| 557 | 585 | ||
| 586 | if (curr_map != map && | ||
| 587 | self->kernel == DSO_TYPE_GUEST_KERNEL && | ||
| 588 | is_default_guest(kmaps->this_kerninfo)) { | ||
| 589 | dso__set_loaded(curr_map->dso, curr_map->type); | ||
| 590 | } | ||
| 591 | |||
| 558 | return count; | 592 | return count; |
| 559 | } | 593 | } |
| 560 | 594 | ||
| @@ -565,7 +599,10 @@ int dso__load_kallsyms(struct dso *self, const char *filename, | |||
| 565 | return -1; | 599 | return -1; |
| 566 | 600 | ||
| 567 | symbols__fixup_end(&self->symbols[map->type]); | 601 | symbols__fixup_end(&self->symbols[map->type]); |
| 568 | self->origin = DSO__ORIG_KERNEL; | 602 | if (self->kernel == DSO_TYPE_GUEST_KERNEL) |
| 603 | self->origin = DSO__ORIG_GUEST_KERNEL; | ||
| 604 | else | ||
| 605 | self->origin = DSO__ORIG_KERNEL; | ||
| 569 | 606 | ||
| 570 | return dso__split_kallsyms(self, map, filter); | 607 | return dso__split_kallsyms(self, map, filter); |
| 571 | } | 608 | } |
| @@ -952,7 +989,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 952 | nr_syms = shdr.sh_size / shdr.sh_entsize; | 989 | nr_syms = shdr.sh_size / shdr.sh_entsize; |
| 953 | 990 | ||
| 954 | memset(&sym, 0, sizeof(sym)); | 991 | memset(&sym, 0, sizeof(sym)); |
| 955 | if (!self->kernel) { | 992 | if (self->kernel == DSO_TYPE_USER) { |
| 956 | self->adjust_symbols = (ehdr.e_type == ET_EXEC || | 993 | self->adjust_symbols = (ehdr.e_type == ET_EXEC || |
| 957 | elf_section_by_name(elf, &ehdr, &shdr, | 994 | elf_section_by_name(elf, &ehdr, &shdr, |
| 958 | ".gnu.prelink_undo", | 995 | ".gnu.prelink_undo", |
| @@ -984,7 +1021,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 984 | 1021 | ||
| 985 | section_name = elf_sec__name(&shdr, secstrs); | 1022 | section_name = elf_sec__name(&shdr, secstrs); |
| 986 | 1023 | ||
| 987 | if (self->kernel || kmodule) { | 1024 | if (self->kernel != DSO_TYPE_USER || kmodule) { |
| 988 | char dso_name[PATH_MAX]; | 1025 | char dso_name[PATH_MAX]; |
| 989 | 1026 | ||
| 990 | if (strcmp(section_name, | 1027 | if (strcmp(section_name, |
| @@ -1011,6 +1048,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 1011 | curr_dso = dso__new(dso_name); | 1048 | curr_dso = dso__new(dso_name); |
| 1012 | if (curr_dso == NULL) | 1049 | if (curr_dso == NULL) |
| 1013 | goto out_elf_end; | 1050 | goto out_elf_end; |
| 1051 | curr_dso->kernel = self->kernel; | ||
| 1014 | curr_map = map__new2(start, curr_dso, | 1052 | curr_map = map__new2(start, curr_dso, |
| 1015 | map->type); | 1053 | map->type); |
| 1016 | if (curr_map == NULL) { | 1054 | if (curr_map == NULL) { |
| @@ -1021,7 +1059,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 1021 | curr_map->unmap_ip = identity__map_ip; | 1059 | curr_map->unmap_ip = identity__map_ip; |
| 1022 | curr_dso->origin = self->origin; | 1060 | curr_dso->origin = self->origin; |
| 1023 | map_groups__insert(kmap->kmaps, curr_map); | 1061 | map_groups__insert(kmap->kmaps, curr_map); |
| 1024 | dsos__add(&dsos__kernel, curr_dso); | 1062 | dsos__add(&self->node, curr_dso); |
| 1025 | dso__set_loaded(curr_dso, map->type); | 1063 | dso__set_loaded(curr_dso, map->type); |
| 1026 | } else | 1064 | } else |
| 1027 | curr_dso = curr_map->dso; | 1065 | curr_dso = curr_map->dso; |
| @@ -1083,7 +1121,7 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id) | |||
| 1083 | return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; | 1121 | return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; |
| 1084 | } | 1122 | } |
| 1085 | 1123 | ||
| 1086 | static bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | 1124 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits) |
| 1087 | { | 1125 | { |
| 1088 | bool have_build_id = false; | 1126 | bool have_build_id = false; |
| 1089 | struct dso *pos; | 1127 | struct dso *pos; |
| @@ -1101,13 +1139,6 @@ static bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | |||
| 1101 | return have_build_id; | 1139 | return have_build_id; |
| 1102 | } | 1140 | } |
| 1103 | 1141 | ||
| 1104 | bool dsos__read_build_ids(bool with_hits) | ||
| 1105 | { | ||
| 1106 | bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits), | ||
| 1107 | ubuildids = __dsos__read_build_ids(&dsos__user, with_hits); | ||
| 1108 | return kbuildids || ubuildids; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | /* | 1142 | /* |
| 1112 | * Align offset to 4 bytes as needed for note name and descriptor data. | 1143 | * Align offset to 4 bytes as needed for note name and descriptor data. |
| 1113 | */ | 1144 | */ |
| @@ -1242,6 +1273,8 @@ char dso__symtab_origin(const struct dso *self) | |||
| 1242 | [DSO__ORIG_BUILDID] = 'b', | 1273 | [DSO__ORIG_BUILDID] = 'b', |
| 1243 | [DSO__ORIG_DSO] = 'd', | 1274 | [DSO__ORIG_DSO] = 'd', |
| 1244 | [DSO__ORIG_KMODULE] = 'K', | 1275 | [DSO__ORIG_KMODULE] = 'K', |
| 1276 | [DSO__ORIG_GUEST_KERNEL] = 'g', | ||
| 1277 | [DSO__ORIG_GUEST_KMODULE] = 'G', | ||
| 1245 | }; | 1278 | }; |
| 1246 | 1279 | ||
| 1247 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) | 1280 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) |
| @@ -1257,11 +1290,20 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
| 1257 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 1290 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
| 1258 | int ret = -1; | 1291 | int ret = -1; |
| 1259 | int fd; | 1292 | int fd; |
| 1293 | struct kernel_info *kerninfo; | ||
| 1294 | const char *root_dir; | ||
| 1260 | 1295 | ||
| 1261 | dso__set_loaded(self, map->type); | 1296 | dso__set_loaded(self, map->type); |
| 1262 | 1297 | ||
| 1263 | if (self->kernel) | 1298 | if (self->kernel == DSO_TYPE_KERNEL) |
| 1264 | return dso__load_kernel_sym(self, map, filter); | 1299 | return dso__load_kernel_sym(self, map, filter); |
| 1300 | else if (self->kernel == DSO_TYPE_GUEST_KERNEL) | ||
| 1301 | return dso__load_guest_kernel_sym(self, map, filter); | ||
| 1302 | |||
| 1303 | if (map->groups && map->groups->this_kerninfo) | ||
| 1304 | kerninfo = map->groups->this_kerninfo; | ||
| 1305 | else | ||
| 1306 | kerninfo = NULL; | ||
| 1265 | 1307 | ||
| 1266 | name = malloc(size); | 1308 | name = malloc(size); |
| 1267 | if (!name) | 1309 | if (!name) |
| @@ -1315,6 +1357,13 @@ more: | |||
| 1315 | case DSO__ORIG_DSO: | 1357 | case DSO__ORIG_DSO: |
| 1316 | snprintf(name, size, "%s", self->long_name); | 1358 | snprintf(name, size, "%s", self->long_name); |
| 1317 | break; | 1359 | break; |
| 1360 | case DSO__ORIG_GUEST_KMODULE: | ||
| 1361 | if (map->groups && map->groups->this_kerninfo) | ||
| 1362 | root_dir = map->groups->this_kerninfo->root_dir; | ||
| 1363 | else | ||
| 1364 | root_dir = ""; | ||
| 1365 | snprintf(name, size, "%s%s", root_dir, self->long_name); | ||
| 1366 | break; | ||
| 1318 | 1367 | ||
| 1319 | default: | 1368 | default: |
| 1320 | goto out; | 1369 | goto out; |
| @@ -1368,7 +1417,8 @@ struct map *map_groups__find_by_name(struct map_groups *self, | |||
| 1368 | return NULL; | 1417 | return NULL; |
| 1369 | } | 1418 | } |
| 1370 | 1419 | ||
| 1371 | static int dso__kernel_module_get_build_id(struct dso *self) | 1420 | static int dso__kernel_module_get_build_id(struct dso *self, |
| 1421 | const char *root_dir) | ||
| 1372 | { | 1422 | { |
| 1373 | char filename[PATH_MAX]; | 1423 | char filename[PATH_MAX]; |
| 1374 | /* | 1424 | /* |
| @@ -1378,8 +1428,8 @@ static int dso__kernel_module_get_build_id(struct dso *self) | |||
| 1378 | const char *name = self->short_name + 1; | 1428 | const char *name = self->short_name + 1; |
| 1379 | 1429 | ||
| 1380 | snprintf(filename, sizeof(filename), | 1430 | snprintf(filename, sizeof(filename), |
| 1381 | "/sys/module/%.*s/notes/.note.gnu.build-id", | 1431 | "%s/sys/module/%.*s/notes/.note.gnu.build-id", |
| 1382 | (int)strlen(name - 1), name); | 1432 | root_dir, (int)strlen(name) - 1, name); |
| 1383 | 1433 | ||
| 1384 | if (sysfs__read_build_id(filename, self->build_id, | 1434 | if (sysfs__read_build_id(filename, self->build_id, |
| 1385 | sizeof(self->build_id)) == 0) | 1435 | sizeof(self->build_id)) == 0) |
| @@ -1388,7 +1438,8 @@ static int dso__kernel_module_get_build_id(struct dso *self) | |||
| 1388 | return 0; | 1438 | return 0; |
| 1389 | } | 1439 | } |
| 1390 | 1440 | ||
| 1391 | static int map_groups__set_modules_path_dir(struct map_groups *self, char *dir_name) | 1441 | static int map_groups__set_modules_path_dir(struct map_groups *self, |
| 1442 | const char *dir_name) | ||
| 1392 | { | 1443 | { |
| 1393 | struct dirent *dent; | 1444 | struct dirent *dent; |
| 1394 | DIR *dir = opendir(dir_name); | 1445 | DIR *dir = opendir(dir_name); |
| @@ -1400,8 +1451,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, char *dir_n | |||
| 1400 | 1451 | ||
| 1401 | while ((dent = readdir(dir)) != NULL) { | 1452 | while ((dent = readdir(dir)) != NULL) { |
| 1402 | char path[PATH_MAX]; | 1453 | char path[PATH_MAX]; |
| 1454 | struct stat st; | ||
| 1455 | |||
| 1456 | /*sshfs might return bad dent->d_type, so we have to stat*/ | ||
| 1457 | sprintf(path, "%s/%s", dir_name, dent->d_name); | ||
| 1458 | if (stat(path, &st)) | ||
| 1459 | continue; | ||
| 1403 | 1460 | ||
| 1404 | if (dent->d_type == DT_DIR) { | 1461 | if (S_ISDIR(st.st_mode)) { |
| 1405 | if (!strcmp(dent->d_name, ".") || | 1462 | if (!strcmp(dent->d_name, ".") || |
| 1406 | !strcmp(dent->d_name, "..")) | 1463 | !strcmp(dent->d_name, "..")) |
| 1407 | continue; | 1464 | continue; |
| @@ -1433,7 +1490,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, char *dir_n | |||
| 1433 | if (long_name == NULL) | 1490 | if (long_name == NULL) |
| 1434 | goto failure; | 1491 | goto failure; |
| 1435 | dso__set_long_name(map->dso, long_name); | 1492 | dso__set_long_name(map->dso, long_name); |
| 1436 | dso__kernel_module_get_build_id(map->dso); | 1493 | dso__kernel_module_get_build_id(map->dso, ""); |
| 1437 | } | 1494 | } |
| 1438 | } | 1495 | } |
| 1439 | 1496 | ||
| @@ -1443,16 +1500,46 @@ failure: | |||
| 1443 | return -1; | 1500 | return -1; |
| 1444 | } | 1501 | } |
| 1445 | 1502 | ||
| 1446 | static int map_groups__set_modules_path(struct map_groups *self) | 1503 | static char *get_kernel_version(const char *root_dir) |
| 1447 | { | 1504 | { |
| 1448 | struct utsname uts; | 1505 | char version[PATH_MAX]; |
| 1506 | FILE *file; | ||
| 1507 | char *name, *tmp; | ||
| 1508 | const char *prefix = "Linux version "; | ||
| 1509 | |||
| 1510 | sprintf(version, "%s/proc/version", root_dir); | ||
| 1511 | file = fopen(version, "r"); | ||
| 1512 | if (!file) | ||
| 1513 | return NULL; | ||
| 1514 | |||
| 1515 | version[0] = '\0'; | ||
| 1516 | tmp = fgets(version, sizeof(version), file); | ||
| 1517 | fclose(file); | ||
| 1518 | |||
| 1519 | name = strstr(version, prefix); | ||
| 1520 | if (!name) | ||
| 1521 | return NULL; | ||
| 1522 | name += strlen(prefix); | ||
| 1523 | tmp = strchr(name, ' '); | ||
| 1524 | if (tmp) | ||
| 1525 | *tmp = '\0'; | ||
| 1526 | |||
| 1527 | return strdup(name); | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | static int map_groups__set_modules_path(struct map_groups *self, | ||
| 1531 | const char *root_dir) | ||
| 1532 | { | ||
| 1533 | char *version; | ||
| 1449 | char modules_path[PATH_MAX]; | 1534 | char modules_path[PATH_MAX]; |
| 1450 | 1535 | ||
| 1451 | if (uname(&uts) < 0) | 1536 | version = get_kernel_version(root_dir); |
| 1537 | if (!version) | ||
| 1452 | return -1; | 1538 | return -1; |
| 1453 | 1539 | ||
| 1454 | snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", | 1540 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", |
| 1455 | uts.release); | 1541 | root_dir, version); |
| 1542 | free(version); | ||
| 1456 | 1543 | ||
| 1457 | return map_groups__set_modules_path_dir(self, modules_path); | 1544 | return map_groups__set_modules_path_dir(self, modules_path); |
| 1458 | } | 1545 | } |
| @@ -1477,11 +1564,13 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | |||
| 1477 | } | 1564 | } |
| 1478 | 1565 | ||
| 1479 | struct map *map_groups__new_module(struct map_groups *self, u64 start, | 1566 | struct map *map_groups__new_module(struct map_groups *self, u64 start, |
| 1480 | const char *filename) | 1567 | const char *filename, |
| 1568 | struct kernel_info *kerninfo) | ||
| 1481 | { | 1569 | { |
| 1482 | struct map *map; | 1570 | struct map *map; |
| 1483 | struct dso *dso = __dsos__findnew(&dsos__kernel, filename); | 1571 | struct dso *dso; |
| 1484 | 1572 | ||
| 1573 | dso = __dsos__findnew(&kerninfo->dsos__kernel, filename); | ||
| 1485 | if (dso == NULL) | 1574 | if (dso == NULL) |
| 1486 | return NULL; | 1575 | return NULL; |
| 1487 | 1576 | ||
| @@ -1489,21 +1578,37 @@ struct map *map_groups__new_module(struct map_groups *self, u64 start, | |||
| 1489 | if (map == NULL) | 1578 | if (map == NULL) |
| 1490 | return NULL; | 1579 | return NULL; |
| 1491 | 1580 | ||
| 1492 | dso->origin = DSO__ORIG_KMODULE; | 1581 | if (is_host_kernel(kerninfo)) |
| 1582 | dso->origin = DSO__ORIG_KMODULE; | ||
| 1583 | else | ||
| 1584 | dso->origin = DSO__ORIG_GUEST_KMODULE; | ||
| 1493 | map_groups__insert(self, map); | 1585 | map_groups__insert(self, map); |
| 1494 | return map; | 1586 | return map; |
| 1495 | } | 1587 | } |
| 1496 | 1588 | ||
| 1497 | static int map_groups__create_modules(struct map_groups *self) | 1589 | static int map_groups__create_modules(struct kernel_info *kerninfo) |
| 1498 | { | 1590 | { |
| 1499 | char *line = NULL; | 1591 | char *line = NULL; |
| 1500 | size_t n; | 1592 | size_t n; |
| 1501 | FILE *file = fopen("/proc/modules", "r"); | 1593 | FILE *file; |
| 1502 | struct map *map; | 1594 | struct map *map; |
| 1595 | const char *root_dir; | ||
| 1596 | const char *modules; | ||
| 1597 | char path[PATH_MAX]; | ||
| 1598 | |||
| 1599 | if (is_default_guest(kerninfo)) | ||
| 1600 | modules = symbol_conf.default_guest_modules; | ||
| 1601 | else { | ||
| 1602 | sprintf(path, "%s/proc/modules", kerninfo->root_dir); | ||
| 1603 | modules = path; | ||
| 1604 | } | ||
| 1503 | 1605 | ||
| 1606 | file = fopen(modules, "r"); | ||
| 1504 | if (file == NULL) | 1607 | if (file == NULL) |
| 1505 | return -1; | 1608 | return -1; |
| 1506 | 1609 | ||
| 1610 | root_dir = kerninfo->root_dir; | ||
| 1611 | |||
| 1507 | while (!feof(file)) { | 1612 | while (!feof(file)) { |
| 1508 | char name[PATH_MAX]; | 1613 | char name[PATH_MAX]; |
| 1509 | u64 start; | 1614 | u64 start; |
| @@ -1532,16 +1637,17 @@ static int map_groups__create_modules(struct map_groups *self) | |||
| 1532 | *sep = '\0'; | 1637 | *sep = '\0'; |
| 1533 | 1638 | ||
| 1534 | snprintf(name, sizeof(name), "[%s]", line); | 1639 | snprintf(name, sizeof(name), "[%s]", line); |
| 1535 | map = map_groups__new_module(self, start, name); | 1640 | map = map_groups__new_module(&kerninfo->kmaps, |
| 1641 | start, name, kerninfo); | ||
| 1536 | if (map == NULL) | 1642 | if (map == NULL) |
| 1537 | goto out_delete_line; | 1643 | goto out_delete_line; |
| 1538 | dso__kernel_module_get_build_id(map->dso); | 1644 | dso__kernel_module_get_build_id(map->dso, root_dir); |
| 1539 | } | 1645 | } |
| 1540 | 1646 | ||
| 1541 | free(line); | 1647 | free(line); |
| 1542 | fclose(file); | 1648 | fclose(file); |
| 1543 | 1649 | ||
| 1544 | return map_groups__set_modules_path(self); | 1650 | return map_groups__set_modules_path(&kerninfo->kmaps, root_dir); |
| 1545 | 1651 | ||
| 1546 | out_delete_line: | 1652 | out_delete_line: |
| 1547 | free(line); | 1653 | free(line); |
| @@ -1708,8 +1814,57 @@ out_fixup: | |||
| 1708 | return err; | 1814 | return err; |
| 1709 | } | 1815 | } |
| 1710 | 1816 | ||
| 1711 | LIST_HEAD(dsos__user); | 1817 | static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, |
| 1712 | LIST_HEAD(dsos__kernel); | 1818 | symbol_filter_t filter) |
| 1819 | { | ||
| 1820 | int err; | ||
| 1821 | const char *kallsyms_filename = NULL; | ||
| 1822 | struct kernel_info *kerninfo; | ||
| 1823 | char path[PATH_MAX]; | ||
| 1824 | |||
| 1825 | if (!map->groups) { | ||
| 1826 | pr_debug("Guest kernel map hasn't the point to groups\n"); | ||
| 1827 | return -1; | ||
| 1828 | } | ||
| 1829 | kerninfo = map->groups->this_kerninfo; | ||
| 1830 | |||
| 1831 | if (is_default_guest(kerninfo)) { | ||
| 1832 | /* | ||
| 1833 | * if the user specified a vmlinux filename, use it and only | ||
| 1834 | * it, reporting errors to the user if it cannot be used. | ||
| 1835 | * Or use file guest_kallsyms inputted by user on commandline | ||
| 1836 | */ | ||
| 1837 | if (symbol_conf.default_guest_vmlinux_name != NULL) { | ||
| 1838 | err = dso__load_vmlinux(self, map, | ||
| 1839 | symbol_conf.default_guest_vmlinux_name, filter); | ||
| 1840 | goto out_try_fixup; | ||
| 1841 | } | ||
| 1842 | |||
| 1843 | kallsyms_filename = symbol_conf.default_guest_kallsyms; | ||
| 1844 | if (!kallsyms_filename) | ||
| 1845 | return -1; | ||
| 1846 | } else { | ||
| 1847 | sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir); | ||
| 1848 | kallsyms_filename = path; | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | err = dso__load_kallsyms(self, kallsyms_filename, map, filter); | ||
| 1852 | if (err > 0) | ||
| 1853 | pr_debug("Using %s for symbols\n", kallsyms_filename); | ||
| 1854 | |||
| 1855 | out_try_fixup: | ||
| 1856 | if (err > 0) { | ||
| 1857 | if (kallsyms_filename != NULL) { | ||
| 1858 | kern_mmap_name(kerninfo, path); | ||
| 1859 | dso__set_long_name(self, | ||
| 1860 | strdup(path)); | ||
| 1861 | } | ||
| 1862 | map__fixup_start(map); | ||
| 1863 | map__fixup_end(map); | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | return err; | ||
| 1867 | } | ||
| 1713 | 1868 | ||
| 1714 | static void dsos__add(struct list_head *head, struct dso *dso) | 1869 | static void dsos__add(struct list_head *head, struct dso *dso) |
| 1715 | { | 1870 | { |
| @@ -1752,10 +1907,16 @@ static void __dsos__fprintf(struct list_head *head, FILE *fp) | |||
| 1752 | } | 1907 | } |
| 1753 | } | 1908 | } |
| 1754 | 1909 | ||
| 1755 | void dsos__fprintf(FILE *fp) | 1910 | void dsos__fprintf(struct rb_root *kerninfo_root, FILE *fp) |
| 1756 | { | 1911 | { |
| 1757 | __dsos__fprintf(&dsos__kernel, fp); | 1912 | struct rb_node *nd; |
| 1758 | __dsos__fprintf(&dsos__user, fp); | 1913 | |
| 1914 | for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) { | ||
| 1915 | struct kernel_info *pos = rb_entry(nd, struct kernel_info, | ||
| 1916 | rb_node); | ||
| 1917 | __dsos__fprintf(&pos->dsos__kernel, fp); | ||
| 1918 | __dsos__fprintf(&pos->dsos__user, fp); | ||
| 1919 | } | ||
| 1759 | } | 1920 | } |
| 1760 | 1921 | ||
| 1761 | static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | 1922 | static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
| @@ -1773,10 +1934,21 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | |||
| 1773 | return ret; | 1934 | return ret; |
| 1774 | } | 1935 | } |
| 1775 | 1936 | ||
| 1776 | size_t dsos__fprintf_buildid(FILE *fp, bool with_hits) | 1937 | size_t dsos__fprintf_buildid(struct rb_root *kerninfo_root, |
| 1938 | FILE *fp, bool with_hits) | ||
| 1777 | { | 1939 | { |
| 1778 | return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) + | 1940 | struct rb_node *nd; |
| 1779 | __dsos__fprintf_buildid(&dsos__user, fp, with_hits)); | 1941 | size_t ret = 0; |
| 1942 | |||
| 1943 | for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) { | ||
| 1944 | struct kernel_info *pos = rb_entry(nd, struct kernel_info, | ||
| 1945 | rb_node); | ||
| 1946 | ret += __dsos__fprintf_buildid(&pos->dsos__kernel, | ||
| 1947 | fp, with_hits); | ||
| 1948 | ret += __dsos__fprintf_buildid(&pos->dsos__user, | ||
| 1949 | fp, with_hits); | ||
| 1950 | } | ||
| 1951 | return ret; | ||
| 1780 | } | 1952 | } |
| 1781 | 1953 | ||
| 1782 | struct dso *dso__new_kernel(const char *name) | 1954 | struct dso *dso__new_kernel(const char *name) |
| @@ -1785,28 +1957,59 @@ struct dso *dso__new_kernel(const char *name) | |||
| 1785 | 1957 | ||
| 1786 | if (self != NULL) { | 1958 | if (self != NULL) { |
| 1787 | dso__set_short_name(self, "[kernel]"); | 1959 | dso__set_short_name(self, "[kernel]"); |
| 1788 | self->kernel = 1; | 1960 | self->kernel = DSO_TYPE_KERNEL; |
| 1961 | } | ||
| 1962 | |||
| 1963 | return self; | ||
| 1964 | } | ||
| 1965 | |||
| 1966 | static struct dso *dso__new_guest_kernel(struct kernel_info *kerninfo, | ||
| 1967 | const char *name) | ||
| 1968 | { | ||
| 1969 | char buff[PATH_MAX]; | ||
| 1970 | struct dso *self; | ||
| 1971 | |||
| 1972 | kern_mmap_name(kerninfo, buff); | ||
| 1973 | self = dso__new(name ?: buff); | ||
| 1974 | if (self != NULL) { | ||
| 1975 | dso__set_short_name(self, "[guest.kernel]"); | ||
| 1976 | self->kernel = DSO_TYPE_GUEST_KERNEL; | ||
| 1789 | } | 1977 | } |
| 1790 | 1978 | ||
| 1791 | return self; | 1979 | return self; |
| 1792 | } | 1980 | } |
| 1793 | 1981 | ||
| 1794 | void dso__read_running_kernel_build_id(struct dso *self) | 1982 | void dso__read_running_kernel_build_id(struct dso *self, |
| 1983 | struct kernel_info *kerninfo) | ||
| 1795 | { | 1984 | { |
| 1796 | if (sysfs__read_build_id("/sys/kernel/notes", self->build_id, | 1985 | char path[PATH_MAX]; |
| 1986 | |||
| 1987 | if (is_default_guest(kerninfo)) | ||
| 1988 | return; | ||
| 1989 | sprintf(path, "%s/sys/kernel/notes", kerninfo->root_dir); | ||
| 1990 | if (sysfs__read_build_id(path, self->build_id, | ||
| 1797 | sizeof(self->build_id)) == 0) | 1991 | sizeof(self->build_id)) == 0) |
| 1798 | self->has_build_id = true; | 1992 | self->has_build_id = true; |
| 1799 | } | 1993 | } |
| 1800 | 1994 | ||
| 1801 | static struct dso *dsos__create_kernel(const char *vmlinux) | 1995 | static struct dso *dsos__create_kernel(struct kernel_info *kerninfo) |
| 1802 | { | 1996 | { |
| 1803 | struct dso *kernel = dso__new_kernel(vmlinux); | 1997 | const char *vmlinux_name = NULL; |
| 1998 | struct dso *kernel; | ||
| 1804 | 1999 | ||
| 1805 | if (kernel != NULL) { | 2000 | if (is_host_kernel(kerninfo)) { |
| 1806 | dso__read_running_kernel_build_id(kernel); | 2001 | vmlinux_name = symbol_conf.vmlinux_name; |
| 1807 | dsos__add(&dsos__kernel, kernel); | 2002 | kernel = dso__new_kernel(vmlinux_name); |
| 2003 | } else { | ||
| 2004 | if (is_default_guest(kerninfo)) | ||
| 2005 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | ||
| 2006 | kernel = dso__new_guest_kernel(kerninfo, vmlinux_name); | ||
| 1808 | } | 2007 | } |
| 1809 | 2008 | ||
| 2009 | if (kernel != NULL) { | ||
| 2010 | dso__read_running_kernel_build_id(kernel, kerninfo); | ||
| 2011 | dsos__add(&kerninfo->dsos__kernel, kernel); | ||
| 2012 | } | ||
| 1810 | return kernel; | 2013 | return kernel; |
| 1811 | } | 2014 | } |
| 1812 | 2015 | ||
| @@ -1950,23 +2153,29 @@ out_free_comm_list: | |||
| 1950 | return -1; | 2153 | return -1; |
| 1951 | } | 2154 | } |
| 1952 | 2155 | ||
| 1953 | int map_groups__create_kernel_maps(struct map_groups *self, | 2156 | int map_groups__create_kernel_maps(struct rb_root *kerninfo_root, pid_t pid) |
| 1954 | struct map *vmlinux_maps[MAP__NR_TYPES]) | ||
| 1955 | { | 2157 | { |
| 1956 | struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name); | 2158 | struct kernel_info *kerninfo; |
| 2159 | struct dso *kernel; | ||
| 1957 | 2160 | ||
| 2161 | kerninfo = kerninfo__findnew(kerninfo_root, pid); | ||
| 2162 | if (kerninfo == NULL) | ||
| 2163 | return -1; | ||
| 2164 | kernel = dsos__create_kernel(kerninfo); | ||
| 1958 | if (kernel == NULL) | 2165 | if (kernel == NULL) |
| 1959 | return -1; | 2166 | return -1; |
| 1960 | 2167 | ||
| 1961 | if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0) | 2168 | if (__map_groups__create_kernel_maps(&kerninfo->kmaps, |
| 2169 | kerninfo->vmlinux_maps, kernel) < 0) | ||
| 1962 | return -1; | 2170 | return -1; |
| 1963 | 2171 | ||
| 1964 | if (symbol_conf.use_modules && map_groups__create_modules(self) < 0) | 2172 | if (symbol_conf.use_modules && |
| 2173 | map_groups__create_modules(kerninfo) < 0) | ||
| 1965 | pr_debug("Problems creating module maps, continuing anyway...\n"); | 2174 | pr_debug("Problems creating module maps, continuing anyway...\n"); |
| 1966 | /* | 2175 | /* |
| 1967 | * Now that we have all the maps created, just set the ->end of them: | 2176 | * Now that we have all the maps created, just set the ->end of them: |
| 1968 | */ | 2177 | */ |
| 1969 | map_groups__fixup_end(self); | 2178 | map_groups__fixup_end(&kerninfo->kmaps); |
| 1970 | return 0; | 2179 | return 0; |
| 1971 | } | 2180 | } |
| 1972 | 2181 | ||
| @@ -2012,3 +2221,46 @@ char *strxfrchar(char *s, char from, char to) | |||
| 2012 | 2221 | ||
| 2013 | return s; | 2222 | return s; |
| 2014 | } | 2223 | } |
| 2224 | |||
| 2225 | int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root) | ||
| 2226 | { | ||
| 2227 | int ret = 0; | ||
| 2228 | struct dirent **namelist = NULL; | ||
| 2229 | int i, items = 0; | ||
| 2230 | char path[PATH_MAX]; | ||
| 2231 | pid_t pid; | ||
| 2232 | |||
| 2233 | if (symbol_conf.default_guest_vmlinux_name || | ||
| 2234 | symbol_conf.default_guest_modules || | ||
| 2235 | symbol_conf.default_guest_kallsyms) { | ||
| 2236 | map_groups__create_kernel_maps(kerninfo_root, | ||
| 2237 | DEFAULT_GUEST_KERNEL_ID); | ||
| 2238 | } | ||
| 2239 | |||
| 2240 | if (symbol_conf.guestmount) { | ||
| 2241 | items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); | ||
| 2242 | if (items <= 0) | ||
| 2243 | return -ENOENT; | ||
| 2244 | for (i = 0; i < items; i++) { | ||
| 2245 | if (!isdigit(namelist[i]->d_name[0])) { | ||
| 2246 | /* Filter out . and .. */ | ||
| 2247 | continue; | ||
| 2248 | } | ||
| 2249 | pid = atoi(namelist[i]->d_name); | ||
| 2250 | sprintf(path, "%s/%s/proc/kallsyms", | ||
| 2251 | symbol_conf.guestmount, | ||
| 2252 | namelist[i]->d_name); | ||
| 2253 | ret = access(path, R_OK); | ||
| 2254 | if (ret) { | ||
| 2255 | pr_debug("Can't access file %s\n", path); | ||
| 2256 | goto failure; | ||
| 2257 | } | ||
| 2258 | map_groups__create_kernel_maps(kerninfo_root, | ||
| 2259 | pid); | ||
| 2260 | } | ||
| 2261 | failure: | ||
| 2262 | free(namelist); | ||
| 2263 | } | ||
| 2264 | |||
| 2265 | return ret; | ||
| 2266 | } | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 757fae3f5ee0..478f5ab37787 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -69,10 +69,15 @@ struct symbol_conf { | |||
| 69 | show_nr_samples, | 69 | show_nr_samples, |
| 70 | use_callchain, | 70 | use_callchain, |
| 71 | exclude_other, | 71 | exclude_other, |
| 72 | full_paths; | 72 | full_paths, |
| 73 | show_cpu_utilization; | ||
| 73 | const char *vmlinux_name, | 74 | const char *vmlinux_name, |
| 74 | *field_sep; | 75 | *field_sep; |
| 75 | char *dso_list_str, | 76 | const char *default_guest_vmlinux_name, |
| 77 | *default_guest_kallsyms, | ||
| 78 | *default_guest_modules; | ||
| 79 | const char *guestmount; | ||
| 80 | char *dso_list_str, | ||
| 76 | *comm_list_str, | 81 | *comm_list_str, |
| 77 | *sym_list_str, | 82 | *sym_list_str, |
| 78 | *col_width_list_str; | 83 | *col_width_list_str; |
| @@ -106,6 +111,13 @@ struct addr_location { | |||
| 106 | u64 addr; | 111 | u64 addr; |
| 107 | char level; | 112 | char level; |
| 108 | bool filtered; | 113 | bool filtered; |
| 114 | unsigned int cpumode; | ||
| 115 | }; | ||
| 116 | |||
| 117 | enum dso_kernel_type { | ||
| 118 | DSO_TYPE_USER = 0, | ||
| 119 | DSO_TYPE_KERNEL, | ||
| 120 | DSO_TYPE_GUEST_KERNEL | ||
| 109 | }; | 121 | }; |
| 110 | 122 | ||
| 111 | struct dso { | 123 | struct dso { |
| @@ -115,7 +127,7 @@ struct dso { | |||
| 115 | u8 adjust_symbols:1; | 127 | u8 adjust_symbols:1; |
| 116 | u8 slen_calculated:1; | 128 | u8 slen_calculated:1; |
| 117 | u8 has_build_id:1; | 129 | u8 has_build_id:1; |
| 118 | u8 kernel:1; | 130 | enum dso_kernel_type kernel; |
| 119 | u8 hit:1; | 131 | u8 hit:1; |
| 120 | u8 annotate_warned:1; | 132 | u8 annotate_warned:1; |
| 121 | unsigned char origin; | 133 | unsigned char origin; |
| @@ -143,34 +155,30 @@ static inline void dso__set_loaded(struct dso *self, enum map_type type) | |||
| 143 | 155 | ||
| 144 | void dso__sort_by_name(struct dso *self, enum map_type type); | 156 | void dso__sort_by_name(struct dso *self, enum map_type type); |
| 145 | 157 | ||
| 146 | extern struct list_head dsos__user, dsos__kernel; | ||
| 147 | |||
| 148 | struct dso *__dsos__findnew(struct list_head *head, const char *name); | 158 | struct dso *__dsos__findnew(struct list_head *head, const char *name); |
| 149 | 159 | ||
| 150 | static inline struct dso *dsos__findnew(const char *name) | ||
| 151 | { | ||
| 152 | return __dsos__findnew(&dsos__user, name); | ||
| 153 | } | ||
| 154 | |||
| 155 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); | 160 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); |
| 156 | int dso__load_vmlinux_path(struct dso *self, struct map *map, | 161 | int dso__load_vmlinux_path(struct dso *self, struct map *map, |
| 157 | symbol_filter_t filter); | 162 | symbol_filter_t filter); |
| 158 | int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, | 163 | int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, |
| 159 | symbol_filter_t filter); | 164 | symbol_filter_t filter); |
| 160 | void dsos__fprintf(FILE *fp); | 165 | void dsos__fprintf(struct rb_root *kerninfo_root, FILE *fp); |
| 161 | size_t dsos__fprintf_buildid(FILE *fp, bool with_hits); | 166 | size_t dsos__fprintf_buildid(struct rb_root *kerninfo_root, |
| 167 | FILE *fp, bool with_hits); | ||
| 162 | 168 | ||
| 163 | size_t dso__fprintf_buildid(struct dso *self, FILE *fp); | 169 | size_t dso__fprintf_buildid(struct dso *self, FILE *fp); |
| 164 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); | 170 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); |
| 165 | 171 | ||
| 166 | enum dso_origin { | 172 | enum dso_origin { |
| 167 | DSO__ORIG_KERNEL = 0, | 173 | DSO__ORIG_KERNEL = 0, |
| 174 | DSO__ORIG_GUEST_KERNEL, | ||
| 168 | DSO__ORIG_JAVA_JIT, | 175 | DSO__ORIG_JAVA_JIT, |
| 169 | DSO__ORIG_BUILD_ID_CACHE, | 176 | DSO__ORIG_BUILD_ID_CACHE, |
| 170 | DSO__ORIG_FEDORA, | 177 | DSO__ORIG_FEDORA, |
| 171 | DSO__ORIG_UBUNTU, | 178 | DSO__ORIG_UBUNTU, |
| 172 | DSO__ORIG_BUILDID, | 179 | DSO__ORIG_BUILDID, |
| 173 | DSO__ORIG_DSO, | 180 | DSO__ORIG_DSO, |
| 181 | DSO__ORIG_GUEST_KMODULE, | ||
| 174 | DSO__ORIG_KMODULE, | 182 | DSO__ORIG_KMODULE, |
| 175 | DSO__ORIG_NOT_FOUND, | 183 | DSO__ORIG_NOT_FOUND, |
| 176 | }; | 184 | }; |
| @@ -178,19 +186,26 @@ enum dso_origin { | |||
| 178 | char dso__symtab_origin(const struct dso *self); | 186 | char dso__symtab_origin(const struct dso *self); |
| 179 | void dso__set_long_name(struct dso *self, char *name); | 187 | void dso__set_long_name(struct dso *self, char *name); |
| 180 | void dso__set_build_id(struct dso *self, void *build_id); | 188 | void dso__set_build_id(struct dso *self, void *build_id); |
| 181 | void dso__read_running_kernel_build_id(struct dso *self); | 189 | void dso__read_running_kernel_build_id(struct dso *self, |
| 190 | struct kernel_info *kerninfo); | ||
| 182 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); | 191 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); |
| 183 | struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, | 192 | struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, |
| 184 | const char *name); | 193 | const char *name); |
| 185 | 194 | ||
| 186 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 195 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
| 187 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 196 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
| 188 | bool dsos__read_build_ids(bool with_hits); | 197 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); |
| 189 | int build_id__sprintf(const u8 *self, int len, char *bf); | 198 | int build_id__sprintf(const u8 *self, int len, char *bf); |
| 190 | int kallsyms__parse(const char *filename, void *arg, | 199 | int kallsyms__parse(const char *filename, void *arg, |
| 191 | int (*process_symbol)(void *arg, const char *name, | 200 | int (*process_symbol)(void *arg, const char *name, |
| 192 | char type, u64 start)); | 201 | char type, u64 start)); |
| 193 | 202 | ||
| 203 | int __map_groups__create_kernel_maps(struct map_groups *self, | ||
| 204 | struct map *vmlinux_maps[MAP__NR_TYPES], | ||
| 205 | struct dso *kernel); | ||
| 206 | int map_groups__create_kernel_maps(struct rb_root *kerninfo_root, pid_t pid); | ||
| 207 | int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root); | ||
| 208 | |||
| 194 | int symbol__init(void); | 209 | int symbol__init(void); |
| 195 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 210 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
| 196 | 211 | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 9c488fcadec9..1dfd9ff8bdcd 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
| @@ -33,12 +33,12 @@ static inline struct map *thread__find_map(struct thread *self, | |||
| 33 | 33 | ||
| 34 | void thread__find_addr_map(struct thread *self, | 34 | void thread__find_addr_map(struct thread *self, |
| 35 | struct perf_session *session, u8 cpumode, | 35 | struct perf_session *session, u8 cpumode, |
| 36 | enum map_type type, u64 addr, | 36 | enum map_type type, pid_t pid, u64 addr, |
| 37 | struct addr_location *al); | 37 | struct addr_location *al); |
| 38 | 38 | ||
| 39 | void thread__find_addr_location(struct thread *self, | 39 | void thread__find_addr_location(struct thread *self, |
| 40 | struct perf_session *session, u8 cpumode, | 40 | struct perf_session *session, u8 cpumode, |
| 41 | enum map_type type, u64 addr, | 41 | enum map_type type, pid_t pid, u64 addr, |
| 42 | struct addr_location *al, | 42 | struct addr_location *al, |
| 43 | symbol_filter_t filter); | 43 | symbol_filter_t filter); |
| 44 | #endif /* __PERF_THREAD_H */ | 44 | #endif /* __PERF_THREAD_H */ |
