[RFC PATCH 5/7] perf: convert perf tracing data into a tracing_data event

From: Tom Zanussi
Date: Wed Mar 03 2010 - 02:06:44 EST


Bypasses the tracing_data perf header code and replaces it with a
synthesized event and processing function that accomplishes the same
thing, used when reading/writing perf data to/from a pipe.

The tracing data is pretty large, and this patch doesn't attempt to
break it down into component events. The tracing_data event itself
doesn't actually contain the tracing data, rather it arranges for the
event processing code to skip over it after it's read, using the
'action' added in a previous patch; in this case the action is 'skip'.

Signed-off-by: Tom Zanussi <tzanussi@xxxxxxxxx>
---
tools/perf/builtin-record.c | 16 ++++++
tools/perf/util/event.h | 7 +++
tools/perf/util/header.c | 53 +++++++++++++++++++++
tools/perf/util/header.h | 6 ++
tools/perf/util/session.c | 14 ++++++
tools/perf/util/session.h | 3 +-
tools/perf/util/trace-event-info.c | 24 ++++++++++
tools/perf/util/trace-event-read.c | 89 ++++++++++++++++++------------------
tools/perf/util/trace-event.h | 4 +-
9 files changed, 170 insertions(+), 46 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 0e3d4cd..95bccdc 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -101,6 +101,11 @@ static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
pc->data_tail = tail;
}

+static void advance_output(size_t size)
+{
+ bytes_written += size;
+}
+
static void write_output(void *buf, size_t size)
{
while (size) {
@@ -581,6 +586,17 @@ static int __cmd_record(int argc, const char **argv)
pr_err("Couldn't synthesize event_types.\n");
return err;
}
+
+ err = event__synthesize_tracing_data(output, attrs,
+ nr_counters,
+ process_synthesized_event,
+ session);
+ if (err <= 0) {
+ pr_err("Couldn't record tracing data.\n");
+ return err;
+ }
+
+ advance_output(err);
}

