1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2018 Arm Limited
7 #include <rte_rcu_qsbr.h>
9 #include <rte_hash_crc.h>
10 #include <rte_malloc.h>
11 #include <rte_cycles.h>
12 #include <rte_random.h>
17 /* Check condition and return an error if true. */
18 #define TEST_RCU_QSBR_RETURN_IF_ERROR(cond, str, ...) do { \
20 printf("ERROR file %s, line %d: " str "\n", __FILE__, \
21 __LINE__, ##__VA_ARGS__); \
26 /* Make sure that this has the same value as __RTE_QSBR_CNT_INIT */
27 #define TEST_RCU_QSBR_CNT_INIT 1
29 static uint16_t enabled_core_ids[RTE_MAX_LCORE];
30 static unsigned int num_cores;
32 static uint32_t *keys;
33 #define TOTAL_ENTRY (1024 * 8)
34 #define COUNTER_VALUE 4096
35 static uint32_t *hash_data[RTE_MAX_LCORE][TOTAL_ENTRY];
36 static uint8_t writer_done;
38 static struct rte_rcu_qsbr *t[RTE_MAX_LCORE];
39 static struct rte_hash *h[RTE_MAX_LCORE];
40 static char hash_name[RTE_MAX_LCORE][8];
42 struct test_rcu_thread_info {
43 /* Index in RCU array */
45 /* Index in hash array */
47 /* lcore IDs registered on the RCU variable */
48 uint16_t r_core_ids[2];
50 static struct test_rcu_thread_info thread_info[RTE_MAX_LCORE/4];
58 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
60 for (i = 0; i < RTE_MAX_LCORE; i++)
61 t[i] = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz,
72 for (i = 0; i < RTE_MAX_LCORE; i++)
79 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
80 * reporting their quiescent state on a QS variable.
83 test_rcu_qsbr_get_memsize(void)
87 printf("\nTest rte_rcu_qsbr_thread_register()\n");
89 sz = rte_rcu_qsbr_get_memsize(0);
90 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 1), "Get Memsize for 0 threads");
92 sz = rte_rcu_qsbr_get_memsize(128);
94 * for machines with cache line size of 64B - 8384
95 * for machines with cache line size of 128 - 16768
97 if (RTE_CACHE_LINE_SIZE == 64)
98 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 8384),
99 "Get Memsize for 128 threads");
100 else if (RTE_CACHE_LINE_SIZE == 128)
101 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 16768),
102 "Get Memsize for 128 threads");
108 * rte_rcu_qsbr_init: Initialize a QSBR variable.
111 test_rcu_qsbr_init(void)
115 printf("\nTest rte_rcu_qsbr_init()\n");
117 r = rte_rcu_qsbr_init(NULL, RTE_MAX_LCORE);
118 TEST_RCU_QSBR_RETURN_IF_ERROR((r != 1), "NULL variable");
124 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
125 * reporting their quiescent state on a QS variable.
128 test_rcu_qsbr_thread_register(void)
132 printf("\nTest rte_rcu_qsbr_thread_register()\n");
134 ret = rte_rcu_qsbr_thread_register(NULL, enabled_core_ids[0]);
135 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
137 ret = rte_rcu_qsbr_thread_register(NULL, 100000);
138 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
139 "NULL variable, invalid thread id");
141 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
143 /* Register valid thread id */
144 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
145 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Valid thread id");
147 /* Re-registering should not return error */
148 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
149 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
150 "Already registered thread id");
152 /* Register valid thread id - max allowed thread id */
153 ret = rte_rcu_qsbr_thread_register(t[0], RTE_MAX_LCORE - 1);
154 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Max thread id");
156 ret = rte_rcu_qsbr_thread_register(t[0], 100000);
157 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
158 "NULL variable, invalid thread id");
164 * rte_rcu_qsbr_thread_unregister: Remove a reader thread, from the list of
165 * threads reporting their quiescent state on a QS variable.
168 test_rcu_qsbr_thread_unregister(void)
170 unsigned int num_threads[3] = {1, RTE_MAX_LCORE, 1};
172 unsigned int skip_thread_id;
176 printf("\nTest rte_rcu_qsbr_thread_unregister()\n");
178 ret = rte_rcu_qsbr_thread_unregister(NULL, enabled_core_ids[0]);
179 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
181 ret = rte_rcu_qsbr_thread_unregister(NULL, 100000);
182 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
183 "NULL variable, invalid thread id");
185 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
187 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
189 ret = rte_rcu_qsbr_thread_unregister(t[0], 100000);
190 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
191 "NULL variable, invalid thread id");
193 /* Find first disabled core */
194 for (i = 0; i < RTE_MAX_LCORE; i++) {
195 if (enabled_core_ids[i] == 0)
198 /* Test with disabled lcore */
199 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
200 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
201 "disabled thread id");
202 /* Unregister already unregistered core */
203 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
204 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
205 "Already unregistered core");
207 /* Test with enabled lcore */
208 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
209 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
210 "enabled thread id");
211 /* Unregister already unregistered core */
212 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
213 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
214 "Already unregistered core");
217 * Test with different thread_ids:
219 * 2 - All possible thread_ids, from 0 to RTE_MAX_LCORE
220 * 3 - thread_id = RTE_MAX_LCORE - 1
222 for (j = 0; j < 3; j++) {
223 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
225 for (i = 0; i < num_threads[j]; i++)
226 rte_rcu_qsbr_thread_register(t[0],
227 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
229 token = rte_rcu_qsbr_start(t[0]);
230 TEST_RCU_QSBR_RETURN_IF_ERROR(
231 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
232 skip_thread_id = rte_rand() % RTE_MAX_LCORE;
233 /* Update quiescent state counter */
234 for (i = 0; i < num_threads[j]; i++) {
235 /* Skip one update */
236 if ((j == 1) && (i == skip_thread_id))
238 rte_rcu_qsbr_quiescent(t[0],
239 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
243 /* Validate the updates */
244 ret = rte_rcu_qsbr_check(t[0], token, false);
245 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
246 "Non-blocking QSBR check");
247 /* Update the previously skipped thread */
248 rte_rcu_qsbr_quiescent(t[0], skip_thread_id);
251 /* Validate the updates */
252 ret = rte_rcu_qsbr_check(t[0], token, false);
253 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
254 "Non-blocking QSBR check");
256 for (i = 0; i < num_threads[j]; i++)
257 rte_rcu_qsbr_thread_unregister(t[0],
258 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
260 /* Check with no thread registered */
261 ret = rte_rcu_qsbr_check(t[0], token, true);
262 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
263 "Blocking QSBR check");
269 * rte_rcu_qsbr_start: Ask the worker threads to report the quiescent state
273 test_rcu_qsbr_start(void)
278 printf("\nTest rte_rcu_qsbr_start()\n");
280 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
282 for (i = 0; i < 3; i++)
283 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
285 token = rte_rcu_qsbr_start(t[0]);
286 TEST_RCU_QSBR_RETURN_IF_ERROR(
287 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
292 test_rcu_qsbr_check_reader(void *arg)
294 struct rte_rcu_qsbr *temp;
295 uint8_t read_type = (uint8_t)((uintptr_t)arg);
299 /* Update quiescent state counter */
300 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[0]);
301 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[1]);
302 rte_rcu_qsbr_thread_unregister(temp, enabled_core_ids[2]);
303 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[3]);
308 * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis-
309 * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API.
312 test_rcu_qsbr_check(void)
317 printf("\nTest rte_rcu_qsbr_check()\n");
319 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
321 token = rte_rcu_qsbr_start(t[0]);
322 TEST_RCU_QSBR_RETURN_IF_ERROR(
323 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
326 ret = rte_rcu_qsbr_check(t[0], 0, false);
327 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Token = 0");
329 ret = rte_rcu_qsbr_check(t[0], token, true);
330 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
332 for (i = 0; i < 3; i++)
333 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
335 ret = rte_rcu_qsbr_check(t[0], token, false);
336 /* Threads are offline, hence this should pass */
337 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
339 token = rte_rcu_qsbr_start(t[0]);
340 TEST_RCU_QSBR_RETURN_IF_ERROR(
341 (token != (TEST_RCU_QSBR_CNT_INIT + 2)), "QSBR Start");
343 ret = rte_rcu_qsbr_check(t[0], token, false);
344 /* Threads are offline, hence this should pass */
345 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
347 for (i = 0; i < 3; i++)
348 rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[i]);
350 ret = rte_rcu_qsbr_check(t[0], token, true);
351 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
353 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
355 for (i = 0; i < 4; i++)
356 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
358 token = rte_rcu_qsbr_start(t[0]);
359 TEST_RCU_QSBR_RETURN_IF_ERROR(
360 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
362 rte_eal_remote_launch(test_rcu_qsbr_check_reader, NULL,
363 enabled_core_ids[0]);
365 rte_eal_mp_wait_lcore();
366 ret = rte_rcu_qsbr_check(t[0], token, true);
367 TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "Blocking QSBR check");
373 test_rcu_qsbr_synchronize_reader(void *arg)
375 uint32_t lcore_id = rte_lcore_id();
378 /* Register and become online */
379 rte_rcu_qsbr_thread_register(t[0], lcore_id);
380 rte_rcu_qsbr_thread_online(t[0], lcore_id);
383 rte_rcu_qsbr_quiescent(t[0], lcore_id);
385 rte_rcu_qsbr_thread_offline(t[0], lcore_id);
386 rte_rcu_qsbr_thread_unregister(t[0], lcore_id);
392 * rte_rcu_qsbr_synchronize: Wait till all the reader threads have entered
393 * the queiscent state.
396 test_rcu_qsbr_synchronize(void)
400 printf("\nTest rte_rcu_qsbr_synchronize()\n");
402 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
404 /* Test if the API returns when there are no threads reporting
405 * QS on the variable.
407 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
409 /* Test if the API returns when there are threads registered
412 for (i = 0; i < RTE_MAX_LCORE; i++)
413 rte_rcu_qsbr_thread_register(t[0], i);
414 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
416 /* Test if the API returns when the caller is also
417 * reporting the QS status.
419 rte_rcu_qsbr_thread_online(t[0], 0);
420 rte_rcu_qsbr_synchronize(t[0], 0);
421 rte_rcu_qsbr_thread_offline(t[0], 0);
423 /* Check the other boundary */
424 rte_rcu_qsbr_thread_online(t[0], RTE_MAX_LCORE - 1);
425 rte_rcu_qsbr_synchronize(t[0], RTE_MAX_LCORE - 1);
426 rte_rcu_qsbr_thread_offline(t[0], RTE_MAX_LCORE - 1);
428 /* Test if the API returns after unregisterng all the threads */
429 for (i = 0; i < RTE_MAX_LCORE; i++)
430 rte_rcu_qsbr_thread_unregister(t[0], i);
431 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
433 /* Test if the API returns with the live threads */
435 for (i = 0; i < num_cores; i++)
436 rte_eal_remote_launch(test_rcu_qsbr_synchronize_reader,
437 NULL, enabled_core_ids[i]);
438 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
439 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
440 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
441 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
442 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
445 rte_eal_mp_wait_lcore();
451 * rte_rcu_qsbr_thread_online: Add a registered reader thread, to
452 * the list of threads reporting their quiescent state on a QS variable.
455 test_rcu_qsbr_thread_online(void)
460 printf("Test rte_rcu_qsbr_thread_online()\n");
462 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
464 /* Register 2 threads to validate that only the
465 * online thread is waited upon.
467 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
468 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[1]);
470 /* Use qsbr_start to verify that the thread_online API
473 token = rte_rcu_qsbr_start(t[0]);
475 /* Make the thread online */
476 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
478 /* Check if the thread is online */
479 ret = rte_rcu_qsbr_check(t[0], token, true);
480 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
482 /* Check if the online thread, can report QS */
483 token = rte_rcu_qsbr_start(t[0]);
484 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
485 ret = rte_rcu_qsbr_check(t[0], token, true);
486 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
488 /* Make all the threads online */
489 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
490 token = rte_rcu_qsbr_start(t[0]);
491 for (i = 0; i < RTE_MAX_LCORE; i++) {
492 rte_rcu_qsbr_thread_register(t[0], i);
493 rte_rcu_qsbr_thread_online(t[0], i);
495 /* Check if all the threads are online */
496 ret = rte_rcu_qsbr_check(t[0], token, true);
497 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
498 /* Check if all the online threads can report QS */
499 token = rte_rcu_qsbr_start(t[0]);
500 for (i = 0; i < RTE_MAX_LCORE; i++)
501 rte_rcu_qsbr_quiescent(t[0], i);
502 ret = rte_rcu_qsbr_check(t[0], token, true);
503 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
509 * rte_rcu_qsbr_thread_offline: Remove a registered reader thread, from
510 * the list of threads reporting their quiescent state on a QS variable.
513 test_rcu_qsbr_thread_offline(void)
518 printf("\nTest rte_rcu_qsbr_thread_offline()\n");
520 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
522 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
524 /* Make the thread offline */
525 rte_rcu_qsbr_thread_offline(t[0], enabled_core_ids[0]);
527 /* Use qsbr_start to verify that the thread_offline API
530 token = rte_rcu_qsbr_start(t[0]);
531 /* Check if the thread is offline */
532 ret = rte_rcu_qsbr_check(t[0], token, true);
533 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread offline");
535 /* Bring an offline thread online and check if it can
538 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
539 /* Check if the online thread, can report QS */
540 token = rte_rcu_qsbr_start(t[0]);
541 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
542 ret = rte_rcu_qsbr_check(t[0], token, true);
543 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline to online");
546 * Check a sequence of online/status/offline/status/online/status
548 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
549 token = rte_rcu_qsbr_start(t[0]);
550 /* Make the threads online */
551 for (i = 0; i < RTE_MAX_LCORE; i++) {
552 rte_rcu_qsbr_thread_register(t[0], i);
553 rte_rcu_qsbr_thread_online(t[0], i);
556 /* Check if all the threads are online */
557 ret = rte_rcu_qsbr_check(t[0], token, true);
558 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
560 /* Check if all the online threads can report QS */
561 token = rte_rcu_qsbr_start(t[0]);
562 for (i = 0; i < RTE_MAX_LCORE; i++)
563 rte_rcu_qsbr_quiescent(t[0], i);
564 ret = rte_rcu_qsbr_check(t[0], token, true);
565 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "report QS");
567 /* Make all the threads offline */
568 for (i = 0; i < RTE_MAX_LCORE; i++)
569 rte_rcu_qsbr_thread_offline(t[0], i);
570 /* Make sure these threads are not being waited on */
571 token = rte_rcu_qsbr_start(t[0]);
572 ret = rte_rcu_qsbr_check(t[0], token, true);
573 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline QS");
575 /* Make the threads online */
576 for (i = 0; i < RTE_MAX_LCORE; i++)
577 rte_rcu_qsbr_thread_online(t[0], i);
578 /* Check if all the online threads can report QS */
579 token = rte_rcu_qsbr_start(t[0]);
580 for (i = 0; i < RTE_MAX_LCORE; i++)
581 rte_rcu_qsbr_quiescent(t[0], i);
582 ret = rte_rcu_qsbr_check(t[0], token, true);
583 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "online again");
589 * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file
592 test_rcu_qsbr_dump(void)
596 printf("\nTest rte_rcu_qsbr_dump()\n");
599 rte_rcu_qsbr_dump(NULL, t[0]);
600 rte_rcu_qsbr_dump(stdout, NULL);
601 rte_rcu_qsbr_dump(NULL, NULL);
603 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
604 rte_rcu_qsbr_init(t[1], RTE_MAX_LCORE);
606 /* QS variable with 0 core mask */
607 rte_rcu_qsbr_dump(stdout, t[0]);
609 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
611 for (i = 1; i < 3; i++)
612 rte_rcu_qsbr_thread_register(t[1], enabled_core_ids[i]);
614 rte_rcu_qsbr_dump(stdout, t[0]);
615 rte_rcu_qsbr_dump(stdout, t[1]);
621 test_rcu_qsbr_reader(void *arg)
623 struct rte_rcu_qsbr *temp;
624 struct rte_hash *hash = NULL;
626 uint32_t lcore_id = rte_lcore_id();
627 struct test_rcu_thread_info *ti;
630 ti = (struct test_rcu_thread_info *)arg;
635 rte_rcu_qsbr_thread_register(temp, lcore_id);
636 rte_rcu_qsbr_thread_online(temp, lcore_id);
637 for (i = 0; i < TOTAL_ENTRY; i++) {
638 rte_rcu_qsbr_lock(temp, lcore_id);
639 if (rte_hash_lookup_data(hash, keys+i,
640 (void **)&pdata) != -ENOENT) {
642 while (pdata[lcore_id] < COUNTER_VALUE)
645 rte_rcu_qsbr_unlock(temp, lcore_id);
647 /* Update quiescent state counter */
648 rte_rcu_qsbr_quiescent(temp, lcore_id);
649 rte_rcu_qsbr_thread_offline(temp, lcore_id);
650 rte_rcu_qsbr_thread_unregister(temp, lcore_id);
651 } while (!writer_done);
657 test_rcu_qsbr_writer(void *arg)
662 struct rte_rcu_qsbr *temp;
663 struct rte_hash *hash = NULL;
664 struct test_rcu_thread_info *ti;
666 ti = (struct test_rcu_thread_info *)arg;
670 /* Delete element from the shared data structure */
671 del = rte_lcore_id() % TOTAL_ENTRY;
672 pos = rte_hash_del_key(hash, keys + del);
674 printf("Delete key failed #%d\n", keys[del]);
677 /* Start the quiescent state query process */
678 token = rte_rcu_qsbr_start(temp);
679 /* Check the quiescent state status */
680 rte_rcu_qsbr_check(temp, token, true);
681 for (i = 0; i < 2; i++) {
682 c = hash_data[ti->ih][del][ti->r_core_ids[i]];
683 if (c != COUNTER_VALUE && c != 0) {
684 printf("Reader lcore id %u did not complete = %u\t",
690 if (rte_hash_free_key_with_position(hash, pos) < 0) {
691 printf("Failed to free the key #%d\n", keys[del]);
694 rte_free(hash_data[ti->ih][del]);
695 hash_data[ti->ih][del] = NULL;
700 static struct rte_hash *
701 init_hash(int hash_id)
704 struct rte_hash *h = NULL;
706 sprintf(hash_name[hash_id], "hash%d", hash_id);
707 struct rte_hash_parameters hash_params = {
708 .entries = TOTAL_ENTRY,
709 .key_len = sizeof(uint32_t),
710 .hash_func_init_val = 0,
711 .socket_id = rte_socket_id(),
712 .hash_func = rte_hash_crc,
714 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
715 .name = hash_name[hash_id],
718 h = rte_hash_create(&hash_params);
720 printf("Hash create Failed\n");
724 for (i = 0; i < TOTAL_ENTRY; i++) {
725 hash_data[hash_id][i] =
726 rte_zmalloc(NULL, sizeof(uint32_t) * RTE_MAX_LCORE, 0);
727 if (hash_data[hash_id][i] == NULL) {
728 printf("No memory\n");
732 keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);
734 printf("No memory\n");
738 for (i = 0; i < TOTAL_ENTRY; i++)
741 for (i = 0; i < TOTAL_ENTRY; i++) {
742 if (rte_hash_add_key_data(h, keys + i,
743 (void *)((uintptr_t)hash_data[hash_id][i]))
745 printf("Hash key add Failed #%d\n", i);
754 * Single writer, Single QS variable, simultaneous QSBR Queries
757 test_rcu_qsbr_sw_sv_3qs(void)
766 printf("Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\n");
768 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
770 /* Shared data structure created */
773 printf("Hash init failed\n");
777 /* No need to fill the registered core IDs as the writer
778 * thread is not launched.
780 thread_info[0].ir = 0;
781 thread_info[0].ih = 0;
783 /* Reader threads are launched */
784 for (i = 0; i < 4; i++)
785 rte_eal_remote_launch(test_rcu_qsbr_reader, &thread_info[0],
786 enabled_core_ids[i]);
788 /* Delete element from the shared data structure */
789 pos[0] = rte_hash_del_key(h[0], keys + 0);
791 printf("Delete key failed #%d\n", keys[0]);
794 /* Start the quiescent state query process */
795 token[0] = rte_rcu_qsbr_start(t[0]);
797 /* Delete element from the shared data structure */
798 pos[1] = rte_hash_del_key(h[0], keys + 3);
800 printf("Delete key failed #%d\n", keys[3]);
803 /* Start the quiescent state query process */
804 token[1] = rte_rcu_qsbr_start(t[0]);
806 /* Delete element from the shared data structure */
807 pos[2] = rte_hash_del_key(h[0], keys + 6);
809 printf("Delete key failed #%d\n", keys[6]);
812 /* Start the quiescent state query process */
813 token[2] = rte_rcu_qsbr_start(t[0]);
815 /* Check the quiescent state status */
816 rte_rcu_qsbr_check(t[0], token[0], true);
817 for (i = 0; i < 4; i++) {
818 c = hash_data[0][0][enabled_core_ids[i]];
819 if (c != COUNTER_VALUE && c != 0) {
820 printf("Reader lcore %d did not complete #0 = %d\n",
821 enabled_core_ids[i], c);
826 if (rte_hash_free_key_with_position(h[0], pos[0]) < 0) {
827 printf("Failed to free the key #%d\n", keys[0]);
830 rte_free(hash_data[0][0]);
831 hash_data[0][0] = NULL;
833 /* Check the quiescent state status */
834 rte_rcu_qsbr_check(t[0], token[1], true);
835 for (i = 0; i < 4; i++) {
836 c = hash_data[0][3][enabled_core_ids[i]];
837 if (c != COUNTER_VALUE && c != 0) {
838 printf("Reader lcore %d did not complete #3 = %d\n",
839 enabled_core_ids[i], c);
844 if (rte_hash_free_key_with_position(h[0], pos[1]) < 0) {
845 printf("Failed to free the key #%d\n", keys[3]);
848 rte_free(hash_data[0][3]);
849 hash_data[0][3] = NULL;
851 /* Check the quiescent state status */
852 rte_rcu_qsbr_check(t[0], token[2], true);
853 for (i = 0; i < 4; i++) {
854 c = hash_data[0][6][enabled_core_ids[i]];
855 if (c != COUNTER_VALUE && c != 0) {
856 printf("Reader lcore %d did not complete #6 = %d\n",
857 enabled_core_ids[i], c);
862 if (rte_hash_free_key_with_position(h[0], pos[2]) < 0) {
863 printf("Failed to free the key #%d\n", keys[6]);
866 rte_free(hash_data[0][6]);
867 hash_data[0][6] = NULL;
871 /* Wait and check return value from reader threads */
872 for (i = 0; i < 4; i++)
873 if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
882 /* Wait until all readers have exited */
883 rte_eal_mp_wait_lcore();
887 for (i = 0; i < TOTAL_ENTRY; i++)
888 rte_free(hash_data[0][i]);
894 * Multi writer, Multiple QS variable, simultaneous QSBR queries
897 test_rcu_qsbr_mw_mv_mqs(void)
900 unsigned int test_cores;
903 test_cores = num_cores / 4;
904 test_cores = test_cores * 4;
906 printf("Test: %d writers, %d QSBR variable, simultaneous QSBR queries\n",
907 test_cores / 2, test_cores / 4);
909 for (i = 0; i < test_cores / 4; i++) {
911 rte_rcu_qsbr_init(t[i], RTE_MAX_LCORE);
914 printf("Hash init failed\n");
917 thread_info[i].ir = i;
918 thread_info[i].ih = i;
919 thread_info[i].r_core_ids[0] = enabled_core_ids[j];
920 thread_info[i].r_core_ids[1] = enabled_core_ids[j + 1];
922 /* Reader threads are launched */
923 rte_eal_remote_launch(test_rcu_qsbr_reader,
924 (void *)&thread_info[i],
925 enabled_core_ids[j]);
926 rte_eal_remote_launch(test_rcu_qsbr_reader,
927 (void *)&thread_info[i],
928 enabled_core_ids[j + 1]);
930 /* Writer threads are launched */
931 rte_eal_remote_launch(test_rcu_qsbr_writer,
932 (void *)&thread_info[i],
933 enabled_core_ids[j + 2]);
934 rte_eal_remote_launch(test_rcu_qsbr_writer,
935 (void *)&thread_info[i],
936 enabled_core_ids[j + 3]);
939 /* Wait and check return value from writer threads */
940 for (i = 0; i < test_cores / 4; i++) {
942 if (rte_eal_wait_lcore(enabled_core_ids[j + 2]) < 0)
945 if (rte_eal_wait_lcore(enabled_core_ids[j + 3]) < 0)
950 /* Wait and check return value from reader threads */
951 for (i = 0; i < test_cores / 4; i++) {
953 if (rte_eal_wait_lcore(enabled_core_ids[j]) < 0)
956 if (rte_eal_wait_lcore(enabled_core_ids[j + 1]) < 0)
960 for (i = 0; i < test_cores / 4; i++)
969 /* Wait until all readers and writers have exited */
970 rte_eal_mp_wait_lcore();
972 for (i = 0; i < test_cores / 4; i++)
975 for (j = 0; j < test_cores / 4; j++)
976 for (i = 0; i < TOTAL_ENTRY; i++)
977 rte_free(hash_data[j][i]);
983 test_rcu_qsbr_main(void)
987 if (rte_lcore_count() < 5) {
988 printf("Not enough cores for rcu_qsbr_autotest, expecting at least 5\n");
993 RTE_LCORE_FOREACH_SLAVE(core_id) {
994 enabled_core_ids[num_cores] = core_id;
998 /* Error-checking test cases */
999 if (test_rcu_qsbr_get_memsize() < 0)
1002 if (test_rcu_qsbr_init() < 0)
1007 if (test_rcu_qsbr_thread_register() < 0)
1010 if (test_rcu_qsbr_thread_unregister() < 0)
1013 if (test_rcu_qsbr_start() < 0)
1016 if (test_rcu_qsbr_check() < 0)
1019 if (test_rcu_qsbr_synchronize() < 0)
1022 if (test_rcu_qsbr_dump() < 0)
1025 if (test_rcu_qsbr_thread_online() < 0)
1028 if (test_rcu_qsbr_thread_offline() < 0)
1031 printf("\nFunctional tests\n");
1033 if (test_rcu_qsbr_sw_sv_3qs() < 0)
1036 if (test_rcu_qsbr_mw_mv_mqs() < 0)
1050 REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main);