perf tools: Introduce perf_session class
authorArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 11 Dec 2009 23:24:02 +0000 (21:24 -0200)
committerIngo Molnar <mingo@elte.hu>
Sat, 12 Dec 2009 06:42:12 +0000 (07:42 +0100)
That does all the initialization boilerplate, opening the file,
reading the header, checking if it is valid, etc.

And that will as well have the threads list, kmap (now) global
variable, etc, so that we can handle two (or more) perf.data files
describing sessions to compare.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260573842-19720-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
15 files changed:
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-buildid-list.c
tools/perf/builtin-kmem.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-timechart.c
tools/perf/builtin-trace.c
tools/perf/util/data_map.c
tools/perf/util/data_map.h
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/session.c [new file with mode: 0644]
tools/perf/util/session.h [new file with mode: 0644]

index e2ee3b589af7b5a163a3903216c461b5f6ece707..406999668cab5b4538317898cd5ebf1c21718109 100644 (file)
@@ -356,7 +356,9 @@ LIB_H += util/parse-options.h
 LIB_H += util/parse-events.h
 LIB_H += util/quote.h
 LIB_H += util/util.h
+LIB_H += util/header.h
 LIB_H += util/help.h
+LIB_H += util/session.h
 LIB_H += util/strbuf.h
 LIB_H += util/string.h
 LIB_H += util/strlist.h
@@ -405,6 +407,7 @@ LIB_OBJS += util/callchain.o
 LIB_OBJS += util/values.o
 LIB_OBJS += util/debug.o
 LIB_OBJS += util/map.o
+LIB_OBJS += util/session.o
 LIB_OBJS += util/thread.o
 LIB_OBJS += util/trace-event-parse.o
 LIB_OBJS += util/trace-event-read.o
index 0bf2e8f9af5776538237fa7e842c33e070b4dbe0..21a78d30d53dcf584a27ede521b34ddeb53118a3 100644 (file)
@@ -25,6 +25,7 @@
 #include "util/thread.h"
 #include "util/sort.h"
 #include "util/hist.h"
+#include "util/session.h"
 #include "util/data_map.h"
 
 static char            const *input_name = "perf.data";
@@ -462,21 +463,23 @@ static struct perf_file_handler file_handler = {
 
 static int __cmd_annotate(void)
 {
-       struct perf_header *header;
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
        struct thread *idle;
        int ret;
 
+       if (session == NULL)
+               return -ENOMEM;
+
        idle = register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
-                                     &event__cwdlen, &event__cwd);
+       ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
        if (ret)
-               return ret;
+               goto out_delete;
 
        if (dump_trace) {
                event__print_totals();
-               return 0;
+               goto out_delete;
        }
 
        if (verbose > 3)
@@ -489,6 +492,8 @@ static int __cmd_annotate(void)
        output__resort(event__total[0]);
 
        find_annotations();
+out_delete:
+       perf_session__delete(session);
 
        return ret;
 }
index dcb6143a000204aa7568f876a44bbf6b6a2619bf..bfd16a1594e4abbcca6d0970eb6bc14571c75c6b 100644 (file)
@@ -11,8 +11,8 @@
 #include "util/cache.h"
 #include "util/data_map.h"
 #include "util/debug.h"
-#include "util/header.h"
 #include "util/parse-options.h"
+#include "util/session.h"
 #include "util/symbol.h"
 
 static char const *input_name = "perf.data";
