From 7099baac537b9e6456f4bb7faa6fda15e130c7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 1 Dec 2009 16:12:48 -0500 Subject: [PATCH] Handle wrap-around in perf event buffer This avoids the triple-mmap trick, which should work, but the third mmap returns EINVAL on my system. This patch just handles the wrap-around case by copying the event in question to a temp buffer. --- collector.c | 71 +++++++++++++++++++++++++--------------------------------- 1 files changed, 31 insertions(+), 40 deletions(-) diff --git a/collector.c b/collector.c index 6f5abe2..e98eac3 100644 --- a/collector.c +++ b/collector.c @@ -211,7 +211,8 @@ static void on_read (gpointer data) { counter_t *counter = data; - int mask = (N_PAGES * get_page_size() - 1); + int size = N_PAGES * get_page_size(); + int mask = size - 1, part; gboolean skip_samples; Collector *collector; uint64_t head, tail; @@ -250,6 +251,9 @@ on_read (gpointer data) while (head - tail >= sizeof (struct perf_event_header)) { struct perf_event_header *header = (void *)(counter->data + (tail & mask)); + counter_event_t *e; + uint32_t buffer[256]; + static int biggest = 0; if (header->size > head - tail) { @@ -265,7 +269,27 @@ on_read (gpointer data) if (header->type == PERF_EVENT_SAMPLE) collector->n_samples++; - process_event (collector, counter, (counter_event_t *)header); + if ((tail & mask) + header->size <= size) + { + e = (counter_event_t *) header; + process_event (collector, counter, e); + } + else + { + if (header->size > sizeof buffer) + e = g_malloc(header->size); + else + e = (counter_event_t *) buffer; + + part = size - (tail & mask); + memcpy(e, header, part); + memcpy((char *) e + part, counter->data, header->size - part); + process_event (collector, counter, e); + + if (e != (counter_event_t *) buffer) + g_free(e); + } + } tail += header->size; @@ -295,41 +319,6 @@ fail (GError **err, const char *what) return NULL; } - -static void * -map_buffer (counter_t *counter, GError **err) -{ - int n_bytes = N_PAGES * get_page_size(); - void *address, *a; - - /* We map the ring buffer twice in consecutive address space, - * so that we don't need special-case code to deal with wrapping. - */ - address = mmap (NULL, n_bytes * 2 + get_page_size(), PROT_NONE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - - if (address == MAP_FAILED) - return fail (err, "mmap"); - - a = mmap (address + n_bytes, n_bytes + get_page_size(), - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FIXED, counter->fd, 0); - - if (a != address + n_bytes) - return fail (err, "mmap"); - - a = mmap (address, n_bytes + get_page_size(), - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FIXED, counter->fd, 0); - - if (a == MAP_FAILED || a != address) - return fail (err, "mmap"); - - if (a != address) - return fail (err, "mmap"); - - return address; -} static counter_t * counter_new (Collector *collector, @@ -376,10 +365,12 @@ counter_new (Collector *collector, counter->collector = collector; counter->fd = fd; - counter->mmap_page = map_buffer (counter, err); + counter->mmap_page = + mmap (NULL, (N_PAGES + 1) * get_page_size(), + PROT_READ | PROT_WRITE, MAP_SHARED, counter->fd, 0); - if (!counter->mmap_page || counter->mmap_page == MAP_FAILED) - return NULL; + if (counter->mmap_page == MAP_FAILED) + return fail (err, "mmap"); counter->data = (uint8_t *)counter->mmap_page + get_page_size (); counter->tail = 0; -- 1.6.5.rc2