return err;
}
+int perf_header__write_pipe(int fd)
+{
+ struct perf_pipe_file_header f_header;
+ int err;
+
+ f_header = (struct perf_pipe_file_header){
+ .magic = PERF_MAGIC,
+ .size = sizeof(f_header),
+ };
+
+ err = do_write(fd, &f_header, sizeof(f_header));
+ if (err < 0) {
+ pr_debug("failed to write perf pipe header\n");
+ return err;
+ }
+
+ return 0;
+}
+
int perf_header__write(struct perf_header *self, int fd, bool at_exit)
{
struct perf_file_header f_header;
return 0;
}
-static int do_read(int fd, void *buf, size_t size)
-{
- while (size) {
- int ret = read(fd, buf, size);
-
- if (ret <= 0)
- return -1;
-
- size -= ret;
- buf += ret;
- }
-
- return 0;
-}
-
static int perf_header__getbuffer64(struct perf_header *self,
int fd, void *buf, size_t size)
{
- if (do_read(fd, buf, size))
+ if (do_read(fd, buf, size) <= 0)
return -1;
if (self->needs_swap)
{
lseek(fd, 0, SEEK_SET);
- if (do_read(fd, self, sizeof(*self)) ||
+ if (do_read(fd, self, sizeof(*self)) <= 0 ||
memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
return -1;
return 0;
}
-int perf_header__read(struct perf_header *self, int fd)
+static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
+ struct perf_header *ph, int fd)
{
+ if (do_read(fd, self, sizeof(*self)) <= 0 ||
+ memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
+ return -1;
+
+ if (self->size != sizeof(*self)) {
+ u64 size = bswap_64(self->size);
+
+ if (size != sizeof(*self))
+ return -1;
+
+ ph->needs_swap = true;
+ }
+
+ return 0;
+}
+
+static int perf_header__read_pipe(struct perf_session *session, int fd)
+{
+ struct perf_header *self = &session->header;
+ struct perf_pipe_file_header f_header;
+
+ if (perf_file_header__read_pipe(&f_header, self, fd) < 0) {
+ pr_debug("incompatible file format\n");
+ return -EINVAL;
+ }
+
+ session->fd = fd;
+
+ return 0;
+}
+
+int perf_header__read(struct perf_session *session, int fd)
+{
+ struct perf_header *self = &session->header;
struct perf_file_header f_header;
struct perf_file_attr f_attr;
u64 f_id;
int nr_attrs, nr_ids, i, j;
+ if (session->fd_pipe)
+ return perf_header__read_pipe(session, fd);
+
if (perf_file_header__read(&f_header, self, fd) < 0) {
pr_debug("incompatible file format\n");
return -EINVAL;
{
struct stat input_stat;
+ if (!strcmp(self->filename, "-")) {
+ self->fd_pipe = true;
+ self->fd = STDIN_FILENO;
+
+ if (perf_header__read(self, self->fd) < 0)
+ pr_err("incompatible file format");
+
+ return 0;
+ }
+
self->fd = open(self->filename, O_RDONLY);
if (self->fd < 0) {
pr_err("failed to open file: %s", self->filename);
goto out_close;
}
- if (perf_header__read(&self->header, self->fd) < 0) {
+ if (perf_header__read(self, self->fd) < 0) {
pr_err("incompatible file format");
goto out_close;
}
return -1;
}
+void perf_session__update_sample_type(struct perf_session *self)
+{
+ self->sample_type = perf_header__sample_type(&self->header);
+}
+
struct perf_session *perf_session__new(const char *filename, int mode, bool force)
{
size_t len = filename ? strlen(filename) + 1 : 0;
goto out_delete;
}
- self->sample_type = perf_header__sample_type(&self->header);
+ perf_session__update_sample_type(self);
out:
return self;
out_free:
[PERF_RECORD_SAMPLE] = "SAMPLE",
};
-unsigned long event__total[PERF_RECORD_MAX];
+unsigned long event__total[PERF_RECORD_HEADER_MAX];
void event__print_totals(void)
{
int i;
- for (i = 0; i < PERF_RECORD_MAX; ++i)
+ for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
+ if (!event__name[i])
+ continue;
pr_info("%10s events: %10ld\n",
event__name[i], event__total[i]);
+ }
}
void mem_bswap_64(void *src, int byte_size)
[PERF_RECORD_LOST] = event__all64_swap,
[PERF_RECORD_READ] = event__read_swap,
[PERF_RECORD_SAMPLE] = event__all64_swap,
- [PERF_RECORD_MAX] = NULL,
+ [PERF_RECORD_HEADER_MAX] = NULL,
};
static int perf_session__process_event(struct perf_session *self,
{
trace_event(event);
- if (event->header.type < PERF_RECORD_MAX) {
+ if (event->header.type < PERF_RECORD_HEADER_MAX) {
dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
offset + head, event->header.size,
event__name[event->header.type]);
return thread;
}
+int do_read(int fd, void *buf, size_t size)
+{
+ void *buf_start = buf;
+
+ while (size) {
+ int ret = read(fd, buf, size);
+
+ if (ret <= 0)
+ return ret;
+
+ size -= ret;
+ buf += ret;
+ }
+
+ return buf - buf_start;
+}
+
+#define session_done() (*(volatile int *)(&session_done))
+volatile int session_done;
+
+static int __perf_session__process_pipe_events(struct perf_session *self,
+ struct perf_event_ops *ops)
+{
+ event_t event;
+ uint32_t size;
+ int skip = 0;
+ u64 head;
+ int err;
+ void *p;
+
+ perf_event_ops__fill_defaults(ops);
+
+ head = 0;
+more:
+ err = do_read(self->fd, &event, sizeof(struct perf_event_header));
+ if (err <= 0) {
+ if (err == 0)
+ goto done;
+
+ pr_err("failed to read event header\n");
+ goto out_err;
+ }
+
+ if (self->header.needs_swap)
+ perf_event_header__bswap(&event.header);
+
+ size = event.header.size;
+ if (size == 0)
+ size = 8;
+
+ p = &event;
+ p += sizeof(struct perf_event_header);
+
+ err = do_read(self->fd, p, size - sizeof(struct perf_event_header));
+ if (err <= 0) {
+ if (err == 0) {
+ pr_err("unexpected end of event stream\n");
+ goto done;
+ }
+
+ pr_err("failed to read event data\n");
+ goto out_err;
+ }
+
+ if (size == 0 ||
+ (skip = perf_session__process_event(self, &event, ops,
+ 0, head)) < 0) {
+ dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
+ head, event.header.size, event.header.type);
+ /*
+ * assume we lost track of the stream, check alignment, and
+ * increment a single u64 in the hope to catch on again 'soon'.
+ */
+ if (unlikely(head & 7))
+ head &= ~7ULL;
+
+ size = 8;
+ }
+
+ head += size;
+
+ dump_printf("\n%#Lx [%#x]: event: %d\n",
+ head, event.header.size, event.header.type);
+
+ if (skip > 0)
+ head += skip;
+
+ if (!session_done())
+ goto more;
+done:
+ err = 0;
+out_err:
+ return err;
+}
+
int __perf_session__process_events(struct perf_session *self,
u64 data_offset, u64 data_size,
u64 file_size, struct perf_event_ops *ops)
self->cwdlen = strlen(self->cwd);
}
- err = __perf_session__process_events(self, self->header.data_offset,
- self->header.data_size,
- self->size, ops);
+ if (!self->fd_pipe)
+ err = __perf_session__process_events(self,
+ self->header.data_offset,
+ self->header.data_size,
+ self->size, ops);
+ else
+ err = __perf_session__process_pipe_events(self, ops);
out_err:
return err;
}