]> git.proxmox.com Git - ovs.git/blob - tests/test-atomic.c
Fix ovs-dpctl-top by removing 3 wrong hunks in py3-compat.patch.
[ovs.git] / tests / test-atomic.c
1 /*
2 * Copyright (c) 2013, 2014 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18 #undef NDEBUG
19 #include "fatal-signal.h"
20 #include "ovs-atomic.h"
21 #include "ovstest.h"
22 #include "ovs-thread.h"
23 #include "timeval.h"
24 #include "util.h"
25 #include "openvswitch/vlog.h"
26
27 VLOG_DEFINE_THIS_MODULE(test_atomic);
28
29 #define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE) \
30 { \
31 ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \
32 BASE_TYPE value, orig; \
33 \
34 atomic_read(&x, &value); \
35 ovs_assert(value == 1); \
36 \
37 atomic_store(&x, 2); \
38 atomic_read(&x, &value); \
39 ovs_assert(value == 2); \
40 \
41 atomic_init(&x, 3); \
42 atomic_read(&x, &value); \
43 ovs_assert(value == 3); \
44 \
45 atomic_add(&x, 1, &orig); \
46 ovs_assert(orig == 3); \
47 atomic_read(&x, &value); \
48 ovs_assert(value == 4); \
49 \
50 atomic_sub(&x, 2, &orig); \
51 ovs_assert(orig == 4); \
52 atomic_read(&x, &value); \
53 ovs_assert(value == 2); \
54 \
55 atomic_or(&x, 6, &orig); \
56 ovs_assert(orig == 2); \
57 atomic_read(&x, &value); \
58 ovs_assert(value == 6); \
59 \
60 atomic_and(&x, 10, &orig); \
61 ovs_assert(orig == 6); \
62 atomic_read(&x, &value); \
63 ovs_assert(value == 2); \
64 \
65 atomic_xor(&x, 10, &orig); \
66 ovs_assert(orig == 2); \
67 atomic_read(&x, &value); \
68 ovs_assert(value == 8); \
69 }
70
71 #define TEST_ATOMIC_TYPE_EXPLICIT(ATOMIC_TYPE, BASE_TYPE, \
72 ORDER_READ, ORDER_STORE, ORDER_RMW) \
73 { \
74 ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \
75 BASE_TYPE value, orig; \
76 \
77 atomic_read_explicit(&x, &value, ORDER_READ); \
78 ovs_assert(value == 1); \
79 \
80 atomic_store_explicit(&x, 2, ORDER_STORE); \
81 atomic_read_explicit(&x, &value, ORDER_READ); \
82 ovs_assert(value == 2); \
83 \
84 atomic_init(&x, 3); \
85 atomic_read_explicit(&x, &value, ORDER_READ); \
86 ovs_assert(value == 3); \
87 \
88 atomic_add_explicit(&x, 1, &orig, ORDER_RMW); \
89 ovs_assert(orig == 3); \
90 atomic_read_explicit(&x, &value, ORDER_READ); \
91 ovs_assert(value == 4); \
92 \
93 atomic_sub_explicit(&x, 2, &orig, ORDER_RMW); \
94 ovs_assert(orig == 4); \
95 atomic_read_explicit(&x, &value, ORDER_READ); \
96 ovs_assert(value == 2); \
97 \
98 atomic_or_explicit(&x, 6, &orig, ORDER_RMW); \
99 ovs_assert(orig == 2); \
100 atomic_read_explicit(&x, &value, ORDER_READ); \
101 ovs_assert(value == 6); \
102 \
103 atomic_and_explicit(&x, 10, &orig, ORDER_RMW); \
104 ovs_assert(orig == 6); \
105 atomic_read_explicit(&x, &value, ORDER_READ); \
106 ovs_assert(value == 2); \
107 \
108 atomic_xor_explicit(&x, 10, &orig, ORDER_RMW); \
109 ovs_assert(orig == 2); \
110 atomic_read_explicit(&x, &value, ORDER_READ); \
111 ovs_assert(value == 8); \
112 }
113
114
115 #define TEST_ATOMIC_ORDER(ORDER_READ, ORDER_STORE, ORDER_RMW) \
116 { \
117 TEST_ATOMIC_TYPE_EXPLICIT(atomic_char, char, \
118 ORDER_READ, ORDER_STORE, ORDER_RMW); \
119 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uchar, unsigned char, \
120 ORDER_READ, ORDER_STORE, ORDER_RMW); \
121 TEST_ATOMIC_TYPE_EXPLICIT(atomic_schar, signed char, \
122 ORDER_READ, ORDER_STORE, ORDER_RMW); \
123 TEST_ATOMIC_TYPE_EXPLICIT(atomic_short, short, \
124 ORDER_READ, ORDER_STORE, ORDER_RMW); \
125 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ushort, unsigned short, \
126 ORDER_READ, ORDER_STORE, ORDER_RMW); \
127 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int, int, \
128 ORDER_READ, ORDER_STORE, ORDER_RMW); \
129 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint, unsigned int, \
130 ORDER_READ, ORDER_STORE, ORDER_RMW); \
131 TEST_ATOMIC_TYPE_EXPLICIT(atomic_long, long int, \
132 ORDER_READ, ORDER_STORE, ORDER_RMW); \
133 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ulong, unsigned long int, \
134 ORDER_READ, ORDER_STORE, ORDER_RMW); \
135 TEST_ATOMIC_TYPE_EXPLICIT(atomic_llong, long long int, \
136 ORDER_READ, ORDER_STORE, ORDER_RMW); \
137 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ullong, unsigned long long int, \
138 ORDER_READ, ORDER_STORE, ORDER_RMW); \
139 TEST_ATOMIC_TYPE_EXPLICIT(atomic_size_t, size_t, \
140 ORDER_READ, ORDER_STORE, ORDER_RMW); \
141 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ptrdiff_t, ptrdiff_t, \
142 ORDER_READ, ORDER_STORE, ORDER_RMW); \
143 TEST_ATOMIC_TYPE_EXPLICIT(atomic_intmax_t, intmax_t, \
144 ORDER_READ, ORDER_STORE, ORDER_RMW); \
145 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintmax_t, uintmax_t, \
146 ORDER_READ, ORDER_STORE, ORDER_RMW); \
147 TEST_ATOMIC_TYPE_EXPLICIT(atomic_intptr_t, intptr_t, \
148 ORDER_READ, ORDER_STORE, ORDER_RMW); \
149 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintptr_t, uintptr_t, \
150 ORDER_READ, ORDER_STORE, ORDER_RMW); \
151 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint8_t, uint8_t, \
152 ORDER_READ, ORDER_STORE, ORDER_RMW); \
153 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int8_t, int8_t, \
154 ORDER_READ, ORDER_STORE, ORDER_RMW); \
155 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint16_t, uint16_t, \
156 ORDER_READ, ORDER_STORE, ORDER_RMW); \
157 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int16_t, int16_t, \
158 ORDER_READ, ORDER_STORE, ORDER_RMW); \
159 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint32_t, uint32_t, \
160 ORDER_READ, ORDER_STORE, ORDER_RMW); \
161 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int32_t, int32_t, \
162 ORDER_READ, ORDER_STORE, ORDER_RMW); \
163 }
164
165 static void
166 test_atomic_flag(void)
167 {
168 atomic_flag flag = ATOMIC_FLAG_INIT;
169 ovs_assert(atomic_flag_test_and_set(&flag) == false);
170 ovs_assert(atomic_flag_test_and_set(&flag) == true);
171 atomic_flag_clear(&flag);
172 ovs_assert(atomic_flag_test_and_set(&flag) == false);
173 }
174
175 static uint32_t a;
176
177 struct atomic_aux {
178 ATOMIC(uint64_t) count;
179 uint32_t b;
180 ATOMIC(uint32_t *) data;
181 ATOMIC(uint64_t) data64;
182 };
183
184 static ATOMIC(struct atomic_aux *) paux = ATOMIC_VAR_INIT(NULL);
185 static struct atomic_aux *auxes = NULL;
186
187 #define ATOMIC_ITEM_COUNT 1000000
188 #define DURATION 5000
189
190 static void *
191 atomic_consumer(void * arg1 OVS_UNUSED)
192 {
193 struct atomic_aux *old_aux = NULL;
194 uint64_t count;
195 long long int stop_time = time_msec() + DURATION;
196
197 do {
198 struct atomic_aux *aux;
199 uint32_t b;
200
201 /* Wait for a new item. We may not be fast enough to process every
202 * item, but we are guaranteed to see the last one. */
203 do {
204 atomic_read_explicit(&paux, &aux, memory_order_consume);
205 } while (aux == old_aux);
206
207 b = aux->b;
208 atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
209 ovs_assert(b == count + 42);
210
211 old_aux = aux;
212 } while (count < ATOMIC_ITEM_COUNT - 1 && time_msec() < stop_time);
213
214 if (time_msec() >= stop_time) {
215 if (count < 10) {
216 VLOG_WARN("atomic_consumer test stopped due to excessive runtime. "
217 "Count = %"PRIu64, count);
218 }
219 }
220
221 return NULL;
222 }
223
224 static void *
225 atomic_producer(void * arg1 OVS_UNUSED)
226 {
227 size_t i;
228
229 for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
230 struct atomic_aux *aux = &auxes[i];
231
232 aux->count = ATOMIC_VAR_INIT(i);
233 aux->b = i + 42;
234
235 /* Publish the new item. */
236 atomic_store_explicit(&paux, aux, memory_order_release);
237 }
238
239 return NULL;
240 }
241
242 static void
243 test_cons_rel(void)
244 {
245 pthread_t reader, writer;
246
247 atomic_init(&paux, NULL);
248
249 auxes = xmalloc(sizeof *auxes * ATOMIC_ITEM_COUNT);
250
251 reader = ovs_thread_create("consumer", atomic_consumer, NULL);
252 writer = ovs_thread_create("producer", atomic_producer, NULL);
253
254 xpthread_join(reader, NULL);
255 xpthread_join(writer, NULL);
256
257 free(auxes);
258 }
259
260 static void *
261 atomic_reader(void *aux_)
262 {
263 struct atomic_aux *aux = aux_;
264 uint64_t count;
265 uint64_t data;
266 long long int now = time_msec();
267 long long int stop_time = now + DURATION;
268
269 do {
270 /* Non-synchronized add. */
271 atomic_add_explicit(&aux->count, 1, &count, memory_order_relaxed);
272
273 do {
274 atomic_read_explicit(&aux->data64, &data, memory_order_acquire);
275 } while (!data && (now = time_msec()) < stop_time);
276
277 if (now >= stop_time) {
278 if (count < 10) {
279 VLOG_WARN("atomic_reader test stopped due to excessive "
280 "runtime. Count = %"PRIu64, count);
281 }
282 break;
283 }
284
285 ovs_assert(data == a && data == aux->b && a == aux->b);
286
287 atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
288
289 ovs_assert(count == 2 * a && count == 2 * aux->b && count == 2 * data);
290
291 atomic_store_explicit(&aux->data64, UINT64_C(0), memory_order_release);
292 } while (count < 2 * ATOMIC_ITEM_COUNT);
293
294 return NULL;
295 }
296
297 static void *
298 atomic_writer(void *aux_)
299 {
300 struct atomic_aux *aux = aux_;
301 uint64_t old_count;
302 uint64_t data;
303 size_t i;
304 long long int now = time_msec();
305 long long int stop_time = now + DURATION;
306
307 for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
308 /* Wait for the reader to be done with the data. */
309 do {
310 atomic_read_explicit(&aux->data64, &data, memory_order_acquire);
311 } while (data && (now = time_msec()) < stop_time);
312
313 if (now >= stop_time) {
314 if (i < 10) {
315 VLOG_WARN("atomic_writer test stopped due to excessive "
316 "runtime, Count = %"PRIuSIZE, i);
317 }
318 break;
319 }
320
321 a = i + 1;
322 atomic_add_explicit(&aux->count, 1, &old_count, memory_order_relaxed);
323 aux->b++;
324 atomic_store_explicit(&aux->data64,
325 (i & 1) ? (uint64_t)aux->b : a, memory_order_release);
326 }
327
328 return NULL;
329 }
330
331 static void
332 test_acq_rel(void)
333 {
334 pthread_t reader, writer;
335 struct atomic_aux *aux = xmalloc(sizeof *aux);
336
337 a = 0;
338 aux->b = 0;
339
340 aux->count = ATOMIC_VAR_INIT(0);
341 atomic_init(&aux->data, NULL);
342 aux->data64 = ATOMIC_VAR_INIT(0);
343
344 reader = ovs_thread_create("reader", atomic_reader, aux);
345 writer = ovs_thread_create("writer", atomic_writer, aux);
346
347 xpthread_join(reader, NULL);
348 xpthread_join(writer, NULL);
349 free(aux);
350 }
351
352 static void
353 test_atomic_plain(void)
354 {
355 TEST_ATOMIC_TYPE(atomic_char, char);
356 TEST_ATOMIC_TYPE(atomic_uchar, unsigned char);
357 TEST_ATOMIC_TYPE(atomic_schar, signed char);
358 TEST_ATOMIC_TYPE(atomic_short, short);
359 TEST_ATOMIC_TYPE(atomic_ushort, unsigned short);
360 TEST_ATOMIC_TYPE(atomic_int, int);
361 TEST_ATOMIC_TYPE(atomic_uint, unsigned int);
362 TEST_ATOMIC_TYPE(atomic_long, long int);
363 TEST_ATOMIC_TYPE(atomic_ulong, unsigned long int);
364 TEST_ATOMIC_TYPE(atomic_llong, long long int);
365 TEST_ATOMIC_TYPE(atomic_ullong, unsigned long long int);
366 TEST_ATOMIC_TYPE(atomic_size_t, size_t);
367 TEST_ATOMIC_TYPE(atomic_ptrdiff_t, ptrdiff_t);
368 TEST_ATOMIC_TYPE(atomic_intmax_t, intmax_t);
369 TEST_ATOMIC_TYPE(atomic_uintmax_t, uintmax_t);
370 TEST_ATOMIC_TYPE(atomic_intptr_t, intptr_t);
371 TEST_ATOMIC_TYPE(atomic_uintptr_t, uintptr_t);
372 TEST_ATOMIC_TYPE(atomic_uint8_t, uint8_t);
373 TEST_ATOMIC_TYPE(atomic_int8_t, int8_t);
374 TEST_ATOMIC_TYPE(atomic_uint16_t, uint16_t);
375 TEST_ATOMIC_TYPE(atomic_int16_t, int16_t);
376 TEST_ATOMIC_TYPE(atomic_uint32_t, uint32_t);
377 TEST_ATOMIC_TYPE(atomic_int32_t, int32_t);
378 TEST_ATOMIC_TYPE(atomic_uint64_t, uint64_t);
379 TEST_ATOMIC_TYPE(atomic_int64_t, int64_t);
380 }
381
382 static void
383 test_atomic_relaxed(void)
384 {
385 TEST_ATOMIC_ORDER(memory_order_relaxed, memory_order_relaxed,
386 memory_order_relaxed);
387 }
388
389 static void
390 test_atomic_consume(void)
391 {
392 TEST_ATOMIC_ORDER(memory_order_consume, memory_order_release,
393 memory_order_release);
394 }
395
396 static void
397 test_atomic_acquire(void)
398 {
399 TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
400 memory_order_release);
401 }
402
403 static void
404 test_atomic_acq_rel(void)
405 {
406 TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
407 memory_order_acq_rel);
408 }
409
410 static void
411 test_atomic_seq_cst(void)
412 {
413 TEST_ATOMIC_ORDER(memory_order_seq_cst, memory_order_seq_cst,
414 memory_order_seq_cst);
415 }
416
417 static void
418 test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
419 {
420 fatal_signal_init();
421 test_atomic_plain();
422 test_atomic_relaxed();
423 test_atomic_consume();
424 test_atomic_acquire();
425 test_atomic_acq_rel();
426 test_atomic_seq_cst();
427
428 test_atomic_flag();
429
430 test_acq_rel();
431 test_cons_rel();
432 }
433
434 OVSTEST_REGISTER("test-atomic", test_atomic_main);