Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : * Copyright(c) 2019 Arm Limited
4 : : */
5 : :
6 : : #include <stdio.h>
7 : : #include <stdint.h>
8 : : #include <unistd.h>
9 : : #include <inttypes.h>
10 : : #include <sys/queue.h>
11 : :
12 : : #include <rte_memory.h>
13 : : #include <rte_per_lcore.h>
14 : : #include <rte_launch.h>
15 : : #include <rte_atomic.h>
16 : : #include <rte_eal.h>
17 : : #include <rte_lcore.h>
18 : : #include <rte_random.h>
19 : : #include <rte_hash_crc.h>
20 : :
21 : : #include "test.h"
22 : :
23 : : #ifndef RTE_TOOLCHAIN_MSVC
24 : : /*
25 : : * Atomic Variables
26 : : * ================
27 : : *
28 : : * - The main test function performs several subtests. The first
29 : : * checks that the usual inc/dec/add/sub functions are working
30 : : * correctly:
31 : : *
32 : : * - Initialize 16-bit, 32-bit and 64-bit atomic variables to specific
33 : : * values.
34 : : *
35 : : * - These variables are incremented and decremented on each core at
36 : : * the same time in ``test_atomic_usual()``.
37 : : *
38 : : * - The function checks that once all lcores finish their function,
39 : : * the value of the atomic variables are still the same.
40 : : *
41 : : * - Test "test and set" functions.
42 : : *
43 : : * - Initialize 16-bit, 32-bit and 64-bit atomic variables to zero.
44 : : *
45 : : * - Invoke ``test_atomic_tas()`` on each lcore: before doing anything
46 : : * else. The cores are waiting a synchro using ``while
47 : : * (rte_atomic32_read(&val) == 0)`` which is triggered by the main test
48 : : * function. Then all cores do a
49 : : * ``rte_atomicXX_test_and_set()`` at the same time. If it is successful,
50 : : * it increments another atomic counter.
51 : : *
52 : : * - The main function checks that the atomic counter was incremented
53 : : * twice only (one for 16-bit, one for 32-bit and one for 64-bit values).
54 : : *
55 : : * - Test "add/sub and return" functions
56 : : *
57 : : * - Initialize 16-bit, 32-bit and 64-bit atomic variables to zero.
58 : : *
59 : : * - Invoke ``test_atomic_addsub_return()`` on each lcore. Before doing
60 : : * anything else, the cores are waiting a synchro. Each lcore does
61 : : * this operation several times::
62 : : *
63 : : * tmp = rte_atomicXX_add_return(&a, 1);
64 : : * atomic_add(&count, tmp);
65 : : * tmp = rte_atomicXX_sub_return(&a, 1);
66 : : * atomic_sub(&count, tmp+1);
67 : : *
68 : : * - At the end of the test, the *count* value must be 0.
69 : : *
70 : : * - Test "128-bit compare and swap" (aarch64 and x86_64 only)
71 : : *
72 : : * - Initialize 128-bit atomic variables to zero.
73 : : *
74 : : * - Invoke ``test_atomic128_cmp_exchange()`` on each lcore. Before doing
75 : : * anything else, the cores are waiting a synchro. Each lcore does
76 : : * these compare and swap (CAS) operations several times::
77 : : *
78 : : * Acquired CAS update counter.val[0] + 2; counter.val[1] + 1;
79 : : * Released CAS update counter.val[0] + 2; counter.val[1] + 1;
80 : : * Acquired_Released CAS update counter.val[0] + 2; counter.val[1] + 1;
81 : : * Relaxed CAS update counter.val[0] + 2; counter.val[1] + 1;
82 : : *
83 : : * - At the end of the test, the *count128* first 64-bit value and
84 : : * second 64-bit value differ by the total iterations.
85 : : *
86 : : * - Test "atomic exchange" functions
87 : : *
88 : : * - Create a 64 bit token that can be tested for data integrity
89 : : *
90 : : * - Invoke ``test_atomic_exchange`` on each lcore. Before doing
91 : : * anything else, the cores wait for a synchronization event.
92 : : * Each core then does the following for N iterations:
93 : : *
94 : : * Generate a new token with a data integrity check
95 : : * Exchange the new token for previously generated token
96 : : * Increment a counter if a corrupt token was received
97 : : *
98 : : * - At the end of the test, the number of corrupted tokens must be 0.
99 : : */
100 : :
101 : : #define NUM_ATOMIC_TYPES 3
102 : :
103 : : #define N 1000000
104 : :
105 : : static rte_atomic16_t a16;
106 : : static rte_atomic32_t a32;
107 : : static rte_atomic64_t a64;
108 : : static rte_atomic64_t count;
109 : : static rte_atomic32_t synchro;
110 : :
111 : : static int
112 : 1 : test_atomic_usual(__rte_unused void *arg)
113 : : {
114 : : unsigned i;
115 : :
116 [ + + ]: 39335 : while (rte_atomic32_read(&synchro) == 0)
117 : : ;
118 : :
119 [ + + ]: 1000001 : for (i = 0; i < N; i++)
120 : : rte_atomic16_inc(&a16);
121 [ + + ]: 1000001 : for (i = 0; i < N; i++)
122 : : rte_atomic16_dec(&a16);
123 [ + + ]: 200001 : for (i = 0; i < (N / 5); i++)
124 : : rte_atomic16_add(&a16, 5);
125 [ + + ]: 200001 : for (i = 0; i < (N / 5); i++)
126 : : rte_atomic16_sub(&a16, 5);
127 : :
128 [ + + ]: 1000001 : for (i = 0; i < N; i++)
129 : : rte_atomic32_inc(&a32);
130 [ + + ]: 1000001 : for (i = 0; i < N; i++)
131 : : rte_atomic32_dec(&a32);
132 [ + + ]: 200001 : for (i = 0; i < (N / 5); i++)
133 : : rte_atomic32_add(&a32, 5);
134 [ + + ]: 200001 : for (i = 0; i < (N / 5); i++)
135 : : rte_atomic32_sub(&a32, 5);
136 : :
137 [ + + ]: 1000001 : for (i = 0; i < N; i++)
138 : : rte_atomic64_inc(&a64);
139 [ + + ]: 1000001 : for (i = 0; i < N; i++)
140 : : rte_atomic64_dec(&a64);
141 [ + + ]: 200001 : for (i = 0; i < (N / 5); i++)
142 : : rte_atomic64_add(&a64, 5);
143 [ + + ]: 200001 : for (i = 0; i < (N / 5); i++)
144 : : rte_atomic64_sub(&a64, 5);
145 : :
146 : 1 : return 0;
147 : : }
148 : :
149 : : static int
150 : 1 : test_atomic_tas(__rte_unused void *arg)
151 : : {
152 [ + + ]: 73309 : while (rte_atomic32_read(&synchro) == 0)
153 : : ;
154 : :
155 [ + - ]: 1 : if (rte_atomic16_test_and_set(&a16))
156 : : rte_atomic64_inc(&count);
157 [ + - ]: 1 : if (rte_atomic32_test_and_set(&a32))
158 : : rte_atomic64_inc(&count);
159 [ + - ]: 1 : if (rte_atomic64_test_and_set(&a64))
160 : : rte_atomic64_inc(&count);
161 : :
162 : 1 : return 0;
163 : : }
164 : :
165 : : static int
166 : 1 : test_atomic_addsub_and_return(__rte_unused void *arg)
167 : : {
168 : : uint32_t tmp16;
169 : : uint32_t tmp32;
170 : : uint64_t tmp64;
171 : : unsigned i;
172 : :
173 [ + + ]: 52494 : while (rte_atomic32_read(&synchro) == 0)
174 : : ;
175 : :
176 [ + + ]: 1000001 : for (i = 0; i < N; i++) {
177 : 1000000 : tmp16 = rte_atomic16_add_return(&a16, 1);
178 : 1000000 : rte_atomic64_add(&count, tmp16);
179 : :
180 : 1000000 : tmp16 = rte_atomic16_sub_return(&a16, 1);
181 : 1000000 : rte_atomic64_sub(&count, tmp16+1);
182 : :
183 : 1000000 : tmp32 = rte_atomic32_add_return(&a32, 1);
184 : 1000000 : rte_atomic64_add(&count, tmp32);
185 : :
186 : : tmp32 = rte_atomic32_sub_return(&a32, 1);
187 : 1000000 : rte_atomic64_sub(&count, tmp32+1);
188 : :
189 : : tmp64 = rte_atomic64_add_return(&a64, 1);
190 : : rte_atomic64_add(&count, tmp64);
191 : :
192 : : tmp64 = rte_atomic64_sub_return(&a64, 1);
193 : : rte_atomic64_sub(&count, tmp64+1);
194 : : }
195 : :
196 : 1 : return 0;
197 : : }
198 : :
199 : : /*
200 : : * rte_atomic32_inc_and_test() would increase a 32 bits counter by one and then
201 : : * test if that counter is equal to 0. It would return true if the counter is 0
202 : : * and false if the counter is not 0. rte_atomic64_inc_and_test() could do the
203 : : * same thing but for a 64 bits counter.
204 : : * Here checks that if the 32/64 bits counter is equal to 0 after being atomically
205 : : * increased by one. If it is, increase the variable of "count" by one which would
206 : : * be checked as the result later.
207 : : *
208 : : */
209 : : static int
210 : 1 : test_atomic_inc_and_test(__rte_unused void *arg)
211 : : {
212 [ + + ]: 88208 : while (rte_atomic32_read(&synchro) == 0)
213 : : ;
214 : :
215 [ + - ]: 1 : if (rte_atomic16_inc_and_test(&a16)) {
216 : : rte_atomic64_inc(&count);
217 : : }
218 [ + - ]: 1 : if (rte_atomic32_inc_and_test(&a32)) {
219 : : rte_atomic64_inc(&count);
220 : : }
221 [ + - ]: 1 : if (rte_atomic64_inc_and_test(&a64)) {
222 : : rte_atomic64_inc(&count);
223 : : }
224 : :
225 : 1 : return 0;
226 : : }
227 : :
228 : : /*
229 : : * rte_atomicXX_dec_and_test() should decrease a 32 bits counter by one and then
230 : : * test if that counter is equal to 0. It should return true if the counter is 0
231 : : * and false if the counter is not 0.
232 : : * This test checks if the counter is equal to 0 after being atomically
233 : : * decreased by one. If it is, increase the value of "count" by one which is to
234 : : * be checked as the result later.
235 : : */
236 : : static int
237 : 1 : test_atomic_dec_and_test(__rte_unused void *arg)
238 : : {
239 [ + + ]: 71613 : while (rte_atomic32_read(&synchro) == 0)
240 : : ;
241 : :
242 [ + - ]: 1 : if (rte_atomic16_dec_and_test(&a16))
243 : : rte_atomic64_inc(&count);
244 : :
245 [ + - ]: 1 : if (rte_atomic32_dec_and_test(&a32))
246 : : rte_atomic64_inc(&count);
247 : :
248 [ + - ]: 1 : if (rte_atomic64_dec_and_test(&a64))
249 : : rte_atomic64_inc(&count);
250 : :
251 : 1 : return 0;
252 : : }
253 : :
254 : : #if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_ARM64)
255 : : static rte_int128_t count128;
256 : :
257 : : /*
258 : : * rte_atomic128_cmp_exchange() should update a 128 bits counter's first 64
259 : : * bits by 2 and the second 64 bits by 1 in this test. It should return true
260 : : * if the compare exchange operation is successful.
261 : : * This test repeats 128 bits compare and swap operations N rounds. In each
262 : : * iteration it runs compare and swap operation with different memory models.
263 : : */
264 : : static int
265 : 1 : test_atomic128_cmp_exchange(__rte_unused void *arg)
266 : : {
267 : : rte_int128_t expected;
268 : : int success;
269 : : unsigned int i;
270 : :
271 [ + + ]: 58436 : while (rte_atomic32_read(&synchro) == 0)
272 : : ;
273 : :
274 : 1 : expected = count128;
275 : :
276 [ + + ]: 1000001 : for (i = 0; i < N; i++) {
277 : : do {
278 : : rte_int128_t desired;
279 : :
280 : 1999999 : desired.val[0] = expected.val[0] + 2;
281 : 1999999 : desired.val[1] = expected.val[1] + 1;
282 : :
283 : : success = rte_atomic128_cmp_exchange(&count128,
284 : : &expected, &desired, 1,
285 : : __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
286 [ + + ]: 1999999 : } while (success == 0);
287 : :
288 : : do {
289 : : rte_int128_t desired;
290 : :
291 : 2000000 : desired.val[0] = expected.val[0] + 2;
292 : 2000000 : desired.val[1] = expected.val[1] + 1;
293 : :
294 : : success = rte_atomic128_cmp_exchange(&count128,
295 : : &expected, &desired, 1,
296 : : __ATOMIC_RELEASE, __ATOMIC_RELAXED);
297 [ + + ]: 2000000 : } while (success == 0);
298 : :
299 : : do {
300 : : rte_int128_t desired;
301 : :
302 : 2000000 : desired.val[0] = expected.val[0] + 2;
303 : 2000000 : desired.val[1] = expected.val[1] + 1;
304 : :
305 : : success = rte_atomic128_cmp_exchange(&count128,
306 : : &expected, &desired, 1,
307 : : __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
308 [ + + ]: 2000000 : } while (success == 0);
309 : :
310 : : do {
311 : : rte_int128_t desired;
312 : :
313 : 2000000 : desired.val[0] = expected.val[0] + 2;
314 : 2000000 : desired.val[1] = expected.val[1] + 1;
315 : :
316 : : success = rte_atomic128_cmp_exchange(&count128,
317 : : &expected, &desired, 1,
318 : : __ATOMIC_RELAXED, __ATOMIC_RELAXED);
319 [ + + ]: 2000000 : } while (success == 0);
320 : : }
321 : :
322 : 1 : return 0;
323 : : }
324 : : #endif
325 : :
326 : : /*
327 : : * Helper definitions/variables/functions for
328 : : * atomic exchange tests
329 : : */
330 : : typedef union {
331 : : uint16_t u16;
332 : : uint8_t u8[2];
333 : : } test16_t;
334 : :
335 : : typedef union {
336 : : uint32_t u32;
337 : : uint16_t u16[2];
338 : : uint8_t u8[4];
339 : : } test32_t;
340 : :
341 : : typedef union {
342 : : uint64_t u64;
343 : : uint32_t u32[2];
344 : : uint16_t u16[4];
345 : : uint8_t u8[8];
346 : : } test64_t;
347 : :
348 : : const uint8_t CRC8_POLY = 0x91;
349 : : uint8_t crc8_table[256];
350 : :
351 : : volatile uint16_t token16;
352 : : volatile uint32_t token32;
353 : : volatile uint64_t token64;
354 : :
355 : : static void
356 : : build_crc8_table(void)
357 : : {
358 : : uint8_t val;
359 : : int i, j;
360 : :
361 [ + + ]: 257 : for (i = 0; i < 256; i++) {
362 : 256 : val = i;
363 [ + + ]: 2304 : for (j = 0; j < 8; j++) {
364 [ + + ]: 2048 : if (val & 1)
365 : 1024 : val ^= CRC8_POLY;
366 : 2048 : val >>= 1;
367 : : }
368 : 256 : crc8_table[i] = val;
369 : : }
370 : : }
371 : :
372 : : static uint8_t
373 : : get_crc8(uint8_t *message, int length)
374 : : {
375 : : uint8_t crc = 0;
376 : : int i;
377 : :
378 [ + + + + : 28000014 : for (i = 0; i < length; i++)
+ + + + +
+ + + + +
+ + + + ]
379 : 22000011 : crc = crc8_table[crc ^ message[i]];
380 : : return crc;
381 : : }
382 : :
383 : : /*
384 : : * The atomic exchange test sets up a token in memory and
385 : : * then spins up multiple lcores whose job is to generate
386 : : * new tokens, exchange that new token for the old one held
387 : : * in memory, and then verify that the old token is still
388 : : * valid (i.e. the exchange did not corrupt the token).
389 : : *
390 : : * A token is made up of random data and 8 bits of crc
391 : : * covering that random data. The following is an example
392 : : * of a 64bit token.
393 : : *
394 : : * +------------+------------+
395 : : * | 63 56 | 55 0 |
396 : : * +------------+------------+
397 : : * | CRC8 | Data |
398 : : * +------------+------------+
399 : : */
400 : : static int
401 : 1 : test_atomic_exchange(__rte_unused void *arg)
402 : : {
403 : : int i;
404 : : test16_t nt16, ot16; /* new token, old token */
405 : : test32_t nt32, ot32;
406 : : test64_t nt64, ot64;
407 : :
408 : : /* Wait until all of the other threads have been dispatched */
409 [ + + ]: 565694 : while (rte_atomic32_read(&synchro) == 0)
410 : : ;
411 : :
412 : : /*
413 : : * Let the battle begin! Every thread attempts to steal the current
414 : : * token with an atomic exchange operation and install its own newly
415 : : * generated token. If the old token is valid (i.e. it has the
416 : : * appropriate crc32 hash for the data) then the test iteration has
417 : : * passed. If the token is invalid, increment the counter.
418 : : */
419 [ + + ]: 1000001 : for (i = 0; i < N; i++) {
420 : :
421 : : /* Test 64bit Atomic Exchange */
422 : 1000000 : nt64.u64 = rte_rand();
423 : 1000000 : nt64.u8[7] = get_crc8(&nt64.u8[0], sizeof(nt64) - 1);
424 : 1000000 : ot64.u64 = rte_atomic64_exchange(&token64, nt64.u64);
425 [ - + ]: 1000000 : if (ot64.u8[7] != get_crc8(&ot64.u8[0], sizeof(ot64) - 1))
426 : : rte_atomic64_inc(&count);
427 : :
428 : : /* Test 32bit Atomic Exchange */
429 : 1000000 : nt32.u32 = (uint32_t)rte_rand();
430 : 1000000 : nt32.u8[3] = get_crc8(&nt32.u8[0], sizeof(nt32) - 1);
431 : 1000000 : ot32.u32 = rte_atomic32_exchange(&token32, nt32.u32);
432 [ - + ]: 1000000 : if (ot32.u8[3] != get_crc8(&ot32.u8[0], sizeof(ot32) - 1))
433 : : rte_atomic64_inc(&count);
434 : :
435 : : /* Test 16bit Atomic Exchange */
436 : 1000000 : nt16.u16 = (uint16_t)rte_rand();
437 : 1000000 : nt16.u8[1] = get_crc8(&nt16.u8[0], sizeof(nt16) - 1);
438 : 1000000 : ot16.u16 = rte_atomic16_exchange(&token16, nt16.u16);
439 [ - + ]: 1000000 : if (ot16.u8[1] != get_crc8(&ot16.u8[0], sizeof(ot16) - 1))
440 : : rte_atomic64_inc(&count);
441 : : }
442 : :
443 : 1 : return 0;
444 : : }
445 : : static int
446 : 1 : test_atomic(void)
447 : : {
448 : : rte_atomic16_init(&a16);
449 : : rte_atomic32_init(&a32);
450 : : rte_atomic64_init(&a64);
451 : : rte_atomic64_init(&count);
452 : : rte_atomic32_init(&synchro);
453 : :
454 : : rte_atomic16_set(&a16, 1UL << 10);
455 : : rte_atomic32_set(&a32, 1UL << 10);
456 : : rte_atomic64_set(&a64, 1ULL << 33);
457 : :
458 : : printf("usual inc/dec/add/sub functions\n");
459 : :
460 : 1 : rte_eal_mp_remote_launch(test_atomic_usual, NULL, SKIP_MAIN);
461 : : rte_atomic32_set(&synchro, 1);
462 : 1 : rte_eal_mp_wait_lcore();
463 : : rte_atomic32_set(&synchro, 0);
464 : :
465 [ - + ]: 1 : if (rte_atomic16_read(&a16) != 1UL << 10) {
466 : : printf("Atomic16 usual functions failed\n");
467 : 0 : return -1;
468 : : }
469 : :
470 [ - + ]: 1 : if (rte_atomic32_read(&a32) != 1UL << 10) {
471 : : printf("Atomic32 usual functions failed\n");
472 : 0 : return -1;
473 : : }
474 : :
475 [ - + ]: 1 : if (rte_atomic64_read(&a64) != 1ULL << 33) {
476 : : printf("Atomic64 usual functions failed\n");
477 : 0 : return -1;
478 : : }
479 : :
480 : : printf("test and set\n");
481 : :
482 : : rte_atomic64_set(&a64, 0);
483 : : rte_atomic32_set(&a32, 0);
484 : : rte_atomic16_set(&a16, 0);
485 : : rte_atomic64_set(&count, 0);
486 : 1 : rte_eal_mp_remote_launch(test_atomic_tas, NULL, SKIP_MAIN);
487 : : rte_atomic32_set(&synchro, 1);
488 : 1 : rte_eal_mp_wait_lcore();
489 : : rte_atomic32_set(&synchro, 0);
490 : :
491 [ - + ]: 1 : if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) {
492 : : printf("Atomic test and set failed\n");
493 : 0 : return -1;
494 : : }
495 : :
496 : : printf("add/sub and return\n");
497 : :
498 : : rte_atomic64_set(&a64, 0);
499 : : rte_atomic32_set(&a32, 0);
500 : : rte_atomic16_set(&a16, 0);
501 : : rte_atomic64_set(&count, 0);
502 : 1 : rte_eal_mp_remote_launch(test_atomic_addsub_and_return, NULL,
503 : : SKIP_MAIN);
504 : : rte_atomic32_set(&synchro, 1);
505 : 1 : rte_eal_mp_wait_lcore();
506 : : rte_atomic32_set(&synchro, 0);
507 : :
508 [ - + ]: 1 : if (rte_atomic64_read(&count) != 0) {
509 : : printf("Atomic add/sub+return failed\n");
510 : 0 : return -1;
511 : : }
512 : :
513 : : /*
514 : : * Set a64, a32 and a16 with the same value of minus "number of worker
515 : : * lcores", launch all worker lcores to atomically increase by one and
516 : : * test them respectively.
517 : : * Each lcore should have only one chance to increase a64 by one and
518 : : * then check if it is equal to 0, but there should be only one lcore
519 : : * that finds that it is 0. It is similar for a32 and a16.
520 : : * Then a variable of "count", initialized to zero, is increased by
521 : : * one if a64, a32 or a16 is 0 after being increased and tested
522 : : * atomically.
523 : : * We can check if "count" is finally equal to 3 to see if all worker
524 : : * lcores performed "atomic inc and test" right.
525 : : */
526 : : printf("inc and test\n");
527 : :
528 : : rte_atomic64_clear(&a64);
529 : : rte_atomic32_clear(&a32);
530 : : rte_atomic16_clear(&a16);
531 : : rte_atomic32_clear(&synchro);
532 : : rte_atomic64_clear(&count);
533 : :
534 : 1 : rte_atomic64_set(&a64, (int64_t)(1 - (int64_t)rte_lcore_count()));
535 : 1 : rte_atomic32_set(&a32, (int32_t)(1 - (int32_t)rte_lcore_count()));
536 : 1 : rte_atomic16_set(&a16, (int16_t)(1 - (int16_t)rte_lcore_count()));
537 : 1 : rte_eal_mp_remote_launch(test_atomic_inc_and_test, NULL, SKIP_MAIN);
538 : : rte_atomic32_set(&synchro, 1);
539 : 1 : rte_eal_mp_wait_lcore();
540 : : rte_atomic32_clear(&synchro);
541 : :
542 [ - + ]: 1 : if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) {
543 : 0 : printf("Atomic inc and test failed %d\n", (int)count.cnt);
544 : 0 : return -1;
545 : : }
546 : :
547 : : /*
548 : : * Same as above, but this time we set the values to "number of worker
549 : : * lcores", and decrement instead of increment.
550 : : */
551 : : printf("dec and test\n");
552 : :
553 : : rte_atomic32_clear(&synchro);
554 : : rte_atomic64_clear(&count);
555 : :
556 : 1 : rte_atomic64_set(&a64, (int64_t)(rte_lcore_count() - 1));
557 : 1 : rte_atomic32_set(&a32, (int32_t)(rte_lcore_count() - 1));
558 : 1 : rte_atomic16_set(&a16, (int16_t)(rte_lcore_count() - 1));
559 : 1 : rte_eal_mp_remote_launch(test_atomic_dec_and_test, NULL, SKIP_MAIN);
560 : : rte_atomic32_set(&synchro, 1);
561 : 1 : rte_eal_mp_wait_lcore();
562 : : rte_atomic32_clear(&synchro);
563 : :
564 [ - + ]: 1 : if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) {
565 : : printf("Atomic dec and test failed\n");
566 : 0 : return -1;
567 : : }
568 : :
569 : : #if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_ARM64)
570 : : /*
571 : : * This case tests the functionality of rte_atomic128_cmp_exchange
572 : : * API. It calls rte_atomic128_cmp_exchange with four kinds of memory
573 : : * models successively on each worker core. Once each 128-bit atomic
574 : : * compare and swap operation is successful, it updates the global
575 : : * 128-bit counter by 2 for the first 64-bit and 1 for the second
576 : : * 64-bit. Each worker core iterates this test N times.
577 : : * At the end of test, verify whether the first 64-bits of the 128-bit
578 : : * counter and the second 64bits is differ by the total iterations. If
579 : : * it is, the test passes.
580 : : */
581 : : printf("128-bit compare and swap test\n");
582 : : uint64_t iterations = 0;
583 : :
584 : : rte_atomic32_clear(&synchro);
585 : 1 : count128.val[0] = 0;
586 : 1 : count128.val[1] = 0;
587 : :
588 : 1 : rte_eal_mp_remote_launch(test_atomic128_cmp_exchange, NULL,
589 : : SKIP_MAIN);
590 : : rte_atomic32_set(&synchro, 1);
591 : 1 : rte_eal_mp_wait_lcore();
592 : : rte_atomic32_clear(&synchro);
593 : :
594 : 1 : iterations = count128.val[0] - count128.val[1];
595 [ - + ]: 1 : if (iterations != (uint64_t)4*N*(rte_lcore_count()-1)) {
596 : : printf("128-bit compare and swap failed\n");
597 : 0 : return -1;
598 : : }
599 : : #endif
600 : :
601 : : /*
602 : : * Test 16/32/64bit atomic exchange.
603 : : */
604 : : test64_t t;
605 : :
606 : : printf("exchange test\n");
607 : :
608 : : rte_atomic32_clear(&synchro);
609 : : rte_atomic64_clear(&count);
610 : :
611 : : /* Generate the CRC8 lookup table */
612 : : build_crc8_table();
613 : :
614 : : /* Create the initial tokens used by the test */
615 : 1 : t.u64 = rte_rand();
616 : 1 : token16 = (get_crc8(&t.u8[0], sizeof(token16) - 1) << 8)
617 : 1 : | (t.u16[0] & 0x00ff);
618 : 1 : token32 = ((uint32_t)get_crc8(&t.u8[0], sizeof(token32) - 1) << 24)
619 : 1 : | (t.u32[0] & 0x00ffffff);
620 : 1 : token64 = ((uint64_t)get_crc8(&t.u8[0], sizeof(token64) - 1) << 56)
621 : 1 : | (t.u64 & 0x00ffffffffffffff);
622 : :
623 : 1 : rte_eal_mp_remote_launch(test_atomic_exchange, NULL, SKIP_MAIN);
624 : : rte_atomic32_set(&synchro, 1);
625 : 1 : rte_eal_mp_wait_lcore();
626 : : rte_atomic32_clear(&synchro);
627 : :
628 [ - + ]: 1 : if (rte_atomic64_read(&count) > 0) {
629 : : printf("Atomic exchange test failed\n");
630 : 0 : return -1;
631 : : }
632 : :
633 : : return 0;
634 : : }
635 : 252 : REGISTER_FAST_TEST(atomic_autotest, false, true, test_atomic);
636 : : #endif /* RTE_TOOLCHAIN_MSVC */
|