14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang * Copyright(c) 2019 Intel Corporation
34418919fSjohnjiang */
44418919fSjohnjiang
54418919fSjohnjiang #include <string.h>
64418919fSjohnjiang
74418919fSjohnjiang #include <rte_atomic.h>
84418919fSjohnjiang #include <rte_lcore.h>
94418919fSjohnjiang #include <rte_malloc.h>
104418919fSjohnjiang #include <rte_random.h>
114418919fSjohnjiang #include <rte_stack.h>
124418919fSjohnjiang
134418919fSjohnjiang #include "test.h"
144418919fSjohnjiang
154418919fSjohnjiang #define STACK_SIZE 4096
164418919fSjohnjiang #define MAX_BULK 32
174418919fSjohnjiang
184418919fSjohnjiang static int
test_stack_push_pop(struct rte_stack * s,void ** obj_table,unsigned int bulk_sz)194418919fSjohnjiang test_stack_push_pop(struct rte_stack *s, void **obj_table, unsigned int bulk_sz)
204418919fSjohnjiang {
214418919fSjohnjiang unsigned int i, ret;
224418919fSjohnjiang void **popped_objs;
234418919fSjohnjiang
244418919fSjohnjiang popped_objs = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0);
254418919fSjohnjiang if (popped_objs == NULL) {
264418919fSjohnjiang printf("[%s():%u] failed to calloc %zu bytes\n",
274418919fSjohnjiang __func__, __LINE__, STACK_SIZE * sizeof(void *));
284418919fSjohnjiang return -1;
294418919fSjohnjiang }
304418919fSjohnjiang
314418919fSjohnjiang for (i = 0; i < STACK_SIZE; i += bulk_sz) {
324418919fSjohnjiang ret = rte_stack_push(s, &obj_table[i], bulk_sz);
334418919fSjohnjiang
344418919fSjohnjiang if (ret != bulk_sz) {
354418919fSjohnjiang printf("[%s():%u] push returned: %d (expected %u)\n",
364418919fSjohnjiang __func__, __LINE__, ret, bulk_sz);
374418919fSjohnjiang rte_free(popped_objs);
384418919fSjohnjiang return -1;
394418919fSjohnjiang }
404418919fSjohnjiang
414418919fSjohnjiang if (rte_stack_count(s) != i + bulk_sz) {
424418919fSjohnjiang printf("[%s():%u] stack count: %u (expected %u)\n",
434418919fSjohnjiang __func__, __LINE__, rte_stack_count(s),
444418919fSjohnjiang i + bulk_sz);
454418919fSjohnjiang rte_free(popped_objs);
464418919fSjohnjiang return -1;
474418919fSjohnjiang }
484418919fSjohnjiang
494418919fSjohnjiang if (rte_stack_free_count(s) != STACK_SIZE - i - bulk_sz) {
504418919fSjohnjiang printf("[%s():%u] stack free count: %u (expected %u)\n",
514418919fSjohnjiang __func__, __LINE__, rte_stack_count(s),
524418919fSjohnjiang STACK_SIZE - i - bulk_sz);
534418919fSjohnjiang rte_free(popped_objs);
544418919fSjohnjiang return -1;
554418919fSjohnjiang }
564418919fSjohnjiang }
574418919fSjohnjiang
584418919fSjohnjiang for (i = 0; i < STACK_SIZE; i += bulk_sz) {
594418919fSjohnjiang ret = rte_stack_pop(s, &popped_objs[i], bulk_sz);
604418919fSjohnjiang
614418919fSjohnjiang if (ret != bulk_sz) {
624418919fSjohnjiang printf("[%s():%u] pop returned: %d (expected %u)\n",
634418919fSjohnjiang __func__, __LINE__, ret, bulk_sz);
644418919fSjohnjiang rte_free(popped_objs);
654418919fSjohnjiang return -1;
664418919fSjohnjiang }
674418919fSjohnjiang
684418919fSjohnjiang if (rte_stack_count(s) != STACK_SIZE - i - bulk_sz) {
694418919fSjohnjiang printf("[%s():%u] stack count: %u (expected %u)\n",
704418919fSjohnjiang __func__, __LINE__, rte_stack_count(s),
714418919fSjohnjiang STACK_SIZE - i - bulk_sz);
724418919fSjohnjiang rte_free(popped_objs);
734418919fSjohnjiang return -1;
744418919fSjohnjiang }
754418919fSjohnjiang
764418919fSjohnjiang if (rte_stack_free_count(s) != i + bulk_sz) {
774418919fSjohnjiang printf("[%s():%u] stack free count: %u (expected %u)\n",
784418919fSjohnjiang __func__, __LINE__, rte_stack_count(s),
794418919fSjohnjiang i + bulk_sz);
804418919fSjohnjiang rte_free(popped_objs);
814418919fSjohnjiang return -1;
824418919fSjohnjiang }
834418919fSjohnjiang }
844418919fSjohnjiang
854418919fSjohnjiang for (i = 0; i < STACK_SIZE; i++) {
864418919fSjohnjiang if (obj_table[i] != popped_objs[STACK_SIZE - i - 1]) {
874418919fSjohnjiang printf("[%s():%u] Incorrect value %p at index 0x%x\n",
884418919fSjohnjiang __func__, __LINE__,
894418919fSjohnjiang popped_objs[STACK_SIZE - i - 1], i);
904418919fSjohnjiang rte_free(popped_objs);
914418919fSjohnjiang return -1;
924418919fSjohnjiang }
934418919fSjohnjiang }
944418919fSjohnjiang
954418919fSjohnjiang rte_free(popped_objs);
964418919fSjohnjiang
974418919fSjohnjiang return 0;
984418919fSjohnjiang }
994418919fSjohnjiang
1004418919fSjohnjiang static int
test_stack_basic(uint32_t flags)1014418919fSjohnjiang test_stack_basic(uint32_t flags)
1024418919fSjohnjiang {
1034418919fSjohnjiang struct rte_stack *s = NULL;
1044418919fSjohnjiang void **obj_table = NULL;
1054418919fSjohnjiang int i, ret = -1;
1064418919fSjohnjiang
1074418919fSjohnjiang obj_table = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0);
1084418919fSjohnjiang if (obj_table == NULL) {
1094418919fSjohnjiang printf("[%s():%u] failed to calloc %zu bytes\n",
1104418919fSjohnjiang __func__, __LINE__, STACK_SIZE * sizeof(void *));
1114418919fSjohnjiang goto fail_test;
1124418919fSjohnjiang }
1134418919fSjohnjiang
1144418919fSjohnjiang for (i = 0; i < STACK_SIZE; i++)
1154418919fSjohnjiang obj_table[i] = (void *)(uintptr_t)i;
1164418919fSjohnjiang
1174418919fSjohnjiang s = rte_stack_create(__func__, STACK_SIZE, rte_socket_id(), flags);
1184418919fSjohnjiang if (s == NULL) {
1194418919fSjohnjiang printf("[%s():%u] failed to create a stack\n",
1204418919fSjohnjiang __func__, __LINE__);
1214418919fSjohnjiang goto fail_test;
1224418919fSjohnjiang }
1234418919fSjohnjiang
1244418919fSjohnjiang if (rte_stack_lookup(__func__) != s) {
1254418919fSjohnjiang printf("[%s():%u] failed to lookup a stack\n",
1264418919fSjohnjiang __func__, __LINE__);
1274418919fSjohnjiang goto fail_test;
1284418919fSjohnjiang }
1294418919fSjohnjiang
1304418919fSjohnjiang if (rte_stack_count(s) != 0) {
1314418919fSjohnjiang printf("[%s():%u] stack count: %u (expected 0)\n",
1324418919fSjohnjiang __func__, __LINE__, rte_stack_count(s));
1334418919fSjohnjiang goto fail_test;
1344418919fSjohnjiang }
1354418919fSjohnjiang
1364418919fSjohnjiang if (rte_stack_free_count(s) != STACK_SIZE) {
1374418919fSjohnjiang printf("[%s():%u] stack free count: %u (expected %u)\n",
1384418919fSjohnjiang __func__, __LINE__, rte_stack_count(s), STACK_SIZE);
1394418919fSjohnjiang goto fail_test;
1404418919fSjohnjiang }
1414418919fSjohnjiang
1424418919fSjohnjiang ret = test_stack_push_pop(s, obj_table, 1);
1434418919fSjohnjiang if (ret) {
1444418919fSjohnjiang printf("[%s():%u] Single object push/pop failed\n",
1454418919fSjohnjiang __func__, __LINE__);
1464418919fSjohnjiang goto fail_test;
1474418919fSjohnjiang }
1484418919fSjohnjiang
1494418919fSjohnjiang ret = test_stack_push_pop(s, obj_table, MAX_BULK);
1504418919fSjohnjiang if (ret) {
1514418919fSjohnjiang printf("[%s():%u] Bulk object push/pop failed\n",
1524418919fSjohnjiang __func__, __LINE__);
1534418919fSjohnjiang goto fail_test;
1544418919fSjohnjiang }
1554418919fSjohnjiang
1564418919fSjohnjiang ret = rte_stack_push(s, obj_table, 2 * STACK_SIZE);
1574418919fSjohnjiang if (ret != 0) {
1584418919fSjohnjiang printf("[%s():%u] Excess objects push succeeded\n",
1594418919fSjohnjiang __func__, __LINE__);
1604418919fSjohnjiang goto fail_test;
1614418919fSjohnjiang }
1624418919fSjohnjiang
1634418919fSjohnjiang ret = rte_stack_pop(s, obj_table, 1);
1644418919fSjohnjiang if (ret != 0) {
1654418919fSjohnjiang printf("[%s():%u] Empty stack pop succeeded\n",
1664418919fSjohnjiang __func__, __LINE__);
1674418919fSjohnjiang goto fail_test;
1684418919fSjohnjiang }
1694418919fSjohnjiang
1704418919fSjohnjiang ret = 0;
1714418919fSjohnjiang
1724418919fSjohnjiang fail_test:
1734418919fSjohnjiang rte_stack_free(s);
1744418919fSjohnjiang
1754418919fSjohnjiang rte_free(obj_table);
1764418919fSjohnjiang
1774418919fSjohnjiang return ret;
1784418919fSjohnjiang }
1794418919fSjohnjiang
1804418919fSjohnjiang static int
test_stack_name_reuse(uint32_t flags)1814418919fSjohnjiang test_stack_name_reuse(uint32_t flags)
1824418919fSjohnjiang {
1834418919fSjohnjiang struct rte_stack *s[2];
1844418919fSjohnjiang
1854418919fSjohnjiang s[0] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), flags);
1864418919fSjohnjiang if (s[0] == NULL) {
1874418919fSjohnjiang printf("[%s():%u] Failed to create a stack\n",
1884418919fSjohnjiang __func__, __LINE__);
1894418919fSjohnjiang return -1;
1904418919fSjohnjiang }
1914418919fSjohnjiang
1924418919fSjohnjiang s[1] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), flags);
1934418919fSjohnjiang if (s[1] != NULL) {
1944418919fSjohnjiang printf("[%s():%u] Failed to detect re-used name\n",
1954418919fSjohnjiang __func__, __LINE__);
1964418919fSjohnjiang return -1;
1974418919fSjohnjiang }
1984418919fSjohnjiang
1994418919fSjohnjiang rte_stack_free(s[0]);
2004418919fSjohnjiang
2014418919fSjohnjiang return 0;
2024418919fSjohnjiang }
2034418919fSjohnjiang
2044418919fSjohnjiang static int
test_stack_name_length(uint32_t flags)2054418919fSjohnjiang test_stack_name_length(uint32_t flags)
2064418919fSjohnjiang {
2074418919fSjohnjiang char name[RTE_STACK_NAMESIZE + 1];
2084418919fSjohnjiang struct rte_stack *s;
2094418919fSjohnjiang
2104418919fSjohnjiang memset(name, 's', sizeof(name));
2114418919fSjohnjiang name[RTE_STACK_NAMESIZE] = '\0';
2124418919fSjohnjiang
2134418919fSjohnjiang s = rte_stack_create(name, STACK_SIZE, rte_socket_id(), flags);
2144418919fSjohnjiang if (s != NULL) {
2154418919fSjohnjiang printf("[%s():%u] Failed to prevent long name\n",
2164418919fSjohnjiang __func__, __LINE__);
2174418919fSjohnjiang return -1;
2184418919fSjohnjiang }
2194418919fSjohnjiang
2204418919fSjohnjiang if (rte_errno != ENAMETOOLONG) {
2214418919fSjohnjiang printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
2224418919fSjohnjiang __func__, __LINE__);
2234418919fSjohnjiang return -1;
2244418919fSjohnjiang }
2254418919fSjohnjiang
2264418919fSjohnjiang return 0;
2274418919fSjohnjiang }
2284418919fSjohnjiang
2294418919fSjohnjiang static int
test_lookup_null(void)2304418919fSjohnjiang test_lookup_null(void)
2314418919fSjohnjiang {
2324418919fSjohnjiang struct rte_stack *s = rte_stack_lookup("stack_not_found");
2334418919fSjohnjiang
2344418919fSjohnjiang if (s != NULL) {
2354418919fSjohnjiang printf("[%s():%u] rte_stack found a non-existent stack\n",
2364418919fSjohnjiang __func__, __LINE__);
2374418919fSjohnjiang return -1;
2384418919fSjohnjiang }
2394418919fSjohnjiang
2404418919fSjohnjiang if (rte_errno != ENOENT) {
2414418919fSjohnjiang printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
2424418919fSjohnjiang __func__, __LINE__);
2434418919fSjohnjiang return -1;
2444418919fSjohnjiang }
2454418919fSjohnjiang
2464418919fSjohnjiang s = rte_stack_lookup(NULL);
2474418919fSjohnjiang
2484418919fSjohnjiang if (s != NULL) {
2494418919fSjohnjiang printf("[%s():%u] rte_stack found a non-existent stack\n",
2504418919fSjohnjiang __func__, __LINE__);
2514418919fSjohnjiang return -1;
2524418919fSjohnjiang }
2534418919fSjohnjiang
2544418919fSjohnjiang if (rte_errno != EINVAL) {
2554418919fSjohnjiang printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
2564418919fSjohnjiang __func__, __LINE__);
2574418919fSjohnjiang return -1;
2584418919fSjohnjiang }
2594418919fSjohnjiang
2604418919fSjohnjiang return 0;
2614418919fSjohnjiang }
2624418919fSjohnjiang
2634418919fSjohnjiang static int
test_free_null(void)2644418919fSjohnjiang test_free_null(void)
2654418919fSjohnjiang {
2664418919fSjohnjiang /* Check whether the library proper handles a NULL pointer */
2674418919fSjohnjiang rte_stack_free(NULL);
2684418919fSjohnjiang
2694418919fSjohnjiang return 0;
2704418919fSjohnjiang }
2714418919fSjohnjiang
2724418919fSjohnjiang #define NUM_ITERS_PER_THREAD 100000
2734418919fSjohnjiang
2744418919fSjohnjiang struct test_args {
2754418919fSjohnjiang struct rte_stack *s;
2764418919fSjohnjiang };
2774418919fSjohnjiang
278*2d9fd380Sjfb8856606 static struct test_args thread_test_args;
279*2d9fd380Sjfb8856606
2804418919fSjohnjiang static int
stack_thread_push_pop(__rte_unused void * args)281*2d9fd380Sjfb8856606 stack_thread_push_pop(__rte_unused void *args)
2824418919fSjohnjiang {
283*2d9fd380Sjfb8856606 void *obj_table[MAX_BULK];
2844418919fSjohnjiang int i;
2854418919fSjohnjiang
2864418919fSjohnjiang for (i = 0; i < NUM_ITERS_PER_THREAD; i++) {
287*2d9fd380Sjfb8856606 unsigned int num;
2884418919fSjohnjiang
289*2d9fd380Sjfb8856606 num = rte_rand() % MAX_BULK;
2904418919fSjohnjiang
291*2d9fd380Sjfb8856606 if (rte_stack_push(thread_test_args.s, obj_table, num) != num) {
2924418919fSjohnjiang printf("[%s():%u] Failed to push %u pointers\n",
2934418919fSjohnjiang __func__, __LINE__, num);
2944418919fSjohnjiang return -1;
2954418919fSjohnjiang }
2964418919fSjohnjiang
297*2d9fd380Sjfb8856606 if (rte_stack_pop(thread_test_args.s, obj_table, num) != num) {
2984418919fSjohnjiang printf("[%s():%u] Failed to pop %u pointers\n",
2994418919fSjohnjiang __func__, __LINE__, num);
3004418919fSjohnjiang return -1;
3014418919fSjohnjiang }
3024418919fSjohnjiang }
3034418919fSjohnjiang
3044418919fSjohnjiang return 0;
3054418919fSjohnjiang }
3064418919fSjohnjiang
3074418919fSjohnjiang static int
test_stack_multithreaded(uint32_t flags)3084418919fSjohnjiang test_stack_multithreaded(uint32_t flags)
3094418919fSjohnjiang {
3104418919fSjohnjiang unsigned int lcore_id;
3114418919fSjohnjiang struct rte_stack *s;
312*2d9fd380Sjfb8856606 int result = 0;
3134418919fSjohnjiang
3144418919fSjohnjiang if (rte_lcore_count() < 2) {
3154418919fSjohnjiang printf("Not enough cores for test_stack_multithreaded, expecting at least 2\n");
3164418919fSjohnjiang return TEST_SKIPPED;
3174418919fSjohnjiang }
3184418919fSjohnjiang
3194418919fSjohnjiang printf("[%s():%u] Running with %u lcores\n",
3204418919fSjohnjiang __func__, __LINE__, rte_lcore_count());
3214418919fSjohnjiang
322*2d9fd380Sjfb8856606 s = rte_stack_create("test", MAX_BULK * rte_lcore_count(), rte_socket_id(), flags);
3234418919fSjohnjiang if (s == NULL) {
3244418919fSjohnjiang printf("[%s():%u] Failed to create a stack\n",
3254418919fSjohnjiang __func__, __LINE__);
3264418919fSjohnjiang return -1;
3274418919fSjohnjiang }
3284418919fSjohnjiang
329*2d9fd380Sjfb8856606 thread_test_args.s = s;
3304418919fSjohnjiang
331*2d9fd380Sjfb8856606 if (rte_eal_mp_remote_launch(stack_thread_push_pop, NULL, CALL_MAIN))
332*2d9fd380Sjfb8856606 rte_panic("Failed to launch tests\n");
3334418919fSjohnjiang
334*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH(lcore_id) {
335*2d9fd380Sjfb8856606 if (rte_eal_wait_lcore(lcore_id) < 0)
336*2d9fd380Sjfb8856606 result = -1;
3374418919fSjohnjiang }
3384418919fSjohnjiang
3394418919fSjohnjiang rte_stack_free(s);
340*2d9fd380Sjfb8856606 return result;
3414418919fSjohnjiang }
3424418919fSjohnjiang
3434418919fSjohnjiang static int
__test_stack(uint32_t flags)3444418919fSjohnjiang __test_stack(uint32_t flags)
3454418919fSjohnjiang {
3464418919fSjohnjiang if (test_stack_basic(flags) < 0)
3474418919fSjohnjiang return -1;
3484418919fSjohnjiang
3494418919fSjohnjiang if (test_lookup_null() < 0)
3504418919fSjohnjiang return -1;
3514418919fSjohnjiang
3524418919fSjohnjiang if (test_free_null() < 0)
3534418919fSjohnjiang return -1;
3544418919fSjohnjiang
3554418919fSjohnjiang if (test_stack_name_reuse(flags) < 0)
3564418919fSjohnjiang return -1;
3574418919fSjohnjiang
3584418919fSjohnjiang if (test_stack_name_length(flags) < 0)
3594418919fSjohnjiang return -1;
3604418919fSjohnjiang
3614418919fSjohnjiang if (test_stack_multithreaded(flags) < 0)
3624418919fSjohnjiang return -1;
3634418919fSjohnjiang
3644418919fSjohnjiang return 0;
3654418919fSjohnjiang }
3664418919fSjohnjiang
3674418919fSjohnjiang static int
test_stack(void)3684418919fSjohnjiang test_stack(void)
3694418919fSjohnjiang {
3704418919fSjohnjiang return __test_stack(0);
3714418919fSjohnjiang }
3724418919fSjohnjiang
3734418919fSjohnjiang static int
test_lf_stack(void)3744418919fSjohnjiang test_lf_stack(void)
3754418919fSjohnjiang {
3764418919fSjohnjiang return __test_stack(RTE_STACK_F_LF);
3774418919fSjohnjiang }
3784418919fSjohnjiang
3794418919fSjohnjiang REGISTER_TEST_COMMAND(stack_autotest, test_stack);
3804418919fSjohnjiang REGISTER_TEST_COMMAND(stack_lf_autotest, test_lf_stack);
381