]> Git Repo - linux.git/blobdiff - tools/perf/util/session.c
perf session: Separating data file properties from session
[linux.git] / tools / perf / util / session.c
index 51f5edf2a6d0d140dd897c58f9d606c9fb25be9d..19fc71678c8e59cfba4497c040a6b3c0fcbb92fb 100644 (file)
 #include "perf_regs.h"
 #include "vdso.h"
 
-static int perf_session__open(struct perf_session *self, bool force)
+static int perf_session__open(struct perf_session *self)
 {
-       struct stat input_stat;
-
-       if (!strcmp(self->filename, "-")) {
-               self->fd_pipe = true;
-               self->fd = STDIN_FILENO;
-
-               if (perf_session__read_header(self) < 0)
-                       pr_err("incompatible file format (rerun with -v to learn more)");
-
-               return 0;
-       }
-
-       self->fd = open(self->filename, O_RDONLY);
-       if (self->fd < 0) {
-               int err = errno;
-
-               pr_err("failed to open %s: %s", self->filename, strerror(err));
-               if (err == ENOENT && !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;
-       }
+       struct perf_data_file *file = self->file;
 
        if (perf_session__read_header(self) < 0) {
                pr_err("incompatible file format (rerun with -v to learn more)");
-               goto out_close;
+               return -1;
        }
 
+       if (perf_data_file__is_pipe(file))
+               return 0;
+
        if (!perf_evlist__valid_sample_type(self->evlist)) {
                pr_err("non matching sample_type");
-               goto out_close;
+               return -1;
        }
 
        if (!perf_evlist__valid_sample_id_all(self->evlist)) {
                pr_err("non matching sample_id_all");
-               goto out_close;
+               return -1;
        }
 
        if (!perf_evlist__valid_read_format(self->evlist)) {
                pr_err("non matching read_format");
-               goto out_close;
+               return -1;
        }
 
-       self->size = input_stat.st_size;
        return 0;
-
-out_close:
-       close(self->fd);
-       self->fd = -1;
-       return -1;
 }
 
 void perf_session__set_id_hdr_size(struct perf_session *session)
@@ -106,39 +67,36 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
        machines__destroy_kernel_maps(&self->machines);
 }
 
