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 | |
| 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>
| -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, |