err = event__synthesize_kernel_mmap(process_synthesized_event,
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index dc6d27b..c111358 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -86,6 +86,7 @@ struct build_id_event {
enum perf_header_event_type { /* above any possible kernel type */
PERF_RECORD_HEADER_ATTR = 64,
PERF_RECORD_HEADER_EVENT_TYPE = 65,
+ PERF_RECORD_HEADER_TRACING_DATA = 66,
PERF_RECORD_HEADER_MAX
};

@@ -107,6 +108,11 @@ struct event_type_event {
struct perf_trace_event_type event_type;
};

+struct tracing_data_event {
+ struct perf_event_header header;
+ u32 size;
+};
+
typedef union event_union {
struct perf_event_header header;
struct ip_event ip;
@@ -118,6 +124,7 @@ typedef union event_union {
struct sample_event sample;
struct attr_event attr;
struct event_type_event event_type;
+ struct tracing_data_event tracing_data;
} event_t;

struct events_stats {
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index cb75e66..5910aee 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -708,6 +708,7 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
perf_event_ops__fill_stop(&header_ops);
header_ops.attr = event__process_attr;
header_ops.event_type = event__process_event_type;
+ header_ops.tracing_data = event__process_tracing_data;
session->fd = fd;

return perf_session__process_events(session, &header_ops);
@@ -954,3 +955,55 @@ int event__process_event_type(event_t *self,

return 0;
}
+
+int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
+ int nb_events,
+ event__handler_t process,
+ struct perf_session *session __unused)
+{
+ event_t ev;
+ ssize_t size = 0, aligned_size = 0, padding;
+ int err = 0;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
+ size = read_tracing_data_size(fd, pattrs, nb_events);
+ if (size <= 0)
+ return size;
+ aligned_size = ALIGN(size, sizeof(u64));
+ padding = aligned_size - size;
+ ev.tracing_data.header.size = sizeof(ev.tracing_data);
+ ev.tracing_data.size = aligned_size;
+
+ process(&ev, session);
+
+ err = read_tracing_data(fd, pattrs, nb_events);
+ write_padded(fd, NULL, 0, padding);
+
+ return aligned_size;
+}
+
+int event__process_tracing_data(event_t *self,
+ struct perf_session *session)
+{
+ ssize_t size_read, padding, size = self->tracing_data.size;
+ off_t offset = lseek(session->fd, 0, SEEK_CUR);
+ char buf[BUFSIZ];
+
+ /* setup for reading amidst mmap */
+ lseek(session->fd, offset + sizeof(struct tracing_data_event),
+ SEEK_SET);
+
+ size_read = trace_report(session->fd);
+
+ padding = ALIGN(size_read, sizeof(u64)) - size_read;
+
+ if (read(session->fd, buf, padding) < 0)
+ die("reading input file");
+
+ if (size_read + padding != size)
+ die("tracing data size mismatch");
+
+ return size_read + padding;
+}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 9d18c9b..a83f375 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -111,5 +111,11 @@ int event__synthesize_event_types(event__handler_t process,
int event__process_event_type(event_t *self,
struct perf_session *session);

+int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
+ int nb_events,
+ event__handler_t process,
+ struct perf_session *session);
+int event__process_tracing_data(event_t *self,
+ struct perf_session *session);

#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index d704bdf..74e9646 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -213,6 +213,8 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
handler->attr = process_event_stub;
if (handler->event_type == NULL)
handler->event_type = process_event_stub;
+ if (handler->tracing_data == NULL)
+ handler->tracing_data = process_event_stub;
}

static int process_event_stop(event_t *event __used,
@@ -235,6 +237,7 @@ void perf_event_ops__fill_stop(struct perf_event_ops *handler)
handler->unthrottle = process_event_stop;
handler->attr = process_event_stop;
handler->event_type = process_event_stop;
+ handler->tracing_data = process_event_stop;
}

static const char *event__name[] = {
@@ -250,6 +253,7 @@ static const char *event__name[] = {
[PERF_RECORD_SAMPLE] = "SAMPLE",
[PERF_RECORD_HEADER_ATTR] = "ATTR",
[PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
+ [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
};

unsigned long event__total[PERF_RECORD_HEADER_MAX];
@@ -342,6 +346,11 @@ static void event__event_type_swap(event_t *self)
bswap_64(self->event_type.event_type.event_id);
}

+static void event__tracing_data_swap(event_t *self)
+{
+ self->tracing_data.size = bswap_32(self->tracing_data.size);
+}
+
typedef void (*event__swap_op)(event_t *self);

static event__swap_op event__swap_ops[] = {
@@ -354,6 +363,7 @@ static event__swap_op event__swap_ops[] = {
[PERF_RECORD_SAMPLE] = event__all64_swap,
[PERF_RECORD_HEADER_ATTR] = event__attr_swap,
[PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap,
+ [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap,
[PERF_RECORD_HEADER_MAX] = NULL,
};

@@ -398,6 +408,10 @@ static int perf_session__process_event(struct perf_session *self,
return ops->attr(event, self);
case PERF_RECORD_HEADER_EVENT_TYPE:
return ops->event_type(event, self);
+ case PERF_RECORD_HEADER_TRACING_DATA:
+ /* setup for reading amidst mmap */
+ lseek(self->fd, offset + head, SEEK_SET);
+ return ops->tracing_data(event, self);
default:
self->unknown_events++;
return -1;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index ea9eb4a..a648af0 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -45,7 +45,8 @@ struct perf_event_ops {
throttle,
unthrottle,
attr,
- event_type;
+ event_type,
+ tracing_data;
};

/*
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 5ea8973..30cd9b5 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -154,10 +154,17 @@ static void put_tracing_file(char *file)
free(file);
}

+static ssize_t calc_data_size;
+
static ssize_t write_or_die(const void *buf, size_t len)
{
int ret;

+ if (calc_data_size) {
+ calc_data_size += len;
+ return len;
+ }
+
ret = write(output_fd, buf, len);
if (ret < 0)
die("writing to '%s'", output_file);
@@ -526,3 +533,20 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)

return 0;
}
+
+ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
+ int nb_events)
+{
+ ssize_t size;
+ int err = 0;
+
+ calc_data_size = 1;
+ err = read_tracing_data(fd, pattrs, nb_events);
+ size = calc_data_size - 1;
+ calc_data_size = 0;
+
+ if (err < 0)
+ return err;
+
+ return size;
+}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 7cd1193..44889c9 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -50,14 +50,37 @@ static int long_size;

static unsigned long page_size;

+static ssize_t calc_data_size;
+
+static int do_read(int fd, void *buf, int size)
+{
+ int rsize = size;
+
+ while (size) {
+ int ret = read(fd, buf, size);
+
+ if (ret <= 0)
+ return -1;
+
+ size -= ret;
+ buf += ret;
+ }
+
+ return rsize;
+}
+
static int read_or_die(void *data, int size)
{
int r;

- r = read(input_fd, data, size);
- if (r != size)
+ r = do_read(input_fd, data, size);
+ if (r <= 0)
die("reading input file (size expected=%d received=%d)",
size, r);
+
+ if (calc_data_size)
+ calc_data_size += r;
+
return r;
}

@@ -82,56 +105,28 @@ static char *read_string(void)
char buf[BUFSIZ];
char *str = NULL;
int size = 0;
- int i;
off_t r;
+ char c;

for (;;) {
- r = read(input_fd, buf, BUFSIZ);
+ r = read(input_fd, &c, 1);
if (r < 0)
die("reading input file");

if (!r)
die("no data");

- for (i = 0; i < r; i++) {
- if (!buf[i])
- break;
- }
- if (i < r)
- break;
+ buf[size++] = c;

- if (str) {
- size += BUFSIZ;
- str = realloc(str, size);
- if (!str)
- die("malloc of size %d", size);
- memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
- } else {
- size = BUFSIZ;
- str = malloc_or_die(size);
- memcpy(str, buf, size);
- }
+ if (!c)
+ break;
}

- /* trailing \0: */
- i++;
-
- /* move the file descriptor to the end of the string */
- r = lseek(input_fd, -(r - i), SEEK_CUR);
- if (r == (off_t)-1)
- die("lseek");
-
- if (str) {
- size += i;
- str = realloc(str, size);
- if (!str)
- die("malloc of size %d", size);
- memcpy(str + (size - i), buf, i);
- } else {
- size = i;
- str = malloc_or_die(i);
- memcpy(str, buf, i);
- }
+ if (calc_data_size)
+ calc_data_size += size;
+
+ str = malloc_or_die(size);
+ memcpy(str, buf, size);

return str;
}
@@ -459,7 +454,7 @@ struct record *trace_read_data(int cpu)
return data;
}

-void trace_report(int fd)
+ssize_t trace_report(int fd)
{
char buf[BUFSIZ];
char test[] = { 23, 8, 68 };
@@ -467,6 +462,9 @@ void trace_report(int fd)
int show_version = 0;
int show_funcs = 0;
int show_printk = 0;
+ ssize_t size;
+
+ calc_data_size = 1;

input_fd = fd;

@@ -499,14 +497,17 @@ void trace_report(int fd)
read_proc_kallsyms();
read_ftrace_printk();

+ size = calc_data_size - 1;
+ calc_data_size = 0;
+
if (show_funcs) {
print_funcs();
- return;
+ return size;
}
if (show_printk) {
print_printk();
- return;
+ return size;
}

- return;
+ return size;
}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index c3269b9..0cb5866 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -162,7 +162,7 @@ struct record *trace_read_data(int cpu);

void parse_set_info(int nr_cpus, int long_sz);

-void trace_report(int fd);
+ssize_t trace_report(int fd);

void *malloc_or_die(unsigned int size);

@@ -258,6 +258,8 @@ void *raw_field_ptr(struct event *event, const char *name, void *data);
unsigned long long eval_flag(const char *flag);

int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
+ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
+ int nb_events);

/* taken from kernel/trace/trace.h */
enum trace_flag_type {
--
1.6.4.GIT

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/