perf record: Synthesize non-exec MMAP records when --data used
authorArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 11 Nov 2013 12:44:09 +0000 (09:44 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 11 Nov 2013 18:56:39 +0000 (15:56 -0300)
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>
tools/perf/builtin-kvm.c
tools/perf/builtin-record.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/tests/code-reading.c
tools/perf/util/event.c
tools/perf/util/event.h

index cd9f92078aba2e42aaadb8b48f7dad04e23f3485..f36e8209c300b86d137ed8869019f7eb629aa2dc 100644 (file)
@@ -1550,10 +1550,10 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
                perf_event__synthesize_thread_map(&kvm->tool,
                                                  kvm->evlist->threads,
                                                  perf_event__process,
-                                                 &kvm->session->machines.host);
+                                                 &kvm->session->machines.host, false);
        else
                perf_event__synthesize_threads(&kvm->tool, perf_event__process,
-                                              &kvm->session->machines.host);
+                                              &kvm->session->machines.host, false);
 
 
        err = kvm_live_open_events(kvm);
index 15280b5e5574669c78376a419a8512eb5e774258..afb252cf6ecad295f3a5d4098beaf6e247f91489 100644 (file)
@@ -482,11 +482,11 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
 
        if (perf_target__has_task(&opts->target))
                err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
-                                                 process_synthesized_event,
-                                                 machine);
+                                                       process_synthesized_event,
+                                                       machine, opts->sample_address);
        else if (perf_target__has_cpu(&opts->target))
                err = perf_event__synthesize_threads(tool, process_synthesized_event,
-                                              machine);
+                                                    machine, opts->sample_address);
        else /* command specified */
                err = 0;
 
index 9acca8856ccb2ba60ee3ae72cb954b6c1932da65..cc96d753db96cd6ad0cfa992140e649e0276e3d8 100644 (file)
@@ -953,10 +953,10 @@ static int __cmd_top(struct perf_top *top)
        if (perf_target__has_task(&opts->target))
                perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
                                                  perf_event__process,
-                                                 &top->session->machines.host);
+                                                 &top->session->machines.host, false);
        else
                perf_event__synthesize_threads(&top->tool, perf_event__process,
-                                              &top->session->machines.host);
+                                              &top->session->machines.host, false);
 
        ret = perf_top__start_counters(top);
        if (ret)
index 68943cad70d426de63f24b4e1edd5d102399f33d..277c2367e0cf122733939c790c2b424dcb80b80f 100644 (file)
@@ -1343,10 +1343,10 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
        if (perf_target__has_task(&trace->opts.target)) {
                err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
                                                        trace__tool_process,
-                                                       trace->host);
+                                                       trace->host, false);
        } else {
                err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
-                                                    trace->host);
+                                                    trace->host, false);
        }
 
        if (err)
index 49ccc3b2995ee30c8c2ad55a4c4b8308d9ad9055..6d9dc198a20064f92370459480675ddf7db07225 100644 (file)
@@ -441,7 +441,7 @@ static int do_test_code_reading(bool try_kcore)
        }
 
        ret = perf_event__synthesize_thread_map(NULL, threads,
-                                               perf_event__process, machine);
+                                               perf_event__process, machine, false);
        if (ret < 0) {
                pr_debug("perf_event__synthesize_thread_map failed\n");
                goto out_err;
index ec9ae1114ed4ca57492948686cf2858d3f2591d8..6e3a846aed0ea99ac2958886a64a512359394cea 100644 (file)
@@ -170,7 +170,8 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                                              union perf_event *event,
                                              pid_t pid, pid_t tgid,
                                              perf_event__handler_t process,
-                                             struct machine *machine)
+                                             struct machine *machine,
+                                             bool mmap_data)
 {
        char filename[PATH_MAX];
        FILE *fp;
@@ -188,10 +189,6 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
        }
 
        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) {
                char bf[BUFSIZ];
@@ -215,9 +212,17 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
 
                if (n != 5)
                        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')
-                       continue;
+               if (prot[2] != 'x') {
+                       if (!mmap_data || prot[0] != 'r')
+                               continue;
+
+                       event->header.misc |= PERF_RECORD_MISC_MMAP_DATA;
+               }
 
                if (!strcmp(execname, ""))
                        strcpy(execname, anonstr);
@@ -304,20 +309,21 @@ static int __event__synthesize_thread(union perf_event *comm_event,
                                      pid_t pid, int full,
                                          perf_event__handler_t process,
                                      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,
                                                 process, machine);
        if (tgid == -1)
                return -1;
        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,
                                      struct thread_map *threads,
                                      perf_event__handler_t process,
-                                     struct machine *machine)
+                                     struct machine *machine,
+                                     bool mmap_data)
 {
        union perf_event *comm_event, *mmap_event;
        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) {
                if (__event__synthesize_thread(comm_event, mmap_event,
                                               threads->map[thread], 0,
-                                              process, tool, machine)) {
+                                              process, tool, machine,
+                                              mmap_data)) {
                        err = -1;
                        break;
                }
@@ -356,10 +363,10 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
 
                        /* if not, generate events for it */
                        if (need_leader &&
-                           __event__synthesize_thread(comm_event,
-                                                     mmap_event,
-                                                     comm_event->comm.pid, 0,
-                                                     process, tool, machine)) {
+                           __event__synthesize_thread(comm_event, mmap_event,
+                                                      comm_event->comm.pid, 0,
+                                                      process, tool, machine,
+                                                      mmap_data)) {
                                err = -1;
                                break;
                        }
@@ -374,7 +381,7 @@ out:
 
 int perf_event__synthesize_threads(struct perf_tool *tool,
                                   perf_event__handler_t process,
-                                  struct machine *machine)
+                                  struct machine *machine, bool mmap_data)
 {
        DIR *proc;
        struct dirent dirent, *next;
@@ -404,7 +411,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
                 * one thread couldn't be synthesized.
                 */
                __event__synthesize_thread(comm_event, mmap_event, pid, 1,
-                                          process, tool, machine);
+                                          process, tool, machine, mmap_data);
        }
 
        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)
 {
-       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.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)
 {
        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.len, event->mmap2.pgoff, event->mmap2.maj,
                       event->mmap2.min, event->mmap2.ino,
                       event->mmap2.ino_generation,
+                      (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x',
                       event->mmap2.filename);
 }
 
index f8d70f3003ab6995a6522846f5807fecb20f2fce..30fec9901e440b459e49b1b6e8d584cc6e0e15a8 100644 (file)
@@ -208,10 +208,10 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool,
 int perf_event__synthesize_thread_map(struct perf_tool *tool,
                                      struct thread_map *threads,
                                      perf_event__handler_t process,
-                                     struct machine *machine);
+                                     struct machine *machine, bool mmap_data);
 int perf_event__synthesize_threads(struct perf_tool *tool,
                                   perf_event__handler_t process,
-                                  struct machine *machine);
+                                  struct machine *machine, bool mmap_data);
 int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
                                       perf_event__handler_t process,
                                       struct machine *machine,