1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2018 Arm Limited
8 #include <rte_rcu_qsbr.h>
10 #include <rte_hash_crc.h>
11 #include <rte_malloc.h>
12 #include <rte_cycles.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 #define TEST_RCU_MAX_LCORE 128
30 uint16_t enabled_core_ids[TEST_RCU_MAX_LCORE];
33 static uint32_t *keys;
34 #define TOTAL_ENTRY (1024 * 8)
35 #define COUNTER_VALUE 4096
36 static uint32_t *hash_data[TEST_RCU_MAX_LCORE][TOTAL_ENTRY];
37 static uint8_t writer_done;
39 static struct rte_rcu_qsbr *t[TEST_RCU_MAX_LCORE];
40 struct rte_hash *h[TEST_RCU_MAX_LCORE];
41 char hash_name[TEST_RCU_MAX_LCORE][8];
43 struct test_rcu_thread_info {
44 /* Index in RCU array */
46 /* Index in hash array */
48 /* lcore IDs registered on the RCU variable */
49 uint16_t r_core_ids[2];
51 struct test_rcu_thread_info thread_info[TEST_RCU_MAX_LCORE/4];
54 get_enabled_cores_mask(void)
57 uint32_t max_cores = rte_lcore_count();
59 if (max_cores > TEST_RCU_MAX_LCORE) {
60 printf("Number of cores exceed %d\n", TEST_RCU_MAX_LCORE);
66 RTE_LCORE_FOREACH_SLAVE(core_id) {
67 enabled_core_ids[num_cores] = core_id;
80 sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
82 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
83 t[i] = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz,
94 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
101 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
102 * reporting their quiescent state on a QS variable.
105 test_rcu_qsbr_get_memsize(void)
109 printf("\nTest rte_rcu_qsbr_thread_register()\n");
111 sz = rte_rcu_qsbr_get_memsize(0);
112 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 1), "Get Memsize for 0 threads");
114 sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
116 * for machines with cache line size of 64B - 8384
117 * for machines with cache line size of 128 - 16768
119 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 8384 && sz != 16768),
126 * rte_rcu_qsbr_init: Initialize a QSBR variable.
129 test_rcu_qsbr_init(void)
133 printf("\nTest rte_rcu_qsbr_init()\n");
135 r = rte_rcu_qsbr_init(NULL, TEST_RCU_MAX_LCORE);
136 TEST_RCU_QSBR_RETURN_IF_ERROR((r != 1), "NULL variable");
142 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
143 * reporting their quiescent state on a QS variable.
146 test_rcu_qsbr_thread_register(void)
150 printf("\nTest rte_rcu_qsbr_thread_register()\n");
152 ret = rte_rcu_qsbr_thread_register(NULL, enabled_core_ids[0]);
153 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
155 ret = rte_rcu_qsbr_thread_register(NULL, 100000);
156 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
157 "NULL variable, invalid thread id");
159 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
161 /* Register valid thread id */
162 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
163 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Valid thread id");
165 /* Re-registering should not return error */
166 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
167 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
168 "Already registered thread id");
170 /* Register valid thread id - max allowed thread id */
171 ret = rte_rcu_qsbr_thread_register(t[0], TEST_RCU_MAX_LCORE - 1);
172 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Max thread id");
174 ret = rte_rcu_qsbr_thread_register(t[0], 100000);
175 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
176 "NULL variable, invalid thread id");
182 * rte_rcu_qsbr_thread_unregister: Remove a reader thread, from the list of
183 * threads reporting their quiescent state on a QS variable.
186 test_rcu_qsbr_thread_unregister(void)
190 uint8_t num_threads[3] = {1, TEST_RCU_MAX_LCORE, 1};
192 printf("\nTest rte_rcu_qsbr_thread_unregister()\n");
194 ret = rte_rcu_qsbr_thread_unregister(NULL, enabled_core_ids[0]);
195 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
197 ret = rte_rcu_qsbr_thread_unregister(NULL, 100000);
198 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
199 "NULL variable, invalid thread id");
201 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
203 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
205 ret = rte_rcu_qsbr_thread_unregister(t[0], 100000);
206 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
207 "NULL variable, invalid thread id");
209 /* Find first disabled core */
210 for (i = 0; i < TEST_RCU_MAX_LCORE; i++) {
211 if (enabled_core_ids[i] == 0)
214 /* Test with disabled lcore */
215 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
216 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
217 "disabled thread id");
218 /* Unregister already unregistered core */
219 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
220 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
221 "Already unregistered core");
223 /* Test with enabled lcore */
224 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
225 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
226 "enabled thread id");
227 /* Unregister already unregistered core */
228 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
229 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
230 "Already unregistered core");
233 * Test with different thread_ids:
235 * 2 - All possible thread_ids, from 0 to TEST_RCU_MAX_LCORE
236 * 3 - thread_id = TEST_RCU_MAX_LCORE - 1
238 for (j = 0; j < 3; j++) {
239 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
241 for (i = 0; i < num_threads[j]; i++)
242 rte_rcu_qsbr_thread_register(t[0],
243 (j == 2) ? (TEST_RCU_MAX_LCORE - 1) : i);
245 token = rte_rcu_qsbr_start(t[0]);
246 TEST_RCU_QSBR_RETURN_IF_ERROR(
247 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
248 /* Update quiescent state counter */
249 for (i = 0; i < num_threads[j]; i++) {
250 /* Skip one update */
251 if (i == (TEST_RCU_MAX_LCORE - 10))
253 rte_rcu_qsbr_quiescent(t[0],
254 (j == 2) ? (TEST_RCU_MAX_LCORE - 1) : i);
258 /* Validate the updates */
259 ret = rte_rcu_qsbr_check(t[0], token, false);
260 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
261 "Non-blocking QSBR check");
262 /* Update the previously skipped thread */
263 rte_rcu_qsbr_quiescent(t[0], TEST_RCU_MAX_LCORE - 10);
266 /* Validate the updates */
267 ret = rte_rcu_qsbr_check(t[0], token, false);
268 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
269 "Non-blocking QSBR check");
271 for (i = 0; i < num_threads[j]; i++)
272 rte_rcu_qsbr_thread_unregister(t[0],
273 (j == 2) ? (TEST_RCU_MAX_LCORE - 1) : i);
275 /* Check with no thread registered */
276 ret = rte_rcu_qsbr_check(t[0], token, true);
277 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
278 "Blocking QSBR check");
284 * rte_rcu_qsbr_start: Ask the worker threads to report the quiescent state
288 test_rcu_qsbr_start(void)
293 printf("\nTest rte_rcu_qsbr_start()\n");
295 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
297 for (i = 0; i < 3; i++)
298 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
300 token = rte_rcu_qsbr_start(t[0]);
301 TEST_RCU_QSBR_RETURN_IF_ERROR(
302 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
307 test_rcu_qsbr_check_reader(void *arg)
309 struct rte_rcu_qsbr *temp;
310 uint8_t read_type = (uint8_t)((uintptr_t)arg);
314 /* Update quiescent state counter */
315 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[0]);
316 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[1]);
317 rte_rcu_qsbr_thread_unregister(temp, enabled_core_ids[2]);
318 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[3]);
323 * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis-
324 * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API.
327 test_rcu_qsbr_check(void)
332 printf("\nTest rte_rcu_qsbr_check()\n");
334 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
336 token = rte_rcu_qsbr_start(t[0]);
337 TEST_RCU_QSBR_RETURN_IF_ERROR(
338 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
341 ret = rte_rcu_qsbr_check(t[0], 0, false);
342 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Token = 0");
344 ret = rte_rcu_qsbr_check(t[0], token, true);
345 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
347 for (i = 0; i < 3; i++)
348 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
350 ret = rte_rcu_qsbr_check(t[0], token, false);
351 /* Threads are offline, hence this should pass */
352 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
354 token = rte_rcu_qsbr_start(t[0]);
355 TEST_RCU_QSBR_RETURN_IF_ERROR(
356 (token != (TEST_RCU_QSBR_CNT_INIT + 2)), "QSBR Start");
358 ret = rte_rcu_qsbr_check(t[0], token, false);
359 /* Threads are offline, hence this should pass */
360 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
362 for (i = 0; i < 3; i++)
363 rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[i]);
365 ret = rte_rcu_qsbr_check(t[0], token, true);
366 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
368 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
370 for (i = 0; i < 4; i++)
371 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
373 token = rte_rcu_qsbr_start(t[0]);
374 TEST_RCU_QSBR_RETURN_IF_ERROR(
375 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
377 rte_eal_remote_launch(test_rcu_qsbr_check_reader, NULL,
378 enabled_core_ids[0]);
380 rte_eal_mp_wait_lcore();
381 ret = rte_rcu_qsbr_check(t[0], token, true);
382 TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "Blocking QSBR check");
388 test_rcu_qsbr_synchronize_reader(void *arg)
390 uint32_t lcore_id = rte_lcore_id();
393 /* Register and become online */
394 rte_rcu_qsbr_thread_register(t[0], lcore_id);
395 rte_rcu_qsbr_thread_online(t[0], lcore_id);
398 rte_rcu_qsbr_quiescent(t[0], lcore_id);
400 rte_rcu_qsbr_thread_offline(t[0], lcore_id);
401 rte_rcu_qsbr_thread_unregister(t[0], lcore_id);
407 * rte_rcu_qsbr_synchronize: Wait till all the reader threads have entered
408 * the queiscent state.
411 test_rcu_qsbr_synchronize(void)
415 printf("\nTest rte_rcu_qsbr_synchronize()\n");
417 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
419 /* Test if the API returns when there are no threads reporting
420 * QS on the variable.
422 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
424 /* Test if the API returns when there are threads registered
427 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
428 rte_rcu_qsbr_thread_register(t[0], i);
429 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
431 /* Test if the API returns when the caller is also
432 * reporting the QS status.
434 rte_rcu_qsbr_thread_online(t[0], 0);
435 rte_rcu_qsbr_synchronize(t[0], 0);
436 rte_rcu_qsbr_thread_offline(t[0], 0);
438 /* Check the other boundary */
439 rte_rcu_qsbr_thread_online(t[0], TEST_RCU_MAX_LCORE - 1);
440 rte_rcu_qsbr_synchronize(t[0], TEST_RCU_MAX_LCORE - 1);
441 rte_rcu_qsbr_thread_offline(t[0], TEST_RCU_MAX_LCORE - 1);
443 /* Test if the API returns after unregisterng all the threads */
444 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
445 rte_rcu_qsbr_thread_unregister(t[0], i);
446 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
448 /* Test if the API returns with the live threads */
450 for (i = 0; i < num_cores; i++)
451 rte_eal_remote_launch(test_rcu_qsbr_synchronize_reader,
452 NULL, enabled_core_ids[i]);
453 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
454 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
455 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
456 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
457 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
460 rte_eal_mp_wait_lcore();
466 * rte_rcu_qsbr_thread_online: Add a registered reader thread, to
467 * the list of threads reporting their quiescent state on a QS variable.
470 test_rcu_qsbr_thread_online(void)
475 printf("Test rte_rcu_qsbr_thread_online()\n");
477 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
479 /* Register 2 threads to validate that only the
480 * online thread is waited upon.
482 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
483 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[1]);
485 /* Use qsbr_start to verify that the thread_online API
488 token = rte_rcu_qsbr_start(t[0]);
490 /* Make the thread online */
491 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
493 /* Check if the thread is online */
494 ret = rte_rcu_qsbr_check(t[0], token, true);
495 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
497 /* Check if the online thread, can report QS */
498 token = rte_rcu_qsbr_start(t[0]);
499 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
500 ret = rte_rcu_qsbr_check(t[0], token, true);
501 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
503 /* Make all the threads online */
504 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
505 token = rte_rcu_qsbr_start(t[0]);
506 for (i = 0; i < TEST_RCU_MAX_LCORE; i++) {
507 rte_rcu_qsbr_thread_register(t[0], i);
508 rte_rcu_qsbr_thread_online(t[0], i);
510 /* Check if all the threads are online */
511 ret = rte_rcu_qsbr_check(t[0], token, true);
512 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
513 /* Check if all the online threads can report QS */
514 token = rte_rcu_qsbr_start(t[0]);
515 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
516 rte_rcu_qsbr_quiescent(t[0], i);
517 ret = rte_rcu_qsbr_check(t[0], token, true);
518 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
524 * rte_rcu_qsbr_thread_offline: Remove a registered reader thread, from
525 * the list of threads reporting their quiescent state on a QS variable.
528 test_rcu_qsbr_thread_offline(void)
533 printf("\nTest rte_rcu_qsbr_thread_offline()\n");
535 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
537 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
539 /* Make the thread offline */
540 rte_rcu_qsbr_thread_offline(t[0], enabled_core_ids[0]);
542 /* Use qsbr_start to verify that the thread_offline API
545 token = rte_rcu_qsbr_start(t[0]);
546 /* Check if the thread is offline */
547 ret = rte_rcu_qsbr_check(t[0], token, true);
548 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread offline");
550 /* Bring an offline thread online and check if it can
553 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
554 /* Check if the online thread, can report QS */
555 token = rte_rcu_qsbr_start(t[0]);
556 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
557 ret = rte_rcu_qsbr_check(t[0], token, true);
558 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline to online");
561 * Check a sequence of online/status/offline/status/online/status
563 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
564 token = rte_rcu_qsbr_start(t[0]);
565 /* Make the threads online */
566 for (i = 0; i < TEST_RCU_MAX_LCORE; i++) {
567 rte_rcu_qsbr_thread_register(t[0], i);
568 rte_rcu_qsbr_thread_online(t[0], i);
571 /* Check if all the threads are online */
572 ret = rte_rcu_qsbr_check(t[0], token, true);
573 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
575 /* Check if all the online threads can report QS */
576 token = rte_rcu_qsbr_start(t[0]);
577 for (i = 0; i < TEST_RCU_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), "report QS");
582 /* Make all the threads offline */
583 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
584 rte_rcu_qsbr_thread_offline(t[0], i);
585 /* Make sure these threads are not being waited on */
586 token = rte_rcu_qsbr_start(t[0]);
587 ret = rte_rcu_qsbr_check(t[0], token, true);
588 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline QS");
590 /* Make the threads online */
591 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
592 rte_rcu_qsbr_thread_online(t[0], i);
593 /* Check if all the online threads can report QS */
594 token = rte_rcu_qsbr_start(t[0]);
595 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
596 rte_rcu_qsbr_quiescent(t[0], i);
597 ret = rte_rcu_qsbr_check(t[0], token, true);
598 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "online again");
604 * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file
607 test_rcu_qsbr_dump(void)
611 printf("\nTest rte_rcu_qsbr_dump()\n");
614 rte_rcu_qsbr_dump(NULL, t[0]);
615 rte_rcu_qsbr_dump(stdout, NULL);
616 rte_rcu_qsbr_dump(NULL, NULL);
618 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
619 rte_rcu_qsbr_init(t[1], TEST_RCU_MAX_LCORE);
621 /* QS variable with 0 core mask */
622 rte_rcu_qsbr_dump(stdout, t[0]);
624 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
626 for (i = 1; i < 3; i++)
627 rte_rcu_qsbr_thread_register(t[1], enabled_core_ids[i]);
629 rte_rcu_qsbr_dump(stdout, t[0]);
630 rte_rcu_qsbr_dump(stdout, t[1]);
636 test_rcu_qsbr_reader(void *arg)
638 struct rte_rcu_qsbr *temp;
639 struct rte_hash *hash = NULL;
641 uint32_t lcore_id = rte_lcore_id();
642 struct test_rcu_thread_info *ti;
645 ti = (struct test_rcu_thread_info *)arg;
650 rte_rcu_qsbr_thread_register(temp, lcore_id);
651 rte_rcu_qsbr_thread_online(temp, lcore_id);
652 for (i = 0; i < TOTAL_ENTRY; i++) {
653 rte_rcu_qsbr_lock(temp, lcore_id);
654 if (rte_hash_lookup_data(hash, keys+i,
655 (void **)&pdata) != -ENOENT) {
657 while (pdata[lcore_id] < COUNTER_VALUE)
660 rte_rcu_qsbr_unlock(temp, lcore_id);
662 /* Update quiescent state counter */
663 rte_rcu_qsbr_quiescent(temp, lcore_id);
664 rte_rcu_qsbr_thread_offline(temp, lcore_id);
665 rte_rcu_qsbr_thread_unregister(temp, lcore_id);
666 } while (!writer_done);
672 test_rcu_qsbr_writer(void *arg)
677 struct rte_rcu_qsbr *temp;
678 struct rte_hash *hash = NULL;
679 struct test_rcu_thread_info *ti;
681 ti = (struct test_rcu_thread_info *)arg;
685 /* Delete element from the shared data structure */
686 del = rte_lcore_id() % TOTAL_ENTRY;
687 pos = rte_hash_del_key(hash, keys + del);
689 printf("Delete key failed #%d\n", keys[del]);
692 /* Start the quiescent state query process */
693 token = rte_rcu_qsbr_start(temp);
694 /* Check the quiescent state status */
695 rte_rcu_qsbr_check(temp, token, true);
696 for (i = 0; i < 2; i++) {
697 c = hash_data[ti->ih][del][ti->r_core_ids[i]];
698 if (c != COUNTER_VALUE && c != 0) {
699 printf("Reader lcore id %u did not complete = %u\t",
705 if (rte_hash_free_key_with_position(hash, pos) < 0) {
706 printf("Failed to free the key #%d\n", keys[del]);
709 rte_free(hash_data[ti->ih][del]);
710 hash_data[ti->ih][del] = NULL;
715 static struct rte_hash *
716 init_hash(int hash_id)
719 struct rte_hash *h = NULL;
721 sprintf(hash_name[hash_id], "hash%d", hash_id);
722 struct rte_hash_parameters hash_params = {
723 .entries = TOTAL_ENTRY,
724 .key_len = sizeof(uint32_t),
725 .hash_func_init_val = 0,
726 .socket_id = rte_socket_id(),
727 .hash_func = rte_hash_crc,
729 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
730 .name = hash_name[hash_id],
733 h = rte_hash_create(&hash_params);
735 printf("Hash create Failed\n");
739 for (i = 0; i < TOTAL_ENTRY; i++) {
740 hash_data[hash_id][i] =
742 sizeof(uint32_t) * TEST_RCU_MAX_LCORE, 0);
743 if (hash_data[hash_id][i] == NULL) {
744 printf("No memory\n");
748 keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);
750 printf("No memory\n");
754 for (i = 0; i < TOTAL_ENTRY; i++)
757 for (i = 0; i < TOTAL_ENTRY; i++) {
758 if (rte_hash_add_key_data(h, keys + i,
759 (void *)((uintptr_t)hash_data[hash_id][i]))
761 printf("Hash key add Failed #%d\n", i);
770 * Single writer, Single QS variable, simultaneous QSBR Queries
773 test_rcu_qsbr_sw_sv_3qs(void)
782 printf("Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\n");
784 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
786 /* Shared data structure created */
789 printf("Hash init failed\n");
793 /* No need to fill the registered core IDs as the writer
794 * thread is not launched.
796 thread_info[0].ir = 0;
797 thread_info[0].ih = 0;
799 /* Reader threads are launched */
800 for (i = 0; i < 4; i++)
801 rte_eal_remote_launch(test_rcu_qsbr_reader, &thread_info[0],
802 enabled_core_ids[i]);
804 /* Delete element from the shared data structure */
805 pos[0] = rte_hash_del_key(h[0], keys + 0);
807 printf("Delete key failed #%d\n", keys[0]);
810 /* Start the quiescent state query process */
811 token[0] = rte_rcu_qsbr_start(t[0]);
813 /* Delete element from the shared data structure */
814 pos[1] = rte_hash_del_key(h[0], keys + 3);
816 printf("Delete key failed #%d\n", keys[3]);
819 /* Start the quiescent state query process */
820 token[1] = rte_rcu_qsbr_start(t[0]);
822 /* Delete element from the shared data structure */
823 pos[2] = rte_hash_del_key(h[0], keys + 6);
825 printf("Delete key failed #%d\n", keys[6]);
828 /* Start the quiescent state query process */
829 token[2] = rte_rcu_qsbr_start(t[0]);
831 /* Check the quiescent state status */
832 rte_rcu_qsbr_check(t[0], token[0], true);
833 for (i = 0; i < 4; i++) {
834 c = hash_data[0][0][enabled_core_ids[i]];
835 if (c != COUNTER_VALUE && c != 0) {
836 printf("Reader lcore %d did not complete #0 = %d\n",
837 enabled_core_ids[i], c);
842 if (rte_hash_free_key_with_position(h[0], pos[0]) < 0) {
843 printf("Failed to free the key #%d\n", keys[0]);
846 rte_free(hash_data[0][0]);
847 hash_data[0][0] = NULL;
849 /* Check the quiescent state status */
850 rte_rcu_qsbr_check(t[0], token[1], true);
851 for (i = 0; i < 4; i++) {
852 c = hash_data[0][3][enabled_core_ids[i]];
853 if (c != COUNTER_VALUE && c != 0) {
854 printf("Reader lcore %d did not complete #3 = %d\n",
855 enabled_core_ids[i], c);
860 if (rte_hash_free_key_with_position(h[0], pos[1]) < 0) {
861 printf("Failed to free the key #%d\n", keys[3]);
864 rte_free(hash_data[0][3]);
865 hash_data[0][3] = NULL;
867 /* Check the quiescent state status */
868 rte_rcu_qsbr_check(t[0], token[2], true);
869 for (i = 0; i < 4; i++) {
870 c = hash_data[0][6][enabled_core_ids[i]];
871 if (c != COUNTER_VALUE && c != 0) {
872 printf("Reader lcore %d did not complete #6 = %d\n",
873 enabled_core_ids[i], c);
878 if (rte_hash_free_key_with_position(h[0], pos[2]) < 0) {
879 printf("Failed to free the key #%d\n", keys[6]);
882 rte_free(hash_data[0][6]);
883 hash_data[0][6] = NULL;
887 /* Wait and check return value from reader threads */
888 for (i = 0; i < 4; i++)
889 if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
898 /* Wait until all readers have exited */
899 rte_eal_mp_wait_lcore();
903 for (i = 0; i < TOTAL_ENTRY; i++)
904 rte_free(hash_data[0][i]);
910 * Multi writer, Multiple QS variable, simultaneous QSBR queries
913 test_rcu_qsbr_mw_mv_mqs(void)
919 test_cores = num_cores / 4;
920 test_cores = test_cores * 4;
922 printf("Test: %d writers, %d QSBR variable, simultaneous QSBR queries\n",
923 test_cores / 2, test_cores / 4);
925 for (i = 0; i < test_cores / 4; i++) {
927 rte_rcu_qsbr_init(t[i], TEST_RCU_MAX_LCORE);
930 printf("Hash init failed\n");
933 thread_info[i].ir = i;
934 thread_info[i].ih = i;
935 thread_info[i].r_core_ids[0] = enabled_core_ids[j];
936 thread_info[i].r_core_ids[1] = enabled_core_ids[j + 1];
938 /* Reader threads are launched */
939 rte_eal_remote_launch(test_rcu_qsbr_reader,
940 (void *)&thread_info[i],
941 enabled_core_ids[j]);
942 rte_eal_remote_launch(test_rcu_qsbr_reader,
943 (void *)&thread_info[i],
944 enabled_core_ids[j + 1]);
946 /* Writer threads are launched */
947 rte_eal_remote_launch(test_rcu_qsbr_writer,
948 (void *)&thread_info[i],
949 enabled_core_ids[j + 2]);
950 rte_eal_remote_launch(test_rcu_qsbr_writer,
951 (void *)&thread_info[i],
952 enabled_core_ids[j + 3]);
955 /* Wait and check return value from writer threads */
956 for (i = 0; i < test_cores / 4; i++) {
958 if (rte_eal_wait_lcore(enabled_core_ids[j + 2]) < 0)
961 if (rte_eal_wait_lcore(enabled_core_ids[j + 3]) < 0)
966 /* Wait and check return value from reader threads */
967 for (i = 0; i < test_cores / 4; i++) {
969 if (rte_eal_wait_lcore(enabled_core_ids[j]) < 0)
972 if (rte_eal_wait_lcore(enabled_core_ids[j + 1]) < 0)
976 for (i = 0; i < test_cores / 4; i++)
985 /* Wait until all readers and writers have exited */
986 rte_eal_mp_wait_lcore();
988 for (i = 0; i < test_cores / 4; i++)
991 for (j = 0; j < test_cores / 4; j++)
992 for (i = 0; i < TOTAL_ENTRY; i++)
993 rte_free(hash_data[j][i]);
999 test_rcu_qsbr_main(void)
1001 if (get_enabled_cores_mask() != 0)
1004 if (num_cores < 4) {
1005 printf("Test failed! Need 4 or more cores\n");
1009 /* Error-checking test cases */
1010 if (test_rcu_qsbr_get_memsize() < 0)
1013 if (test_rcu_qsbr_init() < 0)
1018 if (test_rcu_qsbr_thread_register() < 0)
1021 if (test_rcu_qsbr_thread_unregister() < 0)
1024 if (test_rcu_qsbr_start() < 0)
1027 if (test_rcu_qsbr_check() < 0)
1030 if (test_rcu_qsbr_synchronize() < 0)
1033 if (test_rcu_qsbr_dump() < 0)
1036 if (test_rcu_qsbr_thread_online() < 0)
1039 if (test_rcu_qsbr_thread_offline() < 0)
1042 printf("\nFunctional tests\n");
1044 if (test_rcu_qsbr_sw_sv_3qs() < 0)
1047 if (test_rcu_qsbr_mw_mv_mqs() < 0)
1061 REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main);