-struct perf_session *perf_session__new(const char *filename, int mode,
-                                      bool force, bool repipe,
-                                      struct perf_tool *tool)
+struct perf_session *perf_session__new(struct perf_data_file *file,
+                                      bool repipe, struct perf_tool *tool)
 {
        struct perf_session *self;
-       struct stat st;
-       size_t len;
-
-       if (!filename || !strlen(filename)) {
-               if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
-                       filename = "-";
-               else
-                       filename = "perf.data";
-       }
-
-       len = strlen(filename);
-       self = zalloc(sizeof(*self) + len);
 
-       if (self == NULL)
+       self = zalloc(sizeof(*self));
+       if (!self)
                goto out;
 
-       memcpy(self->filename, filename, len);
        self->repipe = repipe;
        INIT_LIST_HEAD(&self->ordered_samples.samples);
        INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
        INIT_LIST_HEAD(&self->ordered_samples.to_free);
        machines__init(&self->machines);
 
-       if (mode == O_RDONLY) {
-               if (perf_session__open(self, force) < 0)
+       if (file) {
+               if (perf_data_file__open(file))
                        goto out_delete;
-               perf_session__set_id_hdr_size(self);
-       } else if (mode == O_WRONLY) {
+
+               self->file = file;
+
+               if (perf_data_file__is_read(file)) {
+                       if (perf_session__open(self) < 0)
+                               goto out_close;
+
+                       perf_session__set_id_hdr_size(self);
+               }
+       }
+
+       if (!file || perf_data_file__is_write(file)) {
                /*
                 * In O_RDONLY mode this will be performed when reading the
                 * kernel MMAP event, in perf_event__process_mmap().
@@ -153,10 +111,13 @@ struct perf_session *perf_session__new(const char *filename, int mode,
                tool->ordered_samples = false;
        }
 
-out:
        return self;
-out_delete:
+
+ out_close:
+       perf_data_file__close(file);
+ out_delete:
        perf_session__delete(self);
+ out:
        return NULL;
 }
 
@@ -193,7 +154,8 @@ void perf_session__delete(struct perf_session *self)
        perf_session__delete_threads(self);
        perf_session_env__delete(&self->header.env);
        machines__exit(&self->machines);
-       close(self->fd);
+       if (self->file)
+               perf_data_file__close(self->file);
        free(self);
        vdso__exit();
 }
@@ -256,6 +218,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
                tool->sample = process_event_sample_stub;
        if (tool->mmap == NULL)
                tool->mmap = process_event_stub;
+       if (tool->mmap2 == NULL)
+               tool->mmap2 = process_event_stub;
        if (tool->comm == NULL)
                tool->comm = process_event_stub;
        if (tool->fork == NULL)
@@ -395,6 +359,17 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
                swap_sample_id_all(event, &event->read + 1);
 }
 
+static void perf_event__throttle_swap(union perf_event *event,
+                                     bool sample_id_all)
+{
+       event->throttle.time      = bswap_64(event->throttle.time);
+       event->throttle.id        = bswap_64(event->throttle.id);
+       event->throttle.stream_id = bswap_64(event->throttle.stream_id);
+
+       if (sample_id_all)
+               swap_sample_id_all(event, &event->throttle + 1);
+}
+
 static u8 revbyte(u8 b)
 {
        int rev = (b >> 4) | ((b & 0xf) << 4);
@@ -440,6 +415,9 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
        attr->bp_type           = bswap_32(attr->bp_type);
        attr->bp_addr           = bswap_64(attr->bp_addr);
        attr->bp_len            = bswap_64(attr->bp_len);
+       attr->branch_sample_type = bswap_64(attr->branch_sample_type);
+       attr->sample_regs_user   = bswap_64(attr->sample_regs_user);
+       attr->sample_stack_user  = bswap_32(attr->sample_stack_user);
 
        swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
 }
@@ -480,6 +458,8 @@ static perf_event__swap_op perf_event__swap_ops[] = {
        [PERF_RECORD_EXIT]                = perf_event__task_swap,
        [PERF_RECORD_LOST]                = perf_event__all64_swap,
        [PERF_RECORD_READ]                = perf_event__read_swap,
+       [PERF_RECORD_THROTTLE]            = perf_event__throttle_swap,
+       [PERF_RECORD_UNTHROTTLE]          = perf_event__throttle_swap,
        [PERF_RECORD_SAMPLE]              = perf_event__all64_swap,
        [PERF_RECORD_HEADER_ATTR]         = perf_event__hdr_attr_swap,
        [PERF_RECORD_HEADER_EVENT_TYPE]   = perf_event__event_type_swap,
@@ -531,6 +511,9 @@ static int flush_sample_queue(struct perf_session *s,
                return 0;
 
        list_for_each_entry_safe(iter, tmp, head, list) {
+               if (session_done())
+                       return 0;
+
                if (iter->timestamp > limit)
                        break;
 
@@ -855,6 +838,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
        if (sample_type & PERF_SAMPLE_DATA_SRC)
                printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
 
+       if (sample_type & PERF_SAMPLE_TRANSACTION)
+               printf("... transaction: %" PRIx64 "\n", sample->transaction);
+
        if (sample_type & PERF_SAMPLE_READ)
                sample_read__printf(sample, evsel->attr.read_format);
 }
@@ -1026,6 +1012,7 @@ static int perf_session_deliver_event(struct perf_session *session,
 static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
                                            struct perf_tool *tool, u64 file_offset)
 {
+       int fd = perf_data_file__fd(session->file);
        int err;
 
        dump_event(session, event, file_offset, NULL);
@@ -1039,7 +1026,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
                return err;
        case PERF_RECORD_HEADER_TRACING_DATA:
                /* setup for reading amidst mmap */
-               lseek(session->fd, file_offset, SEEK_SET);
+               lseek(fd, file_offset, SEEK_SET);
                return tool->tracing_data(tool, event, session);
        case PERF_RECORD_HEADER_BUILD_ID:
                return tool->build_id(tool, event, session);
@@ -1160,12 +1147,12 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
        }
 }
 
-#define session_done() (*(volatile int *)(&session_done))
 volatile int session_done;
 
 static int __perf_session__process_pipe_events(struct perf_session *self,
                                               struct perf_tool *tool)
 {
+       int fd = perf_data_file__fd(self->file);
        union perf_event *event;
        uint32_t size, cur_size = 0;
        void *buf = NULL;
@@ -1184,7 +1171,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
                return -errno;
 more:
        event = buf;
-       err = readn(self->fd, event, sizeof(struct perf_event_header));
+       err = readn(fd, event, sizeof(struct perf_event_header));
        if (err <= 0) {
                if (err == 0)
                        goto done;
@@ -1216,7 +1203,7 @@ more:
        p += sizeof(struct perf_event_header);
 
        if (size - sizeof(struct perf_event_header)) {
-               err = readn(self->fd, p, size - sizeof(struct perf_event_header));
+               err = readn(fd, p, size - sizeof(struct perf_event_header));
                if (err <= 0) {
                        if (err == 0) {
                                pr_err("unexpected end of event stream\n");
@@ -1243,7 +1230,9 @@ more:
        if (!session_done())
                goto more;
 done:
-       err = 0;
+       /* do the final flush for ordered samples */
+       self->ordered_samples.next_flush = ULLONG_MAX;
+       err = flush_sample_queue(self, tool);
 out_err:
        free(buf);
        perf_session__warn_about_errors(self, tool);
@@ -1295,6 +1284,7 @@ int __perf_session__process_events(struct perf_session *session,
                                   u64 data_offset, u64 data_size,
                                   u64 file_size, struct perf_tool *tool)
 {
+       int fd = perf_data_file__fd(session->file);
        u64 head, page_offset, file_offset, file_pos, progress_next;
        int err, mmap_prot, mmap_flags, map_idx = 0;
        size_t  mmap_size;
@@ -1308,7 +1298,7 @@ int __perf_session__process_events(struct perf_session *session,
        file_offset = page_offset;
        head = data_offset - page_offset;
 
-       if (data_offset + data_size < file_size)
+       if (data_size && (data_offset + data_size < file_size))
                file_size = data_offset + data_size;
 
        progress_next = file_size / 16;
@@ -1327,7 +1317,7 @@ int __perf_session__process_events(struct perf_session *session,
                mmap_flags = MAP_PRIVATE;
        }
 remap:
-       buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd,
+       buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, fd,
                   file_offset);
        if (buf == MAP_FAILED) {
                pr_err("failed to mmap file\n");
@@ -1372,10 +1362,13 @@ more:
                                    "Processing events...");
        }
 
+       if (session_done())
+               goto out;
+
        if (file_pos < file_size)
                goto more;
 
-       err = 0;
+out:
        /* do the final flush for ordered samples */
        session->ordered_samples.next_flush = ULLONG_MAX;
        err = flush_sample_queue(session, tool);
@@ -1389,16 +1382,17 @@ out_err:
 int perf_session__process_events(struct perf_session *self,
                                 struct perf_tool *tool)
 {
+       u64 size = perf_data_file__size(self->file);
        int err;
 
        if (perf_session__register_idle_thread(self) == NULL)
                return -ENOMEM;
 
-       if (!self->fd_pipe)
+       if (!perf_data_file__is_pipe(self->file))
                err = __perf_session__process_events(self,
                                                     self->header.data_offset,
                                                     self->header.data_size,
-                                                    self->size, tool);
+                                                    size, tool);
        else
                err = __perf_session__process_pipe_events(self, tool);
 
@@ -1622,13 +1616,14 @@ int perf_session__cpu_bitmap(struct perf_session *session,
 void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
                                bool full)
 {
+       int fd = perf_data_file__fd(session->file);
        struct stat st;
        int ret;
 
        if (session == NULL || fp == NULL)
                return;
 
-       ret = fstat(session->fd, &st);
+       ret = fstat(fd, &st);
        if (ret == -1)
                return;
 
This page took 0.043919 seconds and 4 git commands to generate.