perf record: Stop intercepting events, use postprocessing to get build-ids
Arnaldo Carvalho de Melo [Wed, 3 Feb 2010 18:52:05 +0000 (16:52 -0200)]
We want to stream events as fast as possible to perf.data, and
also in the future we want to have splice working, when no
interception will be possible.

Using build_id__mark_dso_hit_ops to create the list of DSOs that
back MMAPs we also optimize disk usage in the build-id cache by
only caching DSOs that had hits.

Suggested-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1265223128-11786-6-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

tools/perf/builtin-record.c
tools/perf/util/header.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h

index 949167e..706f001 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "perf.h"
 
+#include "util/build-id.h"
 #include "util/util.h"
 #include "util/parse-options.h"
 #include "util/parse-events.h"
@@ -65,6 +66,7 @@ static int                    nr_poll                         =      0;
 static int                     nr_cpu                          =      0;
 
 static int                     file_new                        =      1;
+static off_t                   post_processing_offset;
 
 static struct perf_session     *session;
 
@@ -114,26 +116,10 @@ static void write_output(void *buf, size_t size)
        }
 }
 
-static void write_event(event_t *buf, size_t size)
-{
-       /*
-       * Add it to the list of DSOs, so that when we finish this
-        * record session we can pick the available build-ids.
-        */
-       if (buf->header.type == PERF_RECORD_MMAP) {
-               struct list_head *head = &dsos__user;
-               if (buf->mmap.header.misc == 1)
-                       head = &dsos__kernel;
-               __dsos__findnew(head, buf->mmap.filename);
-       }
-
-       write_output(buf, size);
-}
-
 static int process_synthesized_event(event_t *event,
                                     struct perf_session *self __used)
 {
-       write_event(event, event->header.size);
+       write_output(event, event->header.size);
        return 0;
 }
 
@@ -185,14 +171,14 @@ static void mmap_read(struct mmap_data *md)
                size = md->mask + 1 - (old & md->mask);
                old += size;
 
-               write_event(buf, size);
+               write_output(buf, size);
        }
 
        buf = &data[old & md->mask];
        size = head - old;
        old += size;
 
-       write_event(buf, size);
+       write_output(buf, size);
 
        md->prev = old;
        mmap_write_tail(md, old);
@@ -402,10 +388,21 @@ static void open_counters(int cpu, pid_t pid)
        nr_cpu++;
 }
 
+static int process_buildids(void)
+{
+       u64 size = lseek(output, 0, SEEK_CUR);
+
+       session->fd = output;
+       return __perf_session__process_events(session, post_processing_offset,
+                                             size - post_processing_offset,
+                                             size, &build_id__mark_dso_hit_ops);
+}
+
 static void atexit_header(void)
 {
        session->header.data_size += bytes_written;
 
+       process_buildids();
        perf_header__write(&session->header, output, true);
 }
 
@@ -558,6 +555,8 @@ static int __cmd_record(int argc, const char **argv)
                        return err;
        }
 
