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 uint16_t enabled_core_ids[RTE_MAX_LCORE];
30 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 struct rte_hash *h[RTE_MAX_LCORE];
40 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 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};
175 printf("\nTest rte_rcu_qsbr_thread_unregister()\n");
177 ret = rte_rcu_qsbr_thread_unregister(NULL, enabled_core_ids[0]);
178 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
180 ret = rte_rcu_qsbr_thread_unregister(NULL, 100000);
181 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
182 "NULL variable, invalid thread id");
184 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
186 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
188 ret = rte_rcu_qsbr_thread_unregister(t[0], 100000);
189 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
190 "NULL variable, invalid thread id");
192 /* Find first disabled core */
193 for (i = 0; i < RTE_MAX_LCORE; i++) {
194 if (enabled_core_ids[i] == 0)
197 /* Test with disabled lcore */
198 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
199 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
200 "disabled thread id");
201 /* Unregister already unregistered core */
202 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
203 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
204 "Already unregistered core");
206 /* Test with enabled lcore */
207 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
208 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
209 "enabled thread id");
210 /* Unregister already unregistered core */
211 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
212 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
213 "Already unregistered core");
216 * Test with different thread_ids:
218 * 2 - All possible thread_ids, from 0 to RTE_MAX_LCORE
219 * 3 - thread_id = RTE_MAX_LCORE - 1
221 for (j = 0; j < 3; j++) {
222 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
224 for (i = 0; i < num_threads[j]; i++)
225 rte_rcu_qsbr_thread_register(t[0],
226 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
228 token = rte_rcu_qsbr_start(t[0]);
229 TEST_RCU_QSBR_RETURN_IF_ERROR(
230 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
231 /* Update quiescent state counter */
232 for (i = 0; i < num_threads[j]; i++) {
233 /* Skip one update */
234 if (i == (RTE_MAX_LCORE - 10))
236 rte_rcu_qsbr_quiescent(t[0],
237 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
241 /* Validate the updates */
242 ret = rte_rcu_qsbr_check(t[0], token, false);
243 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
244 "Non-blocking QSBR check");
245 /* Update the previously skipped thread */
246 rte_rcu_qsbr_quiescent(t[0], RTE_MAX_LCORE - 10);
249 /* Validate the updates */
250 ret = rte_rcu_qsbr_check(t[0], token, false);
251 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
252 "Non-blocking QSBR check");
254 for (i = 0; i < num_threads[j]; i++)
255 rte_rcu_qsbr_thread_unregister(t[0],
256 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
258 /* Check with no thread registered */
259 ret = rte_rcu_qsbr_check(t[0], token, true);
260 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
261 "Blocking QSBR check");
267 * rte_rcu_qsbr_start: Ask the worker threads to report the quiescent state
271 test_rcu_qsbr_start(void)
276 printf("\nTest rte_rcu_qsbr_start()\n");
278 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
280 for (i = 0; i < 3; i++)
281 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
283 token = rte_rcu_qsbr_start(t[0]);
284 TEST_RCU_QSBR_RETURN_IF_ERROR(
285 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
290 test_rcu_qsbr_check_reader(void *arg)
292 struct rte_rcu_qsbr *temp;
293 uint8_t read_type = (uint8_t)((uintptr_t)arg);
297 /* Update quiescent state counter */
298 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[0]);
299 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[1]);
300 rte_rcu_qsbr_thread_unregister(temp, enabled_core_ids[2]);
301 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[3]);
306 * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis-
307 * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API.
310 test_rcu_qsbr_check(void)
315 printf("\nTest rte_rcu_qsbr_check()\n");
317 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
319 token = rte_rcu_qsbr_start(t[0]);
320 TEST_RCU_QSBR_RETURN_IF_ERROR(
321 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
324 ret = rte_rcu_qsbr_check(t[0], 0, false);
325 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Token = 0");
327 ret = rte_rcu_qsbr_check(t[0], token, true);
328 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
330 for (i = 0; i < 3; i++)
331 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
333 ret = rte_rcu_qsbr_check(t[0], token, false);
334 /* Threads are offline, hence this should pass */
335 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
337 token = rte_rcu_qsbr_start(t[0]);
338 TEST_RCU_QSBR_RETURN_IF_ERROR(
339 (token != (TEST_RCU_QSBR_CNT_INIT + 2)), "QSBR Start");
341 ret = rte_rcu_qsbr_check(t[0], token, false);
342 /* Threads are offline, hence this should pass */
343 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
345 for (i = 0; i < 3; i++)
346 rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[i]);
348 ret = rte_rcu_qsbr_check(t[0], token, true);
349 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
351 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
353 for (i = 0; i < 4; i++)
354 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
356 token = rte_rcu_qsbr_start(t[0]);
357 TEST_RCU_QSBR_RETURN_IF_ERROR(
358 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
360 rte_eal_remote_launch(test_rcu_qsbr_check_reader, NULL,
361 enabled_core_ids[0]);
363 rte_eal_mp_wait_lcore();
364 ret = rte_rcu_qsbr_check(t[0], token, true);
365 TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "Blocking QSBR check");
371 test_rcu_qsbr_synchronize_reader(void *arg)
373 uint32_t lcore_id = rte_lcore_id();
376 /* Register and become online */
377 rte_rcu_qsbr_thread_register(t[0], lcore_id);
378 rte_rcu_qsbr_thread_online(t[0], lcore_id);
381 rte_rcu_qsbr_quiescent(t[0], lcore_id);
383 rte_rcu_qsbr_thread_offline(t[0], lcore_id);
384 rte_rcu_qsbr_thread_unregister(t[0], lcore_id);
390 * rte_rcu_qsbr_synchronize: Wait till all the reader threads have entered
391 * the queiscent state.
394 test_rcu_qsbr_synchronize(void)
398 printf("\nTest rte_rcu_qsbr_synchronize()\n");
400 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
402 /* Test if the API returns when there are no threads reporting
403 * QS on the variable.
405 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
407 /* Test if the API returns when there are threads registered
410 for (i = 0; i < RTE_MAX_LCORE; i++)
411 rte_rcu_qsbr_thread_register(t[0], i);
412 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
414 /* Test if the API returns when the caller is also
415 * reporting the QS status.
417 rte_rcu_qsbr_thread_online(t[0], 0);
418 rte_rcu_qsbr_synchronize(t[0], 0);
419 rte_rcu_qsbr_thread_offline(t[0], 0);
421 /* Check the other boundary */
422 rte_rcu_qsbr_thread_online(t[0], RTE_MAX_LCORE - 1);
423 rte_rcu_qsbr_synchronize(t[0], RTE_MAX_LCORE - 1);
424 rte_rcu_qsbr_thread_offline(t[0], RTE_MAX_LCORE - 1);
426 /* Test if the API returns after unregisterng all the threads */
427 for (i = 0; i < RTE_MAX_LCORE; i++)
428 rte_rcu_qsbr_thread_unregister(t[0], i);
429 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
431 /* Test if the API returns with the live threads */
433 for (i = 0; i < num_cores; i++)
434 rte_eal_remote_launch(test_rcu_qsbr_synchronize_reader,
435 NULL, enabled_core_ids[i]);
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);
440 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
443 rte_eal_mp_wait_lcore();
449 * rte_rcu_qsbr_thread_online: Add a registered reader thread, to
450 * the list of threads reporting their quiescent state on a QS variable.
453 test_rcu_qsbr_thread_online(void)
458 printf("Test rte_rcu_qsbr_thread_online()\n");
460 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
462 /* Register 2 threads to validate that only the
463 * online thread is waited upon.
465 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
466 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[1]);
468 /* Use qsbr_start to verify that the thread_online API
471 token = rte_rcu_qsbr_start(t[0]);
473 /* Make the thread online */
474 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
476 /* Check if the thread is online */
477 ret = rte_rcu_qsbr_check(t[0], token, true);
478 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
480 /* Check if the online thread, can report QS */
481 token = rte_rcu_qsbr_start(t[0]);
482 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
483 ret = rte_rcu_qsbr_check(t[0], token, true);
484 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
486 /* Make all the threads online */
487 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
488 token = rte_rcu_qsbr_start(t[0]);
489 for (i = 0; i < RTE_MAX_LCORE; i++) {
490 rte_rcu_qsbr_thread_register(t[0], i);
491 rte_rcu_qsbr_thread_online(t[0], i);
493 /* Check if all the threads are online */
494 ret = rte_rcu_qsbr_check(t[0], token, true);
495 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
496 /* Check if all the online threads can report QS */
497 token = rte_rcu_qsbr_start(t[0]);
498 for (i = 0; i < RTE_MAX_LCORE; i++)
499 rte_rcu_qsbr_quiescent(t[0], i);
500 ret = rte_rcu_qsbr_check(t[0], token, true);
501 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
507 * rte_rcu_qsbr_thread_offline: Remove a registered reader thread, from
508 * the list of threads reporting their quiescent state on a QS variable.
511 test_rcu_qsbr_thread_offline(void)
516 printf("\nTest rte_rcu_qsbr_thread_offline()\n");
518 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
520 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
522 /* Make the thread offline */
523 rte_rcu_qsbr_thread_offline(t[0], enabled_core_ids[0]);
525 /* Use qsbr_start to verify that the thread_offline API
528 token = rte_rcu_qsbr_start(t[0]);
529 /* Check if the thread is offline */
530 ret = rte_rcu_qsbr_check(t[0], token, true);
531 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread offline");
533 /* Bring an offline thread online and check if it can
536 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
537 /* Check if the online thread, can report QS */
538 token = rte_rcu_qsbr_start(t[0]);
539 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
540 ret = rte_rcu_qsbr_check(t[0], token, true);
541 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline to online");
544 * Check a sequence of online/status/offline/status/online/status
546 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
547 token = rte_rcu_qsbr_start(t[0]);
548 /* Make the threads online */
549 for (i = 0; i < RTE_MAX_LCORE; i++) {
550 rte_rcu_qsbr_thread_register(t[0], i);
551 rte_rcu_qsbr_thread_online(t[0], i);
554 /* Check if all the threads are online */
555 ret = rte_rcu_qsbr_check(t[0], token, true);
556 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
558 /* Check if all the online threads can report QS */
559 token = rte_rcu_qsbr_start(t[0]);
560 for (i = 0; i < RTE_MAX_LCORE; i++)
561 rte_rcu_qsbr_quiescent(t[0], i);
562 ret = rte_rcu_qsbr_check(t[0], token, true);
563 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "report QS");
565 /* Make all the threads offline */
566 for (i = 0; i < RTE_MAX_LCORE; i++)
567 rte_rcu_qsbr_thread_offline(t[0], i);
568 /* Make sure these threads are not being waited on */
569 token = rte_rcu_qsbr_start(t[0]);
570 ret = rte_rcu_qsbr_check(t[0], token, true);
571 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline QS");
573 /* Make the threads online */
574 for (i = 0; i < RTE_MAX_LCORE; i++)
575 rte_rcu_qsbr_thread_online(t[0], i);
576 /* Check if all the online threads can report QS */
577 token = rte_rcu_qsbr_start(t[0]);
578 for (i = 0; i < RTE_MAX_LCORE; i++)
579 rte_rcu_qsbr_quiescent(t[0], i);
580 ret = rte_rcu_qsbr_check(t[0], token, true);
581 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "online again");
587 * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file
590 test_rcu_qsbr_dump(void)
594 printf("\nTest rte_rcu_qsbr_dump()\n");
597 rte_rcu_qsbr_dump(NULL, t[0]);
598 rte_rcu_qsbr_dump(stdout, NULL);
599 rte_rcu_qsbr_dump(NULL, NULL);
601 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
602 rte_rcu_qsbr_init(t[1], RTE_MAX_LCORE);
604 /* QS variable with 0 core mask */
605 rte_rcu_qsbr_dump(stdout, t[0]);
607 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
609 for (i = 1; i < 3; i++)
610 rte_rcu_qsbr_thread_register(t[1], enabled_core_ids[i]);
612 rte_rcu_qsbr_dump(stdout, t[0]);
613 rte_rcu_qsbr_dump(stdout, t[1]);
619 test_rcu_qsbr_reader(void *arg)
621 struct rte_rcu_qsbr *temp;
622 struct rte_hash *hash = NULL;
624 uint32_t lcore_id = rte_lcore_id();
625 struct test_rcu_thread_info *ti;
628 ti = (struct test_rcu_thread_info *)arg;
633 rte_rcu_qsbr_thread_register(temp, lcore_id);
634 rte_rcu_qsbr_thread_online(temp, lcore_id);
635 for (i = 0; i < TOTAL_ENTRY; i++) {
636 rte_rcu_qsbr_lock(temp, lcore_id);
637 if (rte_hash_lookup_data(hash, keys+i,
638 (void **)&pdata) != -ENOENT) {
640 while (pdata[lcore_id] < COUNTER_VALUE)
643 rte_rcu_qsbr_unlock(temp, lcore_id);
645 /* Update quiescent state counter */
646 rte_rcu_qsbr_quiescent(temp, lcore_id);
647 rte_rcu_qsbr_thread_offline(temp, lcore_id);
648 rte_rcu_qsbr_thread_unregister(temp, lcore_id);
649 } while (!writer_done);
655 test_rcu_qsbr_writer(void *arg)
660 struct rte_rcu_qsbr *temp;
661 struct rte_hash *hash = NULL;
662 struct test_rcu_thread_info *ti;
664 ti = (struct test_rcu_thread_info *)arg;
668 /* Delete element from the shared data structure */
669 del = rte_lcore_id() % TOTAL_ENTRY;
670 pos = rte_hash_del_key(hash, keys + del);
672 printf("Delete key failed #%d\n", keys[del]);
675 /* Start the quiescent state query process */
676 token = rte_rcu_qsbr_start(temp);
677 /* Check the quiescent state status */
678 rte_rcu_qsbr_check(temp, token, true);
679 for (i = 0; i < 2; i++) {
680 c = hash_data[ti->ih][del][ti->r_core_ids[i]];
681 if (c != COUNTER_VALUE && c != 0) {
682 printf("Reader lcore id %u did not complete = %u\t",
688 if (rte_hash_free_key_with_position(hash, pos) < 0) {
689 printf("Failed to free the key #%d\n", keys[del]);
692 rte_free(hash_data[ti->ih][del]);
693 hash_data[ti->ih][del] = NULL;
698 static struct rte_hash *
699 init_hash(int hash_id)
702 struct rte_hash *h = NULL;
704 sprintf(hash_name[hash_id], "hash%d", hash_id);
705 struct rte_hash_parameters hash_params = {
706 .entries = TOTAL_ENTRY,
707 .key_len = sizeof(uint32_t),
708 .hash_func_init_val = 0,
709 .socket_id = rte_socket_id(),
710 .hash_func = rte_hash_crc,
712 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
713 .name = hash_name[hash_id],
716 h = rte_hash_create(&hash_params);
718 printf("Hash create Failed\n");
722 for (i = 0; i < TOTAL_ENTRY; i++) {
723 hash_data[hash_id][i] =
724 rte_zmalloc(NULL, sizeof(uint32_t) * RTE_MAX_LCORE, 0);
725 if (hash_data[hash_id][i] == NULL) {
726 printf("No memory\n");
730 keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);
732 printf("No memory\n");
736 for (i = 0; i < TOTAL_ENTRY; i++)
739 for (i = 0; i < TOTAL_ENTRY; i++) {
740 if (rte_hash_add_key_data(h, keys + i,
741 (void *)((uintptr_t)hash_data[hash_id][i]))
743 printf("Hash key add Failed #%d\n", i);
752 * Single writer, Single QS variable, simultaneous QSBR Queries
755 test_rcu_qsbr_sw_sv_3qs(void)
764 printf("Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\n");
766 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
768 /* Shared data structure created */
771 printf("Hash init failed\n");
775 /* No need to fill the registered core IDs as the writer
776 * thread is not launched.
778 thread_info[0].ir = 0;
779 thread_info[0].ih = 0;
781 /* Reader threads are launched */
782 for (i = 0; i < 4; i++)
783 rte_eal_remote_launch(test_rcu_qsbr_reader, &thread_info[0],
784 enabled_core_ids[i]);
786 /* Delete element from the shared data structure */
787 pos[0] = rte_hash_del_key(h[0], keys + 0);
789 printf("Delete key failed #%d\n", keys[0]);
792 /* Start the quiescent state query process */
793 token[0] = rte_rcu_qsbr_start(t[0]);
795 /* Delete element from the shared data structure */
796 pos[1] = rte_hash_del_key(h[0], keys + 3);
798 printf("Delete key failed #%d\n", keys[3]);
801 /* Start the quiescent state query process */
802 token[1] = rte_rcu_qsbr_start(t[0]);
804 /* Delete element from the shared data structure */
805 pos[2] = rte_hash_del_key(h[0], keys + 6);
807 printf("Delete key failed #%d\n", keys[6]);
810 /* Start the quiescent state query process */
811 token[2] = rte_rcu_qsbr_start(t[0]);
813 /* Check the quiescent state status */
814 rte_rcu_qsbr_check(t[0], token[0], true);
815 for (i = 0; i < 4; i++) {
816 c = hash_data[0][0][enabled_core_ids[i]];
817 if (c != COUNTER_VALUE && c != 0) {
818 printf("Reader lcore %d did not complete #0 = %d\n",
819 enabled_core_ids[i], c);
824 if (rte_hash_free_key_with_position(h[0], pos[0]) < 0) {
825 printf("Failed to free the key #%d\n", keys[0]);
828 rte_free(hash_data[0][0]);
829 hash_data[0][0] = NULL;
831 /* Check the quiescent state status */
832 rte_rcu_qsbr_check(t[0], token[1], true);
833 for (i = 0; i < 4; i++) {
834 c = hash_data[0][3][enabled_core_ids[i]];
835 if (c != COUNTER_VALUE && c != 0) {
836 printf("Reader lcore %d did not complete #3 = %d\n",
837 enabled_core_ids[i], c);
842 if (rte_hash_free_key_with_position(h[0], pos[1]) < 0) {
843 printf("Failed to free the key #%d\n", keys[3]);
846 rte_free(hash_data[0][3]);
847 hash_data[0][3] = NULL;
849 /* Check the quiescent state status */
850 rte_rcu_qsbr_check(t[0], token[2], true);
851 for (i = 0; i < 4; i++) {
852 c = hash_data[0][6][enabled_core_ids[i]];
853 if (c != COUNTER_VALUE && c != 0) {
854 printf("Reader lcore %d did not complete #6 = %d\n",
855 enabled_core_ids[i], c);
860 if (rte_hash_free_key_with_position(h[0], pos[2]) < 0) {
861 printf("Failed to free the key #%d\n", keys[6]);
864 rte_free(hash_data[0][6]);
865 hash_data[0][6] = NULL;
869 /* Wait and check return value from reader threads */
870 for (i = 0; i < 4; i++)
871 if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
880 /* Wait until all readers have exited */
881 rte_eal_mp_wait_lcore();
885 for (i = 0; i < TOTAL_ENTRY; i++)
886 rte_free(hash_data[0][i]);
892 * Multi writer, Multiple QS variable, simultaneous QSBR queries
895 test_rcu_qsbr_mw_mv_mqs(void)
898 unsigned int test_cores;
901 test_cores = num_cores / 4;
902 test_cores = test_cores * 4;
904 printf("Test: %d writers, %d QSBR variable, simultaneous QSBR queries\n",
905 test_cores / 2, test_cores / 4);
907 for (i = 0; i < test_cores / 4; i++) {
909 rte_rcu_qsbr_init(t[i], RTE_MAX_LCORE);
912 printf("Hash init failed\n");
915 thread_info[i].ir = i;
916 thread_info[i].ih = i;
917 thread_info[i].r_core_ids[0] = enabled_core_ids[j];
918 thread_info[i].r_core_ids[1] = enabled_core_ids[j + 1];
920 /* Reader threads are launched */
921 rte_eal_remote_launch(test_rcu_qsbr_reader,
922 (void *)&thread_info[i],
923 enabled_core_ids[j]);
924 rte_eal_remote_launch(test_rcu_qsbr_reader,
925 (void *)&thread_info[i],
926 enabled_core_ids[j + 1]);
928 /* Writer threads are launched */
929 rte_eal_remote_launch(test_rcu_qsbr_writer,
930 (void *)&thread_info[i],
931 enabled_core_ids[j + 2]);
932 rte_eal_remote_launch(test_rcu_qsbr_writer,
933 (void *)&thread_info[i],
934 enabled_core_ids[j + 3]);
937 /* Wait and check return value from writer threads */
938 for (i = 0; i < test_cores / 4; i++) {
940 if (rte_eal_wait_lcore(enabled_core_ids[j + 2]) < 0)
943 if (rte_eal_wait_lcore(enabled_core_ids[j + 3]) < 0)
948 /* Wait and check return value from reader threads */
949 for (i = 0; i < test_cores / 4; i++) {
951 if (rte_eal_wait_lcore(enabled_core_ids[j]) < 0)
954 if (rte_eal_wait_lcore(enabled_core_ids[j + 1]) < 0)
958 for (i = 0; i < test_cores / 4; i++)
967 /* Wait until all readers and writers have exited */
968 rte_eal_mp_wait_lcore();
970 for (i = 0; i < test_cores / 4; i++)
973 for (j = 0; j < test_cores / 4; j++)
974 for (i = 0; i < TOTAL_ENTRY; i++)
975 rte_free(hash_data[j][i]);
981 test_rcu_qsbr_main(void)
985 if (rte_lcore_count() < 5) {
986 printf("Not enough cores for rcu_qsbr_autotest, expecting at least 5\n");
991 RTE_LCORE_FOREACH_SLAVE(core_id) {
992 enabled_core_ids[num_cores] = core_id;
996 /* Error-checking test cases */
997 if (test_rcu_qsbr_get_memsize() < 0)
1000 if (test_rcu_qsbr_init() < 0)
1005 if (test_rcu_qsbr_thread_register() < 0)
1008 if (test_rcu_qsbr_thread_unregister() < 0)
1011 if (test_rcu_qsbr_start() < 0)
1014 if (test_rcu_qsbr_check() < 0)
1017 if (test_rcu_qsbr_synchronize() < 0)
1020 if (test_rcu_qsbr_dump() < 0)
1023 if (test_rcu_qsbr_thread_online() < 0)
1026 if (test_rcu_qsbr_thread_offline() < 0)
1029 printf("\nFunctional tests\n");
1031 if (test_rcu_qsbr_sw_sv_3qs() < 0)
1034 if (test_rcu_qsbr_mw_mv_mqs() < 0)
1048 REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main);