15e2e61b9SGage Eads /* SPDX-License-Identifier: BSD-3-Clause 25e2e61b9SGage Eads * Copyright(c) 2019 Intel Corporation 35e2e61b9SGage Eads */ 45e2e61b9SGage Eads 55e2e61b9SGage Eads #include <string.h> 65e2e61b9SGage Eads 75e2e61b9SGage Eads #include <rte_atomic.h> 85e2e61b9SGage Eads #include <rte_lcore.h> 95e2e61b9SGage Eads #include <rte_malloc.h> 105e2e61b9SGage Eads #include <rte_random.h> 115e2e61b9SGage Eads #include <rte_stack.h> 125e2e61b9SGage Eads 135e2e61b9SGage Eads #include "test.h" 145e2e61b9SGage Eads 155e2e61b9SGage Eads #define STACK_SIZE 4096 165e2e61b9SGage Eads #define MAX_BULK 32 175e2e61b9SGage Eads 185e2e61b9SGage Eads static int 195e2e61b9SGage Eads test_stack_push_pop(struct rte_stack *s, void **obj_table, unsigned int bulk_sz) 205e2e61b9SGage Eads { 215e2e61b9SGage Eads unsigned int i, ret; 225e2e61b9SGage Eads void **popped_objs; 235e2e61b9SGage Eads 245e2e61b9SGage Eads popped_objs = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0); 255e2e61b9SGage Eads if (popped_objs == NULL) { 265e2e61b9SGage Eads printf("[%s():%u] failed to calloc %zu bytes\n", 275e2e61b9SGage Eads __func__, __LINE__, STACK_SIZE * sizeof(void *)); 285e2e61b9SGage Eads return -1; 295e2e61b9SGage Eads } 305e2e61b9SGage Eads 315e2e61b9SGage Eads for (i = 0; i < STACK_SIZE; i += bulk_sz) { 325e2e61b9SGage Eads ret = rte_stack_push(s, &obj_table[i], bulk_sz); 335e2e61b9SGage Eads 345e2e61b9SGage Eads if (ret != bulk_sz) { 355e2e61b9SGage Eads printf("[%s():%u] push returned: %d (expected %u)\n", 365e2e61b9SGage Eads __func__, __LINE__, ret, bulk_sz); 375e2e61b9SGage Eads rte_free(popped_objs); 385e2e61b9SGage Eads return -1; 395e2e61b9SGage Eads } 405e2e61b9SGage Eads 415e2e61b9SGage Eads if (rte_stack_count(s) != i + bulk_sz) { 425e2e61b9SGage Eads printf("[%s():%u] stack count: %u (expected %u)\n", 435e2e61b9SGage Eads __func__, __LINE__, rte_stack_count(s), 445e2e61b9SGage Eads i + bulk_sz); 455e2e61b9SGage Eads rte_free(popped_objs); 465e2e61b9SGage Eads return -1; 475e2e61b9SGage Eads } 485e2e61b9SGage Eads 495e2e61b9SGage Eads if (rte_stack_free_count(s) != STACK_SIZE - i - bulk_sz) { 505e2e61b9SGage Eads printf("[%s():%u] stack free count: %u (expected %u)\n", 515e2e61b9SGage Eads __func__, __LINE__, rte_stack_count(s), 525e2e61b9SGage Eads STACK_SIZE - i - bulk_sz); 535e2e61b9SGage Eads rte_free(popped_objs); 545e2e61b9SGage Eads return -1; 555e2e61b9SGage Eads } 565e2e61b9SGage Eads } 575e2e61b9SGage Eads 585e2e61b9SGage Eads for (i = 0; i < STACK_SIZE; i += bulk_sz) { 595e2e61b9SGage Eads ret = rte_stack_pop(s, &popped_objs[i], bulk_sz); 605e2e61b9SGage Eads 615e2e61b9SGage Eads if (ret != bulk_sz) { 625e2e61b9SGage Eads printf("[%s():%u] pop returned: %d (expected %u)\n", 635e2e61b9SGage Eads __func__, __LINE__, ret, bulk_sz); 645e2e61b9SGage Eads rte_free(popped_objs); 655e2e61b9SGage Eads return -1; 665e2e61b9SGage Eads } 675e2e61b9SGage Eads 685e2e61b9SGage Eads if (rte_stack_count(s) != STACK_SIZE - i - bulk_sz) { 695e2e61b9SGage Eads printf("[%s():%u] stack count: %u (expected %u)\n", 705e2e61b9SGage Eads __func__, __LINE__, rte_stack_count(s), 715e2e61b9SGage Eads STACK_SIZE - i - bulk_sz); 725e2e61b9SGage Eads rte_free(popped_objs); 735e2e61b9SGage Eads return -1; 745e2e61b9SGage Eads } 755e2e61b9SGage Eads 765e2e61b9SGage Eads if (rte_stack_free_count(s) != i + bulk_sz) { 775e2e61b9SGage Eads printf("[%s():%u] stack free count: %u (expected %u)\n", 785e2e61b9SGage Eads __func__, __LINE__, rte_stack_count(s), 795e2e61b9SGage Eads i + bulk_sz); 805e2e61b9SGage Eads rte_free(popped_objs); 815e2e61b9SGage Eads return -1; 825e2e61b9SGage Eads } 835e2e61b9SGage Eads } 845e2e61b9SGage Eads 855e2e61b9SGage Eads for (i = 0; i < STACK_SIZE; i++) { 865e2e61b9SGage Eads if (obj_table[i] != popped_objs[STACK_SIZE - i - 1]) { 875e2e61b9SGage Eads printf("[%s():%u] Incorrect value %p at index 0x%x\n", 885e2e61b9SGage Eads __func__, __LINE__, 895e2e61b9SGage Eads popped_objs[STACK_SIZE - i - 1], i); 905e2e61b9SGage Eads rte_free(popped_objs); 915e2e61b9SGage Eads return -1; 925e2e61b9SGage Eads } 935e2e61b9SGage Eads } 945e2e61b9SGage Eads 955e2e61b9SGage Eads rte_free(popped_objs); 965e2e61b9SGage Eads 975e2e61b9SGage Eads return 0; 985e2e61b9SGage Eads } 995e2e61b9SGage Eads 1005e2e61b9SGage Eads static int 1010420378bSGage Eads test_stack_basic(uint32_t flags) 1025e2e61b9SGage Eads { 1035e2e61b9SGage Eads struct rte_stack *s = NULL; 1045e2e61b9SGage Eads void **obj_table = NULL; 1055e2e61b9SGage Eads int i, ret = -1; 1065e2e61b9SGage Eads 1075e2e61b9SGage Eads obj_table = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0); 1085e2e61b9SGage Eads if (obj_table == NULL) { 1095e2e61b9SGage Eads printf("[%s():%u] failed to calloc %zu bytes\n", 1105e2e61b9SGage Eads __func__, __LINE__, STACK_SIZE * sizeof(void *)); 1115e2e61b9SGage Eads goto fail_test; 1125e2e61b9SGage Eads } 1135e2e61b9SGage Eads 1145e2e61b9SGage Eads for (i = 0; i < STACK_SIZE; i++) 1155e2e61b9SGage Eads obj_table[i] = (void *)(uintptr_t)i; 1165e2e61b9SGage Eads 1170420378bSGage Eads s = rte_stack_create(__func__, STACK_SIZE, rte_socket_id(), flags); 1185e2e61b9SGage Eads if (s == NULL) { 1195e2e61b9SGage Eads printf("[%s():%u] failed to create a stack\n", 1205e2e61b9SGage Eads __func__, __LINE__); 1215e2e61b9SGage Eads goto fail_test; 1225e2e61b9SGage Eads } 1235e2e61b9SGage Eads 1245e2e61b9SGage Eads if (rte_stack_lookup(__func__) != s) { 1255e2e61b9SGage Eads printf("[%s():%u] failed to lookup a stack\n", 1265e2e61b9SGage Eads __func__, __LINE__); 1275e2e61b9SGage Eads goto fail_test; 1285e2e61b9SGage Eads } 1295e2e61b9SGage Eads 1305e2e61b9SGage Eads if (rte_stack_count(s) != 0) { 1315e2e61b9SGage Eads printf("[%s():%u] stack count: %u (expected 0)\n", 1325e2e61b9SGage Eads __func__, __LINE__, rte_stack_count(s)); 1335e2e61b9SGage Eads goto fail_test; 1345e2e61b9SGage Eads } 1355e2e61b9SGage Eads 1365e2e61b9SGage Eads if (rte_stack_free_count(s) != STACK_SIZE) { 1375e2e61b9SGage Eads printf("[%s():%u] stack free count: %u (expected %u)\n", 1385e2e61b9SGage Eads __func__, __LINE__, rte_stack_count(s), STACK_SIZE); 1395e2e61b9SGage Eads goto fail_test; 1405e2e61b9SGage Eads } 1415e2e61b9SGage Eads 1425e2e61b9SGage Eads ret = test_stack_push_pop(s, obj_table, 1); 1435e2e61b9SGage Eads if (ret) { 1445e2e61b9SGage Eads printf("[%s():%u] Single object push/pop failed\n", 1455e2e61b9SGage Eads __func__, __LINE__); 1465e2e61b9SGage Eads goto fail_test; 1475e2e61b9SGage Eads } 1485e2e61b9SGage Eads 1495e2e61b9SGage Eads ret = test_stack_push_pop(s, obj_table, MAX_BULK); 1505e2e61b9SGage Eads if (ret) { 1515e2e61b9SGage Eads printf("[%s():%u] Bulk object push/pop failed\n", 1525e2e61b9SGage Eads __func__, __LINE__); 1535e2e61b9SGage Eads goto fail_test; 1545e2e61b9SGage Eads } 1555e2e61b9SGage Eads 1565e2e61b9SGage Eads ret = rte_stack_push(s, obj_table, 2 * STACK_SIZE); 1575e2e61b9SGage Eads if (ret != 0) { 1585e2e61b9SGage Eads printf("[%s():%u] Excess objects push succeeded\n", 1595e2e61b9SGage Eads __func__, __LINE__); 1605e2e61b9SGage Eads goto fail_test; 1615e2e61b9SGage Eads } 1625e2e61b9SGage Eads 1635e2e61b9SGage Eads ret = rte_stack_pop(s, obj_table, 1); 1645e2e61b9SGage Eads if (ret != 0) { 1655e2e61b9SGage Eads printf("[%s():%u] Empty stack pop succeeded\n", 1665e2e61b9SGage Eads __func__, __LINE__); 1675e2e61b9SGage Eads goto fail_test; 1685e2e61b9SGage Eads } 1695e2e61b9SGage Eads 1705e2e61b9SGage Eads ret = 0; 1715e2e61b9SGage Eads 1725e2e61b9SGage Eads fail_test: 1735e2e61b9SGage Eads rte_stack_free(s); 1745e2e61b9SGage Eads 1755e2e61b9SGage Eads rte_free(obj_table); 1765e2e61b9SGage Eads 1775e2e61b9SGage Eads return ret; 1785e2e61b9SGage Eads } 1795e2e61b9SGage Eads 1805e2e61b9SGage Eads static int 1810420378bSGage Eads test_stack_name_reuse(uint32_t flags) 1825e2e61b9SGage Eads { 1835e2e61b9SGage Eads struct rte_stack *s[2]; 1845e2e61b9SGage Eads 1850420378bSGage Eads s[0] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), flags); 1865e2e61b9SGage Eads if (s[0] == NULL) { 1875e2e61b9SGage Eads printf("[%s():%u] Failed to create a stack\n", 1885e2e61b9SGage Eads __func__, __LINE__); 1895e2e61b9SGage Eads return -1; 1905e2e61b9SGage Eads } 1915e2e61b9SGage Eads 1920420378bSGage Eads s[1] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), flags); 1935e2e61b9SGage Eads if (s[1] != NULL) { 1945e2e61b9SGage Eads printf("[%s():%u] Failed to detect re-used name\n", 1955e2e61b9SGage Eads __func__, __LINE__); 1965e2e61b9SGage Eads return -1; 1975e2e61b9SGage Eads } 1985e2e61b9SGage Eads 1995e2e61b9SGage Eads rte_stack_free(s[0]); 2005e2e61b9SGage Eads 2015e2e61b9SGage Eads return 0; 2025e2e61b9SGage Eads } 2035e2e61b9SGage Eads 2045e2e61b9SGage Eads static int 2050420378bSGage Eads test_stack_name_length(uint32_t flags) 2065e2e61b9SGage Eads { 2075e2e61b9SGage Eads char name[RTE_STACK_NAMESIZE + 1]; 2085e2e61b9SGage Eads struct rte_stack *s; 2095e2e61b9SGage Eads 2105e2e61b9SGage Eads memset(name, 's', sizeof(name)); 2115e2e61b9SGage Eads name[RTE_STACK_NAMESIZE] = '\0'; 2125e2e61b9SGage Eads 2130420378bSGage Eads s = rte_stack_create(name, STACK_SIZE, rte_socket_id(), flags); 2145e2e61b9SGage Eads if (s != NULL) { 2155e2e61b9SGage Eads printf("[%s():%u] Failed to prevent long name\n", 2165e2e61b9SGage Eads __func__, __LINE__); 2175e2e61b9SGage Eads return -1; 2185e2e61b9SGage Eads } 2195e2e61b9SGage Eads 2205e2e61b9SGage Eads if (rte_errno != ENAMETOOLONG) { 2215e2e61b9SGage Eads printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n", 2225e2e61b9SGage Eads __func__, __LINE__); 2235e2e61b9SGage Eads return -1; 2245e2e61b9SGage Eads } 2255e2e61b9SGage Eads 2265e2e61b9SGage Eads return 0; 2275e2e61b9SGage Eads } 2285e2e61b9SGage Eads 2295e2e61b9SGage Eads static int 2305e2e61b9SGage Eads test_lookup_null(void) 2315e2e61b9SGage Eads { 2325e2e61b9SGage Eads struct rte_stack *s = rte_stack_lookup("stack_not_found"); 2335e2e61b9SGage Eads 2345e2e61b9SGage Eads if (s != NULL) { 2355e2e61b9SGage Eads printf("[%s():%u] rte_stack found a non-existent stack\n", 2365e2e61b9SGage Eads __func__, __LINE__); 2375e2e61b9SGage Eads return -1; 2385e2e61b9SGage Eads } 2395e2e61b9SGage Eads 2405e2e61b9SGage Eads if (rte_errno != ENOENT) { 2415e2e61b9SGage Eads printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n", 2425e2e61b9SGage Eads __func__, __LINE__); 2435e2e61b9SGage Eads return -1; 2445e2e61b9SGage Eads } 2455e2e61b9SGage Eads 2465e2e61b9SGage Eads s = rte_stack_lookup(NULL); 2475e2e61b9SGage Eads 2485e2e61b9SGage Eads if (s != NULL) { 2495e2e61b9SGage Eads printf("[%s():%u] rte_stack found a non-existent stack\n", 2505e2e61b9SGage Eads __func__, __LINE__); 2515e2e61b9SGage Eads return -1; 2525e2e61b9SGage Eads } 2535e2e61b9SGage Eads 2545e2e61b9SGage Eads if (rte_errno != EINVAL) { 2555e2e61b9SGage Eads printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n", 2565e2e61b9SGage Eads __func__, __LINE__); 2575e2e61b9SGage Eads return -1; 2585e2e61b9SGage Eads } 2595e2e61b9SGage Eads 2605e2e61b9SGage Eads return 0; 2615e2e61b9SGage Eads } 2625e2e61b9SGage Eads 2635e2e61b9SGage Eads static int 2645e2e61b9SGage Eads test_free_null(void) 2655e2e61b9SGage Eads { 2665e2e61b9SGage Eads /* Check whether the library proper handles a NULL pointer */ 2675e2e61b9SGage Eads rte_stack_free(NULL); 2685e2e61b9SGage Eads 2695e2e61b9SGage Eads return 0; 2705e2e61b9SGage Eads } 2715e2e61b9SGage Eads 2725e2e61b9SGage Eads #define NUM_ITERS_PER_THREAD 100000 2735e2e61b9SGage Eads 2745e2e61b9SGage Eads struct test_args { 2755e2e61b9SGage Eads struct rte_stack *s; 2765e2e61b9SGage Eads }; 2775e2e61b9SGage Eads 278e67925afSSteven Lariau static struct test_args thread_test_args; 2795e2e61b9SGage Eads 280e67925afSSteven Lariau static int 281e67925afSSteven Lariau stack_thread_push_pop(__rte_unused void *args) 282e67925afSSteven Lariau { 283e67925afSSteven Lariau void *obj_table[MAX_BULK]; 284e67925afSSteven Lariau int i; 2855e2e61b9SGage Eads 2865e2e61b9SGage Eads for (i = 0; i < NUM_ITERS_PER_THREAD; i++) { 287*c51e67c2SSteven Lariau unsigned int num; 2885e2e61b9SGage Eads 289*c51e67c2SSteven Lariau num = rte_rand() % MAX_BULK; 2905e2e61b9SGage Eads 291e67925afSSteven Lariau if (rte_stack_push(thread_test_args.s, obj_table, num) != num) { 2925e2e61b9SGage Eads printf("[%s():%u] Failed to push %u pointers\n", 2935e2e61b9SGage Eads __func__, __LINE__, num); 2945e2e61b9SGage Eads return -1; 2955e2e61b9SGage Eads } 2965e2e61b9SGage Eads 297e67925afSSteven Lariau if (rte_stack_pop(thread_test_args.s, obj_table, num) != num) { 2985e2e61b9SGage Eads printf("[%s():%u] Failed to pop %u pointers\n", 2995e2e61b9SGage Eads __func__, __LINE__, num); 3005e2e61b9SGage Eads return -1; 3015e2e61b9SGage Eads } 3025e2e61b9SGage Eads } 3035e2e61b9SGage Eads 3045e2e61b9SGage Eads return 0; 3055e2e61b9SGage Eads } 3065e2e61b9SGage Eads 3075e2e61b9SGage Eads static int 3080420378bSGage Eads test_stack_multithreaded(uint32_t flags) 3095e2e61b9SGage Eads { 31004442131SSteven Lariau unsigned int lcore_id; 3115e2e61b9SGage Eads struct rte_stack *s; 31204442131SSteven Lariau int result = 0; 3135e2e61b9SGage Eads 314e0f4a0edSDavid Marchand if (rte_lcore_count() < 2) { 315e0f4a0edSDavid Marchand printf("Not enough cores for test_stack_multithreaded, expecting at least 2\n"); 316e0f4a0edSDavid Marchand return TEST_SKIPPED; 317e0f4a0edSDavid Marchand } 318e0f4a0edSDavid Marchand 3195e2e61b9SGage Eads printf("[%s():%u] Running with %u lcores\n", 3205e2e61b9SGage Eads __func__, __LINE__, rte_lcore_count()); 3215e2e61b9SGage Eads 322*c51e67c2SSteven Lariau s = rte_stack_create("test", MAX_BULK * rte_lcore_count(), rte_socket_id(), flags); 3235e2e61b9SGage Eads if (s == NULL) { 3245e2e61b9SGage Eads printf("[%s():%u] Failed to create a stack\n", 3255e2e61b9SGage Eads __func__, __LINE__); 3265e2e61b9SGage Eads return -1; 3275e2e61b9SGage Eads } 3285e2e61b9SGage Eads 329e67925afSSteven Lariau thread_test_args.s = s; 3305e2e61b9SGage Eads 331e67925afSSteven Lariau if (rte_eal_mp_remote_launch(stack_thread_push_pop, NULL, CALL_MASTER)) 332e67925afSSteven Lariau rte_panic("Failed to launch tests\n"); 33304442131SSteven Lariau 33404442131SSteven Lariau RTE_LCORE_FOREACH(lcore_id) { 33504442131SSteven Lariau if (rte_eal_wait_lcore(lcore_id) < 0) 33604442131SSteven Lariau result = -1; 33704442131SSteven Lariau } 3385e2e61b9SGage Eads 3395e2e61b9SGage Eads rte_stack_free(s); 34004442131SSteven Lariau return result; 3415e2e61b9SGage Eads } 3425e2e61b9SGage Eads 3435e2e61b9SGage Eads static int 3440420378bSGage Eads __test_stack(uint32_t flags) 3455e2e61b9SGage Eads { 3460420378bSGage Eads if (test_stack_basic(flags) < 0) 3475e2e61b9SGage Eads return -1; 3485e2e61b9SGage Eads 3495e2e61b9SGage Eads if (test_lookup_null() < 0) 3505e2e61b9SGage Eads return -1; 3515e2e61b9SGage Eads 3525e2e61b9SGage Eads if (test_free_null() < 0) 3535e2e61b9SGage Eads return -1; 3545e2e61b9SGage Eads 3550420378bSGage Eads if (test_stack_name_reuse(flags) < 0) 3565e2e61b9SGage Eads return -1; 3575e2e61b9SGage Eads 3580420378bSGage Eads if (test_stack_name_length(flags) < 0) 3595e2e61b9SGage Eads return -1; 3605e2e61b9SGage Eads 3610420378bSGage Eads if (test_stack_multithreaded(flags) < 0) 3625e2e61b9SGage Eads return -1; 3635e2e61b9SGage Eads 3645e2e61b9SGage Eads return 0; 3655e2e61b9SGage Eads } 3665e2e61b9SGage Eads 3670420378bSGage Eads static int 3680420378bSGage Eads test_stack(void) 3690420378bSGage Eads { 3700420378bSGage Eads return __test_stack(0); 3710420378bSGage Eads } 3720420378bSGage Eads 3730420378bSGage Eads static int 3740420378bSGage Eads test_lf_stack(void) 3750420378bSGage Eads { 3760420378bSGage Eads return __test_stack(RTE_STACK_F_LF); 3770420378bSGage Eads } 3780420378bSGage Eads 3795e2e61b9SGage Eads REGISTER_TEST_COMMAND(stack_autotest, test_stack); 3800420378bSGage Eads REGISTER_TEST_COMMAND(stack_lf_autotest, test_lf_stack); 381