perf/urgent fixes:
. Handle perf.data files with no tracepoints in 'perf trace', fixing a segfault. . Fix up MMAP2 buffer space reservation, a problem that was caught via 'perf test' consistency tests. . Add attr->mmap2 support in the tools, a patch that should've been merged together with the kernel counterpart:13d7a24
"perf: Add attr->mmap2 attribute to an event". Merging it allowed us to catch the MMAP buffer space reservation problem via 'perf test'. From Stephane Eranian. The tools deals with older kernels by disabling this feature, resetting the perf_event_attr.mmap2 bit, when -EINVAL is returned by perf_event_open, just like with perf_event_attr.{sample_id_all,exclude_{guest,host}}. When such fallback happens the perf_missing_features.mmap2 flag is set to true and can be used by tooling that strictly needs this feature to check for its availability on the running kernel. . Make sure we can find PERF_SAMPLE_ID in the variable part of PERF_RECORD_ ring buffer records in 'perf kvm', where direct manipulation of sample_type was being done. Fixed by making use of the perf_evlist__set_sample_bit() helper and by setting the evlist->id_pos in perf_evlist__open(), from Adrian Hunter. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJSMHggAAoJENZQFvNTUqpAGwcP/jPE/xxeyX8+qzCfTs3+I8rs 2vQlqrkHxILF4yFIL9LmPc/cjknfZ2681Z8ExQoRZkwIhnFpPXo3pifpBpUgMpDY sX6oYnevtlg2R1UfEZkpqzpudTalnhvpXapqcyG/ITr83lz4aqRQuB6BEHO/Rk9u FSIar2sov84ZrtgCN5xdrl8eEjqtCM21EmKVGUhsTTeHzjCEE5zNairEPcbkY3j1 diQxk2V4pp3gdAniSkRQ52nwNiQphcUKk9aN2/UdQmzgVJ4JUu6Pl8VpvMeWe0gt sk6j78YUYJY9rW64sRt4JNAh2/70OUp5pQ5z+uYF6xBYTc1isxxGwC+IR/L0FzJe h5yvVIglzKL7LIkT076VzCI44kgGXEtvoqPOnTmCYSXuPNbKfdzFaK9zOr59qvHo 5gd4caPq0OsEC5dpsWkXm/awzrnUpUa7CuVO+2giW6aWxv8/XtbSdoVESaD4qVDG X+KK/lnRI1mH28bZDzR4MxbfXsB8JA4b78sTjk3QAX5jusCPwzdmzg+WtZY6CsQg k/PGT6Pu3YLh0QPCV/1tYqRKPOT1T8Vzvoc/xNX8Yr/KnkV94Deu4otBwOSpthBi 7BUfngXF31bOZxOUpnzoZb3DBFrJjNsHXy78QiIpv5f1DjpfRcDe54+hYxM9uAS1 sD+gvcG60j2mPwpp1ju+ =S8gx -----END PGP SIGNATURE----- Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent Pull perf/urgent fixes from Arnaldo Carvalho de Melo: * Handle perf.data files with no tracepoints in 'perf trace', fixing a segfault. * Fix up MMAP2 buffer space reservation, a problem that was caught via 'perf test' consistency tests. * Add attr->mmap2 support in the tools, a patch that should've been merged together with the kernel counterpart:13d7a24
"perf: Add attr->mmap2 attribute to an event". Merging it allowed us to catch the MMAP buffer space reservation problem via 'perf test'. From Stephane Eranian. The tools deals with older kernels by disabling this feature, resetting the perf_event_attr.mmap2 bit, when -EINVAL is returned by perf_event_open, just like with perf_event_attr.{sample_id_all,exclude_{guest,host}}. When such fallback happens the perf_missing_features.mmap2 flag is set to true and can be used by tooling that strictly needs this feature to check for its availability on the running kernel. * Make sure we can find PERF_SAMPLE_ID in the variable part of PERF_RECORD_ ring buffer records in 'perf kvm', where direct manipulation of sample_type was being done. Fixed by making use of the perf_evlist__set_sample_bit() helper and by setting the evlist->id_pos in perf_evlist__open(), from Adrian Hunter. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
e6d381834d
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1165,16 +1165,16 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
|
|||
struct perf_event_attr *attr = &pos->attr;
|
||||
|
||||
/* make sure these *are* set */
|
||||
attr->sample_type |= PERF_SAMPLE_TID;
|
||||
attr->sample_type |= PERF_SAMPLE_TIME;
|
||||
attr->sample_type |= PERF_SAMPLE_CPU;
|
||||
attr->sample_type |= PERF_SAMPLE_RAW;
|
||||
perf_evsel__set_sample_bit(pos, TID);
|
||||
perf_evsel__set_sample_bit(pos, TIME);
|
||||
perf_evsel__set_sample_bit(pos, CPU);
|
||||
perf_evsel__set_sample_bit(pos, RAW);
|
||||
/* make sure these are *not*; want as small a sample as possible */
|
||||
attr->sample_type &= ~PERF_SAMPLE_PERIOD;
|
||||
attr->sample_type &= ~PERF_SAMPLE_IP;
|
||||
attr->sample_type &= ~PERF_SAMPLE_CALLCHAIN;
|
||||
attr->sample_type &= ~PERF_SAMPLE_ADDR;
|
||||
attr->sample_type &= ~PERF_SAMPLE_READ;
|
||||
perf_evsel__reset_sample_bit(pos, PERIOD);
|
||||
perf_evsel__reset_sample_bit(pos, IP);
|
||||
perf_evsel__reset_sample_bit(pos, CALLCHAIN);
|
||||
perf_evsel__reset_sample_bit(pos, ADDR);
|
||||
perf_evsel__reset_sample_bit(pos, READ);
|
||||
attr->mmap = 0;
|
||||
attr->comm = 0;
|
||||
attr->task = 0;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -64,6 +64,16 @@ void perf_evlist__set_id_pos(struct perf_evlist *evlist)
|
|||
evlist->is_pos = first->is_pos;
|
||||
}
|
||||
|
||||
static void perf_evlist__update_id_pos(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
list_for_each_entry(evsel, &evlist->entries, node)
|
||||
perf_evsel__calc_id_pos(evsel);
|
||||
|
||||
perf_evlist__set_id_pos(evlist);
|
||||
}
|
||||
|
||||
static void perf_evlist__purge(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *pos, *n;
|
||||
|
@ -920,6 +930,8 @@ int perf_evlist__open(struct perf_evlist *evlist)
|
|||
struct perf_evsel *evsel;
|
||||
int err;
|
||||
|
||||
perf_evlist__update_id_pos(evlist);
|
||||
|
||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||
err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
|
||||
if (err < 0)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
@ -1620,52 +1643,26 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
|
|||
const struct perf_evsel_str_handler *assocs,
|
||||
size_t nr_assocs)
|
||||
{
|
||||
struct perf_evlist *evlist = session->evlist;
|
||||
struct event_format *format;
|
||||
struct perf_evsel *evsel;
|
||||
char *tracepoint, *name;
|
||||
size_t i;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < nr_assocs; i++) {
|
||||
err = -ENOMEM;
|
||||
tracepoint = strdup(assocs[i].name);
|
||||
if (tracepoint == NULL)
|
||||
goto out;
|
||||
|
||||
err = -ENOENT;
|
||||
name = strchr(tracepoint, ':');
|
||||
if (name == NULL)
|
||||
goto out_free;
|
||||
|
||||
*name++ = '\0';
|
||||
format = pevent_find_event_by_name(session->pevent,
|
||||
tracepoint, name);
|
||||
if (format == NULL) {
|
||||
/*
|
||||
* Adding a handler for an event not in the session,
|
||||
* just ignore it.
|
||||
*/
|
||||
goto next;
|
||||
}
|
||||
|
||||
evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id);
|
||||
/*
|
||||
* Adding a handler for an event not in the session,
|
||||
* just ignore it.
|
||||
*/
|
||||
evsel = perf_evlist__find_tracepoint_by_name(session->evlist, assocs[i].name);
|
||||
if (evsel == NULL)
|
||||
goto next;
|
||||
continue;
|
||||
|
||||
err = -EEXIST;
|
||||
if (evsel->handler.func != NULL)
|
||||
goto out_free;
|
||||
goto out;
|
||||
evsel->handler.func = assocs[i].handler;
|
||||
next:
|
||||
free(tracepoint);
|
||||
}
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
|
||||
out_free:
|
||||
free(tracepoint);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ struct perf_tool {
|
|||
event_sample sample,
|
||||
read;
|
||||
event_op mmap,
|
||||
mmap2,
|
||||
comm,
|
||||
fork,
|
||||
exit,
|
||||
|
|
Loading…
Reference in New Issue