14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang * Copyright(c) 2010-2014 Intel Corporation
34418919fSjohnjiang * Copyright(c) 2019 Arm Limited
44418919fSjohnjiang */
54418919fSjohnjiang
64418919fSjohnjiang #include <stdio.h>
74418919fSjohnjiang #include <stdint.h>
84418919fSjohnjiang #include <unistd.h>
94418919fSjohnjiang #include <inttypes.h>
104418919fSjohnjiang #include <sys/queue.h>
114418919fSjohnjiang
124418919fSjohnjiang #include <rte_memory.h>
134418919fSjohnjiang #include <rte_per_lcore.h>
144418919fSjohnjiang #include <rte_launch.h>
154418919fSjohnjiang #include <rte_atomic.h>
164418919fSjohnjiang #include <rte_eal.h>
174418919fSjohnjiang #include <rte_lcore.h>
184418919fSjohnjiang #include <rte_random.h>
194418919fSjohnjiang #include <rte_hash_crc.h>
204418919fSjohnjiang
214418919fSjohnjiang #include "test.h"
224418919fSjohnjiang
234418919fSjohnjiang /*
244418919fSjohnjiang * Atomic Variables
254418919fSjohnjiang * ================
264418919fSjohnjiang *
274418919fSjohnjiang * - The main test function performs several subtests. The first
284418919fSjohnjiang * checks that the usual inc/dec/add/sub functions are working
294418919fSjohnjiang * correctly:
304418919fSjohnjiang *
314418919fSjohnjiang * - Initialize 16-bit, 32-bit and 64-bit atomic variables to specific
324418919fSjohnjiang * values.
334418919fSjohnjiang *
344418919fSjohnjiang * - These variables are incremented and decremented on each core at
354418919fSjohnjiang * the same time in ``test_atomic_usual()``.
364418919fSjohnjiang *
374418919fSjohnjiang * - The function checks that once all lcores finish their function,
384418919fSjohnjiang * the value of the atomic variables are still the same.
394418919fSjohnjiang *
404418919fSjohnjiang * - Test "test and set" functions.
414418919fSjohnjiang *
424418919fSjohnjiang * - Initialize 16-bit, 32-bit and 64-bit atomic variables to zero.
434418919fSjohnjiang *
444418919fSjohnjiang * - Invoke ``test_atomic_tas()`` on each lcore: before doing anything
454418919fSjohnjiang * else. The cores are waiting a synchro using ``while
464418919fSjohnjiang * (rte_atomic32_read(&val) == 0)`` which is triggered by the main test
474418919fSjohnjiang * function. Then all cores do a
484418919fSjohnjiang * ``rte_atomicXX_test_and_set()`` at the same time. If it is successful,
494418919fSjohnjiang * it increments another atomic counter.
504418919fSjohnjiang *
514418919fSjohnjiang * - The main function checks that the atomic counter was incremented
524418919fSjohnjiang * twice only (one for 16-bit, one for 32-bit and one for 64-bit values).
534418919fSjohnjiang *
544418919fSjohnjiang * - Test "add/sub and return" functions
554418919fSjohnjiang *
564418919fSjohnjiang * - Initialize 16-bit, 32-bit and 64-bit atomic variables to zero.
574418919fSjohnjiang *
584418919fSjohnjiang * - Invoke ``test_atomic_addsub_return()`` on each lcore. Before doing
594418919fSjohnjiang * anything else, the cores are waiting a synchro. Each lcore does
604418919fSjohnjiang * this operation several times::
614418919fSjohnjiang *
624418919fSjohnjiang * tmp = rte_atomicXX_add_return(&a, 1);
634418919fSjohnjiang * atomic_add(&count, tmp);
644418919fSjohnjiang * tmp = rte_atomicXX_sub_return(&a, 1);
654418919fSjohnjiang * atomic_sub(&count, tmp+1);
664418919fSjohnjiang *
674418919fSjohnjiang * - At the end of the test, the *count* value must be 0.
684418919fSjohnjiang *
694418919fSjohnjiang * - Test "128-bit compare and swap" (aarch64 and x86_64 only)
704418919fSjohnjiang *
714418919fSjohnjiang * - Initialize 128-bit atomic variables to zero.
724418919fSjohnjiang *
734418919fSjohnjiang * - Invoke ``test_atomic128_cmp_exchange()`` on each lcore. Before doing
744418919fSjohnjiang * anything else, the cores are waiting a synchro. Each lcore does
754418919fSjohnjiang * these compare and swap (CAS) operations several times::
764418919fSjohnjiang *
774418919fSjohnjiang * Acquired CAS update counter.val[0] + 2; counter.val[1] + 1;
784418919fSjohnjiang * Released CAS update counter.val[0] + 2; counter.val[1] + 1;
794418919fSjohnjiang * Acquired_Released CAS update counter.val[0] + 2; counter.val[1] + 1;
804418919fSjohnjiang * Relaxed CAS update counter.val[0] + 2; counter.val[1] + 1;
814418919fSjohnjiang *
824418919fSjohnjiang * - At the end of the test, the *count128* first 64-bit value and
834418919fSjohnjiang * second 64-bit value differ by the total iterations.
844418919fSjohnjiang *
854418919fSjohnjiang * - Test "atomic exchange" functions
864418919fSjohnjiang *
874418919fSjohnjiang * - Create a 64 bit token that can be tested for data integrity
884418919fSjohnjiang *
894418919fSjohnjiang * - Invoke ``test_atomic_exchange`` on each lcore. Before doing
904418919fSjohnjiang * anything else, the cores wait for a synchronization event.
914418919fSjohnjiang * Each core then does the follwoing for N iterations:
924418919fSjohnjiang *
934418919fSjohnjiang * Generate a new token with a data integrity check
944418919fSjohnjiang * Exchange the new token for previously generated token
954418919fSjohnjiang * Increment a counter if a corrupt token was received
964418919fSjohnjiang *
974418919fSjohnjiang * - At the end of the test, the number of corrupted tokens must be 0.
984418919fSjohnjiang */
994418919fSjohnjiang
1004418919fSjohnjiang #define NUM_ATOMIC_TYPES 3
1014418919fSjohnjiang
1024418919fSjohnjiang #define N 1000000
1034418919fSjohnjiang
1044418919fSjohnjiang static rte_atomic16_t a16;
1054418919fSjohnjiang static rte_atomic32_t a32;
1064418919fSjohnjiang static rte_atomic64_t a64;
1074418919fSjohnjiang static rte_atomic64_t count;
1084418919fSjohnjiang static rte_atomic32_t synchro;
1094418919fSjohnjiang
1104418919fSjohnjiang static int
test_atomic_usual(__rte_unused void * arg)111*2d9fd380Sjfb8856606 test_atomic_usual(__rte_unused void *arg)
1124418919fSjohnjiang {
1134418919fSjohnjiang unsigned i;
1144418919fSjohnjiang
1154418919fSjohnjiang while (rte_atomic32_read(&synchro) == 0)
1164418919fSjohnjiang ;
1174418919fSjohnjiang
1184418919fSjohnjiang for (i = 0; i < N; i++)
1194418919fSjohnjiang rte_atomic16_inc(&a16);
1204418919fSjohnjiang for (i = 0; i < N; i++)
1214418919fSjohnjiang rte_atomic16_dec(&a16);
1224418919fSjohnjiang for (i = 0; i < (N / 5); i++)
1234418919fSjohnjiang rte_atomic16_add(&a16, 5);
1244418919fSjohnjiang for (i = 0; i < (N / 5); i++)
1254418919fSjohnjiang rte_atomic16_sub(&a16, 5);
1264418919fSjohnjiang
1274418919fSjohnjiang for (i = 0; i < N; i++)
1284418919fSjohnjiang rte_atomic32_inc(&a32);
1294418919fSjohnjiang for (i = 0; i < N; i++)
1304418919fSjohnjiang rte_atomic32_dec(&a32);
1314418919fSjohnjiang for (i = 0; i < (N / 5); i++)
1324418919fSjohnjiang rte_atomic32_add(&a32, 5);
1334418919fSjohnjiang for (i = 0; i < (N / 5); i++)
1344418919fSjohnjiang rte_atomic32_sub(&a32, 5);
1354418919fSjohnjiang
1364418919fSjohnjiang for (i = 0; i < N; i++)
1374418919fSjohnjiang rte_atomic64_inc(&a64);
1384418919fSjohnjiang for (i = 0; i < N; i++)
1394418919fSjohnjiang rte_atomic64_dec(&a64);
1404418919fSjohnjiang for (i = 0; i < (N / 5); i++)
1414418919fSjohnjiang rte_atomic64_add(&a64, 5);
1424418919fSjohnjiang for (i = 0; i < (N / 5); i++)
1434418919fSjohnjiang rte_atomic64_sub(&a64, 5);
1444418919fSjohnjiang
1454418919fSjohnjiang return 0;
1464418919fSjohnjiang }
1474418919fSjohnjiang
1484418919fSjohnjiang static int
test_atomic_tas(__rte_unused void * arg)149*2d9fd380Sjfb8856606 test_atomic_tas(__rte_unused void *arg)
1504418919fSjohnjiang {
1514418919fSjohnjiang while (rte_atomic32_read(&synchro) == 0)
1524418919fSjohnjiang ;
1534418919fSjohnjiang
1544418919fSjohnjiang if (rte_atomic16_test_and_set(&a16))
1554418919fSjohnjiang rte_atomic64_inc(&count);
1564418919fSjohnjiang if (rte_atomic32_test_and_set(&a32))
1574418919fSjohnjiang rte_atomic64_inc(&count);
1584418919fSjohnjiang if (rte_atomic64_test_and_set(&a64))
1594418919fSjohnjiang rte_atomic64_inc(&count);
1604418919fSjohnjiang
1614418919fSjohnjiang return 0;
1624418919fSjohnjiang }
1634418919fSjohnjiang
1644418919fSjohnjiang static int
test_atomic_addsub_and_return(__rte_unused void * arg)165*2d9fd380Sjfb8856606 test_atomic_addsub_and_return(__rte_unused void *arg)
1664418919fSjohnjiang {
1674418919fSjohnjiang uint32_t tmp16;
1684418919fSjohnjiang uint32_t tmp32;
1694418919fSjohnjiang uint64_t tmp64;
1704418919fSjohnjiang unsigned i;
1714418919fSjohnjiang
1724418919fSjohnjiang while (rte_atomic32_read(&synchro) == 0)
1734418919fSjohnjiang ;
1744418919fSjohnjiang
1754418919fSjohnjiang for (i = 0; i < N; i++) {
1764418919fSjohnjiang tmp16 = rte_atomic16_add_return(&a16, 1);
1774418919fSjohnjiang rte_atomic64_add(&count, tmp16);
1784418919fSjohnjiang
1794418919fSjohnjiang tmp16 = rte_atomic16_sub_return(&a16, 1);
1804418919fSjohnjiang rte_atomic64_sub(&count, tmp16+1);
1814418919fSjohnjiang
1824418919fSjohnjiang tmp32 = rte_atomic32_add_return(&a32, 1);
1834418919fSjohnjiang rte_atomic64_add(&count, tmp32);
1844418919fSjohnjiang
1854418919fSjohnjiang tmp32 = rte_atomic32_sub_return(&a32, 1);
1864418919fSjohnjiang rte_atomic64_sub(&count, tmp32+1);
1874418919fSjohnjiang
1884418919fSjohnjiang tmp64 = rte_atomic64_add_return(&a64, 1);
1894418919fSjohnjiang rte_atomic64_add(&count, tmp64);
1904418919fSjohnjiang
1914418919fSjohnjiang tmp64 = rte_atomic64_sub_return(&a64, 1);
1924418919fSjohnjiang rte_atomic64_sub(&count, tmp64+1);
1934418919fSjohnjiang }
1944418919fSjohnjiang
1954418919fSjohnjiang return 0;
1964418919fSjohnjiang }
1974418919fSjohnjiang
1984418919fSjohnjiang /*
1994418919fSjohnjiang * rte_atomic32_inc_and_test() would increase a 32 bits counter by one and then
2004418919fSjohnjiang * test if that counter is equal to 0. It would return true if the counter is 0
2014418919fSjohnjiang * and false if the counter is not 0. rte_atomic64_inc_and_test() could do the
2024418919fSjohnjiang * same thing but for a 64 bits counter.
2034418919fSjohnjiang * Here checks that if the 32/64 bits counter is equal to 0 after being atomically
2044418919fSjohnjiang * increased by one. If it is, increase the variable of "count" by one which would
2054418919fSjohnjiang * be checked as the result later.
2064418919fSjohnjiang *
2074418919fSjohnjiang */
2084418919fSjohnjiang static int
test_atomic_inc_and_test(__rte_unused void * arg)209*2d9fd380Sjfb8856606 test_atomic_inc_and_test(__rte_unused void *arg)
2104418919fSjohnjiang {
2114418919fSjohnjiang while (rte_atomic32_read(&synchro) == 0)
2124418919fSjohnjiang ;
2134418919fSjohnjiang
2144418919fSjohnjiang if (rte_atomic16_inc_and_test(&a16)) {
2154418919fSjohnjiang rte_atomic64_inc(&count);
2164418919fSjohnjiang }
2174418919fSjohnjiang if (rte_atomic32_inc_and_test(&a32)) {
2184418919fSjohnjiang rte_atomic64_inc(&count);
2194418919fSjohnjiang }
2204418919fSjohnjiang if (rte_atomic64_inc_and_test(&a64)) {
2214418919fSjohnjiang rte_atomic64_inc(&count);
2224418919fSjohnjiang }
2234418919fSjohnjiang
2244418919fSjohnjiang return 0;
2254418919fSjohnjiang }
2264418919fSjohnjiang
2274418919fSjohnjiang /*
2284418919fSjohnjiang * rte_atomicXX_dec_and_test() should decrease a 32 bits counter by one and then
2294418919fSjohnjiang * test if that counter is equal to 0. It should return true if the counter is 0
2304418919fSjohnjiang * and false if the counter is not 0.
2314418919fSjohnjiang * This test checks if the counter is equal to 0 after being atomically
2324418919fSjohnjiang * decreased by one. If it is, increase the value of "count" by one which is to
2334418919fSjohnjiang * be checked as the result later.
2344418919fSjohnjiang */
2354418919fSjohnjiang static int
test_atomic_dec_and_test(__rte_unused void * arg)236*2d9fd380Sjfb8856606 test_atomic_dec_and_test(__rte_unused void *arg)
2374418919fSjohnjiang {
2384418919fSjohnjiang while (rte_atomic32_read(&synchro) == 0)
2394418919fSjohnjiang ;
2404418919fSjohnjiang
2414418919fSjohnjiang if (rte_atomic16_dec_and_test(&a16))
2424418919fSjohnjiang rte_atomic64_inc(&count);
2434418919fSjohnjiang
2444418919fSjohnjiang if (rte_atomic32_dec_and_test(&a32))
2454418919fSjohnjiang rte_atomic64_inc(&count);
2464418919fSjohnjiang
2474418919fSjohnjiang if (rte_atomic64_dec_and_test(&a64))
2484418919fSjohnjiang rte_atomic64_inc(&count);
2494418919fSjohnjiang
2504418919fSjohnjiang return 0;
2514418919fSjohnjiang }
2524418919fSjohnjiang
2534418919fSjohnjiang #if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_ARM64)
2544418919fSjohnjiang static rte_int128_t count128;
2554418919fSjohnjiang
2564418919fSjohnjiang /*
2574418919fSjohnjiang * rte_atomic128_cmp_exchange() should update a 128 bits counter's first 64
2584418919fSjohnjiang * bits by 2 and the second 64 bits by 1 in this test. It should return true
2594418919fSjohnjiang * if the compare exchange operation is successful.
2604418919fSjohnjiang * This test repeats 128 bits compare and swap operations N rounds. In each
2614418919fSjohnjiang * iteration it runs compare and swap operation with different memory models.
2624418919fSjohnjiang */
2634418919fSjohnjiang static int
test_atomic128_cmp_exchange(__rte_unused void * arg)264*2d9fd380Sjfb8856606 test_atomic128_cmp_exchange(__rte_unused void *arg)
2654418919fSjohnjiang {
2664418919fSjohnjiang rte_int128_t expected;
2674418919fSjohnjiang int success;
2684418919fSjohnjiang unsigned int i;
2694418919fSjohnjiang
2704418919fSjohnjiang while (rte_atomic32_read(&synchro) == 0)
2714418919fSjohnjiang ;
2724418919fSjohnjiang
2734418919fSjohnjiang expected = count128;
2744418919fSjohnjiang
2754418919fSjohnjiang for (i = 0; i < N; i++) {
2764418919fSjohnjiang do {
2774418919fSjohnjiang rte_int128_t desired;
2784418919fSjohnjiang
2794418919fSjohnjiang desired.val[0] = expected.val[0] + 2;
2804418919fSjohnjiang desired.val[1] = expected.val[1] + 1;
2814418919fSjohnjiang
2824418919fSjohnjiang success = rte_atomic128_cmp_exchange(&count128,
2834418919fSjohnjiang &expected, &desired, 1,
2844418919fSjohnjiang __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
2854418919fSjohnjiang } while (success == 0);
2864418919fSjohnjiang
2874418919fSjohnjiang do {
2884418919fSjohnjiang rte_int128_t desired;
2894418919fSjohnjiang
2904418919fSjohnjiang desired.val[0] = expected.val[0] + 2;
2914418919fSjohnjiang desired.val[1] = expected.val[1] + 1;
2924418919fSjohnjiang
2934418919fSjohnjiang success = rte_atomic128_cmp_exchange(&count128,
2944418919fSjohnjiang &expected, &desired, 1,
2954418919fSjohnjiang __ATOMIC_RELEASE, __ATOMIC_RELAXED);
2964418919fSjohnjiang } while (success == 0);
2974418919fSjohnjiang
2984418919fSjohnjiang do {
2994418919fSjohnjiang rte_int128_t desired;
3004418919fSjohnjiang
3014418919fSjohnjiang desired.val[0] = expected.val[0] + 2;
3024418919fSjohnjiang desired.val[1] = expected.val[1] + 1;
3034418919fSjohnjiang
3044418919fSjohnjiang success = rte_atomic128_cmp_exchange(&count128,
3054418919fSjohnjiang &expected, &desired, 1,
3064418919fSjohnjiang __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
3074418919fSjohnjiang } while (success == 0);
3084418919fSjohnjiang
3094418919fSjohnjiang do {
3104418919fSjohnjiang rte_int128_t desired;
3114418919fSjohnjiang
3124418919fSjohnjiang desired.val[0] = expected.val[0] + 2;
3134418919fSjohnjiang desired.val[1] = expected.val[1] + 1;
3144418919fSjohnjiang
3154418919fSjohnjiang success = rte_atomic128_cmp_exchange(&count128,
3164418919fSjohnjiang &expected, &desired, 1,
3174418919fSjohnjiang __ATOMIC_RELAXED, __ATOMIC_RELAXED);
3184418919fSjohnjiang } while (success == 0);
3194418919fSjohnjiang }
3204418919fSjohnjiang
3214418919fSjohnjiang return 0;
3224418919fSjohnjiang }
3234418919fSjohnjiang #endif
3244418919fSjohnjiang
3254418919fSjohnjiang /*
3264418919fSjohnjiang * Helper definitions/variables/functions for
3274418919fSjohnjiang * atomic exchange tests
3284418919fSjohnjiang */
3294418919fSjohnjiang typedef union {
3304418919fSjohnjiang uint16_t u16;
3314418919fSjohnjiang uint8_t u8[2];
3324418919fSjohnjiang } test16_t;
3334418919fSjohnjiang
3344418919fSjohnjiang typedef union {
3354418919fSjohnjiang uint32_t u32;
3364418919fSjohnjiang uint16_t u16[2];
3374418919fSjohnjiang uint8_t u8[4];
3384418919fSjohnjiang } test32_t;
3394418919fSjohnjiang
3404418919fSjohnjiang typedef union {
3414418919fSjohnjiang uint64_t u64;
3424418919fSjohnjiang uint32_t u32[2];
3434418919fSjohnjiang uint16_t u16[4];
3444418919fSjohnjiang uint8_t u8[8];
3454418919fSjohnjiang } test64_t;
3464418919fSjohnjiang
3474418919fSjohnjiang const uint8_t CRC8_POLY = 0x91;
3484418919fSjohnjiang uint8_t crc8_table[256];
3494418919fSjohnjiang
3504418919fSjohnjiang volatile uint16_t token16;
3514418919fSjohnjiang volatile uint32_t token32;
3524418919fSjohnjiang volatile uint64_t token64;
3534418919fSjohnjiang
3544418919fSjohnjiang static void
build_crc8_table(void)3554418919fSjohnjiang build_crc8_table(void)
3564418919fSjohnjiang {
3574418919fSjohnjiang uint8_t val;
3584418919fSjohnjiang int i, j;
3594418919fSjohnjiang
3604418919fSjohnjiang for (i = 0; i < 256; i++) {
3614418919fSjohnjiang val = i;
3624418919fSjohnjiang for (j = 0; j < 8; j++) {
3634418919fSjohnjiang if (val & 1)
3644418919fSjohnjiang val ^= CRC8_POLY;
3654418919fSjohnjiang val >>= 1;
3664418919fSjohnjiang }
3674418919fSjohnjiang crc8_table[i] = val;
3684418919fSjohnjiang }
3694418919fSjohnjiang }
3704418919fSjohnjiang
3714418919fSjohnjiang static uint8_t
get_crc8(uint8_t * message,int length)3724418919fSjohnjiang get_crc8(uint8_t *message, int length)
3734418919fSjohnjiang {
3744418919fSjohnjiang uint8_t crc = 0;
3754418919fSjohnjiang int i;
3764418919fSjohnjiang
3774418919fSjohnjiang for (i = 0; i < length; i++)
3784418919fSjohnjiang crc = crc8_table[crc ^ message[i]];
3794418919fSjohnjiang return crc;
3804418919fSjohnjiang }
3814418919fSjohnjiang
3824418919fSjohnjiang /*
3834418919fSjohnjiang * The atomic exchange test sets up a token in memory and
3844418919fSjohnjiang * then spins up multiple lcores whose job is to generate
3854418919fSjohnjiang * new tokens, exchange that new token for the old one held
3864418919fSjohnjiang * in memory, and then verify that the old token is still
3874418919fSjohnjiang * valid (i.e. the exchange did not corrupt the token).
3884418919fSjohnjiang *
3894418919fSjohnjiang * A token is made up of random data and 8 bits of crc
3904418919fSjohnjiang * covering that random data. The following is an example
3914418919fSjohnjiang * of a 64bit token.
3924418919fSjohnjiang *
3934418919fSjohnjiang * +------------+------------+
3944418919fSjohnjiang * | 63 56 | 55 0 |
3954418919fSjohnjiang * +------------+------------+
3964418919fSjohnjiang * | CRC8 | Data |
3974418919fSjohnjiang * +------------+------------+
3984418919fSjohnjiang */
3994418919fSjohnjiang static int
test_atomic_exchange(__rte_unused void * arg)400*2d9fd380Sjfb8856606 test_atomic_exchange(__rte_unused void *arg)
4014418919fSjohnjiang {
4024418919fSjohnjiang int i;
4034418919fSjohnjiang test16_t nt16, ot16; /* new token, old token */
4044418919fSjohnjiang test32_t nt32, ot32;
4054418919fSjohnjiang test64_t nt64, ot64;
4064418919fSjohnjiang
4074418919fSjohnjiang /* Wait until all of the other threads have been dispatched */
4084418919fSjohnjiang while (rte_atomic32_read(&synchro) == 0)
4094418919fSjohnjiang ;
4104418919fSjohnjiang
4114418919fSjohnjiang /*
4124418919fSjohnjiang * Let the battle begin! Every thread attempts to steal the current
4134418919fSjohnjiang * token with an atomic exchange operation and install its own newly
4144418919fSjohnjiang * generated token. If the old token is valid (i.e. it has the
4154418919fSjohnjiang * appropriate crc32 hash for the data) then the test iteration has
4164418919fSjohnjiang * passed. If the token is invalid, increment the counter.
4174418919fSjohnjiang */
4184418919fSjohnjiang for (i = 0; i < N; i++) {
4194418919fSjohnjiang
4204418919fSjohnjiang /* Test 64bit Atomic Exchange */
4214418919fSjohnjiang nt64.u64 = rte_rand();
4224418919fSjohnjiang nt64.u8[7] = get_crc8(&nt64.u8[0], sizeof(nt64) - 1);
4234418919fSjohnjiang ot64.u64 = rte_atomic64_exchange(&token64, nt64.u64);
4244418919fSjohnjiang if (ot64.u8[7] != get_crc8(&ot64.u8[0], sizeof(ot64) - 1))
4254418919fSjohnjiang rte_atomic64_inc(&count);
4264418919fSjohnjiang
4274418919fSjohnjiang /* Test 32bit Atomic Exchange */
4284418919fSjohnjiang nt32.u32 = (uint32_t)rte_rand();
4294418919fSjohnjiang nt32.u8[3] = get_crc8(&nt32.u8[0], sizeof(nt32) - 1);
4304418919fSjohnjiang ot32.u32 = rte_atomic32_exchange(&token32, nt32.u32);
4314418919fSjohnjiang if (ot32.u8[3] != get_crc8(&ot32.u8[0], sizeof(ot32) - 1))
4324418919fSjohnjiang rte_atomic64_inc(&count);
4334418919fSjohnjiang
4344418919fSjohnjiang /* Test 16bit Atomic Exchange */
4354418919fSjohnjiang nt16.u16 = (uint16_t)rte_rand();
4364418919fSjohnjiang nt16.u8[1] = get_crc8(&nt16.u8[0], sizeof(nt16) - 1);
4374418919fSjohnjiang ot16.u16 = rte_atomic16_exchange(&token16, nt16.u16);
4384418919fSjohnjiang if (ot16.u8[1] != get_crc8(&ot16.u8[0], sizeof(ot16) - 1))
4394418919fSjohnjiang rte_atomic64_inc(&count);
4404418919fSjohnjiang }
4414418919fSjohnjiang
4424418919fSjohnjiang return 0;
4434418919fSjohnjiang }
4444418919fSjohnjiang static int
test_atomic(void)4454418919fSjohnjiang test_atomic(void)
4464418919fSjohnjiang {
4474418919fSjohnjiang rte_atomic16_init(&a16);
4484418919fSjohnjiang rte_atomic32_init(&a32);
4494418919fSjohnjiang rte_atomic64_init(&a64);
4504418919fSjohnjiang rte_atomic64_init(&count);
4514418919fSjohnjiang rte_atomic32_init(&synchro);
4524418919fSjohnjiang
4534418919fSjohnjiang rte_atomic16_set(&a16, 1UL << 10);
4544418919fSjohnjiang rte_atomic32_set(&a32, 1UL << 10);
4554418919fSjohnjiang rte_atomic64_set(&a64, 1ULL << 33);
4564418919fSjohnjiang
4574418919fSjohnjiang printf("usual inc/dec/add/sub functions\n");
4584418919fSjohnjiang
459*2d9fd380Sjfb8856606 rte_eal_mp_remote_launch(test_atomic_usual, NULL, SKIP_MAIN);
4604418919fSjohnjiang rte_atomic32_set(&synchro, 1);
4614418919fSjohnjiang rte_eal_mp_wait_lcore();
4624418919fSjohnjiang rte_atomic32_set(&synchro, 0);
4634418919fSjohnjiang
4644418919fSjohnjiang if (rte_atomic16_read(&a16) != 1UL << 10) {
4654418919fSjohnjiang printf("Atomic16 usual functions failed\n");
4664418919fSjohnjiang return -1;
4674418919fSjohnjiang }
4684418919fSjohnjiang
4694418919fSjohnjiang if (rte_atomic32_read(&a32) != 1UL << 10) {
4704418919fSjohnjiang printf("Atomic32 usual functions failed\n");
4714418919fSjohnjiang return -1;
4724418919fSjohnjiang }
4734418919fSjohnjiang
4744418919fSjohnjiang if (rte_atomic64_read(&a64) != 1ULL << 33) {
4754418919fSjohnjiang printf("Atomic64 usual functions failed\n");
4764418919fSjohnjiang return -1;
4774418919fSjohnjiang }
4784418919fSjohnjiang
4794418919fSjohnjiang printf("test and set\n");
4804418919fSjohnjiang
4814418919fSjohnjiang rte_atomic64_set(&a64, 0);
4824418919fSjohnjiang rte_atomic32_set(&a32, 0);
4834418919fSjohnjiang rte_atomic16_set(&a16, 0);
4844418919fSjohnjiang rte_atomic64_set(&count, 0);
485*2d9fd380Sjfb8856606 rte_eal_mp_remote_launch(test_atomic_tas, NULL, SKIP_MAIN);
4864418919fSjohnjiang rte_atomic32_set(&synchro, 1);
4874418919fSjohnjiang rte_eal_mp_wait_lcore();
4884418919fSjohnjiang rte_atomic32_set(&synchro, 0);
4894418919fSjohnjiang
4904418919fSjohnjiang if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) {
4914418919fSjohnjiang printf("Atomic test and set failed\n");
4924418919fSjohnjiang return -1;
4934418919fSjohnjiang }
4944418919fSjohnjiang
4954418919fSjohnjiang printf("add/sub and return\n");
4964418919fSjohnjiang
4974418919fSjohnjiang rte_atomic64_set(&a64, 0);
4984418919fSjohnjiang rte_atomic32_set(&a32, 0);
4994418919fSjohnjiang rte_atomic16_set(&a16, 0);
5004418919fSjohnjiang rte_atomic64_set(&count, 0);
5014418919fSjohnjiang rte_eal_mp_remote_launch(test_atomic_addsub_and_return, NULL,
502*2d9fd380Sjfb8856606 SKIP_MAIN);
5034418919fSjohnjiang rte_atomic32_set(&synchro, 1);
5044418919fSjohnjiang rte_eal_mp_wait_lcore();
5054418919fSjohnjiang rte_atomic32_set(&synchro, 0);
5064418919fSjohnjiang
5074418919fSjohnjiang if (rte_atomic64_read(&count) != 0) {
5084418919fSjohnjiang printf("Atomic add/sub+return failed\n");
5094418919fSjohnjiang return -1;
5104418919fSjohnjiang }
5114418919fSjohnjiang
5124418919fSjohnjiang /*
513*2d9fd380Sjfb8856606 * Set a64, a32 and a16 with the same value of minus "number of worker
514*2d9fd380Sjfb8856606 * lcores", launch all worker lcores to atomically increase by one and
5154418919fSjohnjiang * test them respectively.
5164418919fSjohnjiang * Each lcore should have only one chance to increase a64 by one and
5174418919fSjohnjiang * then check if it is equal to 0, but there should be only one lcore
5184418919fSjohnjiang * that finds that it is 0. It is similar for a32 and a16.
5194418919fSjohnjiang * Then a variable of "count", initialized to zero, is increased by
5204418919fSjohnjiang * one if a64, a32 or a16 is 0 after being increased and tested
5214418919fSjohnjiang * atomically.
522*2d9fd380Sjfb8856606 * We can check if "count" is finally equal to 3 to see if all worker
5234418919fSjohnjiang * lcores performed "atomic inc and test" right.
5244418919fSjohnjiang */
5254418919fSjohnjiang printf("inc and test\n");
5264418919fSjohnjiang
5274418919fSjohnjiang rte_atomic64_clear(&a64);
5284418919fSjohnjiang rte_atomic32_clear(&a32);
5294418919fSjohnjiang rte_atomic16_clear(&a16);
5304418919fSjohnjiang rte_atomic32_clear(&synchro);
5314418919fSjohnjiang rte_atomic64_clear(&count);
5324418919fSjohnjiang
5334418919fSjohnjiang rte_atomic64_set(&a64, (int64_t)(1 - (int64_t)rte_lcore_count()));
5344418919fSjohnjiang rte_atomic32_set(&a32, (int32_t)(1 - (int32_t)rte_lcore_count()));
5354418919fSjohnjiang rte_atomic16_set(&a16, (int16_t)(1 - (int16_t)rte_lcore_count()));
536*2d9fd380Sjfb8856606 rte_eal_mp_remote_launch(test_atomic_inc_and_test, NULL, SKIP_MAIN);
5374418919fSjohnjiang rte_atomic32_set(&synchro, 1);
5384418919fSjohnjiang rte_eal_mp_wait_lcore();
5394418919fSjohnjiang rte_atomic32_clear(&synchro);
5404418919fSjohnjiang
5414418919fSjohnjiang if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) {
5424418919fSjohnjiang printf("Atomic inc and test failed %d\n", (int)count.cnt);
5434418919fSjohnjiang return -1;
5444418919fSjohnjiang }
5454418919fSjohnjiang
5464418919fSjohnjiang /*
547*2d9fd380Sjfb8856606 * Same as above, but this time we set the values to "number of worker
5484418919fSjohnjiang * lcores", and decrement instead of increment.
5494418919fSjohnjiang */
5504418919fSjohnjiang printf("dec and test\n");
5514418919fSjohnjiang
5524418919fSjohnjiang rte_atomic32_clear(&synchro);
5534418919fSjohnjiang rte_atomic64_clear(&count);
5544418919fSjohnjiang
5554418919fSjohnjiang rte_atomic64_set(&a64, (int64_t)(rte_lcore_count() - 1));
5564418919fSjohnjiang rte_atomic32_set(&a32, (int32_t)(rte_lcore_count() - 1));
5574418919fSjohnjiang rte_atomic16_set(&a16, (int16_t)(rte_lcore_count() - 1));
558*2d9fd380Sjfb8856606 rte_eal_mp_remote_launch(test_atomic_dec_and_test, NULL, SKIP_MAIN);
5594418919fSjohnjiang rte_atomic32_set(&synchro, 1);
5604418919fSjohnjiang rte_eal_mp_wait_lcore();
5614418919fSjohnjiang rte_atomic32_clear(&synchro);
5624418919fSjohnjiang
5634418919fSjohnjiang if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) {
5644418919fSjohnjiang printf("Atomic dec and test failed\n");
5654418919fSjohnjiang return -1;
5664418919fSjohnjiang }
5674418919fSjohnjiang
5684418919fSjohnjiang #if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_ARM64)
5694418919fSjohnjiang /*
5704418919fSjohnjiang * This case tests the functionality of rte_atomic128_cmp_exchange
5714418919fSjohnjiang * API. It calls rte_atomic128_cmp_exchange with four kinds of memory
572*2d9fd380Sjfb8856606 * models successively on each worker core. Once each 128-bit atomic
5734418919fSjohnjiang * compare and swap operation is successful, it updates the global
5744418919fSjohnjiang * 128-bit counter by 2 for the first 64-bit and 1 for the second
575*2d9fd380Sjfb8856606 * 64-bit. Each worker core iterates this test N times.
5764418919fSjohnjiang * At the end of test, verify whether the first 64-bits of the 128-bit
5774418919fSjohnjiang * counter and the second 64bits is differ by the total iterations. If
5784418919fSjohnjiang * it is, the test passes.
5794418919fSjohnjiang */
5804418919fSjohnjiang printf("128-bit compare and swap test\n");
5814418919fSjohnjiang uint64_t iterations = 0;
5824418919fSjohnjiang
5834418919fSjohnjiang rte_atomic32_clear(&synchro);
5844418919fSjohnjiang count128.val[0] = 0;
5854418919fSjohnjiang count128.val[1] = 0;
5864418919fSjohnjiang
5874418919fSjohnjiang rte_eal_mp_remote_launch(test_atomic128_cmp_exchange, NULL,
588*2d9fd380Sjfb8856606 SKIP_MAIN);
5894418919fSjohnjiang rte_atomic32_set(&synchro, 1);
5904418919fSjohnjiang rte_eal_mp_wait_lcore();
5914418919fSjohnjiang rte_atomic32_clear(&synchro);
5924418919fSjohnjiang
5934418919fSjohnjiang iterations = count128.val[0] - count128.val[1];
5944418919fSjohnjiang if (iterations != 4*N*(rte_lcore_count()-1)) {
5954418919fSjohnjiang printf("128-bit compare and swap failed\n");
5964418919fSjohnjiang return -1;
5974418919fSjohnjiang }
5984418919fSjohnjiang #endif
5994418919fSjohnjiang
6004418919fSjohnjiang /*
6014418919fSjohnjiang * Test 16/32/64bit atomic exchange.
6024418919fSjohnjiang */
6034418919fSjohnjiang test64_t t;
6044418919fSjohnjiang
6054418919fSjohnjiang printf("exchange test\n");
6064418919fSjohnjiang
6074418919fSjohnjiang rte_atomic32_clear(&synchro);
6084418919fSjohnjiang rte_atomic64_clear(&count);
6094418919fSjohnjiang
6104418919fSjohnjiang /* Generate the CRC8 lookup table */
6114418919fSjohnjiang build_crc8_table();
6124418919fSjohnjiang
6134418919fSjohnjiang /* Create the initial tokens used by the test */
6144418919fSjohnjiang t.u64 = rte_rand();
6154418919fSjohnjiang token16 = (get_crc8(&t.u8[0], sizeof(token16) - 1) << 8)
6164418919fSjohnjiang | (t.u16[0] & 0x00ff);
6174418919fSjohnjiang token32 = ((uint32_t)get_crc8(&t.u8[0], sizeof(token32) - 1) << 24)
6184418919fSjohnjiang | (t.u32[0] & 0x00ffffff);
6194418919fSjohnjiang token64 = ((uint64_t)get_crc8(&t.u8[0], sizeof(token64) - 1) << 56)
6204418919fSjohnjiang | (t.u64 & 0x00ffffffffffffff);
6214418919fSjohnjiang
622*2d9fd380Sjfb8856606 rte_eal_mp_remote_launch(test_atomic_exchange, NULL, SKIP_MAIN);
6234418919fSjohnjiang rte_atomic32_set(&synchro, 1);
6244418919fSjohnjiang rte_eal_mp_wait_lcore();
6254418919fSjohnjiang rte_atomic32_clear(&synchro);
6264418919fSjohnjiang
6274418919fSjohnjiang if (rte_atomic64_read(&count) > 0) {
6284418919fSjohnjiang printf("Atomic exchange test failed\n");
6294418919fSjohnjiang return -1;
6304418919fSjohnjiang }
6314418919fSjohnjiang
6324418919fSjohnjiang return 0;
6334418919fSjohnjiang }
6344418919fSjohnjiang REGISTER_TEST_COMMAND(atomic_autotest, test_atomic);
635