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>
16 /* Check condition and return an error if true. */
17 #define TEST_RCU_QSBR_RETURN_IF_ERROR(cond, str, ...) do { \
19 printf("ERROR file %s, line %d: " str "\n", __FILE__, \
20 __LINE__, ##__VA_ARGS__); \
25 /* Make sure that this has the same value as __RTE_QSBR_CNT_INIT */
26 #define TEST_RCU_QSBR_CNT_INIT 1
28 static uint16_t enabled_core_ids[RTE_MAX_LCORE];
29 static unsigned int num_cores;
31 static uint32_t *keys;
32 #define TOTAL_ENTRY (1024 * 8)
33 #define COUNTER_VALUE 4096
34 static uint32_t *hash_data[RTE_MAX_LCORE][TOTAL_ENTRY];
35 static uint8_t writer_done;
37 static struct rte_rcu_qsbr *t[RTE_MAX_LCORE];
38 static struct rte_hash *h[RTE_MAX_LCORE];
39 static char hash_name[RTE_MAX_LCORE][8];
41 struct test_rcu_thread_info {
42 /* Index in RCU array */
44 /* Index in hash array */
46 /* lcore IDs registered on the RCU variable */
47 uint16_t r_core_ids[2];
49 static struct test_rcu_thread_info thread_info[RTE_MAX_LCORE/4];
57 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
59 for (i = 0; i < RTE_MAX_LCORE; i++)
60 t[i] = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz,
71 for (i = 0; i < RTE_MAX_LCORE; i++)
78 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
79 * reporting their quiescent state on a QS variable.
82 test_rcu_qsbr_get_memsize(void)
86 printf("\nTest rte_rcu_qsbr_thread_register()\n");
88 sz = rte_rcu_qsbr_get_memsize(0);
89 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 1), "Get Memsize for 0 threads");
91 sz = rte_rcu_qsbr_get_memsize(128);
93 * for machines with cache line size of 64B - 8384
94 * for machines with cache line size of 128 - 16768
96 if (RTE_CACHE_LINE_SIZE == 64)
97 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 8384),
98 "Get Memsize for 128 threads");
99 else if (RTE_CACHE_LINE_SIZE == 128)
100 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 16768),
101 "Get Memsize for 128 threads");
107 * rte_rcu_qsbr_init: Initialize a QSBR variable.
110 test_rcu_qsbr_init(void)
114 printf("\nTest rte_rcu_qsbr_init()\n");
116 r = rte_rcu_qsbr_init(NULL, RTE_MAX_LCORE);
117 TEST_RCU_QSBR_RETURN_IF_ERROR((r != 1), "NULL variable");
123 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
124 * reporting their quiescent state on a QS variable.
127 test_rcu_qsbr_thread_register(void)
131 printf("\nTest rte_rcu_qsbr_thread_register()\n");
133 ret = rte_rcu_qsbr_thread_register(NULL, enabled_core_ids[0]);
134 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
136 ret = rte_rcu_qsbr_thread_register(NULL, 100000);
137 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
138 "NULL variable, invalid thread id");
140 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
142 /* Register valid thread id */
143 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
144 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Valid thread id");
146 /* Re-registering should not return error */
147 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
148 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
149 "Already registered thread id");
151 /* Register valid thread id - max allowed thread id */
152 ret = rte_rcu_qsbr_thread_register(t[0], RTE_MAX_LCORE - 1);
153 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Max thread id");
155 ret = rte_rcu_qsbr_thread_register(t[0], 100000);
156 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
157 "NULL variable, invalid thread id");
163 * rte_rcu_qsbr_thread_unregister: Remove a reader thread, from the list of
164 * threads reporting their quiescent state on a QS variable.
167 test_rcu_qsbr_thread_unregister(void)
169 unsigned int num_threads[3] = {1, RTE_MAX_LCORE, 1};
174 printf("\nTest rte_rcu_qsbr_thread_unregister()\n");
176 ret = rte_rcu_qsbr_thread_unregister(NULL, enabled_core_ids[0]);
177 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
179 ret = rte_rcu_qsbr_thread_unregister(NULL, 100000);
180 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
181 "NULL variable, invalid thread id");
183 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
185 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
187 ret = rte_rcu_qsbr_thread_unregister(t[0], 100000);
188 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
189 "NULL variable, invalid thread id");
191 /* Find first disabled core */
192 for (i = 0; i < RTE_MAX_LCORE; i++) {
193 if (enabled_core_ids[i] == 0)
196 /* Test with disabled lcore */
197 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
198 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
199 "disabled thread id");
200 /* Unregister already unregistered core */
201 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
202 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
203 "Already unregistered core");
205 /* Test with enabled lcore */
206 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
207 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
208 "enabled thread id");
209 /* Unregister already unregistered core */
210 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
211 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
212 "Already unregistered core");
215 * Test with different thread_ids:
217 * 2 - All possible thread_ids, from 0 to RTE_MAX_LCORE
218 * 3 - thread_id = RTE_MAX_LCORE - 1
220 for (j = 0; j < 3; j++) {
221 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
223 for (i = 0; i < num_threads[j]; i++)
224 rte_rcu_qsbr_thread_register(t[0],
225 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
227 token = rte_rcu_qsbr_start(t[0]);
228 TEST_RCU_QSBR_RETURN_IF_ERROR(
229 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
230 /* Update quiescent state counter */
231 for (i = 0; i < num_threads[j]; i++) {
232 /* Skip one update */
233 if (i == (RTE_MAX_LCORE - 10))
235 rte_rcu_qsbr_quiescent(t[0],
236 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
240 /* Validate the updates */
241 ret = rte_rcu_qsbr_check(t[0], token, false);
242 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
243 "Non-blocking QSBR check");
244 /* Update the previously skipped thread */
245 rte_rcu_qsbr_quiescent(t[0], RTE_MAX_LCORE - 10);
248 /* Validate the updates */
249 ret = rte_rcu_qsbr_check(t[0], token, false);
250 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
251 "Non-blocking QSBR check");
253 for (i = 0; i < num_threads[j]; i++)
254 rte_rcu_qsbr_thread_unregister(t[0],
255 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
257 /* Check with no thread registered */
258 ret = rte_rcu_qsbr_check(t[0], token, true);
259 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
260 "Blocking QSBR check");
266 * rte_rcu_qsbr_start: Ask the worker threads to report the quiescent state
270 test_rcu_qsbr_start(void)
275 printf("\nTest rte_rcu_qsbr_start()\n");
277 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
279 for (i = 0; i < 3; i++)
280 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
282 token = rte_rcu_qsbr_start(t[0]);
283 TEST_RCU_QSBR_RETURN_IF_ERROR(
284 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
289 test_rcu_qsbr_check_reader(void *arg)
291 struct rte_rcu_qsbr *temp;
292 uint8_t read_type = (uint8_t)((uintptr_t)arg);
296 /* Update quiescent state counter */
297 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[0]);
298 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[1]);
299 rte_rcu_qsbr_thread_unregister(temp, enabled_core_ids[2]);
300 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[3]);
305 * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis-
306 * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API.
309 test_rcu_qsbr_check(void)
314 printf("\nTest rte_rcu_qsbr_check()\n");
316 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
318 token = rte_rcu_qsbr_start(t[0]);
319 TEST_RCU_QSBR_RETURN_IF_ERROR(
320 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
323 ret = rte_rcu_qsbr_check(t[0], 0, false);
324 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Token = 0");
326 ret = rte_rcu_qsbr_check(t[0], token, true);
327 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
329 for (i = 0; i < 3; i++)
330 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
332 ret = rte_rcu_qsbr_check(t[0], token, false);
333 /* Threads are offline, hence this should pass */
334 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
336 token = rte_rcu_qsbr_start(t[0]);
337 TEST_RCU_QSBR_RETURN_IF_ERROR(
338 (token != (TEST_RCU_QSBR_CNT_INIT + 2)), "QSBR Start");
340 ret = rte_rcu_qsbr_check(t[0], token, false);
341 /* Threads are offline, hence this should pass */
342 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
344 for (i = 0; i < 3; i++)
345 rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[i]);
347 ret = rte_rcu_qsbr_check(t[0], token, true);
348 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
350 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
352 for (i = 0; i < 4; i++)
353 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
355 token = rte_rcu_qsbr_start(t[0]);
356 TEST_RCU_QSBR_RETURN_IF_ERROR(
357 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
359 rte_eal_remote_launch(test_rcu_qsbr_check_reader, NULL,
360 enabled_core_ids[0]);
362 rte_eal_mp_wait_lcore();
363 ret = rte_rcu_qsbr_check(t[0], token, true);
364 TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "Blocking QSBR check");
370 test_rcu_qsbr_synchronize_reader(void *arg)
372 uint32_t lcore_id = rte_lcore_id();
375 /* Register and become online */
376 rte_rcu_qsbr_thread_register(t[0], lcore_id);
377 rte_rcu_qsbr_thread_online(t[0], lcore_id);
380 rte_rcu_qsbr_quiescent(t[0], lcore_id);
382 rte_rcu_qsbr_thread_offline(t[0], lcore_id);
383 rte_rcu_qsbr_thread_unregister(t[0], lcore_id);
389 * rte_rcu_qsbr_synchronize: Wait till all the reader threads have entered
390 * the queiscent state.
393 test_rcu_qsbr_synchronize(void)
397 printf("\nTest rte_rcu_qsbr_synchronize()\n");
399 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
401 /* Test if the API returns when there are no threads reporting
402 * QS on the variable.
404 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
406 /* Test if the API returns when there are threads registered
409 for (i = 0; i < RTE_MAX_LCORE; i++)
410 rte_rcu_qsbr_thread_register(t[0], i);
411 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
413 /* Test if the API returns when the caller is also
414 * reporting the QS status.
416 rte_rcu_qsbr_thread_online(t[0], 0);
417 rte_rcu_qsbr_synchronize(t[0], 0);
418 rte_rcu_qsbr_thread_offline(t[0], 0);
420 /* Check the other boundary */
421 rte_rcu_qsbr_thread_online(t[0], RTE_MAX_LCORE - 1);
422 rte_rcu_qsbr_synchronize(t[0], RTE_MAX_LCORE - 1);
423 rte_rcu_qsbr_thread_offline(t[0], RTE_MAX_LCORE - 1);
425 /* Test if the API returns after unregisterng all the threads */
426 for (i = 0; i < RTE_MAX_LCORE; i++)
427 rte_rcu_qsbr_thread_unregister(t[0], i);
428 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
430 /* Test if the API returns with the live threads */
432 for (i = 0; i < num_cores; i++)
433 rte_eal_remote_launch(test_rcu_qsbr_synchronize_reader,
434 NULL, enabled_core_ids[i]);
435 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
436 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
437 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
438 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
439 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
442 rte_eal_mp_wait_lcore();
448 * rte_rcu_qsbr_thread_online: Add a registered reader thread, to
449 * the list of threads reporting their quiescent state on a QS variable.
452 test_rcu_qsbr_thread_online(void)
457 printf("Test rte_rcu_qsbr_thread_online()\n");
459 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
461 /* Register 2 threads to validate that only the
462 * online thread is waited upon.
464 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
465 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[1]);
467 /* Use qsbr_start to verify that the thread_online API
470 token = rte_rcu_qsbr_start(t[0]);
472 /* Make the thread online */
473 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
475 /* Check if the thread is online */
476 ret = rte_rcu_qsbr_check(t[0], token, true);
477 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
479 /* Check if the online thread, can report QS */
480 token = rte_rcu_qsbr_start(t[0]);
481 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
482 ret = rte_rcu_qsbr_check(t[0], token, true);
483 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
485 /* Make all the threads online */
486 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
487 token = rte_rcu_qsbr_start(t[0]);
488 for (i = 0; i < RTE_MAX_LCORE; i++) {
489 rte_rcu_qsbr_thread_register(t[0], i);
490 rte_rcu_qsbr_thread_online(t[0], i);
492 /* Check if all the threads are online */
493 ret = rte_rcu_qsbr_check(t[0], token, true);
494 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
495 /* Check if all the online threads can report QS */
496 token = rte_rcu_qsbr_start(t[0]);
497 for (i = 0; i < RTE_MAX_LCORE; i++)
498 rte_rcu_qsbr_quiescent(t[0], i);
499 ret = rte_rcu_qsbr_check(t[0], token, true);
500 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
506 * rte_rcu_qsbr_thread_offline: Remove a registered reader thread, from
507 * the list of threads reporting their quiescent state on a QS variable.
510 test_rcu_qsbr_thread_offline(void)
515 printf("\nTest rte_rcu_qsbr_thread_offline()\n");
517 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
519 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
521 /* Make the thread offline */
522 rte_rcu_qsbr_thread_offline(t[0], enabled_core_ids[0]);
524 /* Use qsbr_start to verify that the thread_offline API
527 token = rte_rcu_qsbr_start(t[0]);
528 /* Check if the thread is offline */
529 ret = rte_rcu_qsbr_check(t[0], token, true);
530 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread offline");
532 /* Bring an offline thread online and check if it can
535 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
536 /* Check if the online thread, can report QS */
537 token = rte_rcu_qsbr_start(t[0]);
538 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
539 ret = rte_rcu_qsbr_check(t[0], token, true);
540 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline to online");
543 * Check a sequence of online/status/offline/status/online/status
545 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
546 token = rte_rcu_qsbr_start(t[0]);
547 /* Make the threads online */
548 for (i = 0; i < RTE_MAX_LCORE; i++) {
549 rte_rcu_qsbr_thread_register(t[0], i);
550 rte_rcu_qsbr_thread_online(t[0], i);
553 /* Check if all the threads are online */
554 ret = rte_rcu_qsbr_check(t[0], token, true);
555 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
557 /* Check if all the online threads can report QS */
558 token = rte_rcu_qsbr_start(t[0]);
559 for (i = 0; i < RTE_MAX_LCORE; i++)
560 rte_rcu_qsbr_quiescent(t[0], i);
561 ret = rte_rcu_qsbr_check(t[0], token, true);
562 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "report QS");
564 /* Make all the threads offline */
565 for (i = 0; i < RTE_MAX_LCORE; i++)
566 rte_rcu_qsbr_thread_offline(t[0], i);
567 /* Make sure these threads are not being waited on */
568 token = rte_rcu_qsbr_start(t[0]);
569 ret = rte_rcu_qsbr_check(t[0], token, true);
570 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline QS");
572 /* Make the threads online */
573 for (i = 0; i < RTE_MAX_LCORE; i++)
574 rte_rcu_qsbr_thread_online(t[0], i);
575 /* Check if all the online threads can report QS */
576 token = rte_rcu_qsbr_start(t[0]);
577 for (i = 0; i < RTE_MAX_LCORE; i++)
578 rte_rcu_qsbr_quiescent(t[0], i);
579 ret = rte_rcu_qsbr_check(t[0], token, true);
580 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "online again");
586 * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file
589 test_rcu_qsbr_dump(void)
593 printf("\nTest rte_rcu_qsbr_dump()\n");
596 rte_rcu_qsbr_dump(NULL, t[0]);
597 rte_rcu_qsbr_dump(stdout, NULL);
598 rte_rcu_qsbr_dump(NULL, NULL);
600 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
601 rte_rcu_qsbr_init(t[1], RTE_MAX_LCORE);
603 /* QS variable with 0 core mask */
604 rte_rcu_qsbr_dump(stdout, t[0]);
606 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
608 for (i = 1; i < 3; i++)
609 rte_rcu_qsbr_thread_register(t[1], enabled_core_ids[i]);
611 rte_rcu_qsbr_dump(stdout, t[0]);
612 rte_rcu_qsbr_dump(stdout, t[1]);
618 test_rcu_qsbr_reader(void *arg)
620 struct rte_rcu_qsbr *temp;
621 struct rte_hash *hash = NULL;
623 uint32_t lcore_id = rte_lcore_id();
624 struct test_rcu_thread_info *ti;
627 ti = (struct test_rcu_thread_info *)arg;
632 rte_rcu_qsbr_thread_register(temp, lcore_id);
633 rte_rcu_qsbr_thread_online(temp, lcore_id);
634 for (i = 0; i < TOTAL_ENTRY; i++) {
635 rte_rcu_qsbr_lock(temp, lcore_id);
636 if (rte_hash_lookup_data(hash, keys+i,
637 (void **)&pdata) != -ENOENT) {
639 while (pdata[lcore_id] < COUNTER_VALUE)
642 rte_rcu_qsbr_unlock(temp, lcore_id);
644 /* Update quiescent state counter */
645 rte_rcu_qsbr_quiescent(temp, lcore_id);
646 rte_rcu_qsbr_thread_offline(temp, lcore_id);
647 rte_rcu_qsbr_thread_unregister(temp, lcore_id);
648 } while (!writer_done);
654 test_rcu_qsbr_writer(void *arg)
659 struct rte_rcu_qsbr *temp;
660 struct rte_hash *hash = NULL;
661 struct test_rcu_thread_info *ti;
663 ti = (struct test_rcu_thread_info *)arg;
667 /* Delete element from the shared data structure */
668 del = rte_lcore_id() % TOTAL_ENTRY;
669 pos = rte_hash_del_key(hash, keys + del);
671 printf("Delete key failed #%d\n", keys[del]);
674 /* Start the quiescent state query process */
675 token = rte_rcu_qsbr_start(temp);
676 /* Check the quiescent state status */
677 rte_rcu_qsbr_check(temp, token, true);
678 for (i = 0; i < 2; i++) {
679 c = hash_data[ti->ih][del][ti->r_core_ids[i]];
680 if (c != COUNTER_VALUE && c != 0) {
681 printf("Reader lcore id %u did not complete = %u\t",
687 if (rte_hash_free_key_with_position(hash, pos) < 0) {
688 printf("Failed to free the key #%d\n", keys[del]);
691 rte_free(hash_data[ti->ih][del]);
692 hash_data[ti->ih][del] = NULL;
697 static struct rte_hash *
698 init_hash(int hash_id)
701 struct rte_hash *h = NULL;
703 sprintf(hash_name[hash_id], "hash%d", hash_id);
704 struct rte_hash_parameters hash_params = {
705 .entries = TOTAL_ENTRY,
706 .key_len = sizeof(uint32_t),
707 .hash_func_init_val = 0,
708 .socket_id = rte_socket_id(),
709 .hash_func = rte_hash_crc,
711 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
712 .name = hash_name[hash_id],
715 h = rte_hash_create(&hash_params);
717 printf("Hash create Failed\n");
721 for (i = 0; i < TOTAL_ENTRY; i++) {
722 hash_data[hash_id][i] =
723 rte_zmalloc(NULL, sizeof(uint32_t) * RTE_MAX_LCORE, 0);
724 if (hash_data[hash_id][i] == NULL) {
725 printf("No memory\n");
729 keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);
731 printf("No memory\n");
735 for (i = 0; i < TOTAL_ENTRY; i++)
738 for (i = 0; i < TOTAL_ENTRY; i++) {
739 if (rte_hash_add_key_data(h, keys + i,
740 (void *)((uintptr_t)hash_data[hash_id][i]))
742 printf("Hash key add Failed #%d\n", i);
751 * Single writer, Single QS variable, simultaneous QSBR Queries
754 test_rcu_qsbr_sw_sv_3qs(void)
763 printf("Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\n");
765 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
767 /* Shared data structure created */
770 printf("Hash init failed\n");
774 /* No need to fill the registered core IDs as the writer
775 * thread is not launched.
777 thread_info[0].ir = 0;
778 thread_info[0].ih = 0;
780 /* Reader threads are launched */
781 for (i = 0; i < 4; i++)
782 rte_eal_remote_launch(test_rcu_qsbr_reader, &thread_info[0],
783 enabled_core_ids[i]);
785 /* Delete element from the shared data structure */
786 pos[0] = rte_hash_del_key(h[0], keys + 0);
788 printf("Delete key failed #%d\n", keys[0]);
791 /* Start the quiescent state query process */
792 token[0] = rte_rcu_qsbr_start(t[0]);
794 /* Delete element from the shared data structure */
795 pos[1] = rte_hash_del_key(h[0], keys + 3);
797 printf("Delete key failed #%d\n", keys[3]);
800 /* Start the quiescent state query process */
801 token[1] = rte_rcu_qsbr_start(t[0]);
803 /* Delete element from the shared data structure */
804 pos[2] = rte_hash_del_key(h[0], keys + 6);
806 printf("Delete key failed #%d\n", keys[6]);
809 /* Start the quiescent state query process */
810 token[2] = rte_rcu_qsbr_start(t[0]);
812 /* Check the quiescent state status */
813 rte_rcu_qsbr_check(t[0], token[0], true);
814 for (i = 0; i < 4; i++) {
815 c = hash_data[0][0][enabled_core_ids[i]];
816 if (c != COUNTER_VALUE && c != 0) {
817 printf("Reader lcore %d did not complete #0 = %d\n",
818 enabled_core_ids[i], c);
823 if (rte_hash_free_key_with_position(h[0], pos[0]) < 0) {
824 printf("Failed to free the key #%d\n", keys[0]);
827 rte_free(hash_data[0][0]);
828 hash_data[0][0] = NULL;
830 /* Check the quiescent state status */
831 rte_rcu_qsbr_check(t[0], token[1], true);
832 for (i = 0; i < 4; i++) {
833 c = hash_data[0][3][enabled_core_ids[i]];
834 if (c != COUNTER_VALUE && c != 0) {
835 printf("Reader lcore %d did not complete #3 = %d\n",
836 enabled_core_ids[i], c);
841 if (rte_hash_free_key_with_position(h[0], pos[1]) < 0) {
842 printf("Failed to free the key #%d\n", keys[3]);
845 rte_free(hash_data[0][3]);
846 hash_data[0][3] = NULL;
848 /* Check the quiescent state status */
849 rte_rcu_qsbr_check(t[0], token[2], true);
850 for (i = 0; i < 4; i++) {
851 c = hash_data[0][6][enabled_core_ids[i]];
852 if (c != COUNTER_VALUE && c != 0) {
853 printf("Reader lcore %d did not complete #6 = %d\n",
854 enabled_core_ids[i], c);
859 if (rte_hash_free_key_with_position(h[0], pos[2]) < 0) {
860 printf("Failed to free the key #%d\n", keys[6]);
863 rte_free(hash_data[0][6]);
864 hash_data[0][6] = NULL;
868 /* Wait and check return value from reader threads */
869 for (i = 0; i < 4; i++)
870 if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
879 /* Wait until all readers have exited */
880 rte_eal_mp_wait_lcore();
884 for (i = 0; i < TOTAL_ENTRY; i++)
885 rte_free(hash_data[0][i]);
891 * Multi writer, Multiple QS variable, simultaneous QSBR queries
894 test_rcu_qsbr_mw_mv_mqs(void)
897 unsigned int test_cores;
900 test_cores = num_cores / 4;
901 test_cores = test_cores * 4;
903 printf("Test: %d writers, %d QSBR variable, simultaneous QSBR queries\n",
904 test_cores / 2, test_cores / 4);
906 for (i = 0; i < test_cores / 4; i++) {
908 rte_rcu_qsbr_init(t[i], RTE_MAX_LCORE);
911 printf("Hash init failed\n");
914 thread_info[i].ir = i;
915 thread_info[i].ih = i;
916 thread_info[i].r_core_ids[0] = enabled_core_ids[j];
917 thread_info[i].r_core_ids[1] = enabled_core_ids[j + 1];
919 /* Reader threads are launched */
920 rte_eal_remote_launch(test_rcu_qsbr_reader,
921 (void *)&thread_info[i],
922 enabled_core_ids[j]);
923 rte_eal_remote_launch(test_rcu_qsbr_reader,
924 (void *)&thread_info[i],
925 enabled_core_ids[j + 1]);
927 /* Writer threads are launched */
928 rte_eal_remote_launch(test_rcu_qsbr_writer,
929 (void *)&thread_info[i],
930 enabled_core_ids[j + 2]);
931 rte_eal_remote_launch(test_rcu_qsbr_writer,
932 (void *)&thread_info[i],
933 enabled_core_ids[j + 3]);
936 /* Wait and check return value from writer threads */
937 for (i = 0; i < test_cores / 4; i++) {
939 if (rte_eal_wait_lcore(enabled_core_ids[j + 2]) < 0)
942 if (rte_eal_wait_lcore(enabled_core_ids[j + 3]) < 0)
947 /* Wait and check return value from reader threads */
948 for (i = 0; i < test_cores / 4; i++) {
950 if (rte_eal_wait_lcore(enabled_core_ids[j]) < 0)
953 if (rte_eal_wait_lcore(enabled_core_ids[j + 1]) < 0)
957 for (i = 0; i < test_cores / 4; i++)
966 /* Wait until all readers and writers have exited */
967 rte_eal_mp_wait_lcore();
969 for (i = 0; i < test_cores / 4; i++)
972 for (j = 0; j < test_cores / 4; j++)
973 for (i = 0; i < TOTAL_ENTRY; i++)
974 rte_free(hash_data[j][i]);
980 test_rcu_qsbr_main(void)
984 if (rte_lcore_count() < 5) {
985 printf("Not enough cores for rcu_qsbr_autotest, expecting at least 5\n");
990 RTE_LCORE_FOREACH_SLAVE(core_id) {
991 enabled_core_ids[num_cores] = core_id;
995 /* Error-checking test cases */
996 if (test_rcu_qsbr_get_memsize() < 0)
999 if (test_rcu_qsbr_init() < 0)
1004 if (test_rcu_qsbr_thread_register() < 0)
1007 if (test_rcu_qsbr_thread_unregister() < 0)
1010 if (test_rcu_qsbr_start() < 0)
1013 if (test_rcu_qsbr_check() < 0)
1016 if (test_rcu_qsbr_synchronize() < 0)
1019 if (test_rcu_qsbr_dump() < 0)
1022 if (test_rcu_qsbr_thread_online() < 0)
1025 if (test_rcu_qsbr_thread_offline() < 0)
1028 printf("\nFunctional tests\n");
1030 if (test_rcu_qsbr_sw_sv_3qs() < 0)
1033 if (test_rcu_qsbr_mw_mv_mqs() < 0)
1047 REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main);