Skip to content

Commit

Permalink
perf tools: Add attr->mmap2 support
Browse files Browse the repository at this point in the history
This patch adds support for the new PERF_RECORD_MMAP2 record type
exposed by the kernel. This is an extended PERF_RECORD_MMAP record.

It adds for each file-backed mapping the device major, minor number and
the inode number and generation.

This triplet uniquely identifies the source of a file-backed mapping. It
can be used to detect identical virtual mappings between processes, for
instance.

The patch will prefer MMAP2 over MMAP.

Signed-off-by: Stephane Eranian <eranian@google.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1377079825-19057-3-git-send-email-eranian@google.com
[ Cope with 314add6 "Change machine__findnew_thread() to set thread pid",
  fix 'perf test' regression test entry affected,
  use perf_missing_features.mmap2 to fallback to not using .mmap2 in older kernels,
  so that new tools can work with kernels where this feature is not present ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Stephane Eranian authored and Arnaldo Carvalho de Melo committed Sep 11, 2013
1 parent e71aa28 commit 5c5e854
Show file tree
Hide file tree
Showing 17 changed files with 200 additions and 25 deletions.
1 change: 1 addition & 0 deletions tools/perf/builtin-annotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 15 additions & 0 deletions tools/perf/builtin-inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions tools/perf/builtin-mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions tools/perf/builtin-report.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions tools/perf/builtin-script.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 11 additions & 4 deletions tools/perf/tests/perf-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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:
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/build-id.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
56 changes: 44 additions & 12 deletions tools/perf/util/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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
*/
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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",
Expand Down Expand Up @@ -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");
}
Expand Down
19 changes: 19 additions & 0 deletions tools/perf/util/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);

Expand Down
16 changes: 12 additions & 4 deletions tools/perf/util/evsel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -1080,8 +1084,11 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
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) {
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions tools/perf/util/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand Down
Loading

0 comments on commit 5c5e854

Please sign in to comment.