@@ -55,56 +55,17 @@ static int perf_file_section__process_buildids(struct perf_file_section *self,
 static int __cmd_buildid_list(void)
 {
        int err = -1;
-       struct perf_header *header;
-       struct perf_file_header f_header;
-       struct stat input_stat;
-       int input = open(input_name, O_RDONLY);
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
 
-       if (input < 0) {
-               pr_err("failed to open file: %s", input_name);
-               if (!strcmp(input_name, "perf.data"))
-                       pr_err("  (try 'perf record' first)");
-               pr_err("\n");
-               goto out;
-       }
-
-       err = fstat(input, &input_stat);
-       if (err < 0) {
-               perror("failed to stat file");
-               goto out_close;
-       }
-
-       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
-               pr_err("file %s not owned by current user or root\n",
-                      input_name);
-               goto out_close;
-       }
-
-       if (!input_stat.st_size) {
-               pr_info("zero-sized file, nothing to do!\n");
-               goto out_close;
-       }
-
-       err = -1;
-       header = perf_header__new();
-       if (header == NULL)
-               goto out_close;
-
-       if (perf_file_header__read(&f_header, header, input) < 0) {
-               pr_warning("incompatible file format");
-               goto out_close;
-       }
+       if (session == NULL)
+               return -1;
 
-       err = perf_header__process_sections(header, input,
+       err = perf_header__process_sections(&session->header, session->fd,
                                         perf_file_section__process_buildids);
+       if (err >= 0)
+               dsos__fprintf_buildid(stdout);
 
-       if (err < 0)
-               goto out_close;
-
-       dsos__fprintf_buildid(stdout);
-out_close:
-       close(input);
-out:
+       perf_session__delete(session);
        return err;
 }
 
index fe73435192b33486036d7c4c19319deaf18b1d0a..2071d248591334f8acfe97802ab12e33b3bbbe30 100644 (file)
@@ -6,6 +6,7 @@
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/header.h"
+#include "util/session.h"
 
 #include "util/parse-options.h"
 #include "util/trace-event.h"
@@ -20,7 +21,6 @@ typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
 
 static char const              *input_name = "perf.data";
 
-static struct perf_header      *header;
 static u64                     sample_type;
 
 static int                     alloc_flag;
@@ -367,11 +367,18 @@ static struct perf_file_handler file_handler = {
 
 static int read_events(void)
 {
+       int err;
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
+
+       if (session == NULL)
+               return -ENOMEM;
+
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name, 0, 0,
-                                      &event__cwdlen, &event__cwd);
+       err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
+       perf_session__delete(session);
+       return err;
 }
 
 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
index 0e519c667e3ac47f8fe9576575f62dc7b1991d83..4decbd14eaed080ac046b8a10c793b721280c1df 100644 (file)
@@ -17,6 +17,7 @@
 #include "util/header.h"
 #include "util/event.h"
 #include "util/debug.h"
+#include "util/session.h"
 #include "util/symbol.h"
 
 #include <unistd.h>
@@ -62,7 +63,7 @@ static int                    nr_cpu                          =      0;
 
 static int                     file_new                        =      1;
 
-struct perf_header             *header                         =   NULL;
+static struct perf_session     *session;
 
 struct mmap_data {
        int                     counter;
@@ -216,12 +217,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
 {
        struct perf_header_attr *h_attr;
 
-       if (nr < header->attrs) {
-               h_attr = header->attr[nr];
+       if (nr < session->header.attrs) {
+               h_attr = session->header.attr[nr];
        } else {
                h_attr = perf_header_attr__new(a);
                if (h_attr != NULL)
-                       if (perf_header__add_attr(header, h_attr) < 0) {
+                       if (perf_header__add_attr(&session->header, h_attr) < 0) {
                                perf_header_attr__delete(h_attr);
                                h_attr = NULL;
                        }
@@ -395,9 +396,9 @@ static void open_counters(int cpu, pid_t pid)
 
 static void atexit_header(void)
 {
-       header->data_size += bytes_written;
+       session->header.data_size += bytes_written;
 
-       perf_header__write(header, output, true);
+       perf_header__write(&session->header, output, true);
 }
 
 static int __cmd_record(int argc, const char **argv)
@@ -440,24 +441,24 @@ static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
 
-       header = perf_header__new();
-       if (header == NULL) {
+       session = perf_session__new(output_name, O_WRONLY, force);
+       if (session == NULL) {
                pr_err("Not enough memory for reading perf file header\n");
                return -1;
        }
 
        if (!file_new) {
-               err = perf_header__read(header, output);
+               err = perf_header__read(&session->header, output);
                if (err < 0)
                        return err;
        }
 
        if (raw_samples) {
-               perf_header__set_feat(header, HEADER_TRACE_INFO);
+               perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
        } else {
                for (i = 0; i < nr_counters; i++) {
                        if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
-                               perf_header__set_feat(header, HEADER_TRACE_INFO);
+                               perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
                                break;
                        }
                }
@@ -481,7 +482,7 @@ static int __cmd_record(int argc, const char **argv)
        }
 
        if (file_new) {
-               err = perf_header__write(header, output, false);
+               err = perf_header__write(&session->header, output, false);
                if (err < 0)
                        return err;
        }
index 2b9eb3a553edb7a72700dca28cb71f321b0b7edd..e2ec49a9b731eab6bb2de7419680107433b7b697 100644 (file)
@@ -22,6 +22,7 @@
 #include "perf.h"
 #include "util/debug.h"
 #include "util/header.h"
+#include "util/session.h"
 
 #include "util/parse-options.h"
 #include "util/parse-events.h"
@@ -52,7 +53,7 @@ static int            exclude_other = 1;
 
 static char            callchain_default_opt[] = "fractal,0.5";
 
-static struct perf_header *header;
+static struct perf_session *session;
 
 static u64             sample_type;
 
@@ -701,7 +702,7 @@ static int process_read_event(event_t *event)
 {
        struct perf_event_attr *attr;
 
-       attr = perf_header__find_attr(event->read.id, header);
+       attr = perf_header__find_attr(event->read.id, &session->header);
 
        if (show_threads) {
                const char *name = attr ? __event_name(attr->type, attr->config)
@@ -766,6 +767,10 @@ static int __cmd_report(void)
        struct thread *idle;
        int ret;
 
+       session = perf_session__new(input_name, O_RDONLY, force);
+       if (session == NULL)
+               return -ENOMEM;
+
        idle = register_idle_thread();
        thread__comm_adjust(idle);
 
@@ -774,14 +779,14 @@ static int __cmd_report(void)
 
        register_perf_file_handler(&file_handler);
 
-       ret = mmap_dispatch_perf_file(&header, input_name, force,
-                                     full_paths, &event__cwdlen, &event__cwd);
+       ret = perf_session__process_events(session, full_paths,
+                                          &event__cwdlen, &event__cwd);
        if (ret)
-               return ret;
+               goto out_delete;
 
        if (dump_trace) {
                event__print_totals();
-               return 0;
+               goto out_delete;
        }
 
        if (verbose > 3)
@@ -796,7 +801,8 @@ static int __cmd_report(void)
 
        if (show_threads)
                perf_read_values_destroy(&show_threads_values);
-
+out_delete:
+       perf_session__delete(session);
        return ret;
 }
 
index 7cca7c15b40ae1b129a2ed6c0db14752517d1d64..65021fe1361e0ae712614fcf0d966d89fcb8789e 100644 (file)
@@ -6,6 +6,7 @@
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/header.h"
+#include "util/session.h"
 
 #include "util/parse-options.h"
 #include "util/trace-event.h"
@@ -21,7 +22,6 @@
 
 static char                    const *input_name = "perf.data";
 
-static struct perf_header      *header;
 static u64                     sample_type;
 
 static char                    default_sort_order[] = "avg, max, switch, runtime";
@@ -1663,11 +1663,18 @@ static struct perf_file_handler file_handler = {
 
 static int read_events(void)
 {
+       int err;
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
+
+       if (session == NULL)
+               return -ENOMEM;
+
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name, 0, 0,
-                                      &event__cwdlen, &event__cwd);
+       err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
+       perf_session__delete(session);
+       return err;
 }
 
 static void print_bad_events(void)
index f472df9561ee8aa972b8c9a540b0c3bf3b5159ed..759dd2b35fdbce539944627043b0922b7b711982 100644 (file)
@@ -1059,15 +1059,17 @@ static struct perf_file_handler file_handler = {
 
 static int __cmd_timechart(void)
 {
-       struct perf_header *header;
+       struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
        int ret;
 
+       if (session == NULL)
+               return -ENOMEM;
+
        register_perf_file_handler(&file_handler);
 
-       ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
-                                     &event__cwdlen, &event__cwd);
+       ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
        if (ret)
-               return EXIT_FAILURE;
+               goto out_delete;
 
        process_samples();
 
@@ -1079,8 +1081,9 @@ static int __cmd_timechart(void)
 
        pr_info("Written %2.1f seconds of trace to %s.\n",
                (last_time - first_time) / 1000000000.0, output_name);
-
-       return EXIT_SUCCESS;
+out_delete:
+       perf_session__delete(session);
+       return ret;
 }
 
 static const char * const timechart_usage[] = {
index c2fcc34486f5c7447b6c5030c8144b35b7bd2d68..0756664666f1021289ac3f610bc06ab685ecac12 100644 (file)
@@ -7,6 +7,7 @@
 #include "util/header.h"
 #include "util/exec_cmd.h"
 #include "util/trace-event.h"
+#include "util/session.h"
 
 static char const              *script_name;
 static char const              *generate_script_lang;
@@ -61,7 +62,7 @@ static int cleanup_scripting(void)
 
 static char const              *input_name = "perf.data";
 
-static struct perf_header      *header;
+static struct perf_session     *session;
 static u64                     sample_type;
 
 static int process_sample_event(event_t *event)
@@ -126,11 +127,18 @@ static struct perf_file_handler file_handler = {
 
 static int __cmd_trace(void)
 {
+       int err;
+
+       session = perf_session__new(input_name, O_RDONLY, 0);
+       if (session == NULL)
+               return -ENOMEM;
+
        register_idle_thread();
        register_perf_file_handler(&file_handler);
 
-       return mmap_dispatch_perf_file(&header, input_name,
-                                      0, 0, &event__cwdlen, &event__cwd);
+       err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
+       perf_session__delete(session);
+       return err;
 }
 
 struct script_spec {
@@ -348,11 +356,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
                        return -1;
                }
 
-               header = perf_header__new();
-               if (header == NULL)
-                       return -1;
-
-               perf_header__read(header, input);
+               perf_header__read(&session->header, input);
                err = scripting_ops->generate_script("perf-trace");
                goto out;
        }
index 59b65d0bd7c1c175225c25041d4e3c535cd3cc01..6d46dda53a29db2fe73c8ddeb22ffd8f0648b034 100644 (file)
@@ -129,23 +129,16 @@ out:
        return err;
 }
 
-int mmap_dispatch_perf_file(struct perf_header **pheader,
-                           const char *input_name,
-                           int force,
-                           int full_paths,
-                           int *cwdlen,
-                           char **cwd)
+int perf_session__process_events(struct perf_session *self,
+                                int full_paths, int *cwdlen, char **cwd)
 {
        int err;
-       struct perf_header *header;
        unsigned long head, shift;
        unsigned long offset = 0;
-       struct stat input_stat;
        size_t  page_size;
        u64 sample_type;
        event_t *event;
        uint32_t size;
-       int input;
        char *buf;
 
        if (curr_handler == NULL) {
@@ -155,56 +148,19 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
 
        page_size = getpagesize();
 
-       input = open(input_name, O_RDONLY);
-       if (input < 0) {
-               pr_err("Failed to open file: %s", input_name);
-               if (!strcmp(input_name, "perf.data"))
-                       pr_err("  (try 'perf record' first)");
-               pr_err("\n");
-               return -errno;
-       }
-
-       if (fstat(input, &input_stat) < 0) {
-               pr_err("failed to stat file");
-               err = -errno;
-               goto out_close;
-       }
-
-       err = -EACCES;
-       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
-               pr_err("file: %s not owned by current user or root\n",
-                       input_name);
-               goto out_close;
-       }
-
-       if (input_stat.st_size == 0) {
-               pr_info("zero-sized file, nothing to do!\n");
-               goto done;
-       }
-
-       err = -ENOMEM;
-       header = perf_header__new();
-       if (header == NULL)
-               goto out_close;
-
-       err = perf_header__read(header, input);
-       if (err < 0)
-               goto out_delete;
-       *pheader = header;
-       head = header->data_offset;
-
-       sample_type = perf_header__sample_type(header);
+       head = self->header.data_offset;
+       sample_type = perf_header__sample_type(&self->header);
 
        err = -EINVAL;
        if (curr_handler->sample_type_check &&
            curr_handler->sample_type_check(sample_type) < 0)
-               goto out_delete;
+               goto out_err;
 
        if (!full_paths) {
                if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
                        pr_err("failed to get the current directory\n");
                        err = -errno;
-                       goto out_delete;
+                       goto out_err;
                }
                *cwd = __cwd;
                *cwdlen = strlen(*cwd);
@@ -219,11 +175,11 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
 
 remap:
        buf = mmap(NULL, page_size * mmap_window, PROT_READ,
-                  MAP_SHARED, input, offset);
+                  MAP_SHARED, self->fd, offset);
        if (buf == MAP_FAILED) {
                pr_err("failed to mmap file\n");
                err = -errno;
-               goto out_delete;
+               goto out_err;
        }
 
 more:
@@ -273,19 +229,14 @@ more:
 
        head += size;
 
-       if (offset + head >= header->data_offset + header->data_size)
+       if (offset + head >= self->header.data_offset + self->header.data_size)
                goto done;
 
-       if (offset + head < (unsigned long)input_stat.st_size)
+       if (offset + head < self->size)
                goto more;
 
 done:
        err = 0;
-out_close:
-       close(input);
-
+out_err:
        return err;
-out_delete:
-       perf_header__delete(header);
-       goto out_close;
 }
index 258a87bcc4fbfc44c40fb35019b71b0cce0212b7..98c5b823388cd3efe8c84582433230ce273b73c5 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "event.h"
 #include "header.h"
+#include "session.h"
 
 typedef int (*event_type_handler_t)(event_t *);
 
@@ -21,12 +22,8 @@ struct perf_file_handler {
 };
 
 void register_perf_file_handler(struct perf_file_handler *handler);
-int mmap_dispatch_perf_file(struct perf_header **pheader,
-                           const char *input_name,
-                           int force,
-                           int full_paths,
-                           int *cwdlen,
-                           char **cwd);
+int perf_session__process_events(struct perf_session *self,
+                                int full_paths, int *cwdlen, char **cwd);
 int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
 
 #endif
index 59a9c0b3033e12352ad0754a0f3cfcb5aaeac3c5..f2e8d87151116c94a78868ba580e56be24382264 100644 (file)
@@ -58,35 +58,19 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
        return 0;
 }
 
-/*
- * Create new perf.data header:
- */
-struct perf_header *perf_header__new(void)
+int perf_header__init(struct perf_header *self)
 {
-       struct perf_header *self = zalloc(sizeof(*self));
-
-       if (self != NULL) {
-               self->size = 1;
-               self->attr = malloc(sizeof(void *));
-
-               if (self->attr == NULL) {
-                       free(self);
-                       self = NULL;
-               }
-       }
-
-       return self;
+       self->size = 1;
+       self->attr = malloc(sizeof(void *));
+       return self->attr == NULL ? -ENOMEM : 0;
 }
 
-void perf_header__delete(struct perf_header *self)
+void perf_header__exit(struct perf_header *self)
 {
        int i;
-
        for (i = 0; i < self->attrs; ++i)
-               perf_header_attr__delete(self->attr[i]);
-
+                perf_header_attr__delete(self->attr[i]);
        free(self->attr);
-       free(self);
 }
 
 int perf_header__add_attr(struct perf_header *self,
index d1dbe2b79c42bfcbf9a3e90e965076b6a5afc075..d118d05d3abe772f1feeb0fb1d425d75de687df0 100644 (file)
@@ -55,8 +55,8 @@ struct perf_header {
        DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
 };
 
-struct perf_header *perf_header__new(void);
-void perf_header__delete(struct perf_header *self);
+int perf_header__init(struct perf_header *self);
+void perf_header__exit(struct perf_header *self);
 
 int perf_header__read(struct perf_header *self, int fd);
 int perf_header__write(struct perf_header *self, int fd, bool at_exit);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
new file mode 100644 (file)
index 0000000..707ce1c
--- /dev/null
@@ -0,0 +1,80 @@
+#include <linux/kernel.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "session.h"
+#include "util.h"
+
+static int perf_session__open(struct perf_session *self, bool force)
+{
+       struct stat input_stat;
+
+       self->fd = open(self->filename, O_RDONLY);
+       if (self->fd < 0) {
+               pr_err("failed to open file: %s", self->filename);
+               if (!strcmp(self->filename, "perf.data"))
+                       pr_err("  (try 'perf record' first)");
+               pr_err("\n");
+               return -errno;
+       }
+
+       if (fstat(self->fd, &input_stat) < 0)
+               goto out_close;
+
+       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
+               pr_err("file %s not owned by current user or root\n",
+                      self->filename);
+               goto out_close;
+       }
+
+       if (!input_stat.st_size) {
+               pr_info("zero-sized file (%s), nothing to do!\n",
+                       self->filename);
+               goto out_close;
+       }
+
+       if (perf_header__read(&self->header, self->fd) < 0) {
+               pr_err("incompatible file format");
+               goto out_close;
+       }
+
+       self->size = input_stat.st_size;
+       return 0;
+
+out_close:
+       close(self->fd);
+       self->fd = -1;
+       return -1;
+}
+
+struct perf_session *perf_session__new(const char *filename, int mode, bool force)
+{
+       size_t len = strlen(filename) + 1;
+       struct perf_session *self = zalloc(sizeof(*self) + len);
+
+       if (self == NULL)
+               goto out;
+
+       if (perf_header__init(&self->header) < 0)
+               goto out_delete;
+
+       memcpy(self->filename, filename, len);
+
+       if (mode == O_RDONLY && perf_session__open(self, force) < 0) {
+               perf_session__delete(self);
+               self = NULL;
+       }
+out:
+       return self;
+out_delete:
+       free(self);
+       return NULL;
+}
+
+void perf_session__delete(struct perf_session *self)
+{
+       perf_header__exit(&self->header);
+       close(self->fd);
+       free(self);
+}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644 (file)
index 0000000..f3699c8
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PERF_SESSION_H
+#define __PERF_SESSION_H
+
+#include "header.h"
+
+struct perf_session {
+       struct perf_header      header;
+       unsigned long           size;
+       int                     fd;
+       char filename[0];
+};
+
+struct perf_session *perf_session__new(const char *filename, int mode, bool force);
+void perf_session__delete(struct perf_session *self);
+
+#endif /* __PERF_SESSION_H */