+       post_processing_offset = lseek(output, 0, SEEK_CUR);
+
        err = event__synthesize_kernel_mmap(process_synthesized_event,
                                            session, "_text");
        if (err < 0) {
index ed3efd7..d5facd5 100644 (file)
@@ -205,8 +205,11 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
        dsos__for_each_with_build_id(pos, head) {
                int err;
                struct build_id_event b;
-               size_t len = pos->long_name_len + 1;
+               size_t len;
 
+               if (!pos->hit)
+                       continue;
+               len = pos->long_name_len + 1;
                len = ALIGN(len, NAME_ALIGN);
                memset(&b, 0, sizeof(b));
                memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
@@ -371,7 +374,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
        u64 sec_start;
        int idx = 0, err;
 
-       if (dsos__read_build_ids())
+       if (dsos__read_build_ids(true))
                perf_header__set_feat(self, HEADER_BUILD_ID);
 
        nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
index aa8a031..74cbc64 100644 (file)
@@ -385,8 +385,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
        return thread;
 }
 
-int perf_session__process_events(struct perf_session *self,
-                                struct perf_event_ops *ops)
+int __perf_session__process_events(struct perf_session *self,
+                                  u64 data_offset, u64 data_size,
+                                  u64 file_size, struct perf_event_ops *ops)
 {
        int err, mmap_prot, mmap_flags;
        u64 head, shift;
@@ -396,32 +397,11 @@ int perf_session__process_events(struct perf_session *self,
        uint32_t size;
        char *buf;
 
-       if (perf_session__register_idle_thread(self) == NULL)
-               return -ENOMEM;
-
        perf_event_ops__fill_defaults(ops);
 
        page_size = sysconf(_SC_PAGESIZE);
 
-       head = self->header.data_offset;
-
-       if (!symbol_conf.full_paths) {
-               char bf[PATH_MAX];
-
-               if (getcwd(bf, sizeof(bf)) == NULL) {
-                       err = -errno;
-out_getcwd_err:
-                       pr_err("failed to get the current directory\n");
-                       goto out_err;
-               }
-               self->cwd = strdup(bf);
-               if (self->cwd == NULL) {
-                       err = -ENOMEM;
-                       goto out_getcwd_err;
-               }
-               self->cwdlen = strlen(self->cwd);
-       }
-
+       head = data_offset;
        shift = page_size * (head / page_size);
        offset += shift;
        head -= shift;
@@ -486,10 +466,10 @@ more:
 
        head += size;
 
-       if (offset + head >= self->header.data_offset + self->header.data_size)
+       if (offset + head >= data_offset + data_size)
                goto done;
 
-       if (offset + head < self->size)
+       if (offset + head < file_size)
                goto more;
 done:
        err = 0;
@@ -497,6 +477,38 @@ out_err:
        return err;
 }
 
+int perf_session__process_events(struct perf_session *self,
+                                struct perf_event_ops *ops)
+{
+       int err;
+
+       if (perf_session__register_idle_thread(self) == NULL)
+               return -ENOMEM;
+
+       if (!symbol_conf.full_paths) {
+               char bf[PATH_MAX];
+
+               if (getcwd(bf, sizeof(bf)) == NULL) {
+                       err = -errno;
+out_getcwd_err:
+                       pr_err("failed to get the current directory\n");
+                       goto out_err;
+               }
+               self->cwd = strdup(bf);
+               if (self->cwd == NULL) {
+                       err = -ENOMEM;
+                       goto out_getcwd_err;
+               }
+               self->cwdlen = strlen(self->cwd);
+       }
+
+       err = __perf_session__process_events(self, self->header.data_offset,
+                                            self->header.data_size,
+                                            self->size, ops);
+out_err:
+       return err;
+}
+
 bool perf_session__has_traces(struct perf_session *self, const char *msg)
 {
        if (!(self->sample_type & PERF_SAMPLE_RAW)) {
index 752d75a..31950fc 100644 (file)
@@ -50,6 +50,9 @@ void perf_session__delete(struct perf_session *self);
 
 void perf_event_header__bswap(struct perf_event_header *self);
 
+int __perf_session__process_events(struct perf_session *self,
+                                  u64 data_offset, u64 data_size, u64 size,
+                                  struct perf_event_ops *ops);
 int perf_session__process_events(struct perf_session *self,
                                 struct perf_event_ops *event_ops);
 
index e752837..bfb0554 100644 (file)
@@ -1076,25 +1076,28 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
        return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
 }
 
-static bool __dsos__read_build_ids(struct list_head *head)
+static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
 {
        bool have_build_id = false;
        struct dso *pos;
 
-       list_for_each_entry(pos, head, node)
+       list_for_each_entry(pos, head, node) {
+               if (with_hits && !pos->hit)
+                       continue;
                if (filename__read_build_id(pos->long_name, pos->build_id,
                                            sizeof(pos->build_id)) > 0) {
                        have_build_id     = true;
                        pos->has_build_id = true;
                }
+       }
 
        return have_build_id;
 }
 
-bool dsos__read_build_ids(void)
+bool dsos__read_build_ids(bool with_hits)
 {
-       bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
-            ubuildids = __dsos__read_build_ids(&dsos__user);
+       bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
+            ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
        return kbuildids || ubuildids;
 }
 
index e90568a..1b4192e 100644 (file)
@@ -157,7 +157,7 @@ struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
 
 int filename__read_build_id(const char *filename, void *bf, size_t size);
 int sysfs__read_build_id(const char *filename, void *bf, size_t size);
-bool dsos__read_build_ids(void);
+bool dsos__read_build_ids(bool with_hits);
 int build_id__sprintf(const u8 *self, int len, char *bf);
 int kallsyms__parse(const char *filename, void *arg,
                    int (*process_symbol)(void *arg, const char *name,