xref: /dpdk/app/test/test_stack.c (revision c51e67c2ee18305913c67cae3c9c3e54860acd86)
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