aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang, Yanmin <yanmin_zhang@linux.intel.com>2010-04-19 01:32:50 -0400
committerAvi Kivity <avi@redhat.com>2010-04-19 05:37:24 -0400
commita1645ce12adb6c9cc9e19d7695466204e3f017fe (patch)
tree5d31aaaf534997e6e9cebc07f38eca35f76986cf
parentff9d07a0e7ce756a183e7c2e483aec452ee6b574 (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>
-rw-r--r--tools/perf/Documentation/perf-kvm.txt67
-rw-r--r--tools/perf/Makefile1
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-buildid-list.c2
-rw-r--r--tools/perf/builtin-diff.c6
-rw-r--r--tools/perf/builtin-kmem.c11
-rw-r--r--tools/perf/builtin-kvm.c144
-rw-r--r--tools/perf/builtin-record.c63
-rw-r--r--tools/perf/builtin-report.c6
-rw-r--r--tools/perf/builtin-top.c75
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/perf.h2
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/event.c280
-rw-r--r--tools/perf/util/event.h10
-rw-r--r--tools/perf/util/header.c213
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/hist.c72
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/map.c139
-rw-r--r--tools/perf/util/map.h75
-rw-r--r--tools/perf/util/probe-event.c7
-rw-r--r--tools/perf/util/session.c77
-rw-r--r--tools/perf/util/session.h28
-rw-r--r--tools/perf/util/sort.h5
-rw-r--r--tools/perf/util/symbol.c382
-rw-r--r--tools/perf/util/symbol.h43
-rw-r--r--tools/perf/util/thread.h4
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 00000000000..93400a0f17f
--- /dev/null
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -0,0 +1,67 @@
1perf-kvm(1)
2==============
3
4NAME
5----
6perf-kvm - Tool to trace/measure kvm guest os
7
8SYNOPSIS
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
17DESCRIPTION
18-----------
19There 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
41OPTIONS
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
65SEE ALSO
66--------
67linkperf: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 57b3569716d..3cb3449a964 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -472,6 +472,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
472BUILTIN_OBJS += $(OUTPUT)builtin-probe.o 472BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
473BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o 473BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
474BUILTIN_OBJS += $(OUTPUT)builtin-lock.o 474BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
475BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
475 476
476PERFLIBS = $(LIB_FILE) 477PERFLIBS = $(LIB_FILE)
477 478
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 06eaebe10d0..f924b4332be 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 af2ad8b92f7..623afe3fdcb 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 3a1d94d75dc..207e860591e 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 513aa8a55db..db474bbf332 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 00000000000..a4c7cae4502
--- /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
22static char *file_name;
23static char name_buffer[256];
24
25int perf_host = 1;
26int perf_guest;
27
28static const char * const kvm_usage[] = {
29 "perf kvm [<options>] {top|record|report|diff|buildid-list}",
30 NULL
31};
32
33static 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
54static 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
72static 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
90static 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
108int 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 a1b99eeac3c..27f992aca8b 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
459static 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
459static int __cmd_record(int argc, const char **argv) 505static 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 7da5fb36526..816edae7c5b 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 40f24dd46ef..dfd7ea7dabd 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
422static long samples; 422static long samples;
423static long userspace_samples; 423static long kernel_samples, us_samples;
424static long exact_samples; 424static long exact_samples;
425static long guest_us_samples, guest_kernel_samples;
425static const char CONSOLE_CLEAR[] = ""; 426static const char CONSOLE_CLEAR[] = "";
426 427
427static void __list_insert_active_sym(struct sym_entry *syme) 428static 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
764static void handle_keypress(int c) 788static 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 10fe49e7048..ab28bca92e5 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);
32extern int cmd_probe(int argc, const char **argv, const char *prefix); 32extern int cmd_probe(int argc, const char **argv, const char *prefix);
33extern int cmd_kmem(int argc, const char **argv, const char *prefix); 33extern int cmd_kmem(int argc, const char **argv, const char *prefix);
34extern int cmd_lock(int argc, const char **argv, const char *prefix); 34extern int cmd_lock(int argc, const char **argv, const char *prefix);
35extern 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 db6ee94d4a8..2a1162d413a 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -19,3 +19,4 @@ perf-trace mainporcelain common
19perf-probe mainporcelain common 19perf-probe mainporcelain common
20perf-kmem mainporcelain common 20perf-kmem mainporcelain common
21perf-lock mainporcelain common 21perf-lock mainporcelain common
22perf-kvm mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index d4be55b6cd3..985cdb4bd00 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 ec212748d65..02821febb70 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
134extern 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 04904b35ba8..0f60a390680 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 571fb25f7eb..e3fa8d3d11b 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
169int event__synthesize_modules(event__handler_t process, 173int 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
251int event__synthesize_kernel_mmap(event__handler_t process, 268int 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
332int event__process_mmap(event_t *self, struct perf_session *session) 375static 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
387static 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) 476out_problem:
387 goto out_problem; 477 return -1;
478}
388 479
389 session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start; 480int 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
445void thread__find_addr_map(struct thread *self, 543void 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 }
465try_again: 593try_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
485void thread__find_addr_location(struct thread *self, 616void 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
560out_filtered: 690out_filtered:
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index e5740ea140a..4af2ed5d48a 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -79,6 +79,7 @@ struct sample_data {
79 79
80struct build_id_event { 80struct 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,
154void event__synthesize_threads(event__handler_t process, 155void event__synthesize_threads(event__handler_t process,
155 struct perf_session *session); 156 struct perf_session *session);
156int event__synthesize_kernel_mmap(event__handler_t process, 157int 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
159int event__synthesize_modules(event__handler_t process, 162int event__synthesize_modules(event__handler_t process,
160 struct perf_session *session); 163 struct perf_session *session,
164 struct kernel_info *kerninfo);
161 165
162int event__process_comm(event_t *self, struct perf_session *session); 166int event__process_comm(event_t *self, struct perf_session *session);
163int event__process_lost(event_t *self, struct perf_session *session); 167int 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 628173ba689..75d01676802 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
193static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) 193static 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
222static int dsos__write_buildid_table(int fd) 224static 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
345static int dsos__cache_build_ids(void) 367static 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
390static 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
361static int perf_header__adds_write(struct perf_header *self, int fd) 407static 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
682static 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;
725out:
726 return err;
727}
728
729static 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;
757out:
758 return err;
759}
760
636static int perf_file_section__process(struct perf_file_section *self, 761static 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
990int event__synthesize_build_id(struct dso *pos, u16 misc, 1115int 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
1016static int __event_synthesize_build_ids(struct list_head *head, u16 misc, 1143static 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,
1035int event__synthesize_build_ids(event__handler_t process, 1164int 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
1061int event__process_build_id(event_t *self, 1204int 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 4214e237565..27591545814 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
121int event__synthesize_build_id(struct dso *pos, u16 misc, 121int 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);
124int event__synthesize_build_ids(event__handler_t process, 125int 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 9c2b8743cef..ad6b22dde27 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
11void __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 ad17f0ad798..9df1c340ec9 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -12,6 +12,9 @@ struct addr_location;
12struct symbol; 12struct symbol;
13struct rb_root; 13struct rb_root;
14 14
15void __perf_session__add_count(struct hist_entry *he,
16 struct addr_location *al,
17 u64 count);
15struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, 18struct 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 37913b241bd..7facd016ec9 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
9const char *map_type__name[MAP__NR_TYPES] = { 10const 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
42struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename, 44struct 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
247void map_groups__flush(struct map_groups *self) 251void 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
516struct 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
550struct 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
573struct 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
594struct 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
618out:
619 return kerninfo;
620}
621
622void 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
635char *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 2031278cc06..30d38d634e0 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];
19struct dso; 19struct dso;
20struct ref_reloc_sym; 20struct ref_reloc_sym;
21struct map_groups; 21struct map_groups;
22struct kernel_info;
22 23
23struct map { 24struct 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
41struct kmap { 43struct kmap {
@@ -43,6 +45,26 @@ struct kmap {
43 struct map_groups *kmaps; 45 struct map_groups *kmaps;
44}; 46};
45 47
48struct 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
58struct 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
46static inline struct kmap *map__kmap(struct map *self) 68static 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
75void map__init(struct map *self, enum map_type type, 97void 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);
77struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename, 99struct 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);
79void map__delete(struct map *self); 102void map__delete(struct map *self);
80struct map *map__clone(struct map *self); 103struct map *map__clone(struct map *self);
@@ -91,11 +114,6 @@ void map__fixup_end(struct map *self);
91 114
92void map__reloc_vmlinux(struct map *self); 115void map__reloc_vmlinux(struct map *self);
93 116
94struct map_groups {
95 struct rb_root maps[MAP__NR_TYPES];
96 struct list_head removed_maps[MAP__NR_TYPES];
97};
98
99size_t __map_groups__fprintf_maps(struct map_groups *self, 117size_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);
101void maps__insert(struct rb_root *maps, struct map *map); 119void maps__insert(struct rb_root *maps, struct map *map);
@@ -106,9 +124,40 @@ int map_groups__clone(struct map_groups *self,
106size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); 124size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
107size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); 125size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
108 126
127struct kernel_info *add_new_kernel_info(struct rb_root *kerninfo_root,
128 pid_t pid, const char *root_dir);
129struct kernel_info *kerninfo__find(struct rb_root *kerninfo_root, pid_t pid);
130struct kernel_info *kerninfo__findnew(struct rb_root *kerninfo_root, pid_t pid);
131struct kernel_info *kerninfo__findhost(struct rb_root *kerninfo_root);
132char *kern_mmap_name(struct kernel_info *kerninfo, char *buff);
133
134/*
135 * Default guest kernel is defined by parameter --guestkallsyms
136 * and --guestmodules
137 */
138static 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
145static 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
152typedef void (*process_kernel_info)(struct kernel_info *kerninfo, void *data);
153void kerninfo__process_allkernels(struct rb_root *kerninfo_root,
154 process_kernel_info process,
155 void *data);
156
109static inline void map_groups__insert(struct map_groups *self, struct map *map) 157static 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
114static inline struct map *map_groups__find(struct map_groups *self, 163static 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
149struct map *map_groups__find_by_name(struct map_groups *self, 198struct 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);
151int __map_groups__create_kernel_maps(struct map_groups *self, 200struct 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,
154int map_groups__create_kernel_maps(struct map_groups *self, 203 struct kernel_info *kerninfo);
155 struct map *vmlinux_maps[MAP__NR_TYPES]); 204
156struct map *map_groups__new_module(struct map_groups *self, u64 start,
157 const char *filename);
158void map_groups__flush(struct map_groups *self); 205void 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 5bf8ab03446..3967f8f63d0 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 */
79static int init_vmlinux(void) 79static 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 0fdf3ebef1e..7d88ae5c270 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
70int 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
70struct perf_session *perf_session__new(const char *filename, int mode, bool force) 81struct 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
402int 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;
438out:
439 return err;
440}
441
442static struct thread *perf_session__register_idle_thread(struct perf_session *self) 414static 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
693int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, 665int 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 0ac14d42dc2..5e47c87b926 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
70bool perf_session__has_traces(struct perf_session *self, const char *msg); 68bool perf_session__has_traces(struct perf_session *self, const char *msg);
71 69
72int perf_header__read_build_ids(struct perf_header *self, int input, 70int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
73 u64 offset, u64 file_size);
74
75int 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
79void mem_bswap_64(void *src, int byte_size); 74void mem_bswap_64(void *src, int byte_size);
80 75
81static inline int __perf_session__create_kernel_maps(struct perf_session *self, 76int 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
88static 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
93static 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
100int do_read(int fd, void *buf, size_t size); 78int do_read(int fd, void *buf, size_t size);
101void perf_session__update_sample_type(struct perf_session *self); 79void perf_session__update_sample_type(struct perf_session *self);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 1d857aa2c01..b7c54eeed9c 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -44,6 +44,11 @@ extern enum sort_type sort__first_dimension;
44struct hist_entry { 44struct 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 f3d4151e46a..e782e7db16c 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);
28static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 28static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
29static int dso__load_kernel_sym(struct dso *self, struct map *map, 29static int dso__load_kernel_sym(struct dso *self, struct map *map,
30 symbol_filter_t filter); 30 symbol_filter_t filter);
31static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
32 symbol_filter_t filter);
31static int vmlinux_path__nr_entries; 33static int vmlinux_path__nr_entries;
32static char **vmlinux_path; 34static 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
1086static bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 1124bool __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
1104bool 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
1371static int dso__kernel_module_get_build_id(struct dso *self) 1420static 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
1391static int map_groups__set_modules_path_dir(struct map_groups *self, char *dir_name) 1441static 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
1446static int map_groups__set_modules_path(struct map_groups *self) 1503static 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
1530static 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
1479struct map *map_groups__new_module(struct map_groups *self, u64 start, 1566struct 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
1497static int map_groups__create_modules(struct map_groups *self) 1589static 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
1546out_delete_line: 1652out_delete_line:
1547 free(line); 1653 free(line);
@@ -1708,8 +1814,57 @@ out_fixup:
1708 return err; 1814 return err;
1709} 1815}
1710 1816
1711LIST_HEAD(dsos__user); 1817static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1712LIST_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
1855out_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
1714static void dsos__add(struct list_head *head, struct dso *dso) 1869static 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
1755void dsos__fprintf(FILE *fp) 1910void 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
1761static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 1922static 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
1776size_t dsos__fprintf_buildid(FILE *fp, bool with_hits) 1937size_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
1782struct dso *dso__new_kernel(const char *name) 1954struct 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
1966static 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
1794void dso__read_running_kernel_build_id(struct dso *self) 1982void 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
1801static struct dso *dsos__create_kernel(const char *vmlinux) 1995static 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
1953int map_groups__create_kernel_maps(struct map_groups *self, 2156int 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
2225int 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 }
2261failure:
2262 free(namelist);
2263 }
2264
2265 return ret;
2266}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 757fae3f5ee..478f5ab3778 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
117enum dso_kernel_type {
118 DSO_TYPE_USER = 0,
119 DSO_TYPE_KERNEL,
120 DSO_TYPE_GUEST_KERNEL
109}; 121};
110 122
111struct dso { 123struct 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
144void dso__sort_by_name(struct dso *self, enum map_type type); 156void dso__sort_by_name(struct dso *self, enum map_type type);
145 157
146extern struct list_head dsos__user, dsos__kernel;
147
148struct dso *__dsos__findnew(struct list_head *head, const char *name); 158struct dso *__dsos__findnew(struct list_head *head, const char *name);
149 159
150static inline struct dso *dsos__findnew(const char *name)
151{
152 return __dsos__findnew(&dsos__user, name);
153}
154
155int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 160int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
156int dso__load_vmlinux_path(struct dso *self, struct map *map, 161int dso__load_vmlinux_path(struct dso *self, struct map *map,
157 symbol_filter_t filter); 162 symbol_filter_t filter);
158int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, 163int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
159 symbol_filter_t filter); 164 symbol_filter_t filter);
160void dsos__fprintf(FILE *fp); 165void dsos__fprintf(struct rb_root *kerninfo_root, FILE *fp);
161size_t dsos__fprintf_buildid(FILE *fp, bool with_hits); 166size_t dsos__fprintf_buildid(struct rb_root *kerninfo_root,
167 FILE *fp, bool with_hits);
162 168
163size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 169size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
164size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 170size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
165 171
166enum dso_origin { 172enum 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 {
178char dso__symtab_origin(const struct dso *self); 186char dso__symtab_origin(const struct dso *self);
179void dso__set_long_name(struct dso *self, char *name); 187void dso__set_long_name(struct dso *self, char *name);
180void dso__set_build_id(struct dso *self, void *build_id); 188void dso__set_build_id(struct dso *self, void *build_id);
181void dso__read_running_kernel_build_id(struct dso *self); 189void dso__read_running_kernel_build_id(struct dso *self,
190 struct kernel_info *kerninfo);
182struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 191struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
183struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 192struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
184 const char *name); 193 const char *name);
185 194
186int filename__read_build_id(const char *filename, void *bf, size_t size); 195int filename__read_build_id(const char *filename, void *bf, size_t size);
187int sysfs__read_build_id(const char *filename, void *bf, size_t size); 196int sysfs__read_build_id(const char *filename, void *bf, size_t size);
188bool dsos__read_build_ids(bool with_hits); 197bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
189int build_id__sprintf(const u8 *self, int len, char *bf); 198int build_id__sprintf(const u8 *self, int len, char *bf);
190int kallsyms__parse(const char *filename, void *arg, 199int 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
203int __map_groups__create_kernel_maps(struct map_groups *self,
204 struct map *vmlinux_maps[MAP__NR_TYPES],
205 struct dso *kernel);
206int map_groups__create_kernel_maps(struct rb_root *kerninfo_root, pid_t pid);
207int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root);
208
194int symbol__init(void); 209int symbol__init(void);
195bool symbol_type__is_a(char symbol_type, enum map_type map_type); 210bool 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 9c488fcadec..1dfd9ff8bdc 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
34void thread__find_addr_map(struct thread *self, 34void 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
39void thread__find_addr_location(struct thread *self, 39void 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 */