summaryrefslogtreecommitdiffstats
path: root/src/test/fio/ring_buffer.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/fio/ring_buffer.h')
-rw-r--r--src/test/fio/ring_buffer.h102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/test/fio/ring_buffer.h b/src/test/fio/ring_buffer.h
new file mode 100644
index 000000000..0e1eb62be
--- /dev/null
+++ b/src/test/fio/ring_buffer.h
@@ -0,0 +1,102 @@
+/*
+ * Very simple and fast lockless ring buffer implementatation for
+ * one producer and one consumer.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Do not overcomplicate, choose generic x86 case */
+#define L1_CACHE_BYTES 64
+#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+
+struct ring_buffer
+{
+ unsigned int read_idx __cacheline_aligned;
+ unsigned int write_idx __cacheline_aligned;
+ unsigned int size;
+ unsigned int low_mask;
+ unsigned int high_mask;
+ unsigned int bit_shift;
+ void *data_ptr;
+};
+
+static inline unsigned int upper_power_of_two(unsigned int v)
+{
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+
+ return v;
+}
+
+static inline int ring_buffer_init(struct ring_buffer* rbuf, unsigned int size)
+{
+ /* Must be pow2 */
+ if (((size-1) & size))
+ size = upper_power_of_two(size);
+
+ size *= sizeof(void *);
+ rbuf->data_ptr = malloc(size);
+ rbuf->size = size;
+ rbuf->read_idx = 0;
+ rbuf->write_idx = 0;
+ rbuf->bit_shift = __builtin_ffs(sizeof(void *))-1;
+ rbuf->low_mask = rbuf->size - 1;
+ rbuf->high_mask = rbuf->size * 2 - 1;
+
+ return 0;
+}
+
+static inline void ring_buffer_deinit(struct ring_buffer* rbuf)
+{
+ free(rbuf->data_ptr);
+}
+
+static inline unsigned int ring_buffer_used_size(const struct ring_buffer* rbuf)
+{
+ __sync_synchronize();
+ return ((rbuf->write_idx - rbuf->read_idx) & rbuf->high_mask) >>
+ rbuf->bit_shift;
+}
+
+static inline void ring_buffer_enqueue(struct ring_buffer* rbuf, void *ptr)
+{
+
+ unsigned int idx;
+
+ /*
+ * Be aware: we do not check that buffer can be full,
+ * assume user of the ring buffer can't submit more.
+ */
+
+ idx = rbuf->write_idx & rbuf->low_mask;
+ *(void **)((uintptr_t)rbuf->data_ptr + idx) = ptr;
+ /* Barrier to be sure stored pointer will be seen properly */
+ __sync_synchronize();
+ rbuf->write_idx = (rbuf->write_idx + sizeof(ptr)) & rbuf->high_mask;
+}
+
+static inline void *ring_buffer_dequeue(struct ring_buffer* rbuf)
+{
+
+ unsigned idx;
+ void *ptr;
+
+ /*
+ * Be aware: we do not check that buffer can be empty,
+ * assume user of the ring buffer called ring_buffer_used_size(),
+ * which returns actual used size and introduces memory barrier
+ * explicitly.
+ */
+
+ idx = rbuf->read_idx & rbuf->low_mask;
+ ptr = *(void **)((uintptr_t)rbuf->data_ptr + idx);
+ rbuf->read_idx = (rbuf->read_idx + sizeof(ptr)) & rbuf->high_mask;
+
+ return ptr;
+}