Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
spsc_ring_tests.h File Reference
#include <sched.h>
#include <stdint.h>
#include <serene/rt/fiber/thread.h>
#include <serene/rt/impl/spsc_ring.h>
#include "acutest.h"
#include "base.h"
Include dependency graph for spsc_ring_tests.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  spsc_pair
struct  spsc_producer_arg

Macros

#define SPSC_RING_TESTS(X)

Typedefs

typedef struct spsc_pair spsc_pair
typedef struct spsc_producer_arg spsc_producer_arg

Functions

static void test_spsc_ring_make_valid ()
static void test_spsc_ring_make_oor ()
static void test_spsc_ring_fill_drain ()
static void test_spsc_ring_elem_bytes ()
static void spsc_producer (void *p)
static void test_spsc_ring_spsc_stress ()

Macro Definition Documentation

◆ SPSC_RING_TESTS

#define SPSC_RING_TESTS ( X)
Value:
X("spsc_ring::make_valid", test_spsc_ring_make_valid), \
X("spsc_ring::make_out_of_range", test_spsc_ring_make_oor), \
X("spsc_ring::fill_drain_wrap", test_spsc_ring_fill_drain), \
X("spsc_ring::elem_bytes", test_spsc_ring_elem_bytes), \
X("spsc_ring::spsc_stress", test_spsc_ring_spsc_stress)
static void test_spsc_ring_make_valid()
static void test_spsc_ring_make_oor()
static void test_spsc_ring_elem_bytes()
static void test_spsc_ring_spsc_stress()
static void test_spsc_ring_fill_drain()

Definition at line 30 of file spsc_ring_tests.h.

30#define SPSC_RING_TESTS(X) \
31 X("spsc_ring::make_valid", test_spsc_ring_make_valid), \
32 X("spsc_ring::make_out_of_range", test_spsc_ring_make_oor), \
33 X("spsc_ring::fill_drain_wrap", test_spsc_ring_fill_drain), \
34 X("spsc_ring::elem_bytes", test_spsc_ring_elem_bytes), \
35 X("spsc_ring::spsc_stress", test_spsc_ring_spsc_stress)

Typedef Documentation

◆ spsc_pair

typedef struct spsc_pair spsc_pair

◆ spsc_producer_arg

typedef struct spsc_producer_arg spsc_producer_arg

Function Documentation

◆ spsc_producer()

void spsc_producer ( void * p)
static

Definition at line 142 of file spsc_ring_tests.h.

142 {
144 for (uint64_t i = 0; i < a->count; i++) {
145 while (!srn_spsc_ring_push(a->ring, &i)) {
146 // Ring full, yield so the consumer gets the CPU. Without this a tight
147 // spin starves the other thread under valgrind's serialized scheduler.
148 sched_yield();
149 }
150 }
151}
bool srn_spsc_ring_push(srn_spsc_ring_t *r, const void *elem)
Producer side.
Definition spsc_ring.c:61
srn_spsc_ring_t * ring
Here is the call graph for this function:
Here is the caller graph for this function:

◆ test_spsc_ring_elem_bytes()

void test_spsc_ring_elem_bytes ( )
static

Definition at line 119 of file spsc_ring_tests.h.

119 {
120 MAKE_ENGINE(mm, engine);
121 MAKE_CONTEXT(engine, ctx);
122
123 srn_spsc_ring_t *r = srn_spsc_ring_make(ctx, 3, sizeof(spsc_pair));
124 TEST_ASSERT(r != nullptr && !HAS_ERROR(*r));
125
126 spsc_pair in = {.a = 0xDEADBEEFU, .b = 0x12345678U};
128
129 spsc_pair out = {0};
131 TEST_CHECK(out.a == 0xDEADBEEFU && out.b == 0x12345678U);
132
133 RELEASE_CONTEXT(ctx);
134 SHUTDOWN_ENGINE(mm, engine);
135}
#define TEST_CHECK(cond)
Definition acutest.h:95
#define TEST_ASSERT(cond)
Definition acutest.h:117
#define RELEASE_CONTEXT(x)
Definition base.h:46
#define SHUTDOWN_ENGINE(mm, engine)
Definition base.h:38
#define MAKE_ENGINE(mm, engine)
Definition base.h:32
#define MAKE_CONTEXT(engine, x)
Definition base.h:42
#define HAS_ERROR(x)
True when x – a value carrying an ERROR_HEADER – has an error attached.
Definition errors.h:63
srn_spsc_ring_t * srn_spsc_ring_make(srn_context_t *ctx, size_t magnitude, size_t elem_size)
Set up a ring by allocating the buf to be the size of cap * elem_size.
Definition spsc_ring.c:27
bool srn_spsc_ring_pop(srn_spsc_ring_t *r, void *out)
Consumer side.
Definition spsc_ring.c:83
Here is the call graph for this function:

◆ test_spsc_ring_fill_drain()

void test_spsc_ring_fill_drain ( )
static

Definition at line 77 of file spsc_ring_tests.h.

