xref: /dpdk/app/test/test_stack.c (revision e0a8442ccd15bafbb7eb150c35331c8e3b828c53)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  */
4 
5 #include <string.h>
6 
7 #include <rte_lcore.h>
8 #include <rte_malloc.h>
9 #include <rte_random.h>
10 #include <rte_stack.h>
11 
12 #include "test.h"
13 
14 #define STACK_SIZE 4096
15 #define MAX_BULK 32
16 
17 static int
test_stack_push_pop(struct rte_stack * s,void ** obj_table,unsigned int bulk_sz)18 test_stack_push_pop(struct rte_stack *s, void **obj_table, unsigned int bulk_sz)
19 {
20 	unsigned int i, ret;
21 	void **popped_objs;
22 
23 	popped_objs = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0);
24 	if (popped_objs == NULL) {
25 		printf("[%s():%u] failed to calloc %zu bytes\n",
26 		       __func__, __LINE__, STACK_SIZE * sizeof(void *));
27 		return -1;
28 	}
29 
30 	for (i = 0; i < STACK_SIZE; i += bulk_sz) {
31 		ret = rte_stack_push(s, &obj_table[i], bulk_sz);
32 
33 		if (ret != bulk_sz) {
34 			printf("[%s():%u] push returned: %d (expected %u)\n",
35 			       __func__, __LINE__, ret, bulk_sz);
36 			rte_free(popped_objs);
37 			return -1;
38 		}
39 
40 		if (rte_stack_count(s) != i + bulk_sz) {
41 			printf("[%s():%u] stack count: %u (expected %u)\n",
42 			       __func__, __LINE__, rte_stack_count(s),
43 			       i + bulk_sz);
44 			rte_free(popped_objs);
45 			return -1;
46 		}
47 
48 		if (rte_stack_free_count(s) != STACK_SIZE - i - bulk_sz) {
49 			printf("[%s():%u] stack free count: %u (expected %u)\n",
50 			       __func__, __LINE__, rte_stack_count(s),
51 			       STACK_SIZE - i - bulk_sz);
52 			rte_free(popped_objs);
53 			return -1;
54 		}
55 	}
56 
57 	for (i = 0; i < STACK_SIZE; i += bulk_sz) {
58 		ret = rte_stack_pop(s, &popped_objs[i], bulk_sz);
59 
60 		if (ret != bulk_sz) {
61 			printf("[%s():%u] pop returned: %d (expected %u)\n",
62 			       __func__, __LINE__, ret, bulk_sz);
63 			rte_free(popped_objs);
64 			return -1;
65 		}
66 
67 		if (rte_stack_count(s) != STACK_SIZE - i - bulk_sz) {
68 			printf("[%s():%u] stack count: %u (expected %u)\n",
69 			       __func__, __LINE__, rte_stack_count(s),
70 			       STACK_SIZE - i - bulk_sz);
71 			rte_free(popped_objs);
72 			return -1;
73 		}
74 
75 		if (rte_stack_free_count(s) != i + bulk_sz) {
76 			printf("[%s():%u] stack free count: %u (expected %u)\n",
77 			       __func__, __LINE__, rte_stack_count(s),
78 			       i + bulk_sz);
79 			rte_free(popped_objs);
80 			return -1;
81 		}
82 	}
83 
84 	for (i = 0; i < STACK_SIZE; i++) {
85 		if (obj_table[i] != popped_objs[STACK_SIZE - i - 1]) {
86 			printf("[%s():%u] Incorrect value %p at index 0x%x\n",
87 			       __func__, __LINE__,
88 			       popped_objs[STACK_SIZE - i - 1], i);
89 			rte_free(popped_objs);
90 			return -1;
91 		}
92 	}
93 
94 	rte_free(popped_objs);
95 
96 	return 0;
97 }
98 
99 static int
test_stack_basic(uint32_t flags)100 test_stack_basic(uint32_t flags)
101 {
102 	struct rte_stack *s = NULL;
103 	void **obj_table = NULL;
104 	int i, ret = -1;
105 
106 	obj_table = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0);
107 	if (obj_table == NULL) {
108 		printf("[%s():%u] failed to calloc %zu bytes\n",
109 		       __func__, __LINE__, STACK_SIZE * sizeof(void *));
110 		goto fail_test;
111 	}
112 
113 	for (i = 0; i < STACK_SIZE; i++)
114 		obj_table[i] = (void *)(uintptr_t)i;
115 
116 	s = rte_stack_create(__func__, STACK_SIZE, rte_socket_id(), flags);
117 	if (s == NULL) {
118 		printf("[%s():%u] failed to create a stack\n",
119 		       __func__, __LINE__);
120 		goto fail_test;
121 	}
122 
123 	if (rte_stack_lookup(__func__) != s) {
124 		printf("[%s():%u] failed to lookup a stack\n",
125 		       __func__, __LINE__);
126 		goto fail_test;
127 	}
128 
129 	if (rte_stack_count(s) != 0) {
130 		printf("[%s():%u] stack count: %u (expected 0)\n",
131 		       __func__, __LINE__, rte_stack_count(s));
132 		goto fail_test;
133 	}
134 
135 	if (rte_stack_free_count(s) != STACK_SIZE) {
136 		printf("[%s():%u] stack free count: %u (expected %u)\n",
137 		       __func__, __LINE__, rte_stack_count(s), STACK_SIZE);
138 		goto fail_test;
139 	}
140 
141 	ret = test_stack_push_pop(s, obj_table, 1);
142 	if (ret) {
143 		printf("[%s():%u] Single object push/pop failed\n",
144 		       __func__, __LINE__);
145 		goto fail_test;
146 	}
147 
148 	ret = test_stack_push_pop(s, obj_table, MAX_BULK);
149 	if (ret) {
150 		printf("[%s():%u] Bulk object push/pop failed\n",
151 		       __func__, __LINE__);
152 		goto fail_test;
153 	}
154 
155 	ret = rte_stack_push(s, obj_table, 2 * STACK_SIZE);
156 	if (ret != 0) {
157 		printf("[%s():%u] Excess objects push succeeded\n",
158 		       __func__, __LINE__);
159 		goto fail_test;
160 	}
161 
162 	ret = rte_stack_pop(s, obj_table, 1);
163 	if (ret != 0) {
164 		printf("[%s():%u] Empty stack pop succeeded\n",
165 		       __func__, __LINE__);
166 		goto fail_test;
167 	}
168 
169 	ret = 0;
170 
171 fail_test:
172 	rte_stack_free(s);
173 
174 	rte_free(obj_table);
175 
176 	return ret;
177 }
178 
179 static int
test_stack_name_reuse(uint32_t flags)180 test_stack_name_reuse(uint32_t flags)
181 {
182 	struct rte_stack *s[2];
183 
184 	s[0] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), flags);
185 	if (s[0] == NULL) {
186 		printf("[%s():%u] Failed to create a stack\n",
187 		       __func__, __LINE__);
188 		return -1;
189 	}
190 
191 	s[1] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), flags);
192 	if (s[1] != NULL) {
193 		printf("[%s():%u] Failed to detect re-used name\n",
194 		       __func__, __LINE__);
195 		return -1;
196 	}
197 
198 	rte_stack_free(s[0]);
199 
200 	return 0;
201 }
202 
203 static int
test_stack_name_length(uint32_t flags)204 test_stack_name_length(uint32_t flags)
205 {
206 	char name[RTE_STACK_NAMESIZE + 1];
207 	struct rte_stack *s;
208 
209 	memset(name, 's', sizeof(name));
210 	name[RTE_STACK_NAMESIZE] = '\0';
211 
212 	s = rte_stack_create(name, STACK_SIZE, rte_socket_id(), flags);
213 	if (s != NULL) {
214 		printf("[%s():%u] Failed to prevent long name\n",
215 		       __func__, __LINE__);
216 		return -1;
217 	}
218 
219 	if (rte_errno != ENAMETOOLONG) {
220 		printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
221 		       __func__, __LINE__);
222 		return -1;
223 	}
224 
225 	return 0;
226 }
227 
228 static int
test_lookup_null(void)229 test_lookup_null(void)
230 {
231 	struct rte_stack *s = rte_stack_lookup("stack_not_found");
232 
233 	if (s != NULL) {
234 		printf("[%s():%u] rte_stack found a non-existent stack\n",
235 		       __func__, __LINE__);
236 		return -1;
237 	}
238 
239 	if (rte_errno != ENOENT) {
240 		printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
241 		       __func__, __LINE__);
242 		return -1;
243 	}
244 
245 	s = rte_stack_lookup(NULL);
246 
247 	if (s != NULL) {
248 		printf("[%s():%u] rte_stack found a non-existent stack\n",
249 		       __func__, __LINE__);
250 		return -1;
251 	}
252 
253 	if (rte_errno != EINVAL) {
254 		printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n",
255 		       __func__, __LINE__);
256 		return -1;
257 	}
258 
259 	return 0;
260 }
261 
262 static int
test_free_null(void)263 test_free_null(void)
264 {
265 	/* Check whether the library proper handles a NULL pointer */
266 	rte_stack_free(NULL);
267 
268 	return 0;
269 }
270 
271 #define NUM_ITERS_PER_THREAD 100000
272 
273 struct test_args {
274 	struct rte_stack *s;
275 };
276 
277 static struct test_args thread_test_args;
278 
279 static int
stack_thread_push_pop(__rte_unused void * args)280 stack_thread_push_pop(__rte_unused void *args)
281 {
282 	void *obj_table[MAX_BULK];
283 	int i;
284 
285 	for (i = 0; i < NUM_ITERS_PER_THREAD; i++) {
286 		unsigned int num;
287 
288 		num = rte_rand() % MAX_BULK;
289 
290 		if (rte_stack_push(thread_test_args.s, obj_table, num) != num) {
291 			printf("[%s():%u] Failed to push %u pointers\n",
292 			       __func__, __LINE__, num);
293 			return -1;
294 		}
295 
296 		if (rte_stack_pop(thread_test_args.s, obj_table, num) != num) {
297 			printf("[%s():%u] Failed to pop %u pointers\n",
298 			       __func__, __LINE__, num);
299 			return -1;
300 		}
301 	}
302 
303 	return 0;
304 }
305 
306 static int
test_stack_multithreaded(uint32_t flags)307 test_stack_multithreaded(uint32_t flags)
308 {
309 	unsigned int lcore_id;
310 	struct rte_stack *s;
311 	int result = 0;
312 
313 	if (rte_lcore_count() < 2) {
314 		printf("Not enough cores for test_stack_multithreaded, expecting at least 2\n");
315 		return TEST_SKIPPED;
316 	}
317 
318 	printf("[%s():%u] Running with %u lcores\n",
319 	       __func__, __LINE__, rte_lcore_count());
320 
321 	s = rte_stack_create("test", MAX_BULK * rte_lcore_count(), rte_socket_id(), flags);
322 	if (s == NULL) {
323 		printf("[%s():%u] Failed to create a stack\n",
324 		       __func__, __LINE__);
325 		return -1;
326 	}
327 
328 	thread_test_args.s = s;
329 
330 	if (rte_eal_mp_remote_launch(stack_thread_push_pop, NULL, CALL_MAIN))
331 		rte_panic("Failed to launch tests\n");
332 
333 	RTE_LCORE_FOREACH(lcore_id) {
334 		if (rte_eal_wait_lcore(lcore_id) < 0)
335 			result = -1;
336 	}
337 
338 	rte_stack_free(s);
339 	return result;
340 }
341 
342 static int
__test_stack(uint32_t flags)343 __test_stack(uint32_t flags)
344 {
345 	if (test_stack_basic(flags) < 0)
346 		return -1;
347 
348 	if (test_lookup_null() < 0)
349 		return -1;
350 
351 	if (test_free_null() < 0)
352 		return -1;
353 
354 	if (test_stack_name_reuse(flags) < 0)
355 		return -1;
356 
357 	if (test_stack_name_length(flags) < 0)
358 		return -1;
359 
360 	if (test_stack_multithreaded(flags) < 0)
361 		return -1;
362 
363 	return 0;
364 }
365 
366 static int
test_stack(void)367 test_stack(void)
368 {
369 	return __test_stack(0);
370 }
371 
372 static int
test_lf_stack(void)373 test_lf_stack(void)
374 {
375 #if defined(RTE_STACK_LF_SUPPORTED)
376 	return __test_stack(RTE_STACK_F_LF);
377 #else
378 	return TEST_SKIPPED;
379 #endif
380 }
381 
382 REGISTER_FAST_TEST(stack_autotest, false, true, test_stack);
383 REGISTER_FAST_TEST(stack_lf_autotest, false, true, test_lf_stack);
384