xref: /dpdk/app/test/test_soring.c (revision 70581c355d6965f7be2dbf1c4fc0d30778c53b98)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2024 Huawei Technologies Co., Ltd
3  */
4 
5 #include <string.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include <inttypes.h>
11 #include <errno.h>
12 #include <sys/queue.h>
13 
14 #include <rte_common.h>
15 #include <rte_log.h>
16 #include <rte_memory.h>
17 #include <rte_launch.h>
18 #include <rte_cycles.h>
19 #include <rte_eal.h>
20 #include <rte_per_lcore.h>
21 #include <rte_lcore.h>
22 #include <rte_branch_prediction.h>
23 #include <rte_malloc.h>
24 #include <rte_random.h>
25 #include <rte_errno.h>
26 #include <rte_hexdump.h>
27 
28 #include <rte_soring.h>
29 
30 #include "test.h"
31 
32 #define MAX_ACQUIRED 20
33 
34 #define SORING_TEST_ASSERT(val, expected) do { \
35 	RTE_TEST_ASSERT(expected == val, \
36 			"%s: expected %u got %u\n", #val, expected, val); \
37 } while (0)
38 
39 static void
40 set_soring_init_param(struct rte_soring_param *prm,
41 		const char *name, uint32_t esize, uint32_t elems,
42 		uint32_t stages, uint32_t stsize,
43 		enum rte_ring_sync_type rst_prod,
44 		enum rte_ring_sync_type rst_cons)
45 {
46 	prm->name = name;
47 	prm->elem_size = esize;
48 	prm->elems = elems;
49 	prm->stages = stages;
50 	prm->meta_size = stsize;
51 	prm->prod_synt = rst_prod;
52 	prm->cons_synt = rst_cons;
53 }
54 
55 static int
56 move_forward_stage(struct rte_soring *sor,
57 		uint32_t num_packets, uint32_t stage)
58 {
59 	uint32_t acquired;
60 	uint32_t ftoken;
61 	uint32_t *acquired_objs[MAX_ACQUIRED];
62 
63 	acquired = rte_soring_acquire_bulk(sor, acquired_objs, stage,
64 			num_packets, &ftoken, NULL);
65 	SORING_TEST_ASSERT(acquired, num_packets);
66 	rte_soring_release(sor, NULL, stage, num_packets,
67 			ftoken);
68 
69 	return 0;
70 }
71 
72 /*
73  * struct rte_soring_param param checking.
74  */
75 static int
76 test_soring_init(void)
77 {
78 	struct rte_soring *sor = NULL;
79 	struct rte_soring_param prm;
80 	int rc;
81 	size_t sz;
82 	memset(&prm, 0, sizeof(prm));
83 
84 	/* init memory */
85 	set_soring_init_param(&prm, "alloc_memory", sizeof(uintptr_t),
86 			4, 1, 4, RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
87 	sz = rte_soring_get_memsize(&prm);
88 	sor = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
89 	RTE_TEST_ASSERT_NOT_NULL(sor, "could not allocate memory for soring");
90 
91 	set_soring_init_param(&prm, "test_invalid_stages", sizeof(uintptr_t),
92 			4, 0, 4, RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
93 	rc = rte_soring_init(sor, &prm);
94 	RTE_TEST_ASSERT_FAIL(rc, "initted soring with invalid num stages");
95 
96 	set_soring_init_param(&prm, "test_invalid_esize", 0,
97 			4, 1, 4, RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
98 	rc = rte_soring_init(sor, &prm);
99 	RTE_TEST_ASSERT_FAIL(rc, "initted soring with 0 esize");
100 
101 	set_soring_init_param(&prm, "test_invalid_esize", 9,
102 			4, 1, 4, RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
103 	rc = rte_soring_init(sor, &prm);
104 	RTE_TEST_ASSERT_FAIL(rc, "initted soring with esize not multiple of 4");
105 
106 	set_soring_init_param(&prm, "test_invalid_rsize", sizeof(uintptr_t),
107 			4, 1, 3, RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
108 	rc = rte_soring_init(sor, &prm);
109 	RTE_TEST_ASSERT_FAIL(rc, "initted soring with rcsize not multiple of 4");
110 
111 	set_soring_init_param(&prm, "test_invalid_elems", sizeof(uintptr_t),
112 			RTE_SORING_ELEM_MAX + 1, 1, 4, RTE_RING_SYNC_MT,
113 			RTE_RING_SYNC_MT);
114 	rc = rte_soring_init(sor, &prm);
115 	RTE_TEST_ASSERT_FAIL(rc, "initted soring with invalid num elements");
116 
117 	rte_free(sor);
118 	return 0;
119 }
120 
121 static int
122 test_soring_get_memsize(void)
123 {
124 
125 	struct rte_soring_param prm;
126 	ssize_t sz;
127 
128 	set_soring_init_param(&prm, "memsize", sizeof(uint32_t *),
129 			10, 1, 0, RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
130 	sz = rte_soring_get_memsize(&prm);
131 	RTE_TEST_ASSERT(sz > 0, "failed to calculate size");
132 
133 	set_soring_init_param(&prm, "memsize", sizeof(uint8_t),
134 			16, UINT32_MAX, sizeof(uint32_t), RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
135 	sz = rte_soring_get_memsize(&prm);
136 	RTE_TEST_ASSERT_EQUAL(sz, -EINVAL, "calculated size incorrect");
137 
138 	set_soring_init_param(&prm, "memsize", 0,
139 			16, UINT32_MAX, sizeof(uint32_t), RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
140 	sz = rte_soring_get_memsize(&prm);
141 	RTE_TEST_ASSERT_EQUAL(sz, -EINVAL, "calculated size incorrect");
142 
143 	return 0;
144 
145 }
146 
147 static int
148 test_soring_stages(void)
149 {
150 	struct rte_soring *sor = NULL;
151 	struct rte_soring_param prm;
152 	uint32_t objs[32];
153 	uint32_t rcs[32];
154 	uint32_t acquired_objs[32];
155 	uint32_t acquired_rcs[32];
156 	uint32_t dequeued_rcs[32];
157 	uint32_t dequeued_objs[32];
158 	size_t ssz;
159 	uint32_t stage, enqueued, dequeued, acquired;
160 	uint32_t i, ftoken;
161 
162 	memset(&prm, 0, sizeof(prm));
163 	set_soring_init_param(&prm, "stages", sizeof(uint32_t), 32,
164 			10000, sizeof(uint32_t), RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
165 	ssz = rte_soring_get_memsize(&prm);
166 	RTE_TEST_ASSERT(ssz > 0, "parameter error calculating ring size");
167 	sor = rte_zmalloc(NULL, ssz, RTE_CACHE_LINE_SIZE);
168 	RTE_TEST_ASSERT_NOT_NULL(sor, "couldn't allocate memory for soring");
169 	rte_soring_init(sor, &prm);
170 
171 	for (i = 0; i < 32; i++) {
172 		rcs[i] = i;
173 		objs[i] = i + 32;
174 	}
175 
176 	enqueued = rte_soring_enqueux_burst(sor, objs, rcs, 32, NULL);
177 	SORING_TEST_ASSERT(enqueued, 32);
178 
179 	for (stage = 0; stage < 10000; stage++) {
180 		int j;
181 		dequeued = rte_soring_dequeue_bulk(sor, dequeued_objs,
182 				32, NULL);
183 		/* check none at end stage */
184 		SORING_TEST_ASSERT(dequeued, 0);
185 
186 		acquired = rte_soring_acquirx_bulk(sor, acquired_objs,
187 				acquired_rcs, stage, 32, &ftoken, NULL);
188 		SORING_TEST_ASSERT(acquired, 32);
189 
190 		for (j = 0; j < 32; j++) {
191 			SORING_TEST_ASSERT(acquired_rcs[j], j + stage);
192 			SORING_TEST_ASSERT(acquired_objs[j], j + stage + 32);
193 			/* modify both queue object and rc */
194 			acquired_objs[j]++;
195 			acquired_rcs[j]++;
196 		}
197 
198 		rte_soring_releasx(sor, acquired_objs,
199 				acquired_rcs, stage, 32,
200 				ftoken);
201 	}
202 
203 	dequeued = rte_soring_dequeux_bulk(sor, dequeued_objs, dequeued_rcs,
204 			32, NULL);
205 	SORING_TEST_ASSERT(dequeued, 32);
206 		for (i = 0; i < 32; i++) {
207 			/* ensure we ended up with the expected values in order */
208 			SORING_TEST_ASSERT(dequeued_rcs[i], i + 10000);
209 			SORING_TEST_ASSERT(dequeued_objs[i], i + 32 + 10000);
210 		}
211 	rte_free(sor);
212 	return 0;
213 }
214 
215 static int
216 test_soring_enqueue_dequeue(void)
217 {
218 	struct rte_soring *sor = NULL;
219 	struct rte_soring_param prm;
220 	int rc;
221 	uint32_t i;
222 	size_t sz;
223 	uint32_t queue_objs[10];
224 	uint32_t *queue_objs_p[10];
225 	uint32_t free_space;
226 	uint32_t enqueued, dequeued;
227 	uint32_t *dequeued_objs[10];
228 
229 	memset(&prm, 0, sizeof(prm));
230 	for (i = 0; i < 10; i++) {
231 		queue_objs[i] = i + 1;
232 		queue_objs_p[i] = &queue_objs[i];
233 	}
234 
235 	/* init memory */
236 	set_soring_init_param(&prm, "enqueue/dequeue", sizeof(uint32_t *),
237 			10, 1, 0, RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
238 	sz = rte_soring_get_memsize(&prm);
239 	sor = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
240 	RTE_TEST_ASSERT_NOT_NULL(sor, "alloc failed for soring");
241 	rc = rte_soring_init(sor, &prm);
242 	RTE_TEST_ASSERT_SUCCESS(rc, "Failed to init soring");
243 
244 	free_space = 0;
245 
246 	enqueued = rte_soring_enqueue_burst(sor, queue_objs_p, 5, &free_space);
247 
248 	SORING_TEST_ASSERT(free_space, 5);
249 	SORING_TEST_ASSERT(enqueued, 5);
250 
251 	/* fixed amount enqueue */
252 	enqueued = rte_soring_enqueue_bulk(sor, queue_objs_p, 7, &free_space);
253 
254 	SORING_TEST_ASSERT(free_space, 5);
255 	SORING_TEST_ASSERT(enqueued, 0);
256 
257 	/* variable amount enqueue */
258 	enqueued = rte_soring_enqueue_burst(sor, queue_objs_p + 5, 7,
259 				&free_space);
260 	SORING_TEST_ASSERT(free_space, 0);
261 	SORING_TEST_ASSERT(enqueued, 5);
262 
263 	/* test no dequeue while stage 0 has not completed */
264 	dequeued = rte_soring_dequeue_bulk(sor, dequeued_objs, 10, NULL);
265 	SORING_TEST_ASSERT(dequeued, 0);
266 	dequeued = rte_soring_dequeue_burst(sor, dequeued_objs, 10, NULL);
267 	SORING_TEST_ASSERT(dequeued, 0);
268 
269 	move_forward_stage(sor, 8, 0);
270 
271 	/* can only dequeue as many as have completed stage */
272 	dequeued = rte_soring_dequeue_bulk(sor, dequeued_objs, 10, NULL);
273 	SORING_TEST_ASSERT(dequeued, 0);
274 	dequeued = rte_soring_dequeue_burst(sor, dequeued_objs, 10, NULL);
275 	SORING_TEST_ASSERT(dequeued, 8);
276 	/* packets remain in order */
277 	for (i = 0; i < dequeued; i++) {
278 		RTE_TEST_ASSERT_EQUAL(dequeued_objs[i],
279 				queue_objs_p[i], "dequeued != enqueued");
280 	}
281 
282 	dequeued = rte_soring_dequeue_burst(sor, dequeued_objs, 1, NULL);
283 	SORING_TEST_ASSERT(dequeued, 0);
284 
285 	move_forward_stage(sor, 2, 0);
286 	dequeued = rte_soring_dequeue_burst(sor, dequeued_objs, 2, NULL);
287 	SORING_TEST_ASSERT(dequeued, 2);
288 	/* packets remain in order */
289 	for (i = 0; i < dequeued; i++) {
290 		RTE_TEST_ASSERT_EQUAL(dequeued_objs[i],
291 				queue_objs_p[i + 8], "dequeued != enqueued");
292 	}
293 
294 	rte_soring_dump(stdout, sor);
295 	rte_free(sor);
296 	return 0;
297 }
298 
299 static int
300 test_soring_acquire_release(void)
301 {
302 
303 	struct rte_soring *sor = NULL;
304 	struct rte_soring_param prm;
305 	int rc, i;
306 	size_t sz;
307 
308 	memset(&prm, 0, sizeof(prm));
309 	uint32_t queue_objs[10];
310 	uint32_t rc_objs[10];
311 	uint32_t acquired_objs[10];
312 	uint32_t dequeued_objs[10];
313 	uint32_t dequeued_rcs[10];
314 	uint32_t s1_acquired_rcs[10];
315 	uint32_t free_space, enqueued, ftoken, acquired, dequeued;
316 
317 	for (i = 0; i < 10; i++) {
318 		queue_objs[i] = i + 5;
319 		rc_objs[i] = i + 10;
320 	}
321 
322 /*init memory*/
323 	set_soring_init_param(&prm, "test_acquire_release", sizeof(uint32_t),
324 			20, 2, sizeof(uint32_t), RTE_RING_SYNC_MT, RTE_RING_SYNC_MT);
325 	sz = rte_soring_get_memsize(&prm);
326 	sor = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
327 	if (sor == NULL) {
328 		printf("%s: alloc(%zu) for FIFO with %u elems failed",
329 			__func__, sz, prm.elems);
330 		return -ENOMEM;
331 	}
332 
333 	/* init ring */
334 	rc = rte_soring_init(sor, &prm);
335 	RTE_TEST_ASSERT_SUCCESS(rc, "failed to init soring");
336 
337 	/* enqueue with associated rc */
338 	enqueued = rte_soring_enqueux_burst(sor, queue_objs, rc_objs, 5,
339 			&free_space);
340 	SORING_TEST_ASSERT(enqueued, 5);
341 	/* enqueue without associated rc */
342 	enqueued = rte_soring_enqueue_burst(sor, queue_objs + 5, 5,
343 			&free_space);
344 	SORING_TEST_ASSERT(enqueued, 5);
345 
346 	/* acquire the objects with rc's and ensure they are as expected */
347 	acquired = rte_soring_acquirx_burst(sor, acquired_objs,
348 			s1_acquired_rcs, 0, 5, &ftoken, NULL);
349 	SORING_TEST_ASSERT(acquired, 5);
350 	for (i = 0; i < 5; i++) {
351 		RTE_TEST_ASSERT_EQUAL(s1_acquired_rcs[i], rc_objs[i],
352 				"acquired rc[%d]: %u != enqueued rc: %u",
353 				i, s1_acquired_rcs[i], rc_objs[i]);
354 		RTE_TEST_ASSERT_EQUAL(acquired_objs[i], queue_objs[i],
355 				"acquired obj[%d]: %u != enqueued obj %u",
356 				i, acquired_objs[i], queue_objs[i]);
357 	}
358 	rte_soring_release(sor, NULL, 0, 5, ftoken);
359 
360 	/* acquire the objects without rc's and ensure they are as expected */
361 	acquired = rte_soring_acquirx_burst(sor, acquired_objs,
362 			s1_acquired_rcs, 0, 5, &ftoken, NULL);
363 	SORING_TEST_ASSERT(acquired, 5);
364 	for (i = 0; i < 5; i++) {
365 		/* as the rc area of memory is zero'd at init this is true
366 		 * but this is a detail of implementation rather than
367 		 * a guarantee.
368 		 */
369 		RTE_TEST_ASSERT_EQUAL(s1_acquired_rcs[i], 0,
370 				"acquired rc not empty");
371 		RTE_TEST_ASSERT_EQUAL(acquired_objs[i], queue_objs[i + 5],
372 				"acquired obj[%d]: %u != enqueued obj %u",
373 				i, acquired_objs[i], queue_objs[i + 5]);
374 	}
375 	/*release the objects, adding rc's */
376 	rte_soring_releasx(sor, NULL, rc_objs + 5, 0, 5,
377 			ftoken);
378 
379 	acquired = rte_soring_acquirx_burst(sor, acquired_objs,
380 			s1_acquired_rcs, 1, 10, &ftoken, NULL);
381 	SORING_TEST_ASSERT(acquired, 10);
382 	for (i = 0; i < 10; i++) {
383 		/* ensure the associated rc's are the ones added at release */
384 		RTE_TEST_ASSERT_EQUAL(s1_acquired_rcs[i], rc_objs[i],
385 				"acquired rc[%d]: %u != enqueued rc: %u",
386 				i, s1_acquired_rcs[i], rc_objs[i]);
387 		RTE_TEST_ASSERT_EQUAL(acquired_objs[i], queue_objs[i],
388 				"acquired obj[%d]: %u != enqueued obj %u",
389 				i, acquired_objs[i], queue_objs[i]);
390 	}
391 	/* release the objects, with rc's set to NULL */
392 	rte_soring_release(sor, NULL, 1, 10, ftoken);
393 
394 	dequeued = rte_soring_dequeux_burst(sor, dequeued_objs, dequeued_rcs,
395 			10, NULL);
396 	SORING_TEST_ASSERT(dequeued, 10);
397 	for (i = 0; i < 10; i++) {
398 		/* ensure the associated rc's are the ones added at release */
399 		RTE_TEST_ASSERT_EQUAL(dequeued_rcs[i], rc_objs[i],
400 				"dequeued rc[%d]: %u != enqueued rc: %u",
401 				i, dequeued_rcs[i], rc_objs[i]);
402 		RTE_TEST_ASSERT_EQUAL(acquired_objs[i], queue_objs[i],
403 				"acquired obj[%d]: %u != enqueued obj %u",
404 				i, acquired_objs[i], queue_objs[i]);
405 	}
406 	rte_soring_dump(stdout, sor);
407 	rte_free(sor);
408 	return 0;
409 }
410 
411 static int
412 test_soring(void)
413 {
414 
415 	/* Negative test cases */
416 	if (test_soring_init() < 0)
417 		goto test_fail;
418 
419 	/* Memory calculations */
420 	if (test_soring_get_memsize() < 0)
421 		goto test_fail;
422 
423 	/* Basic enqueue/dequeue operations */
424 	if (test_soring_enqueue_dequeue() < 0)
425 		goto test_fail;
426 
427 	/* Acquire/release */
428 	if (test_soring_acquire_release() < 0)
429 		goto test_fail;
430 
431 	/* Test large number of stages */
432 	if (test_soring_stages() < 0)
433 		goto test_fail;
434 
435 	return 0;
436 
437 test_fail:
438 	return -1;
439 }
440 
441 REGISTER_FAST_TEST(soring_autotest, true, true, test_soring);
442