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