diff options
author | Stephane Eranian <eranian@google.com> | 2013-08-21 06:10:25 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-09-11 09:09:32 -0400 |
commit | 5c5e854bc760a2e2c878df3cfcf2afa4febcd511 (patch) | |
tree | cc0c44e8d8d9804f30c90f067d08c6cb4c9565ac /tools | |
parent | e71aa28312b208a14cd87fa61e941ac8c85072f4 (diff) |
perf tools: Add attr->mmap2 support
This patch adds support for the new PERF_RECORD_MMAP2 record type
exposed by the kernel. This is an extended PERF_RECORD_MMAP record.
It adds for each file-backed mapping the device major, minor number and
the inode number and generation.
This triplet uniquely identifies the source of a file-backed mapping. It
can be used to detect identical virtual mappings between processes, for
instance.
The patch will prefer MMAP2 over MMAP.
Signed-off-by: Stephane Eranian <eranian@google.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1377079825-19057-3-git-send-email-eranian@google.com
[ Cope with 314add6 "Change machine__findnew_thread() to set thread pid",
fix 'perf test' regression test entry affected,
use perf_missing_features.mmap2 to fallback to not using .mmap2 in older kernels,
so that new tools can work with kernels where this feature is not present ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-annotate.c | 1 | ||||
-rw-r--r-- | tools/perf/builtin-inject.c | 15 | ||||
-rw-r--r-- | tools/perf/builtin-mem.c | 1 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 1 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 1 | ||||
-rw-r--r-- | tools/perf/tests/perf-record.c | 15 | ||||
-rw-r--r-- | tools/perf/util/build-id.c | 1 | ||||
-rw-r--r-- | tools/perf/util/event.c | 56 | ||||
-rw-r--r-- | tools/perf/util/event.h | 19 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 16 | ||||
-rw-r--r-- | tools/perf/util/header.c | 3 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 53 | ||||
-rw-r--r-- | tools/perf/util/machine.h | 1 | ||||
-rw-r--r-- | tools/perf/util/map.c | 8 | ||||
-rw-r--r-- | tools/perf/util/map.h | 8 | ||||
-rw-r--r-- | tools/perf/util/session.c | 25 | ||||
-rw-r--r-- | tools/perf/util/tool.h | 1 |
17 files changed, 200 insertions, 25 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index f988d380c52f..5ebd0c3b71b6 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -277,6 +277,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
277 | .tool = { | 277 | .tool = { |
278 | .sample = process_sample_event, | 278 | .sample = process_sample_event, |
279 | .mmap = perf_event__process_mmap, | 279 | .mmap = perf_event__process_mmap, |
280 | .mmap2 = perf_event__process_mmap2, | ||
280 | .comm = perf_event__process_comm, | 281 | .comm = perf_event__process_comm, |
281 | .exit = perf_event__process_exit, | 282 | .exit = perf_event__process_exit, |
282 | .fork = perf_event__process_fork, | 283 | .fork = perf_event__process_fork, |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 9b336fdb6f71..423875c999b2 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -123,6 +123,19 @@ static int perf_event__repipe_mmap(struct perf_tool *tool, | |||
123 | return err; | 123 | return err; |
124 | } | 124 | } |
125 | 125 | ||
126 | static int perf_event__repipe_mmap2(struct perf_tool *tool, | ||
127 | union perf_event *event, | ||
128 | struct perf_sample *sample, | ||
129 | struct machine *machine) | ||
130 | { | ||
131 | int err; | ||
132 | |||
133 | err = perf_event__process_mmap2(tool, event, sample, machine); | ||
134 | perf_event__repipe(tool, event, sample, machine); | ||
135 | |||
136 | return err; | ||
137 | } | ||
138 | |||
126 | static int perf_event__repipe_fork(struct perf_tool *tool, | 139 | static int perf_event__repipe_fork(struct perf_tool *tool, |
127 | union perf_event *event, | 140 | union perf_event *event, |
128 | struct perf_sample *sample, | 141 | struct perf_sample *sample, |
@@ -339,6 +352,7 @@ static int __cmd_inject(struct perf_inject *inject) | |||
339 | 352 | ||
340 | if (inject->build_ids || inject->sched_stat) { | 353 | if (inject->build_ids || inject->sched_stat) { |
341 | inject->tool.mmap = perf_event__repipe_mmap; | 354 | inject->tool.mmap = perf_event__repipe_mmap; |
355 | inject->tool.mmap2 = perf_event__repipe_mmap2; | ||
342 | inject->tool.fork = perf_event__repipe_fork; | 356 | inject->tool.fork = perf_event__repipe_fork; |
343 | inject->tool.tracing_data = perf_event__repipe_tracing_data; | 357 | inject->tool.tracing_data = perf_event__repipe_tracing_data; |
344 | } | 358 | } |
@@ -390,6 +404,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
390 | .tool = { | 404 | .tool = { |
391 | .sample = perf_event__repipe_sample, | 405 | .sample = perf_event__repipe_sample, |
392 | .mmap = perf_event__repipe, | 406 | .mmap = perf_event__repipe, |
407 | .mmap2 = perf_event__repipe, | ||
393 | .comm = perf_event__repipe, | 408 | .comm = perf_event__repipe, |
394 | .fork = perf_event__repipe, | 409 | .fork = perf_event__repipe, |
395 | .exit = perf_event__repipe, | 410 | .exit = perf_event__repipe, |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 791b432df847..253133a6251d 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -190,6 +190,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
190 | .tool = { | 190 | .tool = { |
191 | .sample = process_sample_event, | 191 | .sample = process_sample_event, |
192 | .mmap = perf_event__process_mmap, | 192 | .mmap = perf_event__process_mmap, |
193 | .mmap2 = perf_event__process_mmap2, | ||
193 | .comm = perf_event__process_comm, | 194 | .comm = perf_event__process_comm, |
194 | .lost = perf_event__process_lost, | 195 | .lost = perf_event__process_lost, |
195 | .fork = perf_event__process_fork, | 196 | .fork = perf_event__process_fork, |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9725aa375414..8e50d8d77419 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -744,6 +744,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
744 | .tool = { | 744 | .tool = { |
745 | .sample = process_sample_event, | 745 | .sample = process_sample_event, |
746 | .mmap = perf_event__process_mmap, | 746 | .mmap = perf_event__process_mmap, |
747 | .mmap2 = perf_event__process_mmap2, | ||
747 | .comm = perf_event__process_comm, | 748 | .comm = perf_event__process_comm, |
748 | .exit = perf_event__process_exit, | 749 | .exit = perf_event__process_exit, |
749 | .fork = perf_event__process_fork, | 750 | .fork = perf_event__process_fork, |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 93a34cef9676..7f31a3ded1b6 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -542,6 +542,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
542 | static struct perf_tool perf_script = { | 542 | static struct perf_tool perf_script = { |
543 | .sample = process_sample_event, | 543 | .sample = process_sample_event, |
544 | .mmap = perf_event__process_mmap, | 544 | .mmap = perf_event__process_mmap, |
545 | .mmap2 = perf_event__process_mmap2, | ||
545 | .comm = perf_event__process_comm, | 546 | .comm = perf_event__process_comm, |
546 | .exit = perf_event__process_exit, | 547 | .exit = perf_event__process_exit, |
547 | .fork = perf_event__process_fork, | 548 | .fork = perf_event__process_fork, |
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 72d8881873b0..b8a7056519ac 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -50,7 +50,7 @@ int test__PERF_RECORD(void) | |||
50 | struct perf_sample sample; | 50 | struct perf_sample sample; |
51 | const char *cmd = "sleep"; | 51 | const char *cmd = "sleep"; |
52 | const char *argv[] = { cmd, "1", NULL, }; | 52 | const char *argv[] = { cmd, "1", NULL, }; |
53 | char *bname; | 53 | char *bname, *mmap_filename; |
54 | u64 prev_time = 0; | 54 | u64 prev_time = 0; |
55 | bool found_cmd_mmap = false, | 55 | bool found_cmd_mmap = false, |
56 | found_libc_mmap = false, | 56 | found_libc_mmap = false, |
@@ -212,6 +212,7 @@ int test__PERF_RECORD(void) | |||
212 | 212 | ||
213 | if ((type == PERF_RECORD_COMM || | 213 | if ((type == PERF_RECORD_COMM || |
214 | type == PERF_RECORD_MMAP || | 214 | type == PERF_RECORD_MMAP || |
215 | type == PERF_RECORD_MMAP2 || | ||
215 | type == PERF_RECORD_FORK || | 216 | type == PERF_RECORD_FORK || |
216 | type == PERF_RECORD_EXIT) && | 217 | type == PERF_RECORD_EXIT) && |
217 | (pid_t)event->comm.pid != evlist->workload.pid) { | 218 | (pid_t)event->comm.pid != evlist->workload.pid) { |
@@ -220,7 +221,8 @@ int test__PERF_RECORD(void) | |||
220 | } | 221 | } |
221 | 222 | ||
222 | if ((type == PERF_RECORD_COMM || | 223 | if ((type == PERF_RECORD_COMM || |
223 | type == PERF_RECORD_MMAP) && | 224 | type == PERF_RECORD_MMAP || |
225 | type == PERF_RECORD_MMAP2) && | ||
224 | event->comm.pid != event->comm.tid) { | 226 | event->comm.pid != event->comm.tid) { |
225 | pr_debug("%s with different pid/tid!\n", name); | 227 | pr_debug("%s with different pid/tid!\n", name); |
226 | ++errs; | 228 | ++errs; |
@@ -236,7 +238,12 @@ int test__PERF_RECORD(void) | |||
236 | case PERF_RECORD_EXIT: | 238 | case PERF_RECORD_EXIT: |
237 | goto found_exit; | 239 | goto found_exit; |
238 | case PERF_RECORD_MMAP: | 240 | case PERF_RECORD_MMAP: |
239 | bname = strrchr(event->mmap.filename, '/'); | 241 | mmap_filename = event->mmap.filename; |
242 | goto check_bname; | ||
243 | case PERF_RECORD_MMAP2: | ||
244 | mmap_filename = event->mmap2.filename; | ||
245 | check_bname: | ||
246 | bname = strrchr(mmap_filename, '/'); | ||
240 | if (bname != NULL) { | 247 | if (bname != NULL) { |
241 | if (!found_cmd_mmap) | 248 | if (!found_cmd_mmap) |
242 | found_cmd_mmap = !strcmp(bname + 1, cmd); | 249 | found_cmd_mmap = !strcmp(bname + 1, cmd); |
@@ -245,7 +252,7 @@ int test__PERF_RECORD(void) | |||
245 | if (!found_ld_mmap) | 252 | if (!found_ld_mmap) |
246 | found_ld_mmap = !strncmp(bname + 1, "ld", 2); | 253 | found_ld_mmap = !strncmp(bname + 1, "ld", 2); |
247 | } else if (!found_vdso_mmap) | 254 | } else if (!found_vdso_mmap) |
248 | found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]"); | 255 | found_vdso_mmap = !strcmp(mmap_filename, "[vdso]"); |
249 | break; | 256 | break; |
250 | 257 | ||
251 | case PERF_RECORD_SAMPLE: | 258 | case PERF_RECORD_SAMPLE: |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index fb584092eb88..7ded71d19d75 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -67,6 +67,7 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, | |||
67 | struct perf_tool build_id__mark_dso_hit_ops = { | 67 | struct perf_tool build_id__mark_dso_hit_ops = { |
68 | .sample = build_id__mark_dso_hit, | 68 | .sample = build_id__mark_dso_hit, |
69 | .mmap = perf_event__process_mmap, | 69 | .mmap = perf_event__process_mmap, |
70 | .mmap2 = perf_event__process_mmap2, | ||
70 | .fork = perf_event__process_fork, | 71 | .fork = perf_event__process_fork, |
71 | .exit = perf_event__exit_del_thread, | 72 | .exit = perf_event__exit_del_thread, |
72 | .attr = perf_event__process_attr, | 73 | .attr = perf_event__process_attr, |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 8d51f21107aa..9b393e7dca6f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -11,6 +11,7 @@ | |||
11 | static const char *perf_event__names[] = { | 11 | static const char *perf_event__names[] = { |
12 | [0] = "TOTAL", | 12 | [0] = "TOTAL", |
13 | [PERF_RECORD_MMAP] = "MMAP", | 13 | [PERF_RECORD_MMAP] = "MMAP", |
14 | [PERF_RECORD_MMAP2] = "MMAP2", | ||
14 | [PERF_RECORD_LOST] = "LOST", | 15 | [PERF_RECORD_LOST] = "LOST", |
15 | [PERF_RECORD_COMM] = "COMM", | 16 | [PERF_RECORD_COMM] = "COMM", |
16 | [PERF_RECORD_EXIT] = "EXIT", | 17 | [PERF_RECORD_EXIT] = "EXIT", |
@@ -186,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
186 | return -1; | 187 | return -1; |
187 | } | 188 | } |
188 | 189 | ||
189 | event->header.type = PERF_RECORD_MMAP; | 190 | event->header.type = PERF_RECORD_MMAP2; |
190 | /* | 191 | /* |
191 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c | 192 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c |
192 | */ | 193 | */ |
@@ -197,7 +198,9 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
197 | char prot[5]; | 198 | char prot[5]; |
198 | char execname[PATH_MAX]; | 199 | char execname[PATH_MAX]; |
199 | char anonstr[] = "//anon"; | 200 | char anonstr[] = "//anon"; |
201 | unsigned int ino; | ||
200 | size_t size; | 202 | size_t size; |
203 | ssize_t n; | ||
201 | 204 | ||
202 | if (fgets(bf, sizeof(bf), fp) == NULL) | 205 | if (fgets(bf, sizeof(bf), fp) == NULL) |
203 | break; | 206 | break; |
@@ -206,9 +209,16 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
206 | strcpy(execname, ""); | 209 | strcpy(execname, ""); |
207 | 210 | ||
208 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ | 211 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ |
209 | sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", | 212 | n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", |
210 | &event->mmap.start, &event->mmap.len, prot, | 213 | &event->mmap2.start, &event->mmap2.len, prot, |
211 | &event->mmap.pgoff, execname); | 214 | &event->mmap2.pgoff, &event->mmap2.maj, |
215 | &event->mmap2.min, | ||
216 | &ino, execname); | ||
217 | |||
218 | event->mmap2.ino = (u64)ino; | ||
219 | |||
220 | if (n != 8) | ||
221 | continue; | ||
212 | 222 | ||
213 | if (prot[2] != 'x') | 223 | if (prot[2] != 'x') |
214 | continue; | 224 | continue; |
@@ -217,15 +227,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
217 | strcpy(execname, anonstr); | 227 | strcpy(execname, anonstr); |
218 | 228 | ||
219 | size = strlen(execname) + 1; | 229 | size = strlen(execname) + 1; |
220 | memcpy(event->mmap.filename, execname, size); | 230 | memcpy(event->mmap2.filename, execname, size); |
221 | size = PERF_ALIGN(size, sizeof(u64)); | 231 | size = PERF_ALIGN(size, sizeof(u64)); |
222 | event->mmap.len -= event->mmap.start; | 232 | event->mmap2.len -= event->mmap.start; |
223 | event->mmap.header.size = (sizeof(event->mmap) - | 233 | event->mmap2.header.size = (sizeof(event->mmap2) - |
224 | (sizeof(event->mmap.filename) - size)); | 234 | (sizeof(event->mmap2.filename) - size)); |
225 | memset(event->mmap.filename + size, 0, machine->id_hdr_size); | 235 | memset(event->mmap2.filename + size, 0, machine->id_hdr_size); |
226 | event->mmap.header.size += machine->id_hdr_size; | 236 | event->mmap2.header.size += machine->id_hdr_size; |
227 | event->mmap.pid = tgid; | 237 | event->mmap2.pid = tgid; |
228 | event->mmap.tid = pid; | 238 | event->mmap2.tid = pid; |
229 | 239 | ||
230 | if (process(tool, event, &synth_sample, machine) != 0) { | 240 | if (process(tool, event, &synth_sample, machine) != 0) { |
231 | rc = -1; | 241 | rc = -1; |
@@ -527,6 +537,17 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) | |||
527 | event->mmap.len, event->mmap.pgoff, event->mmap.filename); | 537 | event->mmap.len, event->mmap.pgoff, event->mmap.filename); |
528 | } | 538 | } |
529 | 539 | ||
540 | size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) | ||
541 | { | ||
542 | return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 | ||
543 | " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n", | ||
544 | event->mmap2.pid, event->mmap2.tid, event->mmap2.start, | ||
545 | event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, | ||
546 | event->mmap2.min, event->mmap2.ino, | ||
547 | event->mmap2.ino_generation, | ||
548 | event->mmap2.filename); | ||
549 | } | ||
550 | |||
530 | int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, | 551 | int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, |
531 | union perf_event *event, | 552 | union perf_event *event, |
532 | struct perf_sample *sample __maybe_unused, | 553 | struct perf_sample *sample __maybe_unused, |
@@ -535,6 +556,14 @@ int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, | |||
535 | return machine__process_mmap_event(machine, event); | 556 | return machine__process_mmap_event(machine, event); |
536 | } | 557 | } |
537 | 558 | ||
559 | int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, | ||
560 | union perf_event *event, | ||
561 | struct perf_sample *sample __maybe_unused, | ||
562 | struct machine *machine) | ||
563 | { | ||
564 | return machine__process_mmap2_event(machine, event); | ||
565 | } | ||
566 | |||
538 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) | 567 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) |
539 | { | 568 | { |
540 | return fprintf(fp, "(%d:%d):(%d:%d)\n", | 569 | return fprintf(fp, "(%d:%d):(%d:%d)\n", |
@@ -574,6 +603,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) | |||
574 | case PERF_RECORD_MMAP: | 603 | case PERF_RECORD_MMAP: |
575 | ret += perf_event__fprintf_mmap(event, fp); | 604 | ret += perf_event__fprintf_mmap(event, fp); |
576 | break; | 605 | break; |
606 | case PERF_RECORD_MMAP2: | ||
607 | ret += perf_event__fprintf_mmap2(event, fp); | ||
608 | break; | ||
577 | default: | 609 | default: |
578 | ret += fprintf(fp, "\n"); | 610 | ret += fprintf(fp, "\n"); |
579 | } | 611 | } |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 93130d856bf0..c67ecc457d29 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -17,6 +17,19 @@ struct mmap_event { | |||
17 | char filename[PATH_MAX]; | 17 | char filename[PATH_MAX]; |
18 | }; | 18 | }; |
19 | 19 | ||
20 | struct mmap2_event { | ||
21 | struct perf_event_header header; | ||
22 | u32 pid, tid; | ||
23 | u64 start; | ||
24 | u64 len; | ||
25 | u64 pgoff; | ||
26 | u32 maj; | ||
27 | u32 min; | ||
28 | u64 ino; | ||
29 | u64 ino_generation; | ||
30 | char filename[PATH_MAX]; | ||
31 | }; | ||
32 | |||
20 | struct comm_event { | 33 | struct comm_event { |
21 | struct perf_event_header header; | 34 | struct perf_event_header header; |
22 | u32 pid, tid; | 35 | u32 pid, tid; |
@@ -159,6 +172,7 @@ struct tracing_data_event { | |||
159 | union perf_event { | 172 | union perf_event { |
160 | struct perf_event_header header; | 173 | struct perf_event_header header; |
161 | struct mmap_event mmap; | 174 | struct mmap_event mmap; |
175 | struct mmap2_event mmap2; | ||
162 | struct comm_event comm; | 176 | struct comm_event comm; |
163 | struct fork_event fork; | 177 | struct fork_event fork; |
164 | struct lost_event lost; | 178 | struct lost_event lost; |
@@ -208,6 +222,10 @@ int perf_event__process_mmap(struct perf_tool *tool, | |||
208 | union perf_event *event, | 222 | union perf_event *event, |
209 | struct perf_sample *sample, | 223 | struct perf_sample *sample, |
210 | struct machine *machine); | 224 | struct machine *machine); |
225 | int perf_event__process_mmap2(struct perf_tool *tool, | ||
226 | union perf_event *event, | ||
227 | struct perf_sample *sample, | ||
228 | struct machine *machine); | ||
211 | int perf_event__process_fork(struct perf_tool *tool, | 229 | int perf_event__process_fork(struct perf_tool *tool, |
212 | union perf_event *event, | 230 | union perf_event *event, |
213 | struct perf_sample *sample, | 231 | struct perf_sample *sample, |
@@ -238,6 +256,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
238 | 256 | ||
239 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); | 257 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); |
240 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); | 258 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); |
259 | size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); | ||
241 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); | 260 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); |
242 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); | 261 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); |
243 | 262 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 3612183e2cc5..0ce9febf1ba0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -27,6 +27,7 @@ | |||
27 | static struct { | 27 | static struct { |
28 | bool sample_id_all; | 28 | bool sample_id_all; |
29 | bool exclude_guest; | 29 | bool exclude_guest; |
30 | bool mmap2; | ||
30 | } perf_missing_features; | 31 | } perf_missing_features; |
31 | 32 | ||
32 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 33 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
@@ -676,8 +677,9 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
676 | if (opts->sample_weight) | 677 | if (opts->sample_weight) |
677 | attr->sample_type |= PERF_SAMPLE_WEIGHT; | 678 | attr->sample_type |= PERF_SAMPLE_WEIGHT; |
678 | 679 | ||
679 | attr->mmap = track; | 680 | attr->mmap = track; |
680 | attr->comm = track; | 681 | attr->mmap2 = track && !perf_missing_features.mmap2; |
682 | attr->comm = track; | ||
681 | 683 | ||
682 | /* | 684 | /* |
683 | * XXX see the function comment above | 685 | * XXX see the function comment above |
@@ -1016,6 +1018,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
1016 | } | 1018 | } |
1017 | 1019 | ||
1018 | fallback_missing_features: | 1020 | fallback_missing_features: |
1021 | if (perf_missing_features.mmap2) | ||
1022 | evsel->attr.mmap2 = 0; | ||
1019 | if (perf_missing_features.exclude_guest) | 1023 | if (perf_missing_features.exclude_guest) |
1020 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; | 1024 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; |
1021 | retry_sample_id: | 1025 | retry_sample_id: |
@@ -1080,8 +1084,11 @@ try_fallback: | |||
1080 | if (err != -EINVAL || cpu > 0 || thread > 0) | 1084 | if (err != -EINVAL || cpu > 0 || thread > 0) |
1081 | goto out_close; | 1085 | goto out_close; |
1082 | 1086 | ||
1083 | if (!perf_missing_features.exclude_guest && | 1087 | if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { |
1084 | (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { | 1088 | perf_missing_features.mmap2 = true; |
1089 | goto fallback_missing_features; | ||
1090 | } else if (!perf_missing_features.exclude_guest && | ||
1091 | (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { | ||
1085 | perf_missing_features.exclude_guest = true; | 1092 | perf_missing_features.exclude_guest = true; |
1086 | goto fallback_missing_features; | 1093 | goto fallback_missing_features; |
1087 | } else if (!perf_missing_features.sample_id_all) { | 1094 | } else if (!perf_missing_features.sample_id_all) { |
@@ -1925,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
1925 | if_print(exclude_hv); | 1932 | if_print(exclude_hv); |
1926 | if_print(exclude_idle); | 1933 | if_print(exclude_idle); |
1927 | if_print(mmap); | 1934 | if_print(mmap); |
1935 | if_print(mmap2); | ||
1928 | if_print(comm); | 1936 | if_print(comm); |
1929 | if_print(freq); | 1937 | if_print(freq); |
1930 | if_print(inherit_stat); | 1938 | if_print(inherit_stat); |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a33197a4fd21..26441d0e571b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1351,6 +1351,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | |||
1351 | 1351 | ||
1352 | fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip); | 1352 | fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip); |
1353 | 1353 | ||
1354 | fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2); | ||
1355 | fprintf(fp, ", attr_mmap = %d", evsel->attr.mmap); | ||
1356 | fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data); | ||
1354 | if (evsel->ids) { | 1357 | if (evsel->ids) { |
1355 | fprintf(fp, ", id = {"); | 1358 | fprintf(fp, ", id = {"); |
1356 | for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { | 1359 | for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 1dca61f0512d..933d14f287ca 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -997,6 +997,54 @@ out_problem: | |||
997 | return -1; | 997 | return -1; |
998 | } | 998 | } |
999 | 999 | ||
1000 | int machine__process_mmap2_event(struct machine *machine, | ||
1001 | union perf_event *event) | ||
1002 | { | ||
1003 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
1004 | struct thread *thread; | ||
1005 | struct map *map; | ||
1006 | enum map_type type; | ||
1007 | int ret = 0; | ||
1008 | |||
1009 | if (dump_trace) | ||
1010 | perf_event__fprintf_mmap2(event, stdout); | ||
1011 | |||
1012 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || | ||
1013 | cpumode == PERF_RECORD_MISC_KERNEL) { | ||
1014 | ret = machine__process_kernel_mmap_event(machine, event); | ||
1015 | if (ret < 0) | ||
1016 | goto out_problem; | ||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | thread = machine__findnew_thread(machine, event->mmap2.pid, | ||
1021 | event->mmap2.pid); | ||
1022 | if (thread == NULL) | ||
1023 | goto out_problem; | ||
1024 | |||
1025 | if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) | ||
1026 | type = MAP__VARIABLE; | ||
1027 | else | ||
1028 | type = MAP__FUNCTION; | ||
1029 | |||
1030 | map = map__new(&machine->user_dsos, event->mmap2.start, | ||
1031 | event->mmap2.len, event->mmap2.pgoff, | ||
1032 | event->mmap2.pid, event->mmap2.maj, | ||
1033 | event->mmap2.min, event->mmap2.ino, | ||
1034 | event->mmap2.ino_generation, | ||
1035 | event->mmap2.filename, type); | ||
1036 | |||
1037 | if (map == NULL) | ||
1038 | goto out_problem; | ||
1039 | |||
1040 | thread__insert_map(thread, map); | ||
1041 | return 0; | ||
1042 | |||
1043 | out_problem: | ||
1044 | dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n"); | ||
1045 | return 0; | ||
1046 | } | ||
1047 | |||
1000 | int machine__process_mmap_event(struct machine *machine, union perf_event *event) | 1048 | int machine__process_mmap_event(struct machine *machine, union perf_event *event) |
1001 | { | 1049 | { |
1002 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 1050 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
@@ -1028,7 +1076,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event | |||
1028 | 1076 | ||
1029 | map = map__new(&machine->user_dsos, event->mmap.start, | 1077 | map = map__new(&machine->user_dsos, event->mmap.start, |
1030 | event->mmap.len, event->mmap.pgoff, | 1078 | event->mmap.len, event->mmap.pgoff, |
1031 | event->mmap.pid, event->mmap.filename, | 1079 | event->mmap.pid, 0, 0, 0, 0, |
1080 | event->mmap.filename, | ||
1032 | type); | 1081 | type); |
1033 | 1082 | ||
1034 | if (map == NULL) | 1083 | if (map == NULL) |
@@ -1101,6 +1150,8 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
1101 | ret = machine__process_comm_event(machine, event); break; | 1150 | ret = machine__process_comm_event(machine, event); break; |
1102 | case PERF_RECORD_MMAP: | 1151 | case PERF_RECORD_MMAP: |
1103 | ret = machine__process_mmap_event(machine, event); break; | 1152 | ret = machine__process_mmap_event(machine, event); break; |
1153 | case PERF_RECORD_MMAP2: | ||
1154 | ret = machine__process_mmap2_event(machine, event); break; | ||
1104 | case PERF_RECORD_FORK: | 1155 | case PERF_RECORD_FORK: |
1105 | ret = machine__process_fork_event(machine, event); break; | 1156 | ret = machine__process_fork_event(machine, event); break; |
1106 | case PERF_RECORD_EXIT: | 1157 | case PERF_RECORD_EXIT: |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 0df925ba6a44..58a6be1fc739 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -45,6 +45,7 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event | |||
45 | int machine__process_fork_event(struct machine *machine, union perf_event *event); | 45 | int machine__process_fork_event(struct machine *machine, union perf_event *event); |
46 | int machine__process_lost_event(struct machine *machine, union perf_event *event); | 46 | int machine__process_lost_event(struct machine *machine, union perf_event *event); |
47 | int machine__process_mmap_event(struct machine *machine, union perf_event *event); | 47 | int machine__process_mmap_event(struct machine *machine, union perf_event *event); |
48 | int machine__process_mmap2_event(struct machine *machine, union perf_event *event); | ||
48 | int machine__process_event(struct machine *machine, union perf_event *event); | 49 | int machine__process_event(struct machine *machine, union perf_event *event); |
49 | 50 | ||
50 | typedef void (*machine__process_t)(struct machine *machine, void *data); | 51 | typedef void (*machine__process_t)(struct machine *machine, void *data); |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 9e8304ca343e..4f6680d2043b 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -48,7 +48,8 @@ void map__init(struct map *map, enum map_type type, | |||
48 | } | 48 | } |
49 | 49 | ||
50 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | 50 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, |
51 | u64 pgoff, u32 pid, char *filename, | 51 | u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, |
52 | u64 ino_gen, char *filename, | ||
52 | enum map_type type) | 53 | enum map_type type) |
53 | { | 54 | { |
54 | struct map *map = malloc(sizeof(*map)); | 55 | struct map *map = malloc(sizeof(*map)); |
@@ -62,6 +63,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
62 | vdso = is_vdso_map(filename); | 63 | vdso = is_vdso_map(filename); |
63 | no_dso = is_no_dso_memory(filename); | 64 | no_dso = is_no_dso_memory(filename); |
64 | 65 | ||
66 | map->maj = d_maj; | ||
67 | map->min = d_min; | ||
68 | map->ino = ino; | ||
69 | map->ino_generation = ino_gen; | ||
70 | |||
65 | if (anon) { | 71 | if (anon) { |
66 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); | 72 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); |
67 | filename = newfilename; | 73 | filename = newfilename; |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 2cc93cbf0e17..4886ca280536 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -36,6 +36,9 @@ struct map { | |||
36 | bool erange_warned; | 36 | bool erange_warned; |
37 | u32 priv; | 37 | u32 priv; |
38 | u64 pgoff; | 38 | u64 pgoff; |
39 | u32 maj, min; /* only valid for MMAP2 record */ | ||
40 | u64 ino; /* only valid for MMAP2 record */ | ||
41 | u64 ino_generation;/* only valid for MMAP2 record */ | ||
39 | 42 | ||
40 | /* ip -> dso rip */ | 43 | /* ip -> dso rip */ |
41 | u64 (*map_ip)(struct map *, u64); | 44 | u64 (*map_ip)(struct map *, u64); |
@@ -88,8 +91,9 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); | |||
88 | void map__init(struct map *map, enum map_type type, | 91 | void map__init(struct map *map, enum map_type type, |
89 | u64 start, u64 end, u64 pgoff, struct dso *dso); | 92 | u64 start, u64 end, u64 pgoff, struct dso *dso); |
90 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | 93 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, |
91 | u64 pgoff, u32 pid, char *filename, | 94 | u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, |
92 | enum map_type type); | 95 | u64 ino_gen, |
96 | char *filename, enum map_type type); | ||
93 | struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 97 | struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
94 | void map__delete(struct map *map); | 98 | void map__delete(struct map *map); |
95 | struct map *map__clone(struct map *map); | 99 | struct map *map__clone(struct map *map); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0308d9ee7a77..51f5edf2a6d0 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -351,6 +351,25 @@ static void perf_event__mmap_swap(union perf_event *event, | |||
351 | } | 351 | } |
352 | } | 352 | } |
353 | 353 | ||
354 | static void perf_event__mmap2_swap(union perf_event *event, | ||
355 | bool sample_id_all) | ||
356 | { | ||
357 | event->mmap2.pid = bswap_32(event->mmap2.pid); | ||
358 | event->mmap2.tid = bswap_32(event->mmap2.tid); | ||
359 | event->mmap2.start = bswap_64(event->mmap2.start); | ||
360 | event->mmap2.len = bswap_64(event->mmap2.len); | ||
361 | event->mmap2.pgoff = bswap_64(event->mmap2.pgoff); | ||
362 | event->mmap2.maj = bswap_32(event->mmap2.maj); | ||
363 | event->mmap2.min = bswap_32(event->mmap2.min); | ||
364 | event->mmap2.ino = bswap_64(event->mmap2.ino); | ||
365 | |||
366 | if (sample_id_all) { | ||
367 | void *data = &event->mmap2.filename; | ||
368 | |||
369 | data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); | ||
370 | swap_sample_id_all(event, data); | ||
371 | } | ||
372 | } | ||
354 | static void perf_event__task_swap(union perf_event *event, bool sample_id_all) | 373 | static void perf_event__task_swap(union perf_event *event, bool sample_id_all) |
355 | { | 374 | { |
356 | event->fork.pid = bswap_32(event->fork.pid); | 375 | event->fork.pid = bswap_32(event->fork.pid); |
@@ -455,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event, | |||
455 | 474 | ||
456 | static perf_event__swap_op perf_event__swap_ops[] = { | 475 | static perf_event__swap_op perf_event__swap_ops[] = { |
457 | [PERF_RECORD_MMAP] = perf_event__mmap_swap, | 476 | [PERF_RECORD_MMAP] = perf_event__mmap_swap, |
477 | [PERF_RECORD_MMAP2] = perf_event__mmap2_swap, | ||
458 | [PERF_RECORD_COMM] = perf_event__comm_swap, | 478 | [PERF_RECORD_COMM] = perf_event__comm_swap, |
459 | [PERF_RECORD_FORK] = perf_event__task_swap, | 479 | [PERF_RECORD_FORK] = perf_event__task_swap, |
460 | [PERF_RECORD_EXIT] = perf_event__task_swap, | 480 | [PERF_RECORD_EXIT] = perf_event__task_swap, |
@@ -851,7 +871,8 @@ static struct machine * | |||
851 | (cpumode == PERF_RECORD_MISC_GUEST_USER))) { | 871 | (cpumode == PERF_RECORD_MISC_GUEST_USER))) { |
852 | u32 pid; | 872 | u32 pid; |
853 | 873 | ||
854 | if (event->header.type == PERF_RECORD_MMAP) | 874 | if (event->header.type == PERF_RECORD_MMAP |
875 | || event->header.type == PERF_RECORD_MMAP2) | ||
855 | pid = event->mmap.pid; | 876 | pid = event->mmap.pid; |
856 | else | 877 | else |
857 | pid = sample->pid; | 878 | pid = sample->pid; |
@@ -978,6 +999,8 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
978 | sample, evsel, machine); | 999 | sample, evsel, machine); |
979 | case PERF_RECORD_MMAP: | 1000 | case PERF_RECORD_MMAP: |
980 | return tool->mmap(tool, event, sample, machine); | 1001 | return tool->mmap(tool, event, sample, machine); |
1002 | case PERF_RECORD_MMAP2: | ||
1003 | return tool->mmap2(tool, event, sample, machine); | ||
981 | case PERF_RECORD_COMM: | 1004 | case PERF_RECORD_COMM: |
982 | return tool->comm(tool, event, sample, machine); | 1005 | return tool->comm(tool, event, sample, machine); |
983 | case PERF_RECORD_FORK: | 1006 | case PERF_RECORD_FORK: |
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 62b16b6165ba..4385816d3d49 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h | |||
@@ -29,6 +29,7 @@ struct perf_tool { | |||
29 | event_sample sample, | 29 | event_sample sample, |
30 | read; | 30 | read; |
31 | event_op mmap, | 31 | event_op mmap, |
32 | mmap2, | ||
32 | comm, | 33 | comm, |
33 | fork, | 34 | fork, |
34 | exit, | 35 | exit, |