[sysprof] Use two consecutive mappings of the ring buffer.



commit 08ba6bfbd369cd5315f3832115ac23bcd63bd7fc
Author: Søren Sandmann Pedersen <ssp redhat com>
Date:   Sun Sep 6 20:43:57 2009 -0400

    Use two consecutive mappings of the ring buffer.
    
    This allows us to not ignore wrapping and just process events instead
    of having to copy the data to temporary storage.

 collector.c |  171 +++++++++++++++++++++++------------------------------------
 1 files changed, 66 insertions(+), 105 deletions(-)
---
diff --git a/collector.c b/collector.c
index 524696c..fbc8580 100644
--- a/collector.c
+++ b/collector.c
@@ -127,130 +127,92 @@ sysprof_perf_counter_open (struct perf_counter_attr *attr,
     return syscall (__NR_perf_counter_open, attr, pid, cpu, group_fd, flags);
 }
 
-static int
-process_event (counter_t *counter, void *data)
-{
-    struct perf_event_header *header = data;
-    
-    counter->callback ((counter_event_t *)header, counter->user_data);
-
-    return header->size;
-}
-
-static int
-n_missing_bytes (const uint8_t *data, int n_bytes)
-{
-    const struct perf_event_header *header;
-    
-    if (n_bytes < sizeof (*header))
-	return sizeof (*header) - n_bytes;
-    
-    header = (const void *)data;
-    
-    if (n_bytes < header->size)
-	return header->size - n_bytes;
-    
-    return 0;
-}
-
-static void
-process_events (counter_t *counter, uint8_t *data, int n_bytes,
-		GString *partial)
-{
-    int n_events;
-    ssize_t n_missing;
-    
-    n_events = 0;
-    
-    while (n_bytes && (n_missing = n_missing_bytes (
-			   (uint8_t *)partial->str, partial->len)))
-    {
-	n_missing = MIN (n_bytes, n_missing);
-	
-	g_string_append_len (partial, (const char *)data, n_missing);
-	
-	data += n_missing;
-	n_bytes -= n_missing;
-    }
-
-    if (partial->len)
-    {
-	int n_used;
-	    
-	if (n_missing_bytes ((uint8_t *)partial->str, partial->len))
-	    return;
-    
-	n_used = process_event (counter, partial->str);
-
-	g_assert (n_used == partial->len);
-
-	g_string_truncate (partial, 0);
-    }
-    
-    while (n_bytes && !n_missing_bytes (data, n_bytes))
-    {
-	int n_used = process_event (counter, data);
-	
-	data += n_used;
-	n_bytes -= n_used;
-    }
-    
-    if (n_missing_bytes (data, n_bytes))
-	g_string_append_len (partial, (char *)data, n_bytes);
-}
-
-
 static void
 on_read (gpointer data)
 {
     uint64_t head, tail;
     counter_t *counter = data;
     int mask = (N_PAGES * process_get_page_size() - 1);
-    uint64_t size;
-    int diff;
-    
+#if 0
+    int n_bytes = mask + 1;
+    int x;
+#endif
+
     tail = counter->tail;
     
     head = counter->mmap_page->data_head;
     rmb();
     
-    diff = head - tail;
-    
-    if (diff < 0)
+    if (head < tail)
     {
-	g_warning ("sysprof fails at reading the buffer\n");
+	g_warning ("sysprof fails at ring buffers\n");
 	
 	tail = head;
     }
     
-    size = head - tail;
+#if 0
+    /* Verify that the double mapping works */
+    x = g_random_int() & mask;
+    g_assert (*(counter->data + x) == *(counter->data + x + n_bytes));
+#endif
     
-    if ((tail & mask) + size != (head & mask))
+    while (head - tail >= sizeof (struct perf_event_header))
     {
-	size = mask + 1 - (tail & mask);
-	
-	g_assert ((tail & mask) + size <= (N_PAGES * process_get_page_size()));
-	
-	process_events (counter, counter->data + (tail & mask),
-			size, counter->partial);
-	
-	tail += size;	
+	struct perf_event_header *header = (void *)(counter->data + (tail & mask));
+
+	if (header->size > head - tail)
+	{
+	    g_print ("asdf\n");
+	    break;
+	}
+
+	counter->callback ((counter_event_t *)header, counter->user_data);
+
+	tail += header->size;
     }
-    
-    size = head - tail;
-    
-    g_assert ((tail & mask) + size <= (N_PAGES * process_get_page_size()));
-    
-    process_events (counter,
-		    counter->data + (tail & mask), size, counter->partial);
-    
-    tail += size;
-    
+
     counter->tail = tail;
     counter->mmap_page->data_tail = tail;
 }
 
-#define fail(x)
+/* FIXME: return proper errors */
+#define fail(x)								\
+    do {								\
+	g_printerr ("the fail is strong %s\n", x);			\
+	exit (-1);							\
+    } while (0)
+
+static void *
+map_buffer (counter_t *counter)
+{ 
+    int n_bytes = N_PAGES * process_get_page_size();
+    void *address, *a;
+
+    address = mmap (NULL, n_bytes * 2 + process_get_page_size(), PROT_NONE,
+		    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+
+    if (address == MAP_FAILED)
+	fail ("mmap");
+
+    a = mmap (address + n_bytes, n_bytes + process_get_page_size(),
+	      PROT_READ | PROT_WRITE,
+	      MAP_SHARED | MAP_FIXED, counter->fd, 0);
+    
+    if (a != address + n_bytes)
+	fail ("mmap");
+
+    a = mmap (address, n_bytes + process_get_page_size(),
+	      PROT_READ | PROT_WRITE,
+	      MAP_SHARED | MAP_FIXED, counter->fd, 0);
+
+    if (a == MAP_FAILED)
+	fail ("mmap");
+
+    if (a != address)
+	fail ("mmap");
+
+    return address;
+}
 
 static counter_t *
 counter_new (int	      cpu,
@@ -283,11 +245,10 @@ counter_new (int	      cpu,
 	fail ("perf_counter_open");
 	return NULL;
     }
-    
+
     counter->fd = fd;
-    counter->mmap_page = mmap (
-	NULL, (N_PAGES + 1) * process_get_page_size(),
-	PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+    counter->mmap_page = map_buffer (counter);
     
     if (counter->mmap_page == MAP_FAILED)
     {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]