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