perf: Convert perf tracing data into a tracing_data event
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 skip return value added to the event processing loop in a previous patch. Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Cc: fweisbec@gmail.com Cc: rostedt@goodmis.org Cc: k-keiichi@bx.jp.nec.com Cc: acme@ghostprotocols.net LKML-Reference: <1270184365-8281-8-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
cd19a035f3
commit
9215545e99
|
@ -104,6 +104,11 @@ static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
|
||||||
pc->data_tail = tail;
|
pc->data_tail = tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void advance_output(size_t size)
|
||||||
|
{
|
||||||
|
bytes_written += size;
|
||||||
|
}
|
||||||
|
|
||||||
static void write_output(void *buf, size_t size)
|
static void write_output(void *buf, size_t size)
|
||||||
{
|
{
|
||||||
while (size) {
|
while (size) {
|
||||||
|
@ -599,6 +604,17 @@ static int __cmd_record(int argc, const char **argv)
|
||||||
pr_err("Couldn't synthesize event_types.\n");
|
pr_err("Couldn't synthesize event_types.\n");
|
||||||
return err;
|
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,
|
err = event__synthesize_kernel_mmap(process_synthesized_event,
|
||||||
|
|
|
@ -269,6 +269,7 @@ static struct perf_event_ops event_ops = {
|
||||||
.read = process_read_event,
|
.read = process_read_event,
|
||||||
.attr = event__process_attr,
|
.attr = event__process_attr,
|
||||||
.event_type = event__process_event_type,
|
.event_type = event__process_event_type,
|
||||||
|
.tracing_data = event__process_tracing_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern volatile int session_done;
|
extern volatile int session_done;
|
||||||
|
|
|
@ -106,6 +106,7 @@ static struct perf_event_ops event_ops = {
|
||||||
.comm = event__process_comm,
|
.comm = event__process_comm,
|
||||||
.attr = event__process_attr,
|
.attr = event__process_attr,
|
||||||
.event_type = event__process_event_type,
|
.event_type = event__process_event_type,
|
||||||
|
.tracing_data = event__process_tracing_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern volatile int session_done;
|
extern volatile int session_done;
|
||||||
|
|
|
@ -86,6 +86,7 @@ struct build_id_event {
|
||||||
enum perf_header_event_type { /* above any possible kernel type */
|
enum perf_header_event_type { /* above any possible kernel type */
|
||||||
PERF_RECORD_HEADER_ATTR = 64,
|
PERF_RECORD_HEADER_ATTR = 64,
|
||||||
PERF_RECORD_HEADER_EVENT_TYPE = 65,
|
PERF_RECORD_HEADER_EVENT_TYPE = 65,
|
||||||
|
PERF_RECORD_HEADER_TRACING_DATA = 66,
|
||||||
PERF_RECORD_HEADER_MAX
|
PERF_RECORD_HEADER_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,6 +108,11 @@ struct event_type_event {
|
||||||
struct perf_trace_event_type event_type;
|
struct perf_trace_event_type event_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tracing_data_event {
|
||||||
|
struct perf_event_header header;
|
||||||
|
u32 size;
|
||||||
|
};
|
||||||
|
|
||||||
typedef union event_union {
|
typedef union event_union {
|
||||||
struct perf_event_header header;
|
struct perf_event_header header;
|
||||||
struct ip_event ip;
|
struct ip_event ip;
|
||||||
|
@ -118,6 +124,7 @@ typedef union event_union {
|
||||||
struct sample_event sample;
|
struct sample_event sample;
|
||||||
struct attr_event attr;
|
struct attr_event attr;
|
||||||
struct event_type_event event_type;
|
struct event_type_event event_type;
|
||||||
|
struct tracing_data_event tracing_data;
|
||||||
} event_t;
|
} event_t;
|
||||||
|
|
||||||
struct events_stats {
|
struct events_stats {
|
||||||
|
|
|
@ -934,3 +934,55 @@ int event__process_event_type(event_t *self,
|
||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -111,5 +111,11 @@ int event__synthesize_event_types(event__handler_t process,
|
||||||
int event__process_event_type(event_t *self,
|
int event__process_event_type(event_t *self,
|
||||||
struct perf_session *session);
|
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 */
|
#endif /* __PERF_HEADER_H */
|
||||||
|
|
|
@ -204,6 +204,8 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
|
||||||
handler->attr = process_event_stub;
|
handler->attr = process_event_stub;
|
||||||
if (handler->event_type == NULL)
|
if (handler->event_type == NULL)
|
||||||
handler->event_type = process_event_stub;
|
handler->event_type = process_event_stub;
|
||||||
|
if (handler->tracing_data == NULL)
|
||||||
|
handler->tracing_data = process_event_stub;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *event__name[] = {
|
static const char *event__name[] = {
|
||||||
|
@ -219,6 +221,7 @@ static const char *event__name[] = {
|
||||||
[PERF_RECORD_SAMPLE] = "SAMPLE",
|
[PERF_RECORD_SAMPLE] = "SAMPLE",
|
||||||
[PERF_RECORD_HEADER_ATTR] = "ATTR",
|
[PERF_RECORD_HEADER_ATTR] = "ATTR",
|
||||||
[PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
|
[PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
|
||||||
|
[PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned long event__total[PERF_RECORD_HEADER_MAX];
|
unsigned long event__total[PERF_RECORD_HEADER_MAX];
|
||||||
|
@ -311,6 +314,11 @@ static void event__event_type_swap(event_t *self)
|
||||||
bswap_64(self->event_type.event_type.event_id);
|
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);
|
typedef void (*event__swap_op)(event_t *self);
|
||||||
|
|
||||||
static event__swap_op event__swap_ops[] = {
|
static event__swap_op event__swap_ops[] = {
|
||||||
|
@ -323,6 +331,7 @@ static event__swap_op event__swap_ops[] = {
|
||||||
[PERF_RECORD_SAMPLE] = event__all64_swap,
|
[PERF_RECORD_SAMPLE] = event__all64_swap,
|
||||||
[PERF_RECORD_HEADER_ATTR] = event__attr_swap,
|
[PERF_RECORD_HEADER_ATTR] = event__attr_swap,
|
||||||
[PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap,
|
[PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap,
|
||||||
|
[PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap,
|
||||||
[PERF_RECORD_HEADER_MAX] = NULL,
|
[PERF_RECORD_HEADER_MAX] = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -367,6 +376,10 @@ static int perf_session__process_event(struct perf_session *self,
|
||||||
return ops->attr(event, self);
|
return ops->attr(event, self);
|
||||||
case PERF_RECORD_HEADER_EVENT_TYPE:
|
case PERF_RECORD_HEADER_EVENT_TYPE:
|
||||||
return ops->event_type(event, self);
|
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:
|
default:
|
||||||
self->unknown_events++;
|
self->unknown_events++;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -46,7 +46,8 @@ struct perf_event_ops {
|
||||||
throttle,
|
throttle,
|
||||||
unthrottle,
|
unthrottle,
|
||||||
attr,
|
attr,
|
||||||
event_type;
|
event_type,
|
||||||
|
tracing_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct perf_session *perf_session__new(const char *filename, int mode, bool force);
|
struct perf_session *perf_session__new(const char *filename, int mode, bool force);
|
||||||
|
|
|
@ -154,10 +154,17 @@ static void put_tracing_file(char *file)
|
||||||
free(file);
|
free(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t calc_data_size;
|
||||||
|
|
||||||
static ssize_t write_or_die(const void *buf, size_t len)
|
static ssize_t write_or_die(const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (calc_data_size) {
|
||||||
|
calc_data_size += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
ret = write(output_fd, buf, len);
|
ret = write(output_fd, buf, len);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
die("writing to '%s'", output_file);
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -50,14 +50,37 @@ static int long_size;
|
||||||
|
|
||||||
static unsigned long page_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)
|
static int read_or_die(void *data, int size)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = read(input_fd, data, size);
|
r = do_read(input_fd, data, size);
|
||||||
if (r != size)
|
if (r <= 0)
|
||||||
die("reading input file (size expected=%d received=%d)",
|
die("reading input file (size expected=%d received=%d)",
|
||||||
size, r);
|
size, r);
|
||||||
|
|
||||||
|
if (calc_data_size)
|
||||||
|
calc_data_size += r;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,56 +105,28 @@ static char *read_string(void)
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
int i;
|
|
||||||
off_t r;
|
off_t r;
|
||||||
|
char c;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
r = read(input_fd, buf, BUFSIZ);
|
r = read(input_fd, &c, 1);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
die("reading input file");
|
die("reading input file");
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
die("no data");
|
die("no data");
|
||||||
|
|
||||||
for (i = 0; i < r; i++) {
|
buf[size++] = c;
|
||||||
if (!buf[i])
|
|
||||||
|
if (!c)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i < r)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (str) {
|
if (calc_data_size)
|
||||||
size += BUFSIZ;
|
calc_data_size += size;
|
||||||
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);
|
str = malloc_or_die(size);
|
||||||
memcpy(str, buf, size);
|
memcpy(str, buf, size);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -459,7 +454,7 @@ struct record *trace_read_data(int cpu)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_report(int fd)
|
ssize_t trace_report(int fd)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
char test[] = { 23, 8, 68 };
|
char test[] = { 23, 8, 68 };
|
||||||
|
@ -467,6 +462,9 @@ void trace_report(int fd)
|
||||||
int show_version = 0;
|
int show_version = 0;
|
||||||
int show_funcs = 0;
|
int show_funcs = 0;
|
||||||
int show_printk = 0;
|
int show_printk = 0;
|
||||||
|
ssize_t size;
|
||||||
|
|
||||||
|
calc_data_size = 1;
|
||||||
|
|
||||||
input_fd = fd;
|
input_fd = fd;
|
||||||
|
|
||||||
|
@ -499,14 +497,17 @@ void trace_report(int fd)
|
||||||
read_proc_kallsyms();
|
read_proc_kallsyms();
|
||||||
read_ftrace_printk();
|
read_ftrace_printk();
|
||||||
|
|
||||||
|
size = calc_data_size - 1;
|
||||||
|
calc_data_size = 0;
|
||||||
|
|
||||||
if (show_funcs) {
|
if (show_funcs) {
|
||||||
print_funcs();
|
print_funcs();
|
||||||
return;
|
return size;
|
||||||
}
|
}
|
||||||
if (show_printk) {
|
if (show_printk) {
|
||||||
print_printk();
|
print_printk();
|
||||||
return;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ struct record *trace_read_data(int cpu);
|
||||||
|
|
||||||
void parse_set_info(int nr_cpus, int long_sz);
|
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);
|
void *malloc_or_die(unsigned int size);
|
||||||
|
|
||||||
|
@ -259,6 +259,8 @@ void *raw_field_ptr(struct event *event, const char *name, void *data);
|
||||||
unsigned long long eval_flag(const char *flag);
|
unsigned long long eval_flag(const char *flag);
|
||||||
|
|
||||||
int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
|
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 */
|
/* taken from kernel/trace/trace.h */
|
||||||
enum trace_flag_type {
|
enum trace_flag_type {
|
||||||
|
|
Loading…
Reference in New Issue