77 {
78 MAKE_ENGINE(mm, engine);
79 MAKE_CONTEXT(engine, ctx);
80
81 srn_spsc_ring_t *r = srn_spsc_ring_make(ctx, 2, sizeof(uint64_t)); // cap 4
82 TEST_ASSERT(r != nullptr && !HAS_ERROR(*r));
83
85
86 for (uint64_t i = 0; i < 4; i++) {
88 }
89
90 uint64_t overflow = 99;
91 TEST_CHECK(!srn_spsc_ring_push(r, &overflow)); // full
93
94 uint64_t v = 0;
95 TEST_CHECK(srn_spsc_ring_pop(r, &v) && v == 0);
96 TEST_CHECK(srn_spsc_ring_pop(r, &v) && v == 1);
97
98 uint64_t a = 4, b = 5; // these wrap into the freed slots
101
102 for (uint64_t expect = 2; expect <= 5; expect++) {
103 TEST_CHECK(srn_spsc_ring_pop(r, &v) && v == expect);
104 }
106 TEST_CHECK(!srn_spsc_ring_pop(r, &v)); // empty
107
108 RELEASE_CONTEXT(ctx);
109 SHUTDOWN_ENGINE(mm, engine);
110}
bool srn_spsc_ring_empty(const srn_spsc_ring_t *r)
Whether the ring currently holds no elements.
Definition spsc_ring.c:103
Here is the call graph for this function:

◆ test_spsc_ring_make_oor()

void test_spsc_ring_make_oor ( )
static

Definition at line 57 of file spsc_ring_tests.h.

57 {
58 MAKE_ENGINE(mm, engine);
59 MAKE_CONTEXT(engine, ctx);
60
61 srn_spsc_ring_t *too_small = srn_spsc_ring_make(ctx, 1, sizeof(int));
62 TEST_ASSERT(too_small != nullptr);
63 TEST_CHECK(HAS_ERROR(*too_small));
64 TEST_ASSERT(too_small->maybe_error->tag == WRONG_RANGE);
65
66 srn_spsc_ring_t *too_big = srn_spsc_ring_make(ctx, 64, sizeof(int));
67 TEST_ASSERT(too_big != nullptr);
68 TEST_CHECK(HAS_ERROR(*too_big));
69 TEST_ASSERT(too_big->maybe_error->tag == WRONG_RANGE);
70
71 RELEASE_CONTEXT(ctx);
72 SHUTDOWN_ENGINE(mm, engine);
73}
@ WRONG_RANGE
Definition errors.h:84
Here is the call graph for this function:

◆ test_spsc_ring_make_valid()

void test_spsc_ring_make_valid ( )
static

Definition at line 39 of file spsc_ring_tests.h.

39 {
40 MAKE_ENGINE(mm, engine);
41 MAKE_CONTEXT(engine, ctx);
42
43 srn_spsc_ring_t *r = srn_spsc_ring_make(ctx, 3, sizeof(uint64_t)); // cap 8
44 TEST_ASSERT(r != nullptr);
46 TEST_CHECK(r->cap == 8);
47 TEST_CHECK(r->mask == 7);
48 TEST_CHECK(r->elem_size == sizeof(uint64_t));
50
51 RELEASE_CONTEXT(ctx);
52 SHUTDOWN_ENGINE(mm, engine);
53}
size_t elem_size
Definition spsc_ring.h:56
SRN_SPSC_RING_CAP_TYPE cap
Definition spsc_ring.h:54
SRN_SPSC_RING_CAP_TYPE mask
Definition spsc_ring.h:55
Here is the call graph for this function:

◆ test_spsc_ring_spsc_stress()

void test_spsc_ring_spsc_stress ( )
static

Definition at line 156 of file spsc_ring_tests.h.

156 {
157 MAKE_ENGINE(mm, engine);
158 MAKE_CONTEXT(engine, ctx);
159
160 srn_spsc_ring_t *r = srn_spsc_ring_make(ctx, 6, sizeof(uint64_t)); // cap 64
161 TEST_ASSERT(r != nullptr && !HAS_ERROR(*r));
162
163 constexpr uint64_t n = 100000;
164 spsc_producer_arg arg = {.ring = r, .count = n};
167
168 bool in_order = true;
169 for (uint64_t i = 0; i < n; i++) {
170 uint64_t v;
171 while (!srn_spsc_ring_pop(r, &v)) {
172 // Ring empty, yield so the producer gets the CPU. Without this a tight
173 // spin starves the producer under valgrind's serialized scheduler.
174 sched_yield();
175 }
176 if (v != i) {
177 in_order = false;
178 break;
179 }
180 }
181 TEST_CHECK(in_order);
183
184 RELEASE_CONTEXT(ctx);
185 SHUTDOWN_ENGINE(mm, engine);
186}
static srn_fiber_result_t producer(srn_context_t *ctx, void *arg)
int n
Definition acutest.h:525
static void spsc_producer(void *p)
srn_thread_status_t srn_thread_join(srn_thread_t *t)
Block until the thread started for t returns.
@ SRN_THREAD_OK
Definition thread.h:62
srn_thread_status_t srn_thread_spawn(srn_thread_t *t, void(*fn)(void *), void *arg)
Run fn(arg) on a new OS thread.
Here is the call graph for this function: