perf record: Synthesize non-exec MMAP records when --data used
When perf_event_attr.mmap_data is set the kernel will generate PERF_RECORD_MMAP events when non-exec (data, SysV mem) mmaps are created, so we need to synthesize from /proc/pid/maps for existing threads, as we do for exec mmaps. Right now just 'perf record' does it, but any other tool that uses perf_event__synthesize_thread(s|map) can request it. Reported-by: Don Zickus <dzickus@redhat.com> Tested-by: Don Zickus <dzickus@redhat.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Bill Gray <bgray@redhat.com> Cc: David Ahern <dsahern@gmail.com> Cc: Don Zickus <dzickus@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Joe Mario <jmario@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Richard Fowles <rfowles@redhat.com> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-ihwzraikx23ian9txinogvv2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
ef503831d8
commit
62605dc50c
7 changed files with 42 additions and 32 deletions
|
@ -1550,10 +1550,10 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
|
||||||
perf_event__synthesize_thread_map(&kvm->tool,
|
perf_event__synthesize_thread_map(&kvm->tool,
|
||||||
kvm->evlist->threads,
|
kvm->evlist->threads,
|
||||||
perf_event__process,
|
perf_event__process,
|
||||||
&kvm->session->machines.host);
|
&kvm->session->machines.host, false);
|
||||||
else
|
else
|
||||||
perf_event__synthesize_threads(&kvm->tool, perf_event__process,
|
perf_event__synthesize_threads(&kvm->tool, perf_event__process,
|
||||||
&kvm->session->machines.host);
|
&kvm->session->machines.host, false);
|
||||||
|
|
||||||
|
|
||||||
err = kvm_live_open_events(kvm);
|
err = kvm_live_open_events(kvm);
|
||||||
|
|
|
@ -482,11 +482,11 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
|
||||||
|
|
||||||
if (perf_target__has_task(&opts->target))
|
if (perf_target__has_task(&opts->target))
|
||||||
err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
|
err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
|
||||||
process_synthesized_event,
|
process_synthesized_event,
|
||||||
machine);
|
machine, opts->sample_address);
|
||||||
else if (perf_target__has_cpu(&opts->target))
|
else if (perf_target__has_cpu(&opts->target))
|
||||||
err = perf_event__synthesize_threads(tool, process_synthesized_event,
|
err = perf_event__synthesize_threads(tool, process_synthesized_event,
|
||||||
machine);
|
machine, opts->sample_address);
|
||||||
else /* command specified */
|
else /* command specified */
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
|
|
|
@ -953,10 +953,10 @@ static int __cmd_top(struct perf_top *top)
|
||||||
if (perf_target__has_task(&opts->target))
|
if (perf_target__has_task(&opts->target))
|
||||||
perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
|
perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
|
||||||
perf_event__process,
|
perf_event__process,
|
||||||
&top->session->machines.host);
|
&top->session->machines.host, false);
|
||||||
else
|
else
|
||||||
perf_event__synthesize_threads(&top->tool, perf_event__process,
|
perf_event__synthesize_threads(&top->tool, perf_event__process,
|
||||||
&top->session->machines.host);
|
&top->session->machines.host, false);
|
||||||
|
|
||||||
ret = perf_top__start_counters(top);
|
ret = perf_top__start_counters(top);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
@ -1343,10 +1343,10 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
|
||||||
if (perf_target__has_task(&trace->opts.target)) {
|
if (perf_target__has_task(&trace->opts.target)) {
|
||||||
err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
|
err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
|
||||||
trace__tool_process,
|
trace__tool_process,
|
||||||
trace->host);
|
trace->host, false);
|
||||||
} else {
|
} else {
|
||||||
err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
|
err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
|
||||||
trace->host);
|
trace->host, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
|
|
@ -441,7 +441,7 @@ static int do_test_code_reading(bool try_kcore)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = perf_event__synthesize_thread_map(NULL, threads,
|
ret = perf_event__synthesize_thread_map(NULL, threads,
|
||||||
perf_event__process, machine);
|
perf_event__process, machine, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_debug("perf_event__synthesize_thread_map failed\n");
|
pr_debug("perf_event__synthesize_thread_map failed\n");
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
|
@ -170,7 +170,8 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
pid_t pid, pid_t tgid,
|
pid_t pid, pid_t tgid,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct machine *machine)
|
struct machine *machine,
|
||||||
|
bool mmap_data)
|
||||||
{
|
{
|
||||||
char filename[PATH_MAX];
|
char filename[PATH_MAX];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
@ -188,10 +189,6 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
|
||||||
}
|
}
|
||||||
|
|
||||||
event->header.type = PERF_RECORD_MMAP;
|
event->header.type = PERF_RECORD_MMAP;
|
||||||
/*
|
|
||||||
* Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
|
|
||||||
*/
|
|
||||||
event->header.misc = PERF_RECORD_MISC_USER;
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
char bf[BUFSIZ];
|
char bf[BUFSIZ];
|
||||||
|
@ -215,9 +212,17 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
|
||||||
|
|
||||||
if (n != 5)
|
if (n != 5)
|
||||||
continue;
|
continue;
|
||||||
|
/*
|
||||||
|
* Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
|
||||||
|
*/
|
||||||
|
event->header.misc = PERF_RECORD_MISC_USER;
|
||||||
|
|
||||||
if (prot[2] != 'x')
|
if (prot[2] != 'x') {
|
||||||
continue;
|
if (!mmap_data || prot[0] != 'r')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
event->header.misc |= PERF_RECORD_MISC_MMAP_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(execname, ""))
|
if (!strcmp(execname, ""))
|
||||||
strcpy(execname, anonstr);
|
strcpy(execname, anonstr);
|
||||||
|
@ -304,20 +309,21 @@ static int __event__synthesize_thread(union perf_event *comm_event,
|
||||||
pid_t pid, int full,
|
pid_t pid, int full,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct perf_tool *tool,
|
struct perf_tool *tool,
|
||||||
struct machine *machine)
|
struct machine *machine, bool mmap_data)
|
||||||
{
|
{
|
||||||
pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
|
pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
|
||||||
process, machine);
|
process, machine);
|
||||||
if (tgid == -1)
|
if (tgid == -1)
|
||||||
return -1;
|
return -1;
|
||||||
return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
|
return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
|
||||||
process, machine);
|
process, machine, mmap_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
||||||
struct thread_map *threads,
|
struct thread_map *threads,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct machine *machine)
|
struct machine *machine,
|
||||||
|
bool mmap_data)
|
||||||
{
|
{
|
||||||
union perf_event *comm_event, *mmap_event;
|
union perf_event *comm_event, *mmap_event;
|
||||||
int err = -1, thread, j;
|
int err = -1, thread, j;
|
||||||
|
@ -334,7 +340,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
||||||
for (thread = 0; thread < threads->nr; ++thread) {
|
for (thread = 0; thread < threads->nr; ++thread) {
|
||||||
if (__event__synthesize_thread(comm_event, mmap_event,
|
if (__event__synthesize_thread(comm_event, mmap_event,
|
||||||
threads->map[thread], 0,
|
threads->map[thread], 0,
|
||||||
process, tool, machine)) {
|
process, tool, machine,
|
||||||
|
mmap_data)) {
|
||||||
err = -1;
|
err = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -356,10 +363,10 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
||||||
|
|
||||||
/* if not, generate events for it */
|
/* if not, generate events for it */
|
||||||
if (need_leader &&
|
if (need_leader &&
|
||||||
__event__synthesize_thread(comm_event,
|
__event__synthesize_thread(comm_event, mmap_event,
|
||||||
mmap_event,
|
comm_event->comm.pid, 0,
|
||||||
comm_event->comm.pid, 0,
|
process, tool, machine,
|
||||||
process, tool, machine)) {
|
mmap_data)) {
|
||||||
err = -1;
|
err = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -374,7 +381,7 @@ out:
|
||||||
|
|
||||||
int perf_event__synthesize_threads(struct perf_tool *tool,
|
int perf_event__synthesize_threads(struct perf_tool *tool,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct machine *machine)
|
struct machine *machine, bool mmap_data)
|
||||||
{
|
{
|
||||||
DIR *proc;
|
DIR *proc;
|
||||||
struct dirent dirent, *next;
|
struct dirent dirent, *next;
|
||||||
|
@ -404,7 +411,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
|
||||||
* one thread couldn't be synthesized.
|
* one thread couldn't be synthesized.
|
||||||
*/
|
*/
|
||||||
__event__synthesize_thread(comm_event, mmap_event, pid, 1,
|
__event__synthesize_thread(comm_event, mmap_event, pid, 1,
|
||||||
process, tool, machine);
|
process, tool, machine, mmap_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
|
@ -528,19 +535,22 @@ int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
|
||||||
|
|
||||||
size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
|
size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
|
||||||
{
|
{
|
||||||
return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
|
return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n",
|
||||||
event->mmap.pid, event->mmap.tid, event->mmap.start,
|
event->mmap.pid, event->mmap.tid, event->mmap.start,
|
||||||
event->mmap.len, event->mmap.pgoff, event->mmap.filename);
|
event->mmap.len, event->mmap.pgoff,
|
||||||
|
(event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x',
|
||||||
|
event->mmap.filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
|
size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
|
||||||
{
|
{
|
||||||
return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
|
return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
|
||||||
" %02x:%02x %"PRIu64" %"PRIu64"]: %s\n",
|
" %02x:%02x %"PRIu64" %"PRIu64"]: %c %s\n",
|
||||||
event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
|
event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
|
||||||
event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
|
event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
|
||||||
event->mmap2.min, event->mmap2.ino,
|
event->mmap2.min, event->mmap2.ino,
|
||||||
event->mmap2.ino_generation,
|
event->mmap2.ino_generation,
|
||||||
|
(event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x',
|
||||||
event->mmap2.filename);
|
event->mmap2.filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,10 +208,10 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool,
|
||||||
int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
||||||
struct thread_map *threads,
|
struct thread_map *threads,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct machine *machine);
|
struct machine *machine, bool mmap_data);
|
||||||
int perf_event__synthesize_threads(struct perf_tool *tool,
|
int perf_event__synthesize_threads(struct perf_tool *tool,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct machine *machine);
|
struct machine *machine, bool mmap_data);
|
||||||
int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
|
int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct machine *machine,
|
struct machine *machine,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue