summaryrefslogtreecommitdiff
path: root/tools/perf/util/trace-event-parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/trace-event-parse.c')
-rw-r--r--tools/perf/util/trace-event-parse.c350
1 files changed, 345 insertions, 5 deletions
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 94775199644e..4ec165a334e2 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -1,18 +1,358 @@
+/*
+ * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
#include "../perf.h"
#include "util.h"
#include "trace-event.h"
-int common_pc(struct scripting_context *context)
+int header_page_size_size;
+int header_page_ts_size;
+int header_page_data_offset;
+
+struct pevent *perf_pevent;
+static struct pevent *pevent;
+
+bool latency_format;
+
+int read_trace_init(int file_bigendian, int host_bigendian)
{
- return parse_common_pc(context->event_data);
+ if (pevent)
+ return 0;
+
+ perf_pevent = pevent_alloc();
+ pevent = perf_pevent;
+
+ pevent_set_file_bigendian(pevent, file_bigendian);
+ pevent_set_host_bigendian(pevent, host_bigendian);
+
+ return 0;
}
-int common_flags(struct scripting_context *context)
+static int get_common_field(struct scripting_context *context,
+ int *offset, int *size, const char *type)
{
- return parse_common_flags(context->event_data);
+ struct event_format *event;
+ struct format_field *field;
+
+ if (!*size) {
+ if (!pevent->events)
+ return 0;
+
+ event = pevent->events[0];
+ field = pevent_find_common_field(event, type);
+ if (!field)
+ return 0;
+ *offset = field->offset;
+ *size = field->size;
+ }
+
+ return pevent_read_number(pevent, context->event_data + *offset, *size);
}
int common_lock_depth(struct scripting_context *context)
{
- return parse_common_lock_depth(context->event_data);
+ static int offset;
+ static int size;
+ int ret;
+
+ ret = get_common_field(context, &size, &offset,
+ "common_lock_depth");
+ if (ret < 0)
+ return -1;
+
+ return ret;
+}
+
+int common_flags(struct scripting_context *context)
+{
+ static int offset;
+ static int size;
+ int ret;
+
+ ret = get_common_field(context, &size, &offset,
+ "common_flags");
+ if (ret < 0)
+ return -1;
+
+ return ret;
+}
+
+int common_pc(struct scripting_context *context)
+{
+ static int offset;
+ static int size;
+ int ret;
+
+ ret = get_common_field(context, &size, &offset,
+ "common_preempt_count");
+ if (ret < 0)
+ return -1;
+
+ return ret;
+}
+
+unsigned long long
+raw_field_value(struct event_format *event, const char *name, void *data)
+{
+ struct format_field *field;
+ unsigned long long val;
+
+ field = pevent_find_any_field(event, name);
+ if (!field)
+ return 0ULL;
+
+ pevent_read_number_field(field, data, &val);
+
+ return val;
+}
+
+void *raw_field_ptr(struct event_format *event, const char *name, void *data)
+{
+ struct format_field *field;
+
+ field = pevent_find_any_field(event, name);
+ if (!field)
+ return NULL;
+
+ if (field->flags & FIELD_IS_DYNAMIC) {
+ int offset;
+
+ offset = *(int *)(data + field->offset);
+ offset &= 0xffff;
+
+ return data + offset;
+ }
+
+ return data + field->offset;
+}
+
+int trace_parse_common_type(void *data)
+{
+ struct record record;
+
+ record.data = data;
+ return pevent_data_type(pevent, &record);
+}
+
+int trace_parse_common_pid(void *data)
+{
+ struct record record;
+
+ record.data = data;
+ return pevent_data_pid(pevent, &record);
+}
+
+unsigned long long read_size(void *ptr, int size)
+{
+ return pevent_read_number(pevent, ptr, size);
+}
+
+struct event_format *trace_find_event(int type)
+{
+ return pevent_find_event(pevent, type);
+}
+
+
+void print_trace_event(int cpu, void *data, int size)
+{
+ struct event_format *event;
+ struct record record;
+ struct trace_seq s;
+ int type;
+
+ type = trace_parse_common_type(data);
+
+ event = trace_find_event(type);
+ if (!event) {
+ warning("ug! no event found for type %d", type);
+ return;
+ }
+
+ memset(&record, 0, sizeof(record));
+ record.cpu = cpu;
+ record.size = size;
+ record.data = data;
+
+ trace_seq_init(&s);
+ pevent_print_event(pevent, &s, &record);
+ trace_seq_do_printf(&s);
+ printf("\n");
+}
+
+void print_event(int cpu, void *data, int size, unsigned long long nsecs,
+ char *comm)
+{
+ struct record record;
+ struct trace_seq s;
+ int pid;
+
+ pevent->latency_format = latency_format;
+
+ record.ts = nsecs;
+ record.cpu = cpu;
+ record.size = size;
+ record.data = data;
+ pid = pevent_data_pid(pevent, &record);
+
+ if (!pevent_pid_is_registered(pevent, pid))
+ pevent_register_comm(pevent, comm, pid);
+
+ trace_seq_init(&s);
+ pevent_print_event(pevent, &s, &record);
+ trace_seq_do_printf(&s);
+ printf("\n");
+}
+
+void parse_proc_kallsyms(char *file, unsigned int size __unused)
+{
+ unsigned long long addr;
+ char *func;
+ char *line;
+ char *next = NULL;
+ char *addr_str;
+ char *mod;
+ char ch;
+
+ line = strtok_r(file, "\n", &next);
+ while (line) {
+ mod = NULL;
+ sscanf(line, "%as %c %as\t[%as",
+ (float *)(void *)&addr_str, /* workaround gcc warning */
+ &ch, (float *)(void *)&func, (float *)(void *)&mod);
+ addr = strtoull(addr_str, NULL, 16);
+ free(addr_str);
+
+ /* truncate the extra ']' */
+ if (mod)
+ mod[strlen(mod) - 1] = 0;
+
+ pevent_register_function(pevent, func, addr, mod);
+ free(func);
+ free(mod);
+
+ line = strtok_r(NULL, "\n", &next);
+ }
+}
+
+void parse_ftrace_printk(char *file, unsigned int size __unused)
+{
+ unsigned long long addr;
+ char *printk;
+ char *line;
+ char *next = NULL;
+ char *addr_str;
+ char *fmt;
+
+ line = strtok_r(file, "\n", &next);
+ while (line) {
+ addr_str = strtok_r(line, ":", &fmt);
+ if (!addr_str) {
+ warning("printk format with empty entry");
+ break;
+ }
+ addr = strtoull(addr_str, NULL, 16);
+ /* fmt still has a space, skip it */
+ printk = strdup(fmt+1);
+ line = strtok_r(NULL, "\n", &next);
+ pevent_register_print_string(pevent, printk, addr);
+ }
+}
+
+int parse_ftrace_file(char *buf, unsigned long size)
+{
+ return pevent_parse_event(pevent, buf, size, "ftrace");
+}
+
+int parse_event_file(char *buf, unsigned long size, char *sys)
+{
+ return pevent_parse_event(pevent, buf, size, sys);
+}
+
+struct event_format *trace_find_next_event(struct event_format *event)
+{
+ static int idx;
+
+ if (!pevent->events)
+ return NULL;
+
+ if (!event) {
+ idx = 0;
+ return pevent->events[0];
+ }
+
+ if (idx < pevent->nr_events && event == pevent->events[idx]) {
+ idx++;
+ if (idx == pevent->nr_events)
+ return NULL;
+ return pevent->events[idx];
+ }
+
+ for (idx = 1; idx < pevent->nr_events; idx++) {
+ if (event == pevent->events[idx - 1])
+ return pevent->events[idx];
+ }
+ return NULL;
+}
+
+struct flag {
+ const char *name;
+ unsigned long long value;
+};
+
+static const struct flag flags[] = {
+ { "HI_SOFTIRQ", 0 },
+ { "TIMER_SOFTIRQ", 1 },
+ { "NET_TX_SOFTIRQ", 2 },
+ { "NET_RX_SOFTIRQ", 3 },
+ { "BLOCK_SOFTIRQ", 4 },
+ { "BLOCK_IOPOLL_SOFTIRQ", 5 },
+ { "TASKLET_SOFTIRQ", 6 },
+ { "SCHED_SOFTIRQ", 7 },
+ { "HRTIMER_SOFTIRQ", 8 },
+ { "RCU_SOFTIRQ", 9 },
+
+ { "HRTIMER_NORESTART", 0 },
+ { "HRTIMER_RESTART", 1 },
+};
+
+unsigned long long eval_flag(const char *flag)
+{
+ int i;
+
+ /*
+ * Some flags in the format files do not get converted.
+ * If the flag is not numeric, see if it is something that
+ * we already know about.
+ */
+ if (isdigit(flag[0]))
+ return strtoull(flag, NULL, 0);
+
+ for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
+ if (strcmp(flags[i].name, flag) == 0)
+ return flags[i].value;
+
+ return 0;
}