2013-08-21 10:09:29

by Stephane Eranian

[permalink] [raw]
Subject: [PATCH v2 0/2] perf: add new PERF_RECORD_MMAP2 record type

This patch series introduces a new record type for mmaps. This
new record is called PERF_RECORD_MMAP2. It provides more information
than the existing PERF_RECORD_MMAP. For each file-backed or
shared memory segment mapping, the device major, minor and the
inode numbers are recorded. This triplet may be used to
disambiguate virtual file-backed mappings between processes.

The triplet could not be fitted into the existing PERF_RECORD_MMAP
record without breaking backward compatibility. This is why we
introduce this new record type.

To activate this new record type, the mmap2 bit must be set
in perf_event_attr struct. It supersedes the mmap bit, but is
distinct from mmap_data. For mmap2 data records, both mmap2 and
mmap_data must be set. For code, only mmap2 must be set.

The series also provides the perf tool support for this new
MMAP2 record type. Perf record activates this mode by default.
The maj, min, ino are not yet exploited by perf report but
will be in subsequent perf tools.

In V2, we added a new field to the MMAP2 record: i_generation.
It captures the generation number of the inode. It can help
further disambiguate mappings. The inode generation is not
avail for MMAP2 records synthesized from /proc/PID/maps.

We also updated the header for the MMAP2 record layout to
show the sample_id struct which is appended if
attr->sample_id_all is set.

Patch is relative to tip.git

Signed-off-by: Stephane Eranian <[email protected]>

Stephane Eranian (2):
perf: add attr->mmap2 attribute to an event
perf tools: add attr->mmap2 support

include/uapi/linux/perf_event.h | 24 ++++++++++++++++-
kernel/events/core.c | 46 +++++++++++++++++++++++++++++---
tools/perf/builtin-annotate.c | 1 +
tools/perf/builtin-inject.c | 15 +++++++++++
tools/perf/builtin-mem.c | 1 +
tools/perf/builtin-report.c | 1 +
tools/perf/builtin-script.c | 1 +
tools/perf/util/build-id.c | 1 +
tools/perf/util/event.c | 56 ++++++++++++++++++++++++++++++---------
tools/perf/util/event.h | 19 +++++++++++++
tools/perf/util/evsel.c | 5 ++--
tools/perf/util/header.c | 3 +++
tools/perf/util/machine.c | 52 +++++++++++++++++++++++++++++++++++-
tools/perf/util/machine.h | 1 +
tools/perf/util/map.c | 8 +++++-
tools/perf/util/map.h | 8 ++++--
tools/perf/util/session.c | 25 ++++++++++++++++-
tools/perf/util/tool.h | 1 +
18 files changed, 244 insertions(+), 24 deletions(-)

--
1.7.10.4


2013-08-21 10:09:34

by Stephane Eranian

[permalink] [raw]
Subject: [PATCH v2 1/2] perf: add attr->mmap2 attribute to an event

Adds a new PERF_RECORD_MMAP2 record type.

Used to request mmap records with more information about
the mapping, including device major, minor and the inode
number and generation for mappings associated with files
or shared memory segments. Works for code and data
(with attr->mmap_data set).

Existing PERF_RECORD_MMAP record is unmodified by this patch.

