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