Anklang 0.3.0-460-gc4ef46ba
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
atomics.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "atomics.hh"
3#include "internal.hh"
4#include "testing.hh"
5
6#define ADEBUG(...) Ase::debug ("atomics", __VA_ARGS__)
7
8namespace {
9using namespace Ase;
10
11static const size_t N_THREADS = std::thread::hardware_concurrency();
12
13TEST_INTEGRITY (atomic_bits_test);
14static void
15atomic_bits_test ()
16{
17 const size_t N = 37;
18 AtomicBits a (37);
19 TASSERT (a.all (0));
20 TASSERT (!a.all (1));
21 TASSERT (!a.any (1));
22 TASSERT (a.any (0));
23 for (size_t i = 0; i < N; i++) {
24 TASSERT (a.any (0));
25 TASSERT (a[i] == false);
26 a.set (i, 1);
27 TASSERT (a[i] == true);
28 TASSERT (a.any (1));
29 TASSERT (!a.all (0));
30 a.set (i, 0);
31 TASSERT (a[i] == false);
32 TASSERT (!a.any (1));
33 TASSERT (a.all (0));
34 }
35 // note, toggling all N bits is not sufficient to change bits in all blocks
36 // i.e. toggle all a.size() bits for all() to flip
37 for (size_t i = 0; i < a.size(); i++)
38 a[i] ^= 1;
39 TASSERT (a.all (1));
40 TASSERT (!a.all (0));
41 TASSERT (!a.any (0));
42 TASSERT (a.any (1));
43 for (size_t i = 0; i < N; i++) {
44 TASSERT (a.all (1));
45 TASSERT (a[i] == true);
46 a[i] ^= 0;
47 TASSERT (a.all (1));
48 TASSERT (a[i] == true);
49 a.set (i, 0);
50 TASSERT (a[i] == false);
51 TASSERT (a.any (0));
52 TASSERT (!a.all (0));
53 a[i] ^= 1;
54 TASSERT (a[i] == true);
55 TASSERT (!a.any (0));
56 TASSERT (a.all (1));
57 }
58}
59
60// Basic Unit test for AtomicIntrusiveStack<>
61struct AisNode { int value = 0; std::atomic<AisNode*> next = nullptr; };
63atomic_next_ptrref (AisNode *node)
64{
65 return node->next;
66}
67
68TEST_INTEGRITY (atomic_mpmcstack_test);
69static void
70atomic_mpmcstack_test()
71{
72 bool was_empty;
74 TASSERT (stack.empty());
75 AisNode n1, n2, n3;
76 n1.value = 1;
77 n2.value = 2;
78 n3.value = 3;
79 was_empty = stack.push (&n1);
80 TASSERT (was_empty);
81 n2.next = &n3;
82 was_empty = stack.push_chain (&n2, &n3);
83 TASSERT (!was_empty);
84 AisNode *node = stack.pop_all();
85 int sum = 0;
86 while (node)
87 {
88 sum += node->value;
89 node = node->next;
90 }
91 TASSERT (sum == 6);
92}
93
94// == MpmcStack<> test ==
95static const size_t COUNTING_THREADS = N_THREADS + 1;
96static constexpr const size_t NUMBER_NODES_PER_THREAD = 9999;
97struct NumberNode {
98 size_t number;
99 Atomic<NumberNode*> intr_ptr_ = nullptr; // atomic intrusive pointer
100};
101using ConcurrentNumberStack = MpmcStack<NumberNode>;
102static ConcurrentNumberStack number_stack;
103static NumberNode *allocated_number_nodes = nullptr;
104static Atomic<unsigned long long> number_totals = 0;
105static void
106run_count_number_nodes (NumberNode *nodes, ssize_t count)
107{
108 const pid_t tid = gettid();
109 unsigned long long totals = 0, l = 0;
110 ssize_t i = 0, r = count / 50, j = -r;
111 while (i < count || j < count)
112 {
113 for (size_t t = 0; t < 77 && i < count; t++)
114 {
115 NumberNode *node = nodes + i;
116 node->number = ++i;
117 number_stack.push (node);
118 }
119 for (size_t t = 0; t < 37 && j < count; t++)
120 {
121 NumberNode *node = number_stack.pop();
122 if (node)
123 {
124 totals += node->number;
125 j++;
126 if (r > 0 && (node->number & 0x1))
127 {
128 r--;
129 node->number = 0;
130 number_stack.push (node); // ABA mixing
131 }
132 }
133 }
134 if (totals > l * 10)
135 {
136 l = totals;
137 if (Test::verbose())
138 printout ("thread %u: %llu\n", tid, totals);
139 }
140 }
141 number_totals += totals;
142}
143
144TEST_INTEGRITY (mpmc_stack_test);
145static void
146mpmc_stack_test()
147{
148 allocated_number_nodes = (NumberNode*) calloc (COUNTING_THREADS * NUMBER_NODES_PER_THREAD, sizeof (NumberNode));
149 assert (allocated_number_nodes);
150
151 std::thread threads[COUNTING_THREADS];
152 for (size_t i = 0; i < COUNTING_THREADS; i++)
153 threads[i] = std::thread (run_count_number_nodes, allocated_number_nodes + i * NUMBER_NODES_PER_THREAD, NUMBER_NODES_PER_THREAD);
154 for (size_t i = 0; i < COUNTING_THREADS; i++)
155 threads[i].join();
156 free (allocated_number_nodes);
157 allocated_number_nodes = nullptr;
158 assert (number_totals == COUNTING_THREADS * (NUMBER_NODES_PER_THREAD * (NUMBER_NODES_PER_THREAD + 1ull)) / 2);
159}
160
161// == AtomicStack<> test ==
162TEST_INTEGRITY (atomic_valuestack_test);
163static void
164atomic_valuestack_test()
165{
167 TASSERT (sstack.empty());
168 bool was_empty, had;
169 std::string s = "foo";
170 was_empty = sstack.push (s);
171 TASSERT (was_empty);
172 TASSERT (!sstack.empty());
173 was_empty = sstack.push (std::string ("bar"));
174 TASSERT (!was_empty);
175 TASSERT (!sstack.empty());
176 had = sstack.pop (s);
177 TASSERT (had && s == "bar");
178 TASSERT (!sstack.empty());
179 had = sstack.pop (s);
180 TASSERT (had && s == "foo");
181 had = sstack.pop (s);
182 TASSERT (!had);
183 TASSERT (sstack.empty());
184}
185
186} // Anon
assert
Vector of atomic bits, operates in blocks of 64 bits.
Definition atomics.hh:232
bool push_chain(T *first, T *last)
Atomically push linked nodes first->…->last onto the stack, returns was_empty.
Definition atomics.hh:38
bool push(T *el)
Atomically push el onto the stack, returns was_empty.
Definition atomics.hh:51
bool empty() const
Check if poppingreturns null.
Definition atomics.hh:32
T count(T... args)
free
T hardware_concurrency(T... args)
#define TEST_INTEGRITY(FUNC)
Register func as an integrity test.
Definition internal.hh:77
bool verbose()
Indicates whether tests should run verbosely.
Definition testing.cc:178
The Anklang C++ API namespace.
Definition api.hh:9
boost::atomic< T > Atomic
Substitute for std::atomic<> with fixes for GCC.
Definition atomics.hh:14
T next(T... args)
bool empty() const
Return true if the stack holds no items.
Definition atomics.hh:181
bool pop(Value &value)
Pop value from top of the stack, returns if value was reassigned (true), otherwise the stack was empt...
Definition atomics.hh:198
bool push(Value &&value)
Add value to top of the stack, returns if the stack was empty (true).
Definition atomics.hh:184
typedef pid_t
#define TASSERT(cond)
Unconditional test assertion, enters breakpoint if not fullfilled.
Definition testing.hh:24