Signed-off-by: Stephane Eranian <[email protected]>
---
include/uapi/linux/perf_event.h | 24 +++++++++++++++++++-
kernel/events/core.c | 46 +++++++++++++++++++++++++++++++++++----
2 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 62c25a2..5268f78 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -275,8 +275,9 @@ struct perf_event_attr {

exclude_callchain_kernel : 1, /* exclude kernel callchains */
exclude_callchain_user : 1, /* exclude user callchains */
+ mmap2 : 1, /* include mmap with inode data */

- __reserved_1 : 41;
+ __reserved_1 : 40;

union {
__u32 wakeup_events; /* wakeup every n events */
@@ -638,6 +639,27 @@ enum perf_event_type {
*/
PERF_RECORD_SAMPLE = 9,

+ /*
+ * The MMAP2 records are an augmented version of MMAP, they add
+ * maj, min, ino numbers to be used to uniquely identify each mapping
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * u32 maj;
+ * u32 min;
+ * u64 ino;
+ * u64 ino_generation;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP2 = 10,
+
PERF_RECORD_MAX, /* non-ABI */
};

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 928fae7..60a5bbd 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4767,7 +4767,7 @@ next:
/*
* task tracking -- fork/exit
*
- * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task
+ * enabled by: attr.comm | attr.mmap | attr.mmap2 | attr.mmap_data | attr.task
*/

struct perf_task_event {
@@ -4787,8 +4787,9 @@ struct perf_task_event {

static int perf_event_task_match(struct perf_event *event)
{
- return event->attr.comm || event->attr.mmap ||
- event->attr.mmap_data || event->attr.task;
+ return event->attr.comm || event->attr.mmap ||
+ event->attr.mmap2 || event->attr.mmap_data ||
+ event->attr.task;
}

static void perf_event_task_output(struct perf_event *event,
@@ -4983,6 +4984,9 @@ struct perf_mmap_event {

const char *file_name;
int file_size;
+ int maj, min;
+ u64 ino;
+ u64 ino_generation;

struct {
struct perf_event_header header;
@@ -5003,7 +5007,7 @@ static int perf_event_mmap_match(struct perf_event *event,
int executable = vma->vm_flags & VM_EXEC;

return (!executable && event->attr.mmap_data) ||
- (executable && event->attr.mmap);
+ (executable && (event->attr.mmap || event->attr.mmap2));
}

static void perf_event_mmap_output(struct perf_event *event,
@@ -5018,6 +5022,13 @@ static void perf_event_mmap_output(struct perf_event *event,
if (!perf_event_mmap_match(event, data))
return;

+ if (event->attr.mmap2) {
+ mmap_event->event_id.header.type = PERF_RECORD_MMAP2;
+ mmap_event->event_id.header.size += sizeof(mmap_event->maj);
+ mmap_event->event_id.header.size += sizeof(mmap_event->min);
+ mmap_event->event_id.header.size += sizeof(mmap_event->ino);
+ }
+
perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
ret = perf_output_begin(&handle, event,
mmap_event->event_id.header.size);
@@ -5028,6 +5039,14 @@ static void perf_event_mmap_output(struct perf_event *event,
mmap_event->event_id.tid = perf_event_tid(event, current);

perf_output_put(&handle, mmap_event->event_id);
+
+ if (event->attr.mmap2) {
+ perf_output_put(&handle, mmap_event->maj);
+ perf_output_put(&handle, mmap_event->min);
+ perf_output_put(&handle, mmap_event->ino);
+ perf_output_put(&handle, mmap_event->ino_generation);
+ }
+
__output_copy(&handle, mmap_event->file_name,
mmap_event->file_size);

@@ -5042,6 +5061,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
{
struct vm_area_struct *vma = mmap_event->vma;
struct file *file = vma->vm_file;
+ int maj = 0, min = 0;
+ u64 ino = 0, gen = 0;
unsigned int size;
char tmp[16];
char *buf = NULL;
@@ -5050,6 +5071,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
memset(tmp, 0, sizeof(tmp));

if (file) {
+ struct inode *inode;
+ dev_t dev;
/*
* d_path works from the end of the rb backwards, so we
* need to add enough zero bytes after the string to handle
@@ -5065,6 +5088,13 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
name = strncpy(tmp, "//toolong", sizeof(tmp));
goto got_name;
}
+ inode = file_inode(vma->vm_file);
+ dev = inode->i_sb->s_dev;
+ ino = inode->i_ino;
+ gen = inode->i_generation;
+ maj = MAJOR(dev);
+ min = MINOR(dev);
+
} else {
if (arch_vma_name(mmap_event->vma)) {
name = strncpy(tmp, arch_vma_name(mmap_event->vma),
@@ -5095,6 +5125,10 @@ got_name:

mmap_event->file_name = name;
mmap_event->file_size = size;
+ mmap_event->maj = maj;
+ mmap_event->min = min;
+ mmap_event->ino = ino;
+ mmap_event->ino_generation = gen;

if (!(vma->vm_flags & VM_EXEC))
mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA;
@@ -5131,6 +5165,10 @@ void perf_event_mmap(struct vm_area_struct *vma)
.len = vma->vm_end - vma->vm_start,
.pgoff = (u64)vma->vm_pgoff << PAGE_SHIFT,
},
+ /* .maj (attr_mmap2 only) */
+ /* .min (attr_mmap2 only) */
+ /* .ino (attr_mmap2 only) */
+ /* .ino_generation (attr_mmap2 only) */
};

perf_event_mmap_event(&mmap_event);
--
1.7.10.4

2013-08-21 10:09:39

by Stephane Eranian

[permalink] [raw]
Subject: [PATCH v2 2/2] 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 <[email protected]>
---
tools/perf/builtin-annotate.c | 1 +
tools/perf/builtin-inject.c | 15 +++++++++++
tools/perf/builtin-mem.c | 1 +
tools/perf/builtin-report.c | 1 +
tools/perf/builtin-script.c | 1 +
tools/perf/util/build-id.c | 1 +
tools/perf/util/event.c | 56 ++++++++++++++++++++++++++++++++---------
tools/perf/util/event.h | 19 ++++++++++++++
tools/perf/util/evsel.c | 5 ++--
tools/perf/util/header.c | 3 +++
tools/perf/util/machine.c | 52 +++++++++++++++++++++++++++++++++++++-
tools/perf/util/machine.h | 1 +
tools/perf/util/map.c | 8 +++++-
tools/perf/util/map.h | 8 ++++--
tools/perf/util/session.c | 25 +++++++++++++++++-
tools/perf/util/tool.h | 1 +
16 files changed, 179 insertions(+), 19 deletions(-)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index f988d38..5ebd0c3 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 1d8de2e..8695f35 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,
return err;
}

+static int perf_event__repipe_mmap2(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct machine *machine)
+{
+ int err;
+
+ err = perf_event__process_mmap2(tool, event, sample, machine);
+ perf_event__repipe(tool, event, sample, machine);
+
+ return err;
+}
+
static int perf_event__repipe_fork(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
@@ -337,6 +350,7 @@ static int __cmd_inject(struct perf_inject *inject)

if (inject->build_ids || inject->sched_stat) {
inject->tool.mmap = perf_event__repipe_mmap;
+ inject->tool.mmap2 = perf_event__repipe_mmap2;
inject->tool.fork = perf_event__repipe_fork;
inject->tool.tracing_data = perf_event__repipe_tracing_data;
}
@@ -388,6 +402,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.tool = {
.sample = perf_event__repipe_sample,
.mmap = perf_event__repipe,
+ .mmap2 = perf_event__repipe,
.comm = perf_event__repipe,
.fork = perf_event__repipe,
.exit = perf_event__repipe,
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 706a1fa..ebf500e 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 958a56a..96625a79 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 2ad9d5b..eed7f77 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -541,6 +541,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
static struct perf_tool perf_script = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 5295625..d8dd29a 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -64,6 +64,7 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
struct perf_tool build_id__mark_dso_hit_ops = {
.sample = build_id__mark_dso_hit,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.fork = perf_event__process_fork,
.exit = perf_event__exit_del_thread,
.attr = perf_event__process_attr,
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 49713ae..3b7134c 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -11,6 +11,7 @@
static const char *perf_event__names[] = {
[0] = "TOTAL",
[PERF_RECORD_MMAP] = "MMAP",
+ [PERF_RECORD_MMAP2] = "MMAP2",
[PERF_RECORD_LOST] = "LOST",
[PERF_RECORD_COMM] = "COMM",
[PERF_RECORD_EXIT] = "EXIT",
@@ -186,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
return -1;
}

- event->header.type = PERF_RECORD_MMAP;
+ event->header.type = PERF_RECORD_MMAP2;
/*
* Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
*/
@@ -197,7 +198,9 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
char prot[5];
char execname[PATH_MAX];
char anonstr[] = "//anon";
+ unsigned int ino;
size_t size;
+ ssize_t n;

if (fgets(bf, sizeof(bf), fp) == NULL)
break;
@@ -206,9 +209,16 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
strcpy(execname, "");

/* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
- sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
- &event->mmap.start, &event->mmap.len, prot,
- &event->mmap.pgoff, execname);
+ n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
+ &event->mmap2.start, &event->mmap2.len, prot,
+ &event->mmap2.pgoff, &event->mmap2.maj,
+ &event->mmap2.min,
+ &ino, execname);
+
+ event->mmap2.ino = (u64)ino;
+
+ if (n != 8)
+ continue;

if (prot[2] != 'x')
continue;
@@ -217,15 +227,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
strcpy(execname, anonstr);

size = strlen(execname) + 1;
- memcpy(event->mmap.filename, execname, size);
+ memcpy(event->mmap2.filename, execname, size);
size = PERF_ALIGN(size, sizeof(u64));
- event->mmap.len -= event->mmap.start;
- event->mmap.header.size = (sizeof(event->mmap) -
- (sizeof(event->mmap.filename) - size));
- memset(event->mmap.filename + size, 0, machine->id_hdr_size);
- event->mmap.header.size += machine->id_hdr_size;
- event->mmap.pid = tgid;
- event->mmap.tid = pid;
+ event->mmap2.len -= event->mmap.start;
+ event->mmap2.header.size = (sizeof(event->mmap2) -
+ (sizeof(event->mmap2.filename) - size));
+ memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
+ event->mmap2.header.size += machine->id_hdr_size;
+ event->mmap2.pid = tgid;
+ event->mmap2.tid = pid;

if (process(tool, event, &synth_sample, machine) != 0) {
rc = -1;
@@ -527,6 +537,17 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
event->mmap.len, event->mmap.pgoff, event->mmap.filename);
}

+size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
+{
+ return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
+ " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n",
+ event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
+ event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
+ event->mmap2.min, event->mmap2.ino,
+ event->mmap2.ino_generation,
+ event->mmap2.filename);
+}
+
int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
@@ -535,6 +556,14 @@ int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
return machine__process_mmap_event(machine, event);
}

+int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine)
+{
+ return machine__process_mmap2_event(machine, event);
+}
+
size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
{
return fprintf(fp, "(%d:%d):(%d:%d)\n",
@@ -574,6 +603,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
case PERF_RECORD_MMAP:
ret += perf_event__fprintf_mmap(event, fp);
break;
+ case PERF_RECORD_MMAP2:
+ ret += perf_event__fprintf_mmap2(event, fp);
+ break;
default:
ret += fprintf(fp, "\n");
}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 15db071..23b3879 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -27,6 +27,19 @@ struct mmap_event {
char filename[PATH_MAX];
};

+struct mmap2_event {
+ struct perf_event_header header;
+ u32 pid, tid;
+ u64 start;
+ u64 len;
+ u64 pgoff;
+ u32 maj;
+ u32 min;
+ u64 ino;
+ u64 ino_generation;
+ char filename[PATH_MAX];
+};
+
struct comm_event {
struct perf_event_header header;
u32 pid, tid;
@@ -168,6 +181,7 @@ union perf_event {
struct perf_event_header header;
struct ip_event ip;
struct mmap_event mmap;
+ struct mmap2_event mmap2;
struct comm_event comm;
struct fork_event fork;
struct lost_event lost;
@@ -217,6 +231,10 @@ int perf_event__process_mmap(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine);
+int perf_event__process_mmap2(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct machine *machine);
int perf_event__process_fork(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
@@ -244,6 +262,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,

size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
size_t perf_event__fprintf(union perf_event *event, FILE *fp);

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 960394e..2bc0e4d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -598,8 +598,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
if (opts->sample_weight)
attr->sample_type |= PERF_SAMPLE_WEIGHT;

- attr->mmap = track;
- attr->comm = track;
+ attr->mmap = track;
+ attr->mmap2 = track;
+ attr->comm = track;

/*
* XXX see the function comment above
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a33197a..26441d0 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)

fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);

+ fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2);
+ fprintf(fp, ", attr_mmap = %d", evsel->attr.mmap);
+ fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data);
if (evsel->ids) {
fprintf(fp, ", id = {");
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 4514e7e..1412e17 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -987,6 +987,53 @@ out_problem:
return -1;
}

+int machine__process_mmap2_event(struct machine *machine,
+ union perf_event *event)
+{
+ u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+ struct thread *thread;
+ struct map *map;
+ enum map_type type;
+ int ret = 0;
+
+ if (dump_trace)
+ perf_event__fprintf_mmap2(event, stdout);
+
+ if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
+ cpumode == PERF_RECORD_MISC_KERNEL) {
+ ret = machine__process_kernel_mmap_event(machine, event);
+ if (ret < 0)
+ goto out_problem;
+ return 0;
+ }
+
+ thread = machine__findnew_thread(machine, event->mmap2.pid);
+ if (thread == NULL)
+ goto out_problem;
+
+ if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
+ type = MAP__VARIABLE;
+ else
+ type = MAP__FUNCTION;
+
+ map = map__new(&machine->user_dsos, event->mmap2.start,
+ event->mmap2.len, event->mmap2.pgoff,
+ event->mmap2.pid, event->mmap2.maj,
+ event->mmap2.min, event->mmap2.ino,
+ event->mmap2.ino_generation,
+ event->mmap2.filename, type);
+
+ if (map == NULL)
+ goto out_problem;
+
+ thread__insert_map(thread, map);
+ return 0;
+
+out_problem:
+ dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
+ return 0;
+}
+
int machine__process_mmap_event(struct machine *machine, union perf_event *event)
{
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -1017,7 +1064,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event

map = map__new(&machine->user_dsos, event->mmap.start,
event->mmap.len, event->mmap.pgoff,
- event->mmap.pid, event->mmap.filename,
+ event->mmap.pid, 0, 0, 0, 0,
+ event->mmap.filename,
type);

if (map == NULL)
@@ -1081,6 +1129,8 @@ int machine__process_event(struct machine *machine, union perf_event *event)
ret = machine__process_comm_event(machine, event); break;
case PERF_RECORD_MMAP:
ret = machine__process_mmap_event(machine, event); break;
+ case PERF_RECORD_MMAP2:
+ ret = machine__process_mmap2_event(machine, event); break;
case PERF_RECORD_FORK:
ret = machine__process_fork_event(machine, event); break;
case PERF_RECORD_EXIT:
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 603ffba..2593147 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
int machine__process_fork_event(struct machine *machine, union perf_event *event);
int machine__process_lost_event(struct machine *machine, union perf_event *event);
int machine__process_mmap_event(struct machine *machine, union perf_event *event);
+int machine__process_mmap2_event(struct machine *machine, union perf_event *event);
int machine__process_event(struct machine *machine, union perf_event *event);

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 9e8304c..4f6680d 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,
}

struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
- u64 pgoff, u32 pid, char *filename,
+ u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
+ u64 ino_gen, char *filename,
enum map_type type)
{
struct map *map = malloc(sizeof(*map));
@@ -62,6 +63,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
vdso = is_vdso_map(filename);
no_dso = is_no_dso_memory(filename);

+ map->maj = d_maj;
+ map->min = d_min;
+ map->ino = ino;
+ map->ino_generation = ino_gen;
+
if (anon) {
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
filename = newfilename;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 2cc93cb..4886ca2 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -36,6 +36,9 @@ struct map {
bool erange_warned;
u32 priv;
u64 pgoff;
+ u32 maj, min; /* only valid for MMAP2 record */
+ u64 ino; /* only valid for MMAP2 record */
+ u64 ino_generation;/* only valid for MMAP2 record */

/* ip -> dso rip */
u64 (*map_ip)(struct map *, u64);
@@ -88,8 +91,9 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
void map__init(struct map *map, enum map_type type,
u64 start, u64 end, u64 pgoff, struct dso *dso);
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
- u64 pgoff, u32 pid, char *filename,
- enum map_type type);
+ u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
+ u64 ino_gen,
+ char *filename, enum map_type type);
struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
void map__delete(struct map *map);
struct map *map__clone(struct map *map);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index de16a77..99e60f9 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,
}
}

+static void perf_event__mmap2_swap(union perf_event *event,
+ bool sample_id_all)
+{
+ event->mmap2.pid = bswap_32(event->mmap2.pid);
+ event->mmap2.tid = bswap_32(event->mmap2.tid);
+ event->mmap2.start = bswap_64(event->mmap2.start);
+ event->mmap2.len = bswap_64(event->mmap2.len);
+ event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);
+ event->mmap2.maj = bswap_32(event->mmap2.maj);
+ event->mmap2.min = bswap_32(event->mmap2.min);
+ event->mmap2.ino = bswap_64(event->mmap2.ino);
+
+ if (sample_id_all) {
+ void *data = &event->mmap2.filename;
+
+ data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
+ swap_sample_id_all(event, data);
+ }
+}
static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
{
event->fork.pid = bswap_32(event->fork.pid);
@@ -455,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event,

static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_MMAP] = perf_event__mmap_swap,
+ [PERF_RECORD_MMAP2] = perf_event__mmap2_swap,
[PERF_RECORD_COMM] = perf_event__comm_swap,
[PERF_RECORD_FORK] = perf_event__task_swap,
[PERF_RECORD_EXIT] = perf_event__task_swap,
@@ -849,7 +869,8 @@ static struct machine *
(cpumode == PERF_RECORD_MISC_GUEST_USER))) {
u32 pid;

- if (event->header.type == PERF_RECORD_MMAP)
+ if (event->header.type == PERF_RECORD_MMAP
+ || event->header.type == PERF_RECORD_MMAP2)
pid = event->mmap.pid;
else
pid = event->ip.pid;
@@ -975,6 +996,8 @@ static int perf_session_deliver_event(struct perf_session *session,
sample, evsel, machine);
case PERF_RECORD_MMAP:
return tool->mmap(tool, event, sample, machine);
+ case PERF_RECORD_MMAP2:
+ return tool->mmap2(tool, event, sample, machine);
case PERF_RECORD_COMM:
return tool->comm(tool, event, sample, machine);
case PERF_RECORD_FORK:
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 62b16b6..4385816 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -29,6 +29,7 @@ struct perf_tool {
event_sample sample,
read;
event_op mmap,
+ mmap2,
comm,
fork,
exit,
--
1.7.10.4

2013-08-22 10:51:20

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

On Wed, Aug 21, 2013 at 12:10:25PM +0200, Stephane Eranian wrote:
> 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 <[email protected]>

Acme, ACK?

2013-08-22 15:58:07

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] perf: add attr->mmap2 attribute to an event

Em Wed, Aug 21, 2013 at 12:10:24PM +0200, Stephane Eranian escreveu:
> Adds a new PERF_RECORD_MMAP2 record type.
>
> Used to request mmap records with more information about
> the mapping, including device major, minor and the inode
> number and generation for mappings associated with files
> or shared memory segments. Works for code and data
> (with attr->mmap_data set).
>
> Existing PERF_RECORD_MMAP record is unmodified by this patch.

So this is exactly what we get from PERF_RECORD_MMAP + a few other
fields, right?

I think we should take the opportunity and remove the fields that are
in PERF_RECORD_MMAP but can be selectively asked for using
->sample_id_all, i.e. we use sample_type to ask for:

PERF_SAMPLE_CPU
PERF_SAMPLE_STREAM_ID
PERF_SAMPLE_ID
PERF_SAMPLE_TIME
PERF_SAMPLE_TID

That should not be present in the PERF_RECORD_MMAP2 fixed payload.

This way we take the opportunity to compress the event by using an
existing facility: attr.sample_id_all and attr.sample_type.

But then this is "just" for the 8 bytes used for pid/tid, selectable via
PERF_SAMPLE_TID, so up to peterz, if you think its not worth the
complexity, Acked.

- Arnaldo

> Signed-off-by: Stephane Eranian <[email protected]>
> ---
> include/uapi/linux/perf_event.h | 24 +++++++++++++++++++-
> kernel/events/core.c | 46 +++++++++++++++++++++++++++++++++++----
> 2 files changed, 65 insertions(+), 5 deletions(-)
>
> diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
> index 62c25a2..5268f78 100644
> --- a/include/uapi/linux/perf_event.h
> +++ b/include/uapi/linux/perf_event.h
> @@ -275,8 +275,9 @@ struct perf_event_attr {
>
> exclude_callchain_kernel : 1, /* exclude kernel callchains */
> exclude_callchain_user : 1, /* exclude user callchains */
> + mmap2 : 1, /* include mmap with inode data */
>
> - __reserved_1 : 41;
> + __reserved_1 : 40;
>
> union {
> __u32 wakeup_events; /* wakeup every n events */
> @@ -638,6 +639,27 @@ enum perf_event_type {
> */
> PERF_RECORD_SAMPLE = 9,
>
> + /*
> + * The MMAP2 records are an augmented version of MMAP, they add
> + * maj, min, ino numbers to be used to uniquely identify each mapping
> + *
> + * struct {
> + * struct perf_event_header header;
> + *
> + * u32 pid, tid;
> + * u64 addr;
> + * u64 len;
> + * u64 pgoff;
> + * u32 maj;
> + * u32 min;
> + * u64 ino;
> + * u64 ino_generation;
> + * char filename[];
> + * struct sample_id sample_id;
> + * };
> + */
> + PERF_RECORD_MMAP2 = 10,
> +
> PERF_RECORD_MAX, /* non-ABI */
> };
>
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 928fae7..60a5bbd 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -4767,7 +4767,7 @@ next:
> /*
> * task tracking -- fork/exit
> *
> - * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task
> + * enabled by: attr.comm | attr.mmap | attr.mmap2 | attr.mmap_data | attr.task
> */
>
> struct perf_task_event {
> @@ -4787,8 +4787,9 @@ struct perf_task_event {
>
> static int perf_event_task_match(struct perf_event *event)
> {
> - return event->attr.comm || event->attr.mmap ||
> - event->attr.mmap_data || event->attr.task;
> + return event->attr.comm || event->attr.mmap ||
> + event->attr.mmap2 || event->attr.mmap_data ||
> + event->attr.task;
> }
>
> static void perf_event_task_output(struct perf_event *event,
> @@ -4983,6 +4984,9 @@ struct perf_mmap_event {
>
> const char *file_name;
> int file_size;
> + int maj, min;
> + u64 ino;
> + u64 ino_generation;
>
> struct {
> struct perf_event_header header;
> @@ -5003,7 +5007,7 @@ static int perf_event_mmap_match(struct perf_event *event,
> int executable = vma->vm_flags & VM_EXEC;
>
> return (!executable && event->attr.mmap_data) ||
> - (executable && event->attr.mmap);
> + (executable && (event->attr.mmap || event->attr.mmap2));
> }
>
> static void perf_event_mmap_output(struct perf_event *event,
> @@ -5018,6 +5022,13 @@ static void perf_event_mmap_output(struct perf_event *event,
> if (!perf_event_mmap_match(event, data))
> return;
>
> + if (event->attr.mmap2) {
> + mmap_event->event_id.header.type = PERF_RECORD_MMAP2;
> + mmap_event->event_id.header.size += sizeof(mmap_event->maj);
> + mmap_event->event_id.header.size += sizeof(mmap_event->min);
> + mmap_event->event_id.header.size += sizeof(mmap_event->ino);
> + }
> +
> perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
> ret = perf_output_begin(&handle, event,
> mmap_event->event_id.header.size);
> @@ -5028,6 +5039,14 @@ static void perf_event_mmap_output(struct perf_event *event,
> mmap_event->event_id.tid = perf_event_tid(event, current);
>
> perf_output_put(&handle, mmap_event->event_id);
> +
> + if (event->attr.mmap2) {
> + perf_output_put(&handle, mmap_event->maj);
> + perf_output_put(&handle, mmap_event->min);
> + perf_output_put(&handle, mmap_event->ino);
> + perf_output_put(&handle, mmap_event->ino_generation);
> + }
> +
> __output_copy(&handle, mmap_event->file_name,
> mmap_event->file_size);
>
> @@ -5042,6 +5061,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
> {
> struct vm_area_struct *vma = mmap_event->vma;
> struct file *file = vma->vm_file;
> + int maj = 0, min = 0;
> + u64 ino = 0, gen = 0;
> unsigned int size;
> char tmp[16];
> char *buf = NULL;
> @@ -5050,6 +5071,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
> memset(tmp, 0, sizeof(tmp));
>
> if (file) {
> + struct inode *inode;
> + dev_t dev;
> /*
> * d_path works from the end of the rb backwards, so we
> * need to add enough zero bytes after the string to handle
> @@ -5065,6 +5088,13 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
> name = strncpy(tmp, "//toolong", sizeof(tmp));
> goto got_name;
> }
> + inode = file_inode(vma->vm_file);
> + dev = inode->i_sb->s_dev;
> + ino = inode->i_ino;
> + gen = inode->i_generation;
> + maj = MAJOR(dev);
> + min = MINOR(dev);
> +
> } else {
> if (arch_vma_name(mmap_event->vma)) {
> name = strncpy(tmp, arch_vma_name(mmap_event->vma),
> @@ -5095,6 +5125,10 @@ got_name:
>
> mmap_event->file_name = name;
> mmap_event->file_size = size;
> + mmap_event->maj = maj;
> + mmap_event->min = min;
> + mmap_event->ino = ino;
> + mmap_event->ino_generation = gen;
>
> if (!(vma->vm_flags & VM_EXEC))
> mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA;
> @@ -5131,6 +5165,10 @@ void perf_event_mmap(struct vm_area_struct *vma)
> .len = vma->vm_end - vma->vm_start,
> .pgoff = (u64)vma->vm_pgoff << PAGE_SHIFT,
> },
> + /* .maj (attr_mmap2 only) */
> + /* .min (attr_mmap2 only) */
> + /* .ino (attr_mmap2 only) */
> + /* .ino_generation (attr_mmap2 only) */
> };
>
> perf_event_mmap_event(&mmap_event);
> --
> 1.7.10.4

2013-08-30 14:03:28

by Stephane Eranian

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Hi,

I realized I have forgotten to patch builtin-inject.c to repipe mmap2 records.
Will resubmit V3.


On Thu, Aug 22, 2013 at 12:51 PM, Peter Zijlstra <[email protected]> wrote:
> On Wed, Aug 21, 2013 at 12:10:25PM +0200, Stephane Eranian wrote:
>> 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 <[email protected]>
>
> Acme, ACK?

2013-08-30 14:09:01

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

On Fri, Aug 30, 2013 at 04:03:26PM +0200, Stephane Eranian wrote:
> Hi,
>
> I realized I have forgotten to patch builtin-inject.c to repipe mmap2 records.
> Will resubmit V3.

OK, I already queued the previous two, it looked fine and the ack was
long in coming. If mingo manages to push out before I can pick up v3
I'll frob a delta patch.

2013-08-30 14:15:47

by Stephane Eranian

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

On Fri, Aug 30, 2013 at 4:08 PM, Peter Zijlstra <[email protected]> wrote:
> On Fri, Aug 30, 2013 at 04:03:26PM +0200, Stephane Eranian wrote:
>> Hi,
>>
>> I realized I have forgotten to patch builtin-inject.c to repipe mmap2 records.
>> Will resubmit V3.
>
> OK, I already queued the previous two, it looked fine and the ack was
> long in coming. If mingo manages to push out before I can pick up v3
> I'll frob a delta patch.

I can submit a separate patch to cover for builtin-inject.c

2013-08-30 17:32:02

by Stephane Eranian

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

False alarm, the changes in builtin-inject.c are in V2.
Nothing more to do.
Sorry about the confusion.


On Fri, Aug 30, 2013 at 4:15 PM, Stephane Eranian <[email protected]> wrote:
> On Fri, Aug 30, 2013 at 4:08 PM, Peter Zijlstra <[email protected]> wrote:
>> On Fri, Aug 30, 2013 at 04:03:26PM +0200, Stephane Eranian wrote:
>>> Hi,
>>>
>>> I realized I have forgotten to patch builtin-inject.c to repipe mmap2 records.
>>> Will resubmit V3.
>>
>> OK, I already queued the previous two, it looked fine and the ack was
>> long in coming. If mingo manages to push out before I can pick up v3
>> I'll frob a delta patch.
>
> I can submit a separate patch to cover for builtin-inject.c

2013-08-31 06:00:59

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support


* Stephane Eranian <[email protected]> wrote:

> False alarm, the changes in builtin-inject.c are in V2. Nothing more to
> do. Sorry about the confusion.

ok, I'll pick up the -v2 patches from Peter.

Thanks,

Ingo

Subject: [tip:perf/core] perf: Add attr->mmap2 attribute to an event

Commit-ID: 13d7a2410fa637f450a29ecb515ac318ee40c741
Gitweb: http://git.kernel.org/tip/13d7a2410fa637f450a29ecb515ac318ee40c741
Author: Stephane Eranian <[email protected]>
AuthorDate: Wed, 21 Aug 2013 12:10:24 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 2 Sep 2013 08:42:48 +0200

perf: Add attr->mmap2 attribute to an event

Adds a new PERF_RECORD_MMAP2 record type which is essence
an expanded version of PERF_RECORD_MMAP.

Used to request mmap records with more information about
the mapping, including device major, minor and the inode
number and generation for mappings associated with files
or shared memory segments. Works for code and data
(with attr->mmap_data set).

Existing PERF_RECORD_MMAP record is unmodified by this patch.

Signed-off-by: Stephane Eranian <[email protected]>
Signed-off-by: Peter Zijlstra <[email protected]>
Cc: Al Viro <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ Added Al to the Cc:. Are the ino, maj/min exports of vma->vm_file OK? ]
Signed-off-by: Ingo Molnar <[email protected]>
---
include/uapi/linux/perf_event.h | 24 ++++++++++++++++++++-
kernel/events/core.c | 46 +++++++++++++++++++++++++++++++++++++----
2 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 42cb7b6..a77f43a 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -276,8 +276,9 @@ struct perf_event_attr {

exclude_callchain_kernel : 1, /* exclude kernel callchains */
exclude_callchain_user : 1, /* exclude user callchains */
+ mmap2 : 1, /* include mmap with inode data */

- __reserved_1 : 41;
+ __reserved_1 : 40;

union {
__u32 wakeup_events; /* wakeup every n events */
@@ -651,6 +652,27 @@ enum perf_event_type {
*/
PERF_RECORD_SAMPLE = 9,

+ /*
+ * The MMAP2 records are an augmented version of MMAP, they add
+ * maj, min, ino numbers to be used to uniquely identify each mapping
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * u32 maj;
+ * u32 min;
+ * u64 ino;
+ * u64 ino_generation;
+ * char filename[];
+ * struct sample_id sample_id;
+ * };
+ */
+ PERF_RECORD_MMAP2 = 10,
+
PERF_RECORD_MAX, /* non-ABI */
};

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 15d0f24..c7ee497 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4776,7 +4776,7 @@ next:
/*
* task tracking -- fork/exit
*
- * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task
+ * enabled by: attr.comm | attr.mmap | attr.mmap2 | attr.mmap_data | attr.task
*/

struct perf_task_event {
@@ -4796,8 +4796,9 @@ struct perf_task_event {

static int perf_event_task_match(struct perf_event *event)
{
- return event->attr.comm || event->attr.mmap ||
- event->attr.mmap_data || event->attr.task;
+ return event->attr.comm || event->attr.mmap ||
+ event->attr.mmap2 || event->attr.mmap_data ||
+ event->attr.task;
}

static void perf_event_task_output(struct perf_event *event,
@@ -4992,6 +4993,9 @@ struct perf_mmap_event {

const char *file_name;
int file_size;
+ int maj, min;
+ u64 ino;
+ u64 ino_generation;

struct {
struct perf_event_header header;
@@ -5012,7 +5016,7 @@ static int perf_event_mmap_match(struct perf_event *event,
int executable = vma->vm_flags & VM_EXEC;

return (!executable && event->attr.mmap_data) ||
- (executable && event->attr.mmap);
+ (executable && (event->attr.mmap || event->attr.mmap2));
}

static void perf_event_mmap_output(struct perf_event *event,
@@ -5027,6 +5031,13 @@ static void perf_event_mmap_output(struct perf_event *event,
if (!perf_event_mmap_match(event, data))
return;

+ if (event->attr.mmap2) {
+ mmap_event->event_id.header.type = PERF_RECORD_MMAP2;
+ mmap_event->event_id.header.size += sizeof(mmap_event->maj);
+ mmap_event->event_id.header.size += sizeof(mmap_event->min);
+ mmap_event->event_id.header.size += sizeof(mmap_event->ino);
+ }
+
perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
ret = perf_output_begin(&handle, event,
mmap_event->event_id.header.size);
@@ -5037,6 +5048,14 @@ static void perf_event_mmap_output(struct perf_event *event,
mmap_event->event_id.tid = perf_event_tid(event, current);

perf_output_put(&handle, mmap_event->event_id);
+
+ if (event->attr.mmap2) {
+ perf_output_put(&handle, mmap_event->maj);
+ perf_output_put(&handle, mmap_event->min);
+ perf_output_put(&handle, mmap_event->ino);
+ perf_output_put(&handle, mmap_event->ino_generation);
+ }
+
__output_copy(&handle, mmap_event->file_name,
mmap_event->file_size);

@@ -5051,6 +5070,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
{
struct vm_area_struct *vma = mmap_event->vma;
struct file *file = vma->vm_file;
+ int maj = 0, min = 0;
+ u64 ino = 0, gen = 0;
unsigned int size;
char tmp[16];
char *buf = NULL;
@@ -5059,6 +5080,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
memset(tmp, 0, sizeof(tmp));

if (file) {
+ struct inode *inode;
+ dev_t dev;
/*
* d_path works from the end of the rb backwards, so we
* need to add enough zero bytes after the string to handle
@@ -5074,6 +5097,13 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
name = strncpy(tmp, "//toolong", sizeof(tmp));
goto got_name;
}
+ inode = file_inode(vma->vm_file);
+ dev = inode->i_sb->s_dev;
+ ino = inode->i_ino;
+ gen = inode->i_generation;
+ maj = MAJOR(dev);
+ min = MINOR(dev);
+
} else {
if (arch_vma_name(mmap_event->vma)) {
name = strncpy(tmp, arch_vma_name(mmap_event->vma),
@@ -5104,6 +5134,10 @@ got_name:

mmap_event->file_name = name;
mmap_event->file_size = size;
+ mmap_event->maj = maj;
+ mmap_event->min = min;
+ mmap_event->ino = ino;
+ mmap_event->ino_generation = gen;

if (!(vma->vm_flags & VM_EXEC))
mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA;
@@ -5140,6 +5174,10 @@ void perf_event_mmap(struct vm_area_struct *vma)
.len = vma->vm_end - vma->vm_start,
.pgoff = (u64)vma->vm_pgoff << PAGE_SHIFT,
},
+ /* .maj (attr_mmap2 only) */
+ /* .min (attr_mmap2 only) */
+ /* .ino (attr_mmap2 only) */
+ /* .ino_generation (attr_mmap2 only) */
};

perf_event_mmap_event(&mmap_event);

2013-09-09 19:47:52

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Em Wed, Aug 21, 2013 at 12:10:25PM +0200, Stephane Eranian escreveu:
> 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.

I noticed the kernel part is in, and I'm going to use MMAP2 on that new
tool, so tried merging it, but:

I fixed it up wrt another patch that makes machine__find_thread receive pid/tid
but then 'perf test' complains about it, see below, trying to fix...

- Arnaldo


[root@sandy ~]# perf test -v 7
7: Validate PERF_RECORD_* events & perf_sample fields :
--- start ---
57503587100282 0 PERF_RECORD_SAMPLE
57503587104415 0 PERF_RECORD_SAMPLE
57503587106039 0 PERF_RECORD_SAMPLE
57503587107362 0 PERF_RECORD_SAMPLE
57503588263263 0 PERF_RECORD_COMM: sleep:1439
6180457940383 -1728826693 PERF_RECORD_MMAP2 1439/1439: [0x400000(0x7000) @ 0 00:1d 311442 9016]: /usr/bin/sleep
MMAP2 going backwards in time, prev=57503588263263, curr=6180457940383
MMAP2 with unexpected cpu, expected 0, got -1728826693
MMAP2 with unexpected pid, expected 1439, got 1701606191
MMAP2 with unexpected tid, expected 1439, got 28773
Unexpected perf_event->header.type 10!
6180457940383 -1728754371 PERF_RECORD_MMAP2 1439/1439: [0x3b7e000000(0x223000) @ 0 00:1d 309186 9016]: /usr/lib64/ld-2.16.so
MMAP2 with unexpected cpu, expected 0, got -1728754371
MMAP2 with unexpected pid, expected 1439, got 1932408369
MMAP2 with unexpected tid, expected 1439, got 111
Unexpected perf_event->header.type 10!
6180457940383 -1728699354 PERF_RECORD_MMAP2 1439/1439: [0x7fff2bdff000(0x1000) @ 0x7fff2bdff000 00:00 0 0]: [vdso]
MMAP2 with unexpected cpu, expected 0, got -1728699354
MMAP2 with unexpected pid, expected 1439, got 1935963739
MMAP2 with unexpected tid, expected 1439, got 23919
Unexpected perf_event->header.type 10!
6180457940383 -1728433298 PERF_RECORD_MMAP2 1439/1439: [0x3b7e400000(0x3b8000) @ 0 00:1d 309187 9016]: /usr/lib64/libc-2.16.so
MMAP2 with unexpected cpu, expected 0, got -1728433298
MMAP2 with unexpected pid, expected 1439, got 909192754
MMAP2 with unexpected tid, expected 1439, got 7303982
Unexpected perf_event->header.type 10!
57504589856948 0 PERF_RECORD_EXIT(1439:1439):(1439:1439)
PERF_RECORD_MMAP for sleep missing!
PERF_RECORD_MMAP for libc missing!
PERF_RECORD_MMAP for ld missing!
PERF_RECORD_MMAP for [vdso] missing!
---- end ----
Validate PERF_RECORD_* events & perf_sample fields: FAILED!
[root@sandy ~]#

2013-09-09 19:48:51

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Em Mon, Sep 09, 2013 at 04:47:45PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Wed, Aug 21, 2013 at 12:10:25PM +0200, Stephane Eranian escreveu:
> > 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.
>
> I noticed the kernel part is in, and I'm going to use MMAP2 on that new
> tool, so tried merging it, but:
>
> I fixed it up wrt another patch that makes machine__find_thread receive pid/tid
> but then 'perf test' complains about it, see below, trying to fix...

Following patch makes it progress a bit, still checking why it is not
enough...

- Arnaldo

diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 72d8881..b8a7056 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -50,7 +50,7 @@ int test__PERF_RECORD(void)
struct perf_sample sample;
const char *cmd = "sleep";
const char *argv[] = { cmd, "1", NULL, };
- char *bname;
+ char *bname, *mmap_filename;
u64 prev_time = 0;
bool found_cmd_mmap = false,
found_libc_mmap = false,
@@ -212,6 +212,7 @@ int test__PERF_RECORD(void)

if ((type == PERF_RECORD_COMM ||
type == PERF_RECORD_MMAP ||
+ type == PERF_RECORD_MMAP2 ||
type == PERF_RECORD_FORK ||
type == PERF_RECORD_EXIT) &&
(pid_t)event->comm.pid != evlist->workload.pid) {
@@ -220,7 +221,8 @@ int test__PERF_RECORD(void)
}

if ((type == PERF_RECORD_COMM ||
- type == PERF_RECORD_MMAP) &&
+ type == PERF_RECORD_MMAP ||
+ type == PERF_RECORD_MMAP2) &&
event->comm.pid != event->comm.tid) {
pr_debug("%s with different pid/tid!\n", name);
++errs;
@@ -236,7 +238,12 @@ int test__PERF_RECORD(void)
case PERF_RECORD_EXIT:
goto found_exit;
case PERF_RECORD_MMAP:
- bname = strrchr(event->mmap.filename, '/');
+ mmap_filename = event->mmap.filename;
+ goto check_bname;
+ case PERF_RECORD_MMAP2:
+ mmap_filename = event->mmap2.filename;
+ check_bname:
+ bname = strrchr(mmap_filename, '/');
if (bname != NULL) {
if (!found_cmd_mmap)
found_cmd_mmap = !strcmp(bname + 1, cmd);
@@ -245,7 +252,7 @@ int test__PERF_RECORD(void)
if (!found_ld_mmap)
found_ld_mmap = !strncmp(bname + 1, "ld", 2);
} else if (!found_vdso_mmap)
- found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
+ found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
break;

case PERF_RECORD_SAMPLE:

2013-09-10 09:17:20

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

On Mon, Sep 09, 2013 at 04:47:45PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Wed, Aug 21, 2013 at 12:10:25PM +0200, Stephane Eranian escreveu:
> > 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.
>
> I noticed the kernel part is in, and I'm going to use MMAP2 on that new
> tool, so tried merging it, but:
>
> I fixed it up wrt another patch that makes machine__find_thread receive pid/tid
> but then 'perf test' complains about it, see below, trying to fix...

Right, so I fed both patches to Ingo, but apparently (checked IRC
backlog) the tools patch didn't apply due to collisions with patches
from acme.

Apparently Ingo forgot to prod both of you to resolve (as I was out on
PTO).

2013-09-10 13:00:12

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support


Em Mon, Sep 09, 2013 at 04:48:44PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Mon, Sep 09, 2013 at 04:47:45PM -0300, Arnaldo Carvalho de Melo escreveu:
> > I noticed the kernel part is in, and I'm going to use MMAP2 on that new
> > tool, so tried merging it, but:
> >
> > I fixed it up wrt another patch that makes machine__find_thread receive pid/tid
> > but then 'perf test' complains about it, see below, trying to fix...
>
> Following patch makes it progress a bit, still checking why it is not
> enough...

Without your patch:

[root@sandy ~]# perf test -v 7
7: Validate PERF_RECORD_* events & perf_sample fields :
--- start ---
61118374953766 0 PERF_RECORD_SAMPLE
61118374958840 0 PERF_RECORD_SAMPLE
61118374961420 0 PERF_RECORD_SAMPLE
61118374964293 0 PERF_RECORD_SAMPLE
61118376117716 0 PERF_RECORD_COMM: sleep:5096
61118376153724 0 PERF_RECORD_MMAP 5096/5096: [0x400000(0x7000) @ 0]: /usr/bin/sleep
61118376190304 0 PERF_RECORD_MMAP 5096/5096: [0x3b7e000000(0x223000) @ 0]: /usr/lib64/ld-2.16.so
61118376229562 0 PERF_RECORD_MMAP 5096/5096: [0x7fff2f9ff000(0x1000) @ 0x7fff2f9ff000]: [vdso]
61118376526654 0 PERF_RECORD_MMAP 5096/5096: [0x3b7e400000(0x3b8000) @ 0]: /usr/lib64/libc-2.16.so
61119377689687 0 PERF_RECORD_EXIT(5096:5096):(5096:5096)
---- end ----
Validate PERF_RECORD_* events & perf_sample fields: Ok
[root@sandy ~]#

So the tstamp grows monotonically, then, after your patch + the patch at the
end of this message:

[root@sandy ~]# perf test -v 7
7: Validate PERF_RECORD_* events & perf_sample fields :
--- start ---
61315294449606 0 PERF_RECORD_SAMPLE
61315294453161 0 PERF_RECORD_SAMPLE
61315294454441 0 PERF_RECORD_SAMPLE
61315294455709 0 PERF_RECORD_SAMPLE
61315295600899 0 PERF_RECORD_COMM: sleep:6500
27917287430500 342521613 PERF_RECORD_MMAP2 6500/6500: [0x400000(0x7000) @ 0 00:1d 311442 9016]: /usr/bin/sleep
MMAP2 going backwards in time, prev=61315295600899, curr=27917287430500
MMAP2 with unexpected cpu, expected 0, got 342521613
MMAP2 with unexpected pid, expected 6500, got 1701606191
MMAP2 with unexpected tid, expected 6500, got 28773
27917287430500 342561333 PERF_RECORD_MMAP2 6500/6500: [0x3b7e000000(0x223000) @ 0 00:1d 309186 9016]: /usr/lib64/ld-2.16.so
MMAP2 with unexpected cpu, expected 0, got 342561333
MMAP2 with unexpected pid, expected 6500, got 1932408369
MMAP2 with unexpected tid, expected 6500, got 111
27917287430500 342600095 PERF_RECORD_MMAP2 6500/6500: [0x7fffbd7dc000(0x1000) @ 0x7fffbd7dc000 00:00 0 0]: [vdso]
MMAP2 with unexpected cpu, expected 0, got 342600095
MMAP2 with unexpected pid, expected 6500, got 1935963739
MMAP2 with unexpected tid, expected 6500, got 23919
27917287430500 342882834 PERF_RECORD_MMAP2 6500/6500: [0x3b7e400000(0x3b8000) @ 0 00:1d 309187 9016]: /usr/lib64/libc-2.16.so
MMAP2 with unexpected cpu, expected 0, got 342882834
MMAP2 with unexpected pid, expected 6500, got 909192754
MMAP2 with unexpected tid, expected 6500, got 7303982
61316297195411 0 PERF_RECORD_EXIT(6500:6500):(6500:6500)
---- end ----
Validate PERF_RECORD_* events & perf_sample fields: FAILED!
[root@sandy ~]#

So everything that is in perf_sample, i.e. in the variable area, selected via
sample_type, is invalid for PERF_RECORD_MMAP2.

This is on:

[root@sandy ~]# uname -a
Linux sandy.ghostprotocols.net.home 3.11.0+ #1 SMP Wed Sep 4 16:47:14 BRT 2013 x86_64 x86_64 x86_64 GNU/Linux
[root@sandy ~]#

Humm, looking at perf_event_mmap_output it seems this was missed, will rebuild
a kernel and retest...

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 2207efc..dd236b6 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5039,6 +5039,7 @@ static void perf_event_mmap_output(struct perf_event *event,
mmap_event->event_id.header.size += sizeof(mmap_event->maj);
mmap_event->event_id.header.size += sizeof(mmap_event->min);
mmap_event->event_id.header.size += sizeof(mmap_event->ino);
+ mmap_event->event_id.header.size += sizeof(mmap_event->ino_generation);
}

perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);

> - Arnaldo
>
> diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
> index 72d8881..b8a7056 100644
> --- a/tools/perf/tests/perf-record.c
> +++ b/tools/perf/tests/perf-record.c
> @@ -50,7 +50,7 @@ int test__PERF_RECORD(void)
> struct perf_sample sample;
> const char *cmd = "sleep";
> const char *argv[] = { cmd, "1", NULL, };
> - char *bname;
> + char *bname, *mmap_filename;
> u64 prev_time = 0;
> bool found_cmd_mmap = false,
> found_libc_mmap = false,
> @@ -212,6 +212,7 @@ int test__PERF_RECORD(void)
>
> if ((type == PERF_RECORD_COMM ||
> type == PERF_RECORD_MMAP ||
> + type == PERF_RECORD_MMAP2 ||
> type == PERF_RECORD_FORK ||
> type == PERF_RECORD_EXIT) &&
> (pid_t)event->comm.pid != evlist->workload.pid) {
> @@ -220,7 +221,8 @@ int test__PERF_RECORD(void)
> }
>
> if ((type == PERF_RECORD_COMM ||
> - type == PERF_RECORD_MMAP) &&
> + type == PERF_RECORD_MMAP ||
> + type == PERF_RECORD_MMAP2) &&
> event->comm.pid != event->comm.tid) {
> pr_debug("%s with different pid/tid!\n", name);
> ++errs;
> @@ -236,7 +238,12 @@ int test__PERF_RECORD(void)
> case PERF_RECORD_EXIT:
> goto found_exit;
> case PERF_RECORD_MMAP:
> - bname = strrchr(event->mmap.filename, '/');
> + mmap_filename = event->mmap.filename;
> + goto check_bname;
> + case PERF_RECORD_MMAP2:
> + mmap_filename = event->mmap2.filename;
> + check_bname:
> + bname = strrchr(mmap_filename, '/');
> if (bname != NULL) {
> if (!found_cmd_mmap)
> found_cmd_mmap = !strcmp(bname + 1, cmd);
> @@ -245,7 +252,7 @@ int test__PERF_RECORD(void)
> if (!found_ld_mmap)
> found_ld_mmap = !strncmp(bname + 1, "ld", 2);
> } else if (!found_vdso_mmap)
> - found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
> + found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
> break;
>
> case PERF_RECORD_SAMPLE:

2013-09-10 13:05:06

by Stephane Eranian

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

On Tue, Sep 10, 2013 at 3:00 PM, Arnaldo Carvalho de Melo
<[email protected]> wrote:
>
>
> Em Mon, Sep 09, 2013 at 04:48:44PM -0300, Arnaldo Carvalho de Melo escreveu:
> > Em Mon, Sep 09, 2013 at 04:47:45PM -0300, Arnaldo Carvalho de Melo escreveu:
> > > I noticed the kernel part is in, and I'm going to use MMAP2 on that new
> > > tool, so tried merging it, but:
> > >
> > > I fixed it up wrt another patch that makes machine__find_thread receive pid/tid
> > > but then 'perf test' complains about it, see below, trying to fix...
> >
> > Following patch makes it progress a bit, still checking why it is not
> > enough...
>
> Without your patch:
>
> [root@sandy ~]# perf test -v 7
> 7: Validate PERF_RECORD_* events & perf_sample fields :
> --- start ---
> 61118374953766 0 PERF_RECORD_SAMPLE
> 61118374958840 0 PERF_RECORD_SAMPLE
> 61118374961420 0 PERF_RECORD_SAMPLE
> 61118374964293 0 PERF_RECORD_SAMPLE
> 61118376117716 0 PERF_RECORD_COMM: sleep:5096
> 61118376153724 0 PERF_RECORD_MMAP 5096/5096: [0x400000(0x7000) @ 0]: /usr/bin/sleep
> 61118376190304 0 PERF_RECORD_MMAP 5096/5096: [0x3b7e000000(0x223000) @ 0]: /usr/lib64/ld-2.16.so
> 61118376229562 0 PERF_RECORD_MMAP 5096/5096: [0x7fff2f9ff000(0x1000) @ 0x7fff2f9ff000]: [vdso]
> 61118376526654 0 PERF_RECORD_MMAP 5096/5096: [0x3b7e400000(0x3b8000) @ 0]: /usr/lib64/libc-2.16.so
> 61119377689687 0 PERF_RECORD_EXIT(5096:5096):(5096:5096)
> ---- end ----
> Validate PERF_RECORD_* events & perf_sample fields: Ok
> [root@sandy ~]#
>
> So the tstamp grows monotonically, then, after your patch + the patch at the
> end of this message:
>
> [root@sandy ~]# perf test -v 7
> 7: Validate PERF_RECORD_* events & perf_sample fields :
> --- start ---
> 61315294449606 0 PERF_RECORD_SAMPLE
> 61315294453161 0 PERF_RECORD_SAMPLE
> 61315294454441 0 PERF_RECORD_SAMPLE
> 61315294455709 0 PERF_RECORD_SAMPLE
> 61315295600899 0 PERF_RECORD_COMM: sleep:6500
> 27917287430500 342521613 PERF_RECORD_MMAP2 6500/6500: [0x400000(0x7000) @ 0 00:1d 311442 9016]: /usr/bin/sleep
> MMAP2 going backwards in time, prev=61315295600899, curr=27917287430500
> MMAP2 with unexpected cpu, expected 0, got 342521613
> MMAP2 with unexpected pid, expected 6500, got 1701606191
> MMAP2 with unexpected tid, expected 6500, got 28773
> 27917287430500 342561333 PERF_RECORD_MMAP2 6500/6500: [0x3b7e000000(0x223000) @ 0 00:1d 309186 9016]: /usr/lib64/ld-2.16.so
> MMAP2 with unexpected cpu, expected 0, got 342561333
> MMAP2 with unexpected pid, expected 6500, got 1932408369
> MMAP2 with unexpected tid, expected 6500, got 111
> 27917287430500 342600095 PERF_RECORD_MMAP2 6500/6500: [0x7fffbd7dc000(0x1000) @ 0x7fffbd7dc000 00:00 0 0]: [vdso]
> MMAP2 with unexpected cpu, expected 0, got 342600095
> MMAP2 with unexpected pid, expected 6500, got 1935963739
> MMAP2 with unexpected tid, expected 6500, got 23919
> 27917287430500 342882834 PERF_RECORD_MMAP2 6500/6500: [0x3b7e400000(0x3b8000) @ 0 00:1d 309187 9016]: /usr/lib64/libc-2.16.so
> MMAP2 with unexpected cpu, expected 0, got 342882834
> MMAP2 with unexpected pid, expected 6500, got 909192754
> MMAP2 with unexpected tid, expected 6500, got 7303982
> 61316297195411 0 PERF_RECORD_EXIT(6500:6500):(6500:6500)
> ---- end ----
> Validate PERF_RECORD_* events & perf_sample fields: FAILED!
> [root@sandy ~]#
>
> So everything that is in perf_sample, i.e. in the variable area, selected via
> sample_type, is invalid for PERF_RECORD_MMAP2.
>
> This is on:
>
> [root@sandy ~]# uname -a
> Linux sandy.ghostprotocols.net.home 3.11.0+ #1 SMP Wed Sep 4 16:47:14 BRT 2013 x86_64 x86_64 x86_64 GNU/Linux
> [root@sandy ~]#
>
> Humm, looking at perf_event_mmap_output it seems this was missed, will rebuild
> a kernel and retest...
>
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 2207efc..dd236b6 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -5039,6 +5039,7 @@ static void perf_event_mmap_output(struct perf_event *event,
> mmap_event->event_id.header.size += sizeof(mmap_event->maj);
> mmap_event->event_id.header.size += sizeof(mmap_event->min);
> mmap_event->event_id.header.size += sizeof(mmap_event->ino);
> + mmap_event->event_id.header.size += sizeof(mmap_event->ino_generation);
> }
>
> perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
>
Arg, yes, this is missing.
Do you want to submit the patch?
Thanks for tracking it down.

>
> > - Arnaldo
> >
> > diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
> > index 72d8881..b8a7056 100644
> > --- a/tools/perf/tests/perf-record.c
> > +++ b/tools/perf/tests/perf-record.c
> > @@ -50,7 +50,7 @@ int test__PERF_RECORD(void)
> > struct perf_sample sample;
> > const char *cmd = "sleep";
> > const char *argv[] = { cmd, "1", NULL, };
> > - char *bname;
> > + char *bname, *mmap_filename;
> > u64 prev_time = 0;
> > bool found_cmd_mmap = false,
> > found_libc_mmap = false,
> > @@ -212,6 +212,7 @@ int test__PERF_RECORD(void)
> >
> > if ((type == PERF_RECORD_COMM ||
> > type == PERF_RECORD_MMAP ||
> > + type == PERF_RECORD_MMAP2 ||
> > type == PERF_RECORD_FORK ||
> > type == PERF_RECORD_EXIT) &&
> > (pid_t)event->comm.pid != evlist->workload.pid) {
> > @@ -220,7 +221,8 @@ int test__PERF_RECORD(void)
> > }
> >
> > if ((type == PERF_RECORD_COMM ||
> > - type == PERF_RECORD_MMAP) &&
> > + type == PERF_RECORD_MMAP ||
> > + type == PERF_RECORD_MMAP2) &&
> > event->comm.pid != event->comm.tid) {
> > pr_debug("%s with different pid/tid!\n", name);
> > ++errs;
> > @@ -236,7 +238,12 @@ int test__PERF_RECORD(void)
> > case PERF_RECORD_EXIT:
> > goto found_exit;
> > case PERF_RECORD_MMAP:
> > - bname = strrchr(event->mmap.filename, '/');
> > + mmap_filename = event->mmap.filename;
> > + goto check_bname;
> > + case PERF_RECORD_MMAP2:
> > + mmap_filename = event->mmap2.filename;
> > + check_bname:
> > + bname = strrchr(mmap_filename, '/');
> > if (bname != NULL) {
> > if (!found_cmd_mmap)
> > found_cmd_mmap = !strcmp(bname + 1, cmd);
> > @@ -245,7 +252,7 @@ int test__PERF_RECORD(void)
> > if (!found_ld_mmap)
> > found_ld_mmap = !strncmp(bname + 1, "ld", 2);
> > } else if (!found_vdso_mmap)
> > - found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
> > + found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
> > break;
> >
> > case PERF_RECORD_SAMPLE:

2013-09-10 13:17:35

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Em Tue, Sep 10, 2013 at 03:05:03PM +0200, Stephane Eranian escreveu:
> On Tue, Sep 10, 2013 at 3:00 PM, Arnaldo Carvalho de Melo <[email protected]> wrote:
> > Em Mon, Sep 09, 2013 at 04:48:44PM -0300, Arnaldo Carvalho de Melo escreveu:
> > > Em Mon, Sep 09, 2013 at 04:47:45PM -0300, Arnaldo Carvalho de Melo escreveu:
> > > > I noticed the kernel part is in, and I'm going to use MMAP2 on that new
> > > > tool, so tried merging it, but:
> > > >
> > > > I fixed it up wrt another patch that makes machine__find_thread receive pid/tid
> > > > but then 'perf test' complains about it, see below, trying to fix...
> > >
> > > Following patch makes it progress a bit, still checking why it is not
> > > enough...
> >
> > Without your patch:
> >
> > [root@sandy ~]# perf test -v 7
> > 7: Validate PERF_RECORD_* events & perf_sample fields :
> > --- start ---
> > 61118374953766 0 PERF_RECORD_SAMPLE
> > 61118374958840 0 PERF_RECORD_SAMPLE
> > 61118374961420 0 PERF_RECORD_SAMPLE
> > 61118374964293 0 PERF_RECORD_SAMPLE
> > 61118376117716 0 PERF_RECORD_COMM: sleep:5096
> > 61118376153724 0 PERF_RECORD_MMAP 5096/5096: [0x400000(0x7000) @ 0]: /usr/bin/sleep
> > 61118376190304 0 PERF_RECORD_MMAP 5096/5096: [0x3b7e000000(0x223000) @ 0]: /usr/lib64/ld-2.16.so
> > 61118376229562 0 PERF_RECORD_MMAP 5096/5096: [0x7fff2f9ff000(0x1000) @ 0x7fff2f9ff000]: [vdso]
> > 61118376526654 0 PERF_RECORD_MMAP 5096/5096: [0x3b7e400000(0x3b8000) @ 0]: /usr/lib64/libc-2.16.so
> > 61119377689687 0 PERF_RECORD_EXIT(5096:5096):(5096:5096)
> > ---- end ----
> > Validate PERF_RECORD_* events & perf_sample fields: Ok
> > [root@sandy ~]#
> >
> > So the tstamp grows monotonically, then, after your patch + the patch at the
> > end of this message:
> >
> > [root@sandy ~]# perf test -v 7
> > 7: Validate PERF_RECORD_* events & perf_sample fields :
> > --- start ---
> > 61315294449606 0 PERF_RECORD_SAMPLE
> > 61315294453161 0 PERF_RECORD_SAMPLE
> > 61315294454441 0 PERF_RECORD_SAMPLE
> > 61315294455709 0 PERF_RECORD_SAMPLE
> > 61315295600899 0 PERF_RECORD_COMM: sleep:6500
> > 27917287430500 342521613 PERF_RECORD_MMAP2 6500/6500: [0x400000(0x7000) @ 0 00:1d 311442 9016]: /usr/bin/sleep
> > MMAP2 going backwards in time, prev=61315295600899, curr=27917287430500
> > MMAP2 with unexpected cpu, expected 0, got 342521613
> > MMAP2 with unexpected pid, expected 6500, got 1701606191
> > MMAP2 with unexpected tid, expected 6500, got 28773
> > 27917287430500 342561333 PERF_RECORD_MMAP2 6500/6500: [0x3b7e000000(0x223000) @ 0 00:1d 309186 9016]: /usr/lib64/ld-2.16.so
> > MMAP2 with unexpected cpu, expected 0, got 342561333
> > MMAP2 with unexpected pid, expected 6500, got 1932408369
> > MMAP2 with unexpected tid, expected 6500, got 111
> > 27917287430500 342600095 PERF_RECORD_MMAP2 6500/6500: [0x7fffbd7dc000(0x1000) @ 0x7fffbd7dc000 00:00 0 0]: [vdso]
> > MMAP2 with unexpected cpu, expected 0, got 342600095
> > MMAP2 with unexpected pid, expected 6500, got 1935963739
> > MMAP2 with unexpected tid, expected 6500, got 23919
> > 27917287430500 342882834 PERF_RECORD_MMAP2 6500/6500: [0x3b7e400000(0x3b8000) @ 0 00:1d 309187 9016]: /usr/lib64/libc-2.16.so
> > MMAP2 with unexpected cpu, expected 0, got 342882834
> > MMAP2 with unexpected pid, expected 6500, got 909192754
> > MMAP2 with unexpected tid, expected 6500, got 7303982
> > 61316297195411 0 PERF_RECORD_EXIT(6500:6500):(6500:6500)
> > ---- end ----
> > Validate PERF_RECORD_* events & perf_sample fields: FAILED!
> > [root@sandy ~]#
> >
> > So everything that is in perf_sample, i.e. in the variable area, selected via
> > sample_type, is invalid for PERF_RECORD_MMAP2.
> >
> > This is on:
> >
> > [root@sandy ~]# uname -a
> > Linux sandy.ghostprotocols.net.home 3.11.0+ #1 SMP Wed Sep 4 16:47:14 BRT 2013 x86_64 x86_64 x86_64 GNU/Linux
> > [root@sandy ~]#
> >
> > Humm, looking at perf_event_mmap_output it seems this was missed, will rebuild
> > a kernel and retest...
> >
> > diff --git a/kernel/events/core.c b/kernel/events/core.c
> > index 2207efc..dd236b6 100644
> > --- a/kernel/events/core.c
> > +++ b/kernel/events/core.c
> > @@ -5039,6 +5039,7 @@ static void perf_event_mmap_output(struct perf_event *event,
> > mmap_event->event_id.header.size += sizeof(mmap_event->maj);
> > mmap_event->event_id.header.size += sizeof(mmap_event->min);
> > mmap_event->event_id.header.size += sizeof(mmap_event->ino);
> > + mmap_event->event_id.header.size += sizeof(mmap_event->ino_generation);
> > }
> >
> > perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
> >
> Arg, yes, this is missing.
> Do you want to submit the patch?

I will, in some jiffies, just rebooting with the patched kernel to
re-run tperf test.

> Thanks for tracking it down.

np :-)

- Arnaldo

2013-09-10 19:59:05

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Em Tue, Sep 10, 2013 at 10:17:28AM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Tue, Sep 10, 2013 at 03:05:03PM +0200, Stephane Eranian escreveu:
> > On Tue, Sep 10, 2013 at 3:00 PM, Arnaldo Carvalho de Melo <[email protected]> wrote:
> > > Em Mon, Sep 09, 2013 at 04:48:44PM -0300, Arnaldo Carvalho de Melo escreveu:
> > > +++ b/kernel/events/core.c
> > > @@ -5039,6 +5039,7 @@ static void perf_event_mmap_output(struct perf_event *event,
> > > mmap_event->event_id.header.size += sizeof(mmap_event->maj);
> > > mmap_event->event_id.header.size += sizeof(mmap_event->min);
> > > mmap_event->event_id.header.size += sizeof(mmap_event->ino);
> > > + mmap_event->event_id.header.size += sizeof(mmap_event->ino_generation);
> > > }
> > > perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);

> > Arg, yes, this is missing.
> > Do you want to submit the patch?

> I will, in some jiffies, just rebooting with the patched kernel to
> re-run tperf test.

> > Thanks for tracking it down.

> np :-)

More fallout, this time the resulting tools fail to run on older
kernels, i.e. any kernel that doesn't have perf_event_attr.mmap2,
doesn't matter the event type:

[acme@zoo linux]$ perf record usleep 1
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (cycles).
/bin/dmesg may provide additional information.
No CONFIG_PERF_EVENTS=y kernel support configured?

usleep: Terminated
[acme@zoo linux]$ perf record -e cpu-clock usleep 1
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (cpu-clock).
/bin/dmesg may provide additional information.
No CONFIG_PERF_EVENTS=y kernel support configured?

usleep: Terminated
[acme@zoo linux]$

That is because kernel/events/core.c perf_copy_attr() has this test:

if (attr->__reserved_1)
return -EINVAL;

So we must have the handling we have for other things that were added
in the past, like .sample_id_all, .exclude_guest, etc, like is done in
the attached patch, please ack.

Ingo, since you haven't merged my latest perf/urgent pull req, do you
want me to fold this into the patch that makes the tooling side use
PERF_RECORD_MMAP2?

- Arnaldo


Attachments:
(No filename) (2.24 kB)
perf_mmap2_fallback.patch (1.46 kB)
Download all attachments

2013-09-10 20:16:45

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Em Tue, Sep 10, 2013 at 04:58:47PM -0300, Arnaldo Carvalho de Melo escreveu:
> So we must have the handling we have for other things that were added
> in the past, like .sample_id_all, .exclude_guest, etc, like is done in
> the attached patch, please ack.
>
> Ingo, since you haven't merged my latest perf/urgent pull req, do you
> want me to fold this into the patch that makes the tooling side use
> PERF_RECORD_MMAP2?
>
> - Arnaldo


Also there was this minor thing I'll have in this patch too:

@@ -1926,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
if_print(exclude_hv);
if_print(exclude_idle);
if_print(mmap);
+ if_print(mmap2);
if_print(comm);
if_print(freq);
if_print(inherit_stat);

2013-09-11 14:42:59

by Stephane Eranian

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Arnaldo,

Do you have all those changes in a git tree somewhere.
I want to help test and debug this part too.
Thanks.


On Tue, Sep 10, 2013 at 10:16 PM, Arnaldo Carvalho de Melo
<[email protected]> wrote:
> Em Tue, Sep 10, 2013 at 04:58:47PM -0300, Arnaldo Carvalho de Melo escreveu:
>> So we must have the handling we have for other things that were added
>> in the past, like .sample_id_all, .exclude_guest, etc, like is done in
>> the attached patch, please ack.
>>
>> Ingo, since you haven't merged my latest perf/urgent pull req, do you
>> want me to fold this into the patch that makes the tooling side use
>> PERF_RECORD_MMAP2?
>>
>> - Arnaldo
>
>
> Also there was this minor thing I'll have in this patch too:
>
> @@ -1926,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
> if_print(exclude_hv);
> if_print(exclude_idle);
> if_print(mmap);
> + if_print(mmap2);
> if_print(comm);
> if_print(freq);
> if_print(inherit_stat);

2013-09-11 14:53:50

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Em Wed, Sep 11, 2013 at 04:42:57PM +0200, Stephane Eranian escreveu:
> Arnaldo,
>
> Do you have all those changes in a git tree somewhere.
> I want to help test and debug this part too.
> Thanks.

Right now its all in my perf/urgent branch at:

git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git

For reference, the affected patch, with my updates, is here:

commit 5c5e854bc760a2e2c878df3cfcf2afa4febcd511
Author: Stephane Eranian <[email protected]>
Date: Wed Aug 21 12:10:25 2013 +0200

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 <[email protected]>
Cc: Andi Kleen <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ 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 <[email protected]>

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index f988d38..5ebd0c3 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 9b336fd..423875c 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,
return err;
}

+static int perf_event__repipe_mmap2(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct machine *machine)
+{
+ int err;
+
+ err = perf_event__process_mmap2(tool, event, sample, machine);
+ perf_event__repipe(tool, event, sample, machine);
+
+ return err;
+}
+
static int perf_event__repipe_fork(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
@@ -339,6 +352,7 @@ static int __cmd_inject(struct perf_inject *inject)

if (inject->build_ids || inject->sched_stat) {
inject->tool.mmap = perf_event__repipe_mmap;
+ inject->tool.mmap2 = perf_event__repipe_mmap2;
inject->tool.fork = perf_event__repipe_fork;
inject->tool.tracing_data = perf_event__repipe_tracing_data;
}
@@ -390,6 +404,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.tool = {
.sample = perf_event__repipe_sample,
.mmap = perf_event__repipe,
+ .mmap2 = perf_event__repipe,
.comm = perf_event__repipe,
.fork = perf_event__repipe,
.exit = perf_event__repipe,
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 791b432..253133a 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 9725aa3..8e50d8d 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 93a34ce..7f31a3d 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,
static struct perf_tool perf_script = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 72d8881..b8a7056 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -50,7 +50,7 @@ int test__PERF_RECORD(void)
struct perf_sample sample;
const char *cmd = "sleep";
const char *argv[] = { cmd, "1", NULL, };
- char *bname;
+ char *bname, *mmap_filename;
u64 prev_time = 0;
bool found_cmd_mmap = false,
found_libc_mmap = false,
@@ -212,6 +212,7 @@ int test__PERF_RECORD(void)

if ((type == PERF_RECORD_COMM ||
type == PERF_RECORD_MMAP ||
+ type == PERF_RECORD_MMAP2 ||
type == PERF_RECORD_FORK ||
type == PERF_RECORD_EXIT) &&
(pid_t)event->comm.pid != evlist->workload.pid) {
@@ -220,7 +221,8 @@ int test__PERF_RECORD(void)
}

if ((type == PERF_RECORD_COMM ||
- type == PERF_RECORD_MMAP) &&
+ type == PERF_RECORD_MMAP ||
+ type == PERF_RECORD_MMAP2) &&
event->comm.pid != event->comm.tid) {
pr_debug("%s with different pid/tid!\n", name);
++errs;
@@ -236,7 +238,12 @@ int test__PERF_RECORD(void)
case PERF_RECORD_EXIT:
goto found_exit;
case PERF_RECORD_MMAP:
- bname = strrchr(event->mmap.filename, '/');
+ mmap_filename = event->mmap.filename;
+ goto check_bname;
+ case PERF_RECORD_MMAP2:
+ mmap_filename = event->mmap2.filename;
+ check_bname:
+ bname = strrchr(mmap_filename, '/');
if (bname != NULL) {
if (!found_cmd_mmap)
found_cmd_mmap = !strcmp(bname + 1, cmd);
@@ -245,7 +252,7 @@ int test__PERF_RECORD(void)
if (!found_ld_mmap)
found_ld_mmap = !strncmp(bname + 1, "ld", 2);
} else if (!found_vdso_mmap)
- found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
+ found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
break;

case PERF_RECORD_SAMPLE:
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index fb58409..7ded71d 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,
struct perf_tool build_id__mark_dso_hit_ops = {
.sample = build_id__mark_dso_hit,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.fork = perf_event__process_fork,
.exit = perf_event__exit_del_thread,
.attr = perf_event__process_attr,
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 8d51f21..9b393e7 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -11,6 +11,7 @@
static const char *perf_event__names[] = {
[0] = "TOTAL",
[PERF_RECORD_MMAP] = "MMAP",
+ [PERF_RECORD_MMAP2] = "MMAP2",
[PERF_RECORD_LOST] = "LOST",
[PERF_RECORD_COMM] = "COMM",
[PERF_RECORD_EXIT] = "EXIT",
@@ -186,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
return -1;
}

- event->header.type = PERF_RECORD_MMAP;
+ event->header.type = PERF_RECORD_MMAP2;
/*
* Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
*/
@@ -197,7 +198,9 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
char prot[5];
char execname[PATH_MAX];
char anonstr[] = "//anon";
+ unsigned int ino;
size_t size;
+ ssize_t n;

if (fgets(bf, sizeof(bf), fp) == NULL)
break;
@@ -206,9 +209,16 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
strcpy(execname, "");

/* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
- sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
- &event->mmap.start, &event->mmap.len, prot,
- &event->mmap.pgoff, execname);
+ n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
+ &event->mmap2.start, &event->mmap2.len, prot,
+ &event->mmap2.pgoff, &event->mmap2.maj,
+ &event->mmap2.min,
+ &ino, execname);
+
+ event->mmap2.ino = (u64)ino;
+
+ if (n != 8)
+ continue;

if (prot[2] != 'x')
continue;
@@ -217,15 +227,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
strcpy(execname, anonstr);

size = strlen(execname) + 1;
- memcpy(event->mmap.filename, execname, size);
+ memcpy(event->mmap2.filename, execname, size);
size = PERF_ALIGN(size, sizeof(u64));
- event->mmap.len -= event->mmap.start;
- event->mmap.header.size = (sizeof(event->mmap) -
- (sizeof(event->mmap.filename) - size));
- memset(event->mmap.filename + size, 0, machine->id_hdr_size);
- event->mmap.header.size += machine->id_hdr_size;
- event->mmap.pid = tgid;
- event->mmap.tid = pid;
+ event->mmap2.len -= event->mmap.start;
+ event->mmap2.header.size = (sizeof(event->mmap2) -
+ (sizeof(event->mmap2.filename) - size));
+ memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
+ event->mmap2.header.size += machine->id_hdr_size;
+ event->mmap2.pid = tgid;
+ event->mmap2.tid = pid;

if (process(tool, event, &synth_sample, machine) != 0) {
rc = -1;
@@ -527,6 +537,17 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
event->mmap.len, event->mmap.pgoff, event->mmap.filename);
}

+size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
+{
+ return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
+ " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n",
+ event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
+ event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
+ event->mmap2.min, event->mmap2.ino,
+ event->mmap2.ino_generation,
+ event->mmap2.filename);
+}
+
int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
@@ -535,6 +556,14 @@ int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
return machine__process_mmap_event(machine, event);
}

+int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine)
+{
+ return machine__process_mmap2_event(machine, event);
+}
+
size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
{
return fprintf(fp, "(%d:%d):(%d:%d)\n",
@@ -574,6 +603,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
case PERF_RECORD_MMAP:
ret += perf_event__fprintf_mmap(event, fp);
break;
+ case PERF_RECORD_MMAP2:
+ ret += perf_event__fprintf_mmap2(event, fp);
+ break;
default:
ret += fprintf(fp, "\n");
}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 93130d8..c67ecc4 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -17,6 +17,19 @@ struct mmap_event {
char filename[PATH_MAX];
};

+struct mmap2_event {
+ struct perf_event_header header;
+ u32 pid, tid;
+ u64 start;
+ u64 len;
+ u64 pgoff;
+ u32 maj;
+ u32 min;
+ u64 ino;
+ u64 ino_generation;
+ char filename[PATH_MAX];
+};
+
struct comm_event {
struct perf_event_header header;
u32 pid, tid;
@@ -159,6 +172,7 @@ struct tracing_data_event {
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
+ struct mmap2_event mmap2;
struct comm_event comm;
struct fork_event fork;
struct lost_event lost;
@@ -208,6 +222,10 @@ int perf_event__process_mmap(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine);
+int perf_event__process_mmap2(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct machine *machine);
int perf_event__process_fork(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
@@ -238,6 +256,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,

size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
size_t perf_event__fprintf(union perf_event *event, FILE *fp);

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3612183..0ce9feb 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -27,6 +27,7 @@
static struct {
bool sample_id_all;
bool exclude_guest;
+ bool mmap2;
} perf_missing_features;

#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
@@ -676,8 +677,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
if (opts->sample_weight)
attr->sample_type |= PERF_SAMPLE_WEIGHT;

- attr->mmap = track;
- attr->comm = track;
+ attr->mmap = track;
+ attr->mmap2 = track && !perf_missing_features.mmap2;
+ attr->comm = track;

/*
* XXX see the function comment above
@@ -1016,6 +1018,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
}

fallback_missing_features:
+ if (perf_missing_features.mmap2)
+ evsel->attr.mmap2 = 0;
if (perf_missing_features.exclude_guest)
evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
retry_sample_id:
@@ -1080,8 +1084,11 @@ try_fallback:
if (err != -EINVAL || cpu > 0 || thread > 0)
goto out_close;

- if (!perf_missing_features.exclude_guest &&
- (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
+ if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
+ perf_missing_features.mmap2 = true;
+ goto fallback_missing_features;
+ } else if (!perf_missing_features.exclude_guest &&
+ (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
perf_missing_features.exclude_guest = true;
goto fallback_missing_features;
} else if (!perf_missing_features.sample_id_all) {
@@ -1925,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
if_print(exclude_hv);
if_print(exclude_idle);
if_print(mmap);
+ if_print(mmap2);
if_print(comm);
if_print(freq);
if_print(inherit_stat);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a33197a..26441d0 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)

fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);

+ fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2);
+ fprintf(fp, ", attr_mmap = %d", evsel->attr.mmap);
+ fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data);
if (evsel->ids) {
fprintf(fp, ", id = {");
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 1dca61f..933d14f 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -997,6 +997,54 @@ out_problem:
return -1;
}

+int machine__process_mmap2_event(struct machine *machine,
+ union perf_event *event)
+{
+ u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+ struct thread *thread;
+ struct map *map;
+ enum map_type type;
+ int ret = 0;
+
+ if (dump_trace)
+ perf_event__fprintf_mmap2(event, stdout);
+
+ if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
+ cpumode == PERF_RECORD_MISC_KERNEL) {
+ ret = machine__process_kernel_mmap_event(machine, event);
+ if (ret < 0)
+ goto out_problem;
+ return 0;
+ }
+
+ thread = machine__findnew_thread(machine, event->mmap2.pid,
+ event->mmap2.pid);
+ if (thread == NULL)
+ goto out_problem;
+
+ if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
+ type = MAP__VARIABLE;
+ else
+ type = MAP__FUNCTION;
+
+ map = map__new(&machine->user_dsos, event->mmap2.start,
+ event->mmap2.len, event->mmap2.pgoff,
+ event->mmap2.pid, event->mmap2.maj,
+ event->mmap2.min, event->mmap2.ino,
+ event->mmap2.ino_generation,
+ event->mmap2.filename, type);
+
+ if (map == NULL)
+ goto out_problem;
+
+ thread__insert_map(thread, map);
+ return 0;
+
+out_problem:
+ dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
+ return 0;
+}
+
int machine__process_mmap_event(struct machine *machine, union perf_event *event)
{
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

map = map__new(&machine->user_dsos, event->mmap.start,
event->mmap.len, event->mmap.pgoff,
- event->mmap.pid, event->mmap.filename,
+ event->mmap.pid, 0, 0, 0, 0,
+ event->mmap.filename,
type);

if (map == NULL)
@@ -1101,6 +1150,8 @@ int machine__process_event(struct machine *machine, union perf_event *event)
ret = machine__process_comm_event(machine, event); break;
case PERF_RECORD_MMAP:
ret = machine__process_mmap_event(machine, event); break;
+ case PERF_RECORD_MMAP2:
+ ret = machine__process_mmap2_event(machine, event); break;
case PERF_RECORD_FORK:
ret = machine__process_fork_event(machine, event); break;
case PERF_RECORD_EXIT:
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 0df925b..58a6be1 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
int machine__process_fork_event(struct machine *machine, union perf_event *event);
int machine__process_lost_event(struct machine *machine, union perf_event *event);
int machine__process_mmap_event(struct machine *machine, union perf_event *event);
+int machine__process_mmap2_event(struct machine *machine, union perf_event *event);
int machine__process_event(struct machine *machine, union perf_event *event);

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 9e8304c..4f6680d 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,
}

struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
- u64 pgoff, u32 pid, char *filename,
+ u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
+ u64 ino_gen, char *filename,
enum map_type type)
{
struct map *map = malloc(sizeof(*map));
@@ -62,6 +63,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
vdso = is_vdso_map(filename);
no_dso = is_no_dso_memory(filename);

+ map->maj = d_maj;
+ map->min = d_min;
+ map->ino = ino;
+ map->ino_generation = ino_gen;
+
if (anon) {
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
filename = newfilename;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 2cc93cb..4886ca2 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -36,6 +36,9 @@ struct map {
bool erange_warned;
u32 priv;
u64 pgoff;
+ u32 maj, min; /* only valid for MMAP2 record */
+ u64 ino; /* only valid for MMAP2 record */
+ u64 ino_generation;/* only valid for MMAP2 record */

/* ip -> dso rip */
u64 (*map_ip)(struct map *, u64);
@@ -88,8 +91,9 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
void map__init(struct map *map, enum map_type type,
u64 start, u64 end, u64 pgoff, struct dso *dso);
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
- u64 pgoff, u32 pid, char *filename,
- enum map_type type);
+ u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
+ u64 ino_gen,
+ char *filename, enum map_type type);
struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
void map__delete(struct map *map);
struct map *map__clone(struct map *map);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0308d9e..51f5edf 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,
}
}

+static void perf_event__mmap2_swap(union perf_event *event,
+ bool sample_id_all)
+{
+ event->mmap2.pid = bswap_32(event->mmap2.pid);
+ event->mmap2.tid = bswap_32(event->mmap2.tid);
+ event->mmap2.start = bswap_64(event->mmap2.start);
+ event->mmap2.len = bswap_64(event->mmap2.len);
+ event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);
+ event->mmap2.maj = bswap_32(event->mmap2.maj);
+ event->mmap2.min = bswap_32(event->mmap2.min);
+ event->mmap2.ino = bswap_64(event->mmap2.ino);
+
+ if (sample_id_all) {
+ void *data = &event->mmap2.filename;
+
+ data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
+ swap_sample_id_all(event, data);
+ }
+}
static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
{
event->fork.pid = bswap_32(event->fork.pid);
@@ -455,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event,

static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_MMAP] = perf_event__mmap_swap,
+ [PERF_RECORD_MMAP2] = perf_event__mmap2_swap,
[PERF_RECORD_COMM] = perf_event__comm_swap,
[PERF_RECORD_FORK] = perf_event__task_swap,
[PERF_RECORD_EXIT] = perf_event__task_swap,
@@ -851,7 +871,8 @@ static struct machine *
(cpumode == PERF_RECORD_MISC_GUEST_USER))) {
u32 pid;

- if (event->header.type == PERF_RECORD_MMAP)
+ if (event->header.type == PERF_RECORD_MMAP
+ || event->header.type == PERF_RECORD_MMAP2)
pid = event->mmap.pid;
else
pid = sample->pid;
@@ -978,6 +999,8 @@ static int perf_session_deliver_event(struct perf_session *session,
sample, evsel, machine);
case PERF_RECORD_MMAP:
return tool->mmap(tool, event, sample, machine);
+ case PERF_RECORD_MMAP2:
+ return tool->mmap2(tool, event, sample, machine);
case PERF_RECORD_COMM:
return tool->comm(tool, event, sample, machine);
case PERF_RECORD_FORK:
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 62b16b6..4385816 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -29,6 +29,7 @@ struct perf_tool {
event_sample sample,
read;
event_op mmap,
+ mmap2,
comm,
fork,
exit,

2013-09-11 15:28:49

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support

Em Wed, Sep 11, 2013 at 11:53:41AM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Wed, Sep 11, 2013 at 04:42:57PM +0200, Stephane Eranian escreveu:
> > Do you have all those changes in a git tree somewhere.
> > I want to help test and debug this part too.
> > Thanks.

> Right now its all in my perf/urgent branch at:

> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git

And these are the results on a kernel that has the PERF_RECORD_MMAP2
functionality, for a workload started from 'perf record' and for an
existing process, so that we can check the synthesizing code:

[root@zoo ~]# perf record usleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.014 MB perf.data (~615 samples) ]

Now lets check the events details, just cycles, in this case, use more
if you want to check that just the first one has mmap2 set:

[root@zoo ~]# perf evlist -v
cycles: sample_freq=4000, size: 96, sample_type: IP|TID|TIME|PERIOD,
disabled: 1, inherit: 1, mmap: 1, mmap2: 1, comm: 1, freq: 1,
enable_on_exec: 1, sample_id_all: 1, exclude_guest: 1
[root@zoo ~]#

Now lets see if MMAP2 records were produced:

[root@zoo ~]# perf report -D | grep PERF_RECORD_MMAP2
776650444880 0x3838 [0x60]: PERF_RECORD_MMAP2 2918/2918: [0x400000(0x2000) @ 0 08:07 655426 1850659034]: /usr/bin/usleep
776650454592 0x3898 [0x68]: PERF_RECORD_MMAP2 2918/2918: [0x33c1200000(0x223000) @ 0 08:07 656485 1850658205]: /usr/lib64/ld-2.16.so
776650465705 0x3900 [0x58]: PERF_RECORD_MMAP2 2918/2918: [0x7fffbc72d000(0x1000) @ 0x7fffbc72d000 00:00 0 0]: [vdso]
776650549828 0x3980 [0x70]: PERF_RECORD_MMAP2 2918/2918: [0x33d2a00000(0x20a000) @ 0 08:07 655569 1850658370]: /usr/lib64/libpopt.so.0.0.0
776650577550 0x39f0 [0x68]: PERF_RECORD_MMAP2 2918/2918: [0x33c1600000(0x3b8000) @ 0 08:07 661541 1850658206]: /usr/lib64/libc-2.16.so
[root@zoo ~]#

Yeah, for all the userspace DSOs, the kernel modules and vmlinux
remained as MMAP records:

[root@zoo ~]# perf report -D | grep -w PERF_RECORD_MMAP | head -4
0 0xd8 [0x50]: PERF_RECORD_MMAP -1/0: [0(0xffffffff9fffffff) @ 0xffffffff81000000]: [kernel.kallsyms]_text
0 0x128 [0x70]: PERF_RECORD_MMAP -1/0: [0xffffffffa0000000(0x5fff) @ 0]: /lib/modules/3.11.0+/kernel/drivers/acpi/video.ko
0 0x198 [0x70]: PERF_RECORD_MMAP -1/0: [0xffffffffa0006000(0x5fff) @ 0]: /lib/modules/3.11.0+/kernel/fs/efivarfs/efivarfs.ko
0 0x208 [0x70]: PERF_RECORD_MMAP -1/0: [0xffffffffa000c000(0xafff) @ 0]: /lib/modules/3.11.0+/kernel/drivers/i2c/i2c-core.ko
[root@zoo ~]#

[root@zoo ~]# perf report -D | grep PERF_RECORD_MMAP | cut -f 4 -d' ' | sort | uniq -c
119 PERF_RECORD_MMAP
5 PERF_RECORD_MMAP2
[root@zoo ~]

[root@zoo ~]# lsmod | grep -v '^Module.*Size.*Used by$' | wc -l
118
[root@zoo ~]#

I.e. 118 (yeah, distros load a lot of those these days!) plus vmlinux.

And if we observe an existing thread, say the current shell interpreter:

[acme@zoo linux]$ perf record -e instructions,cycles -p 1878 usleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.014 MB perf.data (~615 samples) ]
[acme@zoo linux]$ perf evlist -v
instructions: sample_freq=4000, config: 1, size: 96, sample_type: IP|TID|ID|PERIOD, read_format: ID, disabled: 1, mmap: 1, mmap2: 1, comm: 1, freq: 1, sample_id_all: 1, exclude_guest: 1
cycles: sample_freq=4000, size: 96, sample_type: IP|TID|ID|PERIOD, read_format: ID, disabled: 1, freq: 1, sample_id_all: 1, exclude_guest: 1
[acme@zoo linux]$

Used two to check that the second event has no mmap2 bit set, just like for
mmap, comm, etc.

[acme@zoo linux]$ perf report -D | grep PERF_RECORD_MMAP2
0x37c8 [0x60]: PERF_RECORD_MMAP2 1878/1878: [0x400000(0xda000) @ 0 08:07 662168 0]: /usr/bin/bash
0x3828 [0x68]: PERF_RECORD_MMAP2 1878/1878: [0x33c1200000(0x20000) @ 0 08:07 656485 0]: /usr/lib64/ld-2.16.so
0x3890 [0x68]: PERF_RECORD_MMAP2 1878/1878: [0x33c1600000(0x1ad000) @ 0 08:07 661541 0]: /usr/lib64/libc-2.16.so
0x38f8 [0x70]: PERF_RECORD_MMAP2 1878/1878: [0x33c1e00000(0x3000) @ 0 08:07 671656 0]: /usr/lib64/libdl-2.16.so
0x3968 [0x70]: PERF_RECORD_MMAP2 1878/1878: [0x33d9200000(0x25000) @ 0 08:07 675312 0]: /usr/lib64/libtinfo.so.5.9
0x39d8 [0x70]: PERF_RECORD_MMAP2 1878/1878: [0x7f2f70bb9000(0xc000) @ 0 08:07 662885 0]: /usr/lib64/libnss_files-2.16.so
0x3a48 [0x58]: PERF_RECORD_MMAP2 1878/1878: [0x7fffdb5ff000(0x1000) @ 0 00:00 0 0]: [vdso]
0x3aa0 [0x60]: PERF_RECORD_MMAP2 1878/1878: [0xffffffffff600000(0x1000) @ 0 00:00 0 0]: [vsyscall]
[acme@zoo linux]$

Now lets look at the exec maps for this existing thread, to check that
we rightly synthesized them:

[acme@zoo linux]$ grep xp /proc/1878/maps
00400000-004da000 r-xp 00000000 08:07 662168 /usr/bin/bash
33c1200000-33c1220000 r-xp 00000000 08:07 656485 /usr/lib64/ld-2.16.so
33c1600000-33c17ad000 r-xp 00000000 08:07 661541 /usr/lib64/libc-2.16.so
33c1e00000-33c1e03000 r-xp 00000000 08:07 671656 /usr/lib64/libdl-2.16.so
33d9200000-33d9225000 r-xp 00000000 08:07 675312 /usr/lib64/libtinfo.so.5.9
7f2f70bb9000-7f2f70bc5000 r-xp 00000000 08:07 662885 /usr/lib64/libnss_files-2.16.so
7fffdb5ff000-7fffdb600000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
[acme@zoo linux]$

Yeah, maj, min, inode seems all ok, i_generation is zero, as expected.

Now its just a matter of using this extra info in a tool! 8-)

I haven't performed all these tests when running on an older kernel, just checked that
PERF_RECORD_MMAP was present, PERF_RECORD_MMAP2, as expected, were not, probably they
will be present only for the synthesized events, right? The ones coming from the kernel
were all PERF_RECORD_MMAP, as expected.

- Arnaldo

2013-09-12 06:35:35

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] perf tools: add attr->mmap2 support


* Arnaldo Carvalho de Melo <[email protected]> wrote:

> I haven't performed all these tests when running on an older kernel,
> just checked that PERF_RECORD_MMAP was present, PERF_RECORD_MMAP2, as
> expected, were not, probably they will be present only for the
> synthesized events, right? The ones coming from the kernel were all
> PERF_RECORD_MMAP, as expected.

Older kernel functionality looked fine here.

Thanks,

Ingo

Subject: [tip:perf/urgent] perf tools: Add attr->mmap2 support

Commit-ID: 5c5e854bc760a2e2c878df3cfcf2afa4febcd511
Gitweb: http://git.kernel.org/tip/5c5e854bc760a2e2c878df3cfcf2afa4febcd511
Author: Stephane Eranian <[email protected]>
AuthorDate: Wed, 21 Aug 2013 12:10:25 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 11 Sep 2013 10:09:32 -0300

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 <[email protected]>
Cc: Andi Kleen <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ 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 <[email protected]>
---
tools/perf/builtin-annotate.c | 1 +
tools/perf/builtin-inject.c | 15 +++++++++++
tools/perf/builtin-mem.c | 1 +
tools/perf/builtin-report.c | 1 +
tools/perf/builtin-script.c | 1 +
tools/perf/tests/perf-record.c | 15 ++++++++---
tools/perf/util/build-id.c | 1 +
tools/perf/util/event.c | 56 +++++++++++++++++++++++++++++++++---------
tools/perf/util/event.h | 19 ++++++++++++++
tools/perf/util/evsel.c | 16 +++++++++---
tools/perf/util/header.c | 3 +++
tools/perf/util/machine.c | 53 ++++++++++++++++++++++++++++++++++++++-
tools/perf/util/machine.h | 1 +
tools/perf/util/map.c | 8 +++++-
tools/perf/util/map.h | 8 ++++--
tools/perf/util/session.c | 25 ++++++++++++++++++-
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 f988d38..5ebd0c3 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 9b336fd..423875c 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,
return err;
}

+static int perf_event__repipe_mmap2(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct machine *machine)
+{
+ int err;
+
+ err = perf_event__process_mmap2(tool, event, sample, machine);
+ perf_event__repipe(tool, event, sample, machine);
+
+ return err;
+}
+
static int perf_event__repipe_fork(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
@@ -339,6 +352,7 @@ static int __cmd_inject(struct perf_inject *inject)

if (inject->build_ids || inject->sched_stat) {
inject->tool.mmap = perf_event__repipe_mmap;
+ inject->tool.mmap2 = perf_event__repipe_mmap2;
inject->tool.fork = perf_event__repipe_fork;
inject->tool.tracing_data = perf_event__repipe_tracing_data;
}
@@ -390,6 +404,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.tool = {
.sample = perf_event__repipe_sample,
.mmap = perf_event__repipe,
+ .mmap2 = perf_event__repipe,
.comm = perf_event__repipe,
.fork = perf_event__repipe,
.exit = perf_event__repipe,
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 791b432..253133a 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 9725aa3..8e50d8d 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)
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 93a34ce..7f31a3d 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,
static struct perf_tool perf_script = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 72d8881..b8a7056 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -50,7 +50,7 @@ int test__PERF_RECORD(void)
struct perf_sample sample;
const char *cmd = "sleep";
const char *argv[] = { cmd, "1", NULL, };
- char *bname;
+ char *bname, *mmap_filename;
u64 prev_time = 0;
bool found_cmd_mmap = false,
found_libc_mmap = false,
@@ -212,6 +212,7 @@ int test__PERF_RECORD(void)

if ((type == PERF_RECORD_COMM ||
type == PERF_RECORD_MMAP ||
+ type == PERF_RECORD_MMAP2 ||
type == PERF_RECORD_FORK ||
type == PERF_RECORD_EXIT) &&
(pid_t)event->comm.pid != evlist->workload.pid) {
@@ -220,7 +221,8 @@ int test__PERF_RECORD(void)
}

if ((type == PERF_RECORD_COMM ||
- type == PERF_RECORD_MMAP) &&
+ type == PERF_RECORD_MMAP ||
+ type == PERF_RECORD_MMAP2) &&
event->comm.pid != event->comm.tid) {
pr_debug("%s with different pid/tid!\n", name);
++errs;
@@ -236,7 +238,12 @@ int test__PERF_RECORD(void)
case PERF_RECORD_EXIT:
goto found_exit;
case PERF_RECORD_MMAP:
- bname = strrchr(event->mmap.filename, '/');
+ mmap_filename = event->mmap.filename;
+ goto check_bname;
+ case PERF_RECORD_MMAP2:
+ mmap_filename = event->mmap2.filename;
+ check_bname:
+ bname = strrchr(mmap_filename, '/');
if (bname != NULL) {
if (!found_cmd_mmap)
found_cmd_mmap = !strcmp(bname + 1, cmd);
@@ -245,7 +252,7 @@ int test__PERF_RECORD(void)
if (!found_ld_mmap)
found_ld_mmap = !strncmp(bname + 1, "ld", 2);
} else if (!found_vdso_mmap)
- found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
+ found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
break;

case PERF_RECORD_SAMPLE:
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index fb58409..7ded71d 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,
struct perf_tool build_id__mark_dso_hit_ops = {
.sample = build_id__mark_dso_hit,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.fork = perf_event__process_fork,
.exit = perf_event__exit_del_thread,
.attr = perf_event__process_attr,
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 8d51f21..9b393e7 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -11,6 +11,7 @@
static const char *perf_event__names[] = {
[0] = "TOTAL",
[PERF_RECORD_MMAP] = "MMAP",
+ [PERF_RECORD_MMAP2] = "MMAP2",
[PERF_RECORD_LOST] = "LOST",
[PERF_RECORD_COMM] = "COMM",
[PERF_RECORD_EXIT] = "EXIT",
@@ -186,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
return -1;
}

- event->header.type = PERF_RECORD_MMAP;
+ event->header.type = PERF_RECORD_MMAP2;
/*
* Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
*/
@@ -197,7 +198,9 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
char prot[5];
char execname[PATH_MAX];
char anonstr[] = "//anon";
+ unsigned int ino;
size_t size;
+ ssize_t n;

if (fgets(bf, sizeof(bf), fp) == NULL)
break;
@@ -206,9 +209,16 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
strcpy(execname, "");

/* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
- sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
- &event->mmap.start, &event->mmap.len, prot,
- &event->mmap.pgoff, execname);
+ n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
+ &event->mmap2.start, &event->mmap2.len, prot,
+ &event->mmap2.pgoff, &event->mmap2.maj,
+ &event->mmap2.min,
+ &ino, execname);
+
+ event->mmap2.ino = (u64)ino;
+
+ if (n != 8)
+ continue;

if (prot[2] != 'x')
continue;
@@ -217,15 +227,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
strcpy(execname, anonstr);

size = strlen(execname) + 1;
- memcpy(event->mmap.filename, execname, size);
+ memcpy(event->mmap2.filename, execname, size);
size = PERF_ALIGN(size, sizeof(u64));
- event->mmap.len -= event->mmap.start;
- event->mmap.header.size = (sizeof(event->mmap) -
- (sizeof(event->mmap.filename) - size));
- memset(event->mmap.filename + size, 0, machine->id_hdr_size);
- event->mmap.header.size += machine->id_hdr_size;
- event->mmap.pid = tgid;
- event->mmap.tid = pid;
+ event->mmap2.len -= event->mmap.start;
+ event->mmap2.header.size = (sizeof(event->mmap2) -
+ (sizeof(event->mmap2.filename) - size));
+ memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
+ event->mmap2.header.size += machine->id_hdr_size;
+ event->mmap2.pid = tgid;
+ event->mmap2.tid = pid;

if (process(tool, event, &synth_sample, machine) != 0) {
rc = -1;
@@ -527,6 +537,17 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
event->mmap.len, event->mmap.pgoff, event->mmap.filename);
}

+size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
+{
+ return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
+ " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n",
+ event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
+ event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
+ event->mmap2.min, event->mmap2.ino,
+ event->mmap2.ino_generation,
+ event->mmap2.filename);
+}
+
int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
@@ -535,6 +556,14 @@ int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
return machine__process_mmap_event(machine, event);
}

+int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine)
+{
+ return machine__process_mmap2_event(machine, event);
+}
+
size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
{
return fprintf(fp, "(%d:%d):(%d:%d)\n",
@@ -574,6 +603,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
case PERF_RECORD_MMAP:
ret += perf_event__fprintf_mmap(event, fp);
break;
+ case PERF_RECORD_MMAP2:
+ ret += perf_event__fprintf_mmap2(event, fp);
+ break;
default:
ret += fprintf(fp, "\n");
}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 93130d8..c67ecc4 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -17,6 +17,19 @@ struct mmap_event {
char filename[PATH_MAX];
};

+struct mmap2_event {
+ struct perf_event_header header;
+ u32 pid, tid;
+ u64 start;
+ u64 len;
+ u64 pgoff;
+ u32 maj;
+ u32 min;
+ u64 ino;
+ u64 ino_generation;
+ char filename[PATH_MAX];
+};
+
struct comm_event {
struct perf_event_header header;
u32 pid, tid;
@@ -159,6 +172,7 @@ struct tracing_data_event {
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
+ struct mmap2_event mmap2;
struct comm_event comm;
struct fork_event fork;
struct lost_event lost;
@@ -208,6 +222,10 @@ int perf_event__process_mmap(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine);
+int perf_event__process_mmap2(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct machine *machine);
int perf_event__process_fork(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
@@ -238,6 +256,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,

size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
size_t perf_event__fprintf(union perf_event *event, FILE *fp);

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3612183..0ce9feb 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -27,6 +27,7 @@
static struct {
bool sample_id_all;
bool exclude_guest;
+ bool mmap2;
} perf_missing_features;

#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
@@ -676,8 +677,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
if (opts->sample_weight)
attr->sample_type |= PERF_SAMPLE_WEIGHT;

- attr->mmap = track;
- attr->comm = track;
+ attr->mmap = track;
+ attr->mmap2 = track && !perf_missing_features.mmap2;
+ attr->comm = track;

/*
* XXX see the function comment above
@@ -1016,6 +1018,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
}

fallback_missing_features:
+ if (perf_missing_features.mmap2)
+ evsel->attr.mmap2 = 0;
if (perf_missing_features.exclude_guest)
evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
retry_sample_id:
@@ -1080,8 +1084,11 @@ try_fallback:
if (err != -EINVAL || cpu > 0 || thread > 0)
goto out_close;

- if (!perf_missing_features.exclude_guest &&
- (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
+ if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
+ perf_missing_features.mmap2 = true;
+ goto fallback_missing_features;
+ } else if (!perf_missing_features.exclude_guest &&
+ (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
perf_missing_features.exclude_guest = true;
goto fallback_missing_features;
} else if (!perf_missing_features.sample_id_all) {
@@ -1925,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
if_print(exclude_hv);
if_print(exclude_idle);
if_print(mmap);
+ if_print(mmap2);
if_print(comm);
if_print(freq);
if_print(inherit_stat);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a33197a..26441d0 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)

fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);

+ fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2);
+ fprintf(fp, ", attr_mmap = %d", evsel->attr.mmap);
+ fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data);
if (evsel->ids) {
fprintf(fp, ", id = {");
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 1dca61f..933d14f 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -997,6 +997,54 @@ out_problem:
return -1;
}

+int machine__process_mmap2_event(struct machine *machine,
+ union perf_event *event)
+{
+ u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+ struct thread *thread;
+ struct map *map;
+ enum map_type type;
+ int ret = 0;
+
+ if (dump_trace)
+ perf_event__fprintf_mmap2(event, stdout);
+
+ if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
+ cpumode == PERF_RECORD_MISC_KERNEL) {
+ ret = machine__process_kernel_mmap_event(machine, event);
+ if (ret < 0)
+ goto out_problem;
+ return 0;
+ }
+
+ thread = machine__findnew_thread(machine, event->mmap2.pid,
+ event->mmap2.pid);
+ if (thread == NULL)
+ goto out_problem;
+
+ if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
+ type = MAP__VARIABLE;
+ else
+ type = MAP__FUNCTION;
+
+ map = map__new(&machine->user_dsos, event->mmap2.start,
+ event->mmap2.len, event->mmap2.pgoff,
+ event->mmap2.pid, event->mmap2.maj,
+ event->mmap2.min, event->mmap2.ino,
+ event->mmap2.ino_generation,
+ event->mmap2.filename, type);
+
+ if (map == NULL)
+ goto out_problem;
+
+ thread__insert_map(thread, map);
+ return 0;
+
+out_problem:
+ dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
+ return 0;
+}
+
int machine__process_mmap_event(struct machine *machine, union perf_event *event)
{
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

map = map__new(&machine->user_dsos, event->mmap.start,
event->mmap.len, event->mmap.pgoff,
- event->mmap.pid, event->mmap.filename,
+ event->mmap.pid, 0, 0, 0, 0,
+ event->mmap.filename,
type);

if (map == NULL)
@@ -1101,6 +1150,8 @@ int machine__process_event(struct machine *machine, union perf_event *event)
ret = machine__process_comm_event(machine, event); break;
case PERF_RECORD_MMAP:
ret = machine__process_mmap_event(machine, event); break;
+ case PERF_RECORD_MMAP2:
+ ret = machine__process_mmap2_event(machine, event); break;
case PERF_RECORD_FORK:
ret = machine__process_fork_event(machine, event); break;
case PERF_RECORD_EXIT:
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 0df925b..58a6be1 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
int machine__process_fork_event(struct machine *machine, union perf_event *event);
int machine__process_lost_event(struct machine *machine, union perf_event *event);
int machine__process_mmap_event(struct machine *machine, union perf_event *event);
+int machine__process_mmap2_event(struct machine *machine, union perf_event *event);
int machine__process_event(struct machine *machine, union perf_event *event);

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 9e8304c..4f6680d 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,
}

struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
- u64 pgoff, u32 pid, char *filename,
+ u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
+ u64 ino_gen, char *filename,
enum map_type type)
{
struct map *map = malloc(sizeof(*map));
@@ -62,6 +63,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
vdso = is_vdso_map(filename);
no_dso = is_no_dso_memory(filename);

+ map->maj = d_maj;
+ map->min = d_min;
+ map->ino = ino;
+ map->ino_generation = ino_gen;
+
if (anon) {
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
filename = newfilename;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 2cc93cb..4886ca2 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -36,6 +36,9 @@ struct map {
bool erange_warned;
u32 priv;
u64 pgoff;
+ u32 maj, min; /* only valid for MMAP2 record */
+ u64 ino; /* only valid for MMAP2 record */
+ u64 ino_generation;/* only valid for MMAP2 record */

/* ip -> dso rip */
u64 (*map_ip)(struct map *, u64);
@@ -88,8 +91,9 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
void map__init(struct map *map, enum map_type type,
u64 start, u64 end, u64 pgoff, struct dso *dso);
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
- u64 pgoff, u32 pid, char *filename,
- enum map_type type);
+ u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
+ u64 ino_gen,
+ char *filename, enum map_type type);
struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
void map__delete(struct map *map);
struct map *map__clone(struct map *map);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0308d9e..51f5edf 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,
}
}

+static void perf_event__mmap2_swap(union perf_event *event,
+ bool sample_id_all)
+{
+ event->mmap2.pid = bswap_32(event->mmap2.pid);
+ event->mmap2.tid = bswap_32(event->mmap2.tid);
+ event->mmap2.start = bswap_64(event->mmap2.start);
+ event->mmap2.len = bswap_64(event->mmap2.len);
+ event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);
+ event->mmap2.maj = bswap_32(event->mmap2.maj);
+ event->mmap2.min = bswap_32(event->mmap2.min);
+ event->mmap2.ino = bswap_64(event->mmap2.ino);
+
+ if (sample_id_all) {
+ void *data = &event->mmap2.filename;
+
+ data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
+ swap_sample_id_all(event, data);
+ }
+}
static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
{
event->fork.pid = bswap_32(event->fork.pid);
@@ -455,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event,

static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_MMAP] = perf_event__mmap_swap,
+ [PERF_RECORD_MMAP2] = perf_event__mmap2_swap,
[PERF_RECORD_COMM] = perf_event__comm_swap,
[PERF_RECORD_FORK] = perf_event__task_swap,
[PERF_RECORD_EXIT] = perf_event__task_swap,
@@ -851,7 +871,8 @@ static struct machine *
(cpumode == PERF_RECORD_MISC_GUEST_USER))) {
u32 pid;

- if (event->header.type == PERF_RECORD_MMAP)
+ if (event->header.type == PERF_RECORD_MMAP
+ || event->header.type == PERF_RECORD_MMAP2)
pid = event->mmap.pid;
else
pid = sample->pid;
@@ -978,6 +999,8 @@ static int perf_session_deliver_event(struct perf_session *session,
sample, evsel, machine);
case PERF_RECORD_MMAP:
return tool->mmap(tool, event, sample, machine);
+ case PERF_RECORD_MMAP2:
+ return tool->mmap2(tool, event, sample, machine);
case PERF_RECORD_COMM:
return tool->comm(tool, event, sample, machine);
case PERF_RECORD_FORK:
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 62b16b6..4385816 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -29,6 +29,7 @@ struct perf_tool {
event_sample sample,
read;
event_op mmap,
+ mmap2,
comm,
fork,
exit,