xref: /dpdk/app/test/test_stack.c (revision e0a8442ccd15bafbb7eb150c35331c8e3b828c53)
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_lcore.h>
85e2e61b9SGage Eads #include <rte_malloc.h>
95e2e61b9SGage Eads #include <rte_random.h>
105e2e61b9SGage Eads #include <rte_stack.h>
115e2e61b9SGage Eads 
125e2e61b9SGage Eads #include "test.h"
135e2e61b9SGage Eads 
145e2e61b9SGage Eads #define STACK_SIZE 4096
155e2e61b9SGage Eads #define MAX_BULK 32
165e2e61b9SGage Eads 
175e2e61b9SGage Eads static int
test_stack_push_pop(struct rte_stack * s,void ** obj_table,unsigned int bulk_sz)185e2e61b9SGage Eads test_stack_push_pop(struct rte_stack *s, void **obj_table, unsigned int bulk_sz)
195e2e61b9SGage Eads {
205e2e61b9SGage Eads 	unsigned int i, ret;
215e2e61b9SGage Eads 	void **popped_objs;
225e2e61b9SGage Eads 
235e2e61b9SGage Eads 	popped_objs = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0);
245e2e61b9SGage Eads 	if (popped_objs == NULL) {
255e2e61b9SGage Eads 		printf("[%s():%u] failed to calloc %zu bytes\n",
265e2e61b9SGage Eads 		       __func__, __LINE__, STACK_SIZE * sizeof(void *));
275e2e61b9SGage Eads 		return -1;
285e2e61b9SGage Eads 	}
295e2e61b9SGage Eads 
305e2e61b9SGage Eads 	for (i = 0; i < STACK_SIZE; i += bulk_sz) {
315e2e61b9SGage Eads 		ret = rte_stack_push(s, &obj_table[i], bulk_sz);
325e2e61b9SGage Eads 
335e2e61b9SGage Eads 		if (ret != bulk_sz) {
345e2e61b9SGage Eads 			printf("[%s():%u] push returned: %d (expected %u)\n",
355e2e61b9SGage Eads 			       __func__, __LINE__, ret, bulk_sz);
365e2e61b9SGage Eads 			rte_free(popped_objs);
375e2e61b9SGage Eads 			return -1;
385e2e61b9SGage Eads 		}
395e2e61b9SGage Eads 
405e2e61b9SGage Eads 		if (rte_stack_count(s) != i + bulk_sz) {
415e2e61b9SGage Eads 			printf("[%s():%u] stack count: %u (expected %u)\n",
425e2e61b9SGage Eads 			       __func__, __LINE__, rte_stack_count(s),
435e2e61b9SGage Eads 			       i + bulk_sz);
445e2e61b9SGage Eads 			rte_free(popped_objs);
455e2e61b9SGage Eads 			return -1;
465e2e61b9SGage Eads 		}
475e2e61b9SGage Eads 
485e2e61b9SGage Eads 		if (rte_stack_free_count(s) != STACK_SIZE - i - bulk_sz) {
495e2e61b9SGage Eads 			printf("[%s():%u] stack free count: %u (expected %u)\n",
505e2e61b9SGage Eads 			       __func__, __LINE__, rte_stack_count(s),
515e2e61b9SGage Eads 			       STACK_SIZE - i - bulk_sz);
525e2e61b9SGage Eads 			rte_free(popped_objs);
535e2e61b9SGage Eads 			return -1;
545e2e61b9SGage Eads 		}
555e2e61b9SGage Eads 	}
565e2e61b9SGage Eads 
575e2e61b9SGage Eads 	for (i = 0; i < STACK_SIZE; i += bulk_sz) {
585e2e61b9SGage Eads 		ret = rte_stack_pop(s, &popped_objs[i], bulk_sz);
595e2e61b9SGage Eads 
605e2e61b9SGage Eads 		if (ret != bulk_sz) {
615e2e61b9SGage Eads 			printf("[%s():%u] pop returned: %d (expected %u)\n",
625e2e61b9SGage Eads 			       __func__, __LINE__, ret, bulk_sz);
635e2e61b9SGage Eads 			rte_free(popped_objs);
645e2e61b9SGage Eads 			return -1;
655e2e61b9SGage Eads 		}
665e2e61b9SGage Eads 
675e2e61b9SGage Eads 		if (rte_stack_count(s) != STACK_SIZE - i - bulk_sz) {
685e2e61b9SGage Eads 			printf("[%s():%u] stack count: %u (expected %u)\n",
695e2e61b9SGage Eads 			       __func__, __LINE__, rte_stack_count(s),
705e2e61b9SGage Eads 			       STACK_SIZE - i - bulk_sz);
715e2e61b9SGage Eads 			rte_free(popped_objs);
725e2e61b9SGage Eads 			return -1;
735e2e61b9SGage Eads 		}
745e2e61b9SGage Eads 
755e2e61b9SGage Eads 		if (rte_stack_free_count(s) != i + bulk_sz) {
765e2e61b9SGage Eads 			printf("[%s():%u] stack free count: %u (expected %u)\n",
775e2e61b9SGage Eads 			       __func__, __LINE__, rte_stack_count(s),
785e2e61b9SGage Eads 			       i + bulk_sz);
795e2e61b9SGage Eads 			rte_free(popped_objs);
805e2e61b9SGage Eads 			return -1;
815e2e61b9SGage Eads 		}
825e2e61b9SGage Eads 	}
835e2e61b9SGage Eads 
845e2e61b9SGage Eads 	for (i = 0; i < STACK_SIZE; i++) {
855e2e61b9SGage Eads 		if (obj_table[i] != popped_objs[STACK_SIZE - i - 1]) {
865e2e61b9SGage Eads 			printf("[%s():%u] Incorrect value %p at index 0x%x\n",
875e2e61b9SGage Eads 			       __func__, __LINE__,
885e2e61b9SGage Eads 			       popped_objs[STACK_SIZE - i - 1], i);
895e2e61b9SGage Eads 			rte_free(popped_objs);
905e2e61b9SGage Eads 			return -1;
915e2e61b9SGage Eads 		}
925e2e61b9SGage Eads 	}
935e2e61b9SGage Eads 
945e2e61b9SGage Eads 	rte_free(popped_objs);
955e2e61b9SGage Eads 
965e2e61b9SGage Eads 	return 0;
975e2e61b9SGage Eads }
985e2e61b9SGage Eads 
995e2e61b9SGage Eads static int
test_stack_basic(uint32_t flags)1000420378bSGage Eads test_stack_basic(uint32_t flags)
1015e2e61b9SGage Eads {
1025e2e61b9SGage Eads 	struct rte_stack *s = NULL;
1035e2e61b9SGage Eads 	void **obj_table = NULL;
1045e2e61b9SGage Eads 	int i, ret = -1;
1055e2e61b9SGage Eads 
1065e2e61b9SGage Eads 	obj_table = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0);
1075e2e61b9SGage Eads 	if (obj_table == NULL) {
1085e2e61b9SGage Eads 		printf("[%s():%u] failed to calloc %zu bytes\n",
1095e2e61b9SGage Eads 		       __func__, __LINE__, STACK_SIZE * sizeof(void *));
1105e2e61b9SGage Eads 		goto fail_test;
1115e2e61b9SGage Eads 	}
1125e2e61b9SGage Eads 
1135e2e61b9SGage Eads 	for (i = 0; i < STACK_SIZE; i++)
1145e2e61b9SGage Eads 		obj_table[i] = (void *)(uintptr_t)i;
1155e2e61b9SGage Eads 
1160420378bSGage Eads 	s = rte_stack_create(__func__, STACK_SIZE, rte_socket_id(), flags);
1175e2e61b9SGage Eads 	if (s == NULL) {
1185e2e61b9SGage Eads 		printf("[%s():%u] failed to create a stack\n",
1195e2e61b9SGage Eads 		       __func__, __LINE__);
1205e2e61b9SGage Eads 		goto fail_test;
1215e2e61b9SGage Eads 	}
1225e2e61b9SGage Eads 
1235e2e61b9SGage Eads 	if (rte_stack_lookup(__func__) != s) {
1245e2e61b9SGage Eads 		printf("[%s():%u] failed to lookup a stack\n",
1255e2e61b9SGage Eads 		       __func__, __LINE__);
1265e2e61b9SGage Eads 		goto fail_test;
1275e2e61b9SGage Eads 	}
1285e2e61b9SGage Eads 
1295e2e61b9SGage Eads 	if (rte_stack_count(s) != 0) {
1305e2e61b9SGage Eads 		printf("[%s():%u] stack count: %u (expected 0)\n",
1315e2e61b9SGage Eads 		       __func__, __LINE__, rte_stack_count(s));
1325e2e61b9SGage Eads 		goto fail_test;
1335e2e61b9SGage Eads 	}
1345e2e61b9SGage Eads 
1355e2e61b9SGage Eads 	if (rte_stack_free_count(s) != STACK_SIZE) {
1365e2e61b9SGage Eads 		printf("[%s():%u] stack free count: %u (expected %u)\n",
1375e2e61b9SGage Eads 		       __func__, __LINE__, rte_stack_count(s), STACK_SIZE);
1385e2e61b9SGage Eads 		goto fail_test;
1395e2e61b9SGage Eads 	}
1405e2e61b9SGage Eads 
1415e2e61b9SGage Eads 	ret = test_stack_push_pop(s, obj_table, 1);
1425e2e61b9SGage Eads 	if (ret) {
1435e2e61b9SGage Eads 		printf("[%s():%u] Single object push/pop failed\n",
1445e2e61b9SGage Eads 		       __func__, __LINE__);
1455e2e61b9SGage Eads 		goto fail_test;
1465e2e61b9SGage Eads 	}
1475e2e61b9SGage Eads 
1485e2e61b9SGage Eads 	ret = test_stack_push_pop(s, obj_table, MAX_BULK);
1495e2e61b9SGage Eads 	if (ret) {
1505e2e61b9SGage Eads 		printf("[%s():%u] Bulk object push/pop failed\n",
1515e2e61b9SGage Eads 		       __func__, __LINE__);
1525e2e61b9SGage Eads 		goto fail_test;
1535e2e61b9SGage Eads 	}
1545e2e61b9SGage Eads 
1555e2e61b9SGage Eads 	ret = rte_stack_push(s, obj_table, 2 * STACK_SIZE);
1565e2e61b9SGage Eads 	if (ret != 0) {
1575e2e61b9SGage Eads 		printf("[%s():%u] Excess objects push succeeded\n",
1585e2e61b9SGage Eads 		       __func__, __LINE__);
1595e2e61b9SGage Eads 		goto fail_test;
1605e2e61b9SGage Eads 	}
1615e2e61b9SGage Eads 
1625e2e61b9SGage Eads 	ret = rte_stack_pop(s, obj_table, 1);
1635e2e61b9SGage Eads 	if (ret != 0) {
1645e2e61b9SGage Eads 		printf("[%s():%u] Empty stack pop succeeded\n",
1655e2e61b9SGage Eads 		       __func__, __LINE__);
1665e2e61b9SGage Eads 		goto fail_test;
1675e2e61b9SGage Eads 	}
1685e2e61b9SGage Eads 
1695e2e61b9SGage Eads 	ret = 0;
1705e2e61b9SGage Eads 
1715e2e61b9SGage Eads fail_test:
1725e2e61b9SGage Eads 	rte_stack_free(s);
1735e2e61b9SGage Eads 
1745e2e61b9SGage Eads 	rte_free(obj_table);
1755e2e61b9SGage Eads 
1765e2e61b9SGage Eads 	return ret;
1775e2e61b9SGage Eads }
1785e2e61b9SGage Eads 
1795e2e61b9SGage Eads static int
test_stack_name_reuse(uint32_t flags)1800420378bSGage Eads test_stack_name_reuse(uint32_t flags)
1815e2e61b9SGage Eads {
1825e2e61b9SGage Eads 	struct rte_stack *s[2];
1835e2e61b9SGage Eads 
1840420378bSGage Eads 	s[0] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), flags);
1855e2e61b9SGage Eads 	if (s[0] == NULL) {
1865e2e61b9SGage Eads 		printf("[%s():%u] Failed to create a stack\n",
1875e2e61b9SGage Eads 		       __func__, __LINE__);
1885e2e61b9SGage Eads 		return -1;
1895e2e61b9SGage Eads 	}
1905e2e61b9SGage Eads 
1910420378bSGage Eads 	s[1] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), flags);
1925e2e61b9SGage Eads 	if (s[1] != NULL) {
1935e2e61b9SGage Eads 		printf("[%s():%u] Failed to detect re-used name\n",
1945e2e61b9SGage Eads 		       __func__, __LINE__);
1955e2e61b9SGage Eads 		return -1;
1965e2e61b9SGage Eads 	}
1975e2e61b9SGage Eads 
1985e2e61b9SGage Eads 	rte_stack_free(s[0]);
1995e2e61b9SGage Eads 
2005e2e61b9SGage Eads 	return 0;
2015e2e61b9SGage Eads }
2025e2e61b9SGage Eads 
2035e2e61b9SGage Eads static int
test_stack_name_length(uint32_t flags)2040420378bSGage Eads test_stack_name_length(uint32_t flags)
2055e2e61b9SGage Eads {
2065e2e61b9SGage Eads 	char name[RTE_STACK_NAMESIZE + 1];
2075e2e61b9SGage Eads 	struct rte_stack *s;
2085e2e61b9SGage Eads 
2095e2e61b9SGage Eads 	memset(name, 's', sizeof(name));
2105e2e61b9SGage Eads 	name[RTE_STACK_NAMESIZE] = '\0';
2115e2e61b9SGage Eads 
2120420378bSGage Eads 	s = rte_stack_create(name, STACK_SIZE, rte_socket_id(), flags);
2135e2e61b9SGage Eads 	if (s != NULL) {
2145e2e61b9SGage Eads 		printf("[%s():%u] Failed to prevent long name\n",
2155e2e61b9SGage Eads 		       __func__, __LINE__);
2165e2e61b9SGage Eads 		return -1;
2175e2e61b9SGage Eads 	}
2185e2e61b9SGage Eads 
2195e2e61b9SGage Eads 	if (rte_errno != ENAMETOOLONG) {
2205e2e61b9SGage Eads 		printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
2215e2e61b9SGage Eads 		       __func__, __LINE__);
2225e2e61b9SGage Eads 		return -1;
2235e2e61b9SGage Eads 	}
2245e2e61b9SGage Eads 
2255e2e61b9SGage Eads 	return 0;
2265e2e61b9SGage Eads }
2275e2e61b9SGage Eads 
2285e2e61b9SGage Eads static int
test_lookup_null(void)2295e2e61b9SGage Eads test_lookup_null(void)
2305e2e61b9SGage Eads {
2315e2e61b9SGage Eads 	struct rte_stack *s = rte_stack_lookup("stack_not_found");
2325e2e61b9SGage Eads 
2335e2e61b9SGage Eads 	if (s != NULL) {
2345e2e61b9SGage Eads 		printf("[%s():%u] rte_stack found a non-existent stack\n",
2355e2e61b9SGage Eads 		       __func__, __LINE__);
2365e2e61b9SGage Eads 		return -1;
2375e2e61b9SGage Eads 	}
2385e2e61b9SGage Eads 
2395e2e61b9SGage Eads 	if (rte_errno != ENOENT) {
2405e2e61b9SGage Eads 		printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
2415e2e61b9SGage Eads 		       __func__, __LINE__);
2425e2e61b9SGage Eads 		return -1;
2435e2e61b9SGage Eads 	}
2445e2e61b9SGage Eads 
2455e2e61b9SGage Eads 	s = rte_stack_lookup(NULL);
2465e2e61b9SGage Eads 
2475e2e61b9SGage Eads 	if (s != NULL) {
2485e2e61b9SGage Eads 		printf("[%s():%u] rte_stack found a non-existent stack\n",
2495e2e61b9SGage Eads 		       __func__, __LINE__);
2505e2e61b9SGage Eads 		return -1;
2515e2e61b9SGage Eads 	}
2525e2e61b9SGage Eads 
2535e2e61b9SGage Eads 	if (rte_errno != EINVAL) {
2545e2e61b9SGage Eads 		printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
2555e2e61b9SGage Eads 		       __func__, __LINE__);
2565e2e61b9SGage Eads 		return -1;
2575e2e61b9SGage Eads 	}
2585e2e61b9SGage Eads 
2595e2e61b9SGage Eads 	return 0;
2605e2e61b9SGage Eads }
2615e2e61b9SGage Eads 
2625e2e61b9SGage Eads static int
test_free_null(void)2635e2e61b9SGage Eads test_free_null(void)
2645e2e61b9SGage Eads {
2655e2e61b9SGage Eads 	/* Check whether the library proper handles a NULL pointer */
2665e2e61b9SGage Eads 	rte_stack_free(NULL);
2675e2e61b9SGage Eads 
2685e2e61b9SGage Eads 	return 0;
2695e2e61b9SGage Eads }
2705e2e61b9SGage Eads 
2715e2e61b9SGage Eads #define NUM_ITERS_PER_THREAD 100000
2725e2e61b9SGage Eads 
2735e2e61b9SGage Eads struct test_args {
2745e2e61b9SGage Eads 	struct rte_stack *s;
2755e2e61b9SGage Eads };
2765e2e61b9SGage Eads 
277e67925afSSteven Lariau static struct test_args thread_test_args;
2785e2e61b9SGage Eads 
279e67925afSSteven Lariau static int
stack_thread_push_pop(__rte_unused void * args)280e67925afSSteven Lariau stack_thread_push_pop(__rte_unused void *args)
281e67925afSSteven Lariau {
282e67925afSSteven Lariau 	void *obj_table[MAX_BULK];
283e67925afSSteven Lariau 	int i;
2845e2e61b9SGage Eads 
2855e2e61b9SGage Eads 	for (i = 0; i < NUM_ITERS_PER_THREAD; i++) {
286c51e67c2SSteven Lariau 		unsigned int num;
2875e2e61b9SGage Eads 
288c51e67c2SSteven Lariau 		num = rte_rand() % MAX_BULK;
2895e2e61b9SGage Eads 
290e67925afSSteven Lariau 		if (rte_stack_push(thread_test_args.s, obj_table, num) != num) {
2915e2e61b9SGage Eads 			printf("[%s():%u] Failed to push %u pointers\n",
2925e2e61b9SGage Eads 			       __func__, __LINE__, num);
2935e2e61b9SGage Eads 			return -1;
2945e2e61b9SGage Eads 		}
2955e2e61b9SGage Eads 
296e67925afSSteven Lariau 		if (rte_stack_pop(thread_test_args.s, obj_table, num) != num) {
2975e2e61b9SGage Eads 			printf("[%s():%u] Failed to pop %u pointers\n",
2985e2e61b9SGage Eads 			       __func__, __LINE__, num);
2995e2e61b9SGage Eads 			return -1;
3005e2e61b9SGage Eads 		}
3015e2e61b9SGage Eads 	}
3025e2e61b9SGage Eads 
3035e2e61b9SGage Eads 	return 0;
3045e2e61b9SGage Eads }
3055e2e61b9SGage Eads 
3065e2e61b9SGage Eads static int
test_stack_multithreaded(uint32_t flags)3070420378bSGage Eads test_stack_multithreaded(uint32_t flags)
3085e2e61b9SGage Eads {
30904442131SSteven Lariau 	unsigned int lcore_id;
3105e2e61b9SGage Eads 	struct rte_stack *s;
31104442131SSteven Lariau 	int result = 0;
3125e2e61b9SGage Eads 
313e0f4a0edSDavid Marchand 	if (rte_lcore_count() < 2) {
314e0f4a0edSDavid Marchand 		printf("Not enough cores for test_stack_multithreaded, expecting at least 2\n");
315e0f4a0edSDavid Marchand 		return TEST_SKIPPED;
316e0f4a0edSDavid Marchand 	}
317e0f4a0edSDavid Marchand 
3185e2e61b9SGage Eads 	printf("[%s():%u] Running with %u lcores\n",
3195e2e61b9SGage Eads 	       __func__, __LINE__, rte_lcore_count());
3205e2e61b9SGage Eads 
321c51e67c2SSteven Lariau 	s = rte_stack_create("test", MAX_BULK * rte_lcore_count(), rte_socket_id(), flags);
3225e2e61b9SGage Eads 	if (s == NULL) {
3235e2e61b9SGage Eads 		printf("[%s():%u] Failed to create a stack\n",
3245e2e61b9SGage Eads 		       __func__, __LINE__);
3255e2e61b9SGage Eads 		return -1;
3265e2e61b9SGage Eads 	}
3275e2e61b9SGage Eads 
328e67925afSSteven Lariau 	thread_test_args.s = s;
3295e2e61b9SGage Eads 
330cb056611SStephen Hemminger 	if (rte_eal_mp_remote_launch(stack_thread_push_pop, NULL, CALL_MAIN))
331e67925afSSteven Lariau 		rte_panic("Failed to launch tests\n");
33204442131SSteven Lariau 
33304442131SSteven Lariau 	RTE_LCORE_FOREACH(lcore_id) {
33404442131SSteven Lariau 		if (rte_eal_wait_lcore(lcore_id) < 0)
33504442131SSteven Lariau 			result = -1;
33604442131SSteven Lariau 	}
3375e2e61b9SGage Eads 
3385e2e61b9SGage Eads 	rte_stack_free(s);
33904442131SSteven Lariau 	return result;
3405e2e61b9SGage Eads }
3415e2e61b9SGage Eads 
3425e2e61b9SGage Eads static int
__test_stack(uint32_t flags)3430420378bSGage Eads __test_stack(uint32_t flags)
3445e2e61b9SGage Eads {
3450420378bSGage Eads 	if (test_stack_basic(flags) < 0)
3465e2e61b9SGage Eads 		return -1;
3475e2e61b9SGage Eads 
3485e2e61b9SGage Eads 	if (test_lookup_null() < 0)
3495e2e61b9SGage Eads 		return -1;
3505e2e61b9SGage Eads 
3515e2e61b9SGage Eads 	if (test_free_null() < 0)
3525e2e61b9SGage Eads 		return -1;
3535e2e61b9SGage Eads 
3540420378bSGage Eads 	if (test_stack_name_reuse(flags) < 0)
3555e2e61b9SGage Eads 		return -1;
3565e2e61b9SGage Eads 
3570420378bSGage Eads 	if (test_stack_name_length(flags) < 0)
3585e2e61b9SGage Eads 		return -1;
3595e2e61b9SGage Eads 
3600420378bSGage Eads 	if (test_stack_multithreaded(flags) < 0)
3615e2e61b9SGage Eads 		return -1;
3625e2e61b9SGage Eads 
3635e2e61b9SGage Eads 	return 0;
3645e2e61b9SGage Eads }
3655e2e61b9SGage Eads 
3660420378bSGage Eads static int
test_stack(void)3670420378bSGage Eads test_stack(void)
3680420378bSGage Eads {
3690420378bSGage Eads 	return __test_stack(0);
3700420378bSGage Eads }
3710420378bSGage Eads 
3720420378bSGage Eads static int
test_lf_stack(void)3730420378bSGage Eads test_lf_stack(void)
3740420378bSGage Eads {
3751abb185dSStanislaw Kardach #if defined(RTE_STACK_LF_SUPPORTED)
3760420378bSGage Eads 	return __test_stack(RTE_STACK_F_LF);
3771abb185dSStanislaw Kardach #else
3781abb185dSStanislaw Kardach 	return TEST_SKIPPED;
3791abb185dSStanislaw Kardach #endif
3800420378bSGage Eads }
3810420378bSGage Eads 
382*e0a8442cSBruce Richardson REGISTER_FAST_TEST(stack_autotest, false, true, test_stack);
383*e0a8442cSBruce Richardson REGISTER_FAST_TEST(stack_lf_autotest, false, true, test_lf_stack);
384