perf: store and retrieve trace event names in the perf.data file

Arjan van de Ven
2009-08-09T21:49:35Z

In order to be able to use trace events, a key aspect is the "type" field;
this is the id of the event that you recorded, as stored in the /sys/kernel/debug/events/*/*/id file.
What is currently missing is a way to map the id number (which is not abi stable)
to the event that was recorded.
This patch adds the facility that stores the trace event name and id in the perf.data file,
and then allows users of it to map the ID back to the original string.

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b92a457..73eeefb 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -48,7 +48,7 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)

struct perf_header *perf_header__new(void)
{
- struct perf_header *self = malloc(sizeof(*self));
+ struct perf_header *self = malloc(sizeof(struct perf_header));

if (!self)
die("nomem");
@@ -86,6 +86,45 @@ void perf_header__add_attr(struct perf_header *self,
self->attr[pos] = attr;
}

+struct perf_trace_event_type
+{
+ u64 event_id;
+ char name[64];
+};
+
+static int event_count;
+static struct perf_trace_event_type *events;
+
+void perf_header__push_event(u64 id, const char *name)
+{
+ if (strlen(name) > 64) {
+ printf("Event %s will be truncated\n", name);
+ }
+ if (!events) {
+ events = malloc(sizeof(struct perf_trace_event_type));
+ if (!events)
+ die("nomem");
+ } else {
+ events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type));
+ if (!events)
+ die("nomem");
+ }
+ memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
+ events[event_count].event_id = id;
+ strncpy(events[event_count].name, name, 63);
+ event_count++;
+}
+
+char * perf_header__find_event(u64 id)
+{
+ int i;
+ for (i = 0 ; i < event_count; i++) {
+ if (events[i].event_id == id)
+ return events[i].name;
+ }
+ return NULL;
+}
+
static const char *__perf_magic = "PERFFILE";

#define PERF_MAGIC (*(u64 *)__perf_magic)
@@ -106,6 +145,7 @@ struct perf_file_header {
u64 attr_size;
struct perf_file_section attrs;
struct perf_file_section data;
+ struct perf_file_section event_types;
};

static void do_write(int fd, void *buf, size_t size)
@@ -154,6 +194,11 @@ void perf_header__write(struct perf_header *self, int fd)
do_write(fd, &f_attr, sizeof(f_attr));
}

+ self->event_offset = lseek(fd, 0, SEEK_CUR);
+ self->event_size = event_count * sizeof(struct perf_trace_event_type);
+ if (events)
+ do_write(fd, events, self->event_size);
+

self->data_offset = lseek(fd, 0, SEEK_CUR);

@@ -169,6 +214,10 @@ void perf_header__write(struct perf_header *self, int fd)
.offset = self->data_offset,
.size = self->data_size,
},
+ .event_types = {
+ .offset = self->event_offset,
+ .size = self->event_size,
+ },
};

lseek(fd, 0, SEEK_SET);
@@ -237,6 +286,20 @@ struct perf_header *perf_header__read(int fd)
self->data_offset = f_header.data.offset;
self->data_size = f_header.data.size;

+ printf("event_types.size = %i \n", (int)f_header.event_types.size);
+
+ if (f_header.event_types.size) {
+
+ lseek(fd, f_header.event_types.offset, SEEK_SET);
+ events = malloc(f_header.event_types.size);
+ if (!events)
+ die("nomem");
+ do_read(fd, events, f_header.event_types.size);
+ event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
+ }
+ self->event_offset = f_header.event_types.offset;
+ self->event_size = f_header.event_types.size;
+
lseek(fd, self->data_offset + self->data_size, SEEK_SET);

self->frozen = 1;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index bf28044..606a8fb 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -19,6 +19,8 @@ struct perf_header {
s64 attr_offset;
u64 data_offset;
u64 data_size;
+ u64 event_offset;
+ u64 event_size;
};

struct perf_header *perf_header__read(int fd);
@@ -27,6 +29,10 @@ void perf_header__write(struct perf_header *self, int fd);
void perf_header__add_attr(struct perf_header *self,
struct perf_header_attr *attr);

+void perf_header__push_event(u64 id, const char *name);
+char * perf_header__find_event(u64 id);
+
+
struct perf_header_attr *
perf_header_attr__new(struct perf_counter_attr *attr);
void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4858d83..e8c5255 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -6,6 +6,7 @@
#include "exec_cmd.h"
#include "string.h"
#include "cache.h"
+#include "header.h"

extern char *strcasestr(const char *haystack, const char *needle);

@@ -543,10 +544,32 @@ static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
return 1;
}

+static void store_event_type(const char *orgname)
+{
+ char filename[PATH_MAX], *c;
+ FILE *file;
+ int id;
+
+ sprintf(filename, "/sys/kernel/debug/tracing/events/%s/id", orgname);
+ c = strchr(filename, ':');
+ if (c) *c = '/';
+
+ file = fopen(filename, "r");
+ if (!file)
+ return;
+ fscanf(file, "%i", &id);
+ fclose(file);
+ perf_header__push_event(id, orgname);
+}
+
+
int parse_events(const struct option *opt __used, const char *str, int unset __used)
{
struct perf_counter_attr attr;

+ if (strchr(str, ':'))
+ store_event_type(str);
+
for (;;) {
if (nr_counters == MAX_COUNTERS)
return -1;