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(RTE_MAX_LCORE);
94 * for machines with cache line size of 64B - 8384
95 * for machines with cache line size of 128 - 16768
97 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 8384 && sz != 16768),
104 * rte_rcu_qsbr_init: Initialize a QSBR variable.
107 test_rcu_qsbr_init(void)
111 printf("\nTest rte_rcu_qsbr_init()\n");
113 r = rte_rcu_qsbr_init(NULL, RTE_MAX_LCORE);
114 TEST_RCU_QSBR_RETURN_IF_ERROR((r != 1), "NULL variable");
120 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
121 * reporting their quiescent state on a QS variable.
124 test_rcu_qsbr_thread_register(void)
128 printf("\nTest rte_rcu_qsbr_thread_register()\n");
130 ret = rte_rcu_qsbr_thread_register(NULL, enabled_core_ids[0]);
131 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
133 ret = rte_rcu_qsbr_thread_register(NULL, 100000);
134 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
135 "NULL variable, invalid thread id");
137 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
139 /* Register valid thread id */
140 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
141 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Valid thread id");
143 /* Re-registering should not return error */
144 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
145 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
146 "Already registered thread id");
148 /* Register valid thread id - max allowed thread id */
149 ret = rte_rcu_qsbr_thread_register(t[0], RTE_MAX_LCORE - 1);
150 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Max thread id");
152 ret = rte_rcu_qsbr_thread_register(t[0], 100000);
153 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
154 "NULL variable, invalid thread id");
160 * rte_rcu_qsbr_thread_unregister: Remove a reader thread, from the list of
161 * threads reporting their quiescent state on a QS variable.
164 test_rcu_qsbr_thread_unregister(void)
166 unsigned int num_threads[3] = {1, RTE_MAX_LCORE, 1};
171 printf("\nTest rte_rcu_qsbr_thread_unregister()\n");
173 ret = rte_rcu_qsbr_thread_unregister(NULL, enabled_core_ids[0]);
174 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
176 ret = rte_rcu_qsbr_thread_unregister(NULL, 100000);
177 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
178 "NULL variable, invalid thread id");
180 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
182 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
184 ret = rte_rcu_qsbr_thread_unregister(t[0], 100000);
185 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
186 "NULL variable, invalid thread id");
188 /* Find first disabled core */
189 for (i = 0; i < RTE_MAX_LCORE; i++) {
190 if (enabled_core_ids[i] == 0)
193 /* Test with disabled lcore */
194 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
195 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
196 "disabled thread id");
197 /* Unregister already unregistered core */
198 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
199 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
200 "Already unregistered core");
202 /* Test with enabled lcore */
203 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
204 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
205 "enabled thread id");
206 /* Unregister already unregistered core */
207 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
208 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
209 "Already unregistered core");
212 * Test with different thread_ids:
214 * 2 - All possible thread_ids, from 0 to RTE_MAX_LCORE
215 * 3 - thread_id = RTE_MAX_LCORE - 1
217 for (j = 0; j < 3; j++) {
218 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
220 for (i = 0; i < num_threads[j]; i++)
221 rte_rcu_qsbr_thread_register(t[0],
222 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
224 token = rte_rcu_qsbr_start(t[0]);
225 TEST_RCU_QSBR_RETURN_IF_ERROR(
226 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
227 /* Update quiescent state counter */
228 for (i = 0; i < num_threads[j]; i++) {
229 /* Skip one update */
230 if (i == (RTE_MAX_LCORE - 10))
232 rte_rcu_qsbr_quiescent(t[0],
233 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
237 /* Validate the updates */
238 ret = rte_rcu_qsbr_check(t[0], token, false);
239 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
240 "Non-blocking QSBR check");
241 /* Update the previously skipped thread */
242 rte_rcu_qsbr_quiescent(t[0], RTE_MAX_LCORE - 10);
245 /* Validate the updates */
246 ret = rte_rcu_qsbr_check(t[0], token, false);
247 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
248 "Non-blocking QSBR check");
250 for (i = 0; i < num_threads[j]; i++)
251 rte_rcu_qsbr_thread_unregister(t[0],
252 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
254 /* Check with no thread registered */
255 ret = rte_rcu_qsbr_check(t[0], token, true);
256 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
257 "Blocking QSBR check");
263 * rte_rcu_qsbr_start: Ask the worker threads to report the quiescent state
267 test_rcu_qsbr_start(void)
272 printf("\nTest rte_rcu_qsbr_start()\n");
274 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
276 for (i = 0; i < 3; i++)
277 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
279 token = rte_rcu_qsbr_start(t[0]);
280 TEST_RCU_QSBR_RETURN_IF_ERROR(
281 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
286 test_rcu_qsbr_check_reader(void *arg)
288 struct rte_rcu_qsbr *temp;
289 uint8_t read_type = (uint8_t)((uintptr_t)arg);
293 /* Update quiescent state counter */
294 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[0]);
295 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[1]);
296 rte_rcu_qsbr_thread_unregister(temp, enabled_core_ids[2]);
297 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[3]);
302 * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis-
303 * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API.
306 test_rcu_qsbr_check(void)
311 printf("\nTest rte_rcu_qsbr_check()\n");
313 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
315 token = rte_rcu_qsbr_start(t[0]);
316 TEST_RCU_QSBR_RETURN_IF_ERROR(
317 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
320 ret = rte_rcu_qsbr_check(t[0], 0, false);
321 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Token = 0");
323 ret = rte_rcu_qsbr_check(t[0], token, true);
324 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
326 for (i = 0; i < 3; i++)
327 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
329 ret = rte_rcu_qsbr_check(t[0], token, false);
330 /* Threads are offline, hence this should pass */
331 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
333 token = rte_rcu_qsbr_start(t[0]);
334 TEST_RCU_QSBR_RETURN_IF_ERROR(
335 (token != (TEST_RCU_QSBR_CNT_INIT + 2)), "QSBR Start");
337 ret = rte_rcu_qsbr_check(t[0], token, false);
338 /* Threads are offline, hence this should pass */
339 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
341 for (i = 0; i < 3; i++)
342 rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[i]);
344 ret = rte_rcu_qsbr_check(t[0], token, true);
345 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
347 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
349 for (i = 0; i < 4; i++)
350 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
352 token = rte_rcu_qsbr_start(t[0]);
353 TEST_RCU_QSBR_RETURN_IF_ERROR(
354 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
356 rte_eal_remote_launch(test_rcu_qsbr_check_reader, NULL,
357 enabled_core_ids[0]);
359 rte_eal_mp_wait_lcore();
360 ret = rte_rcu_qsbr_check(t[0], token, true);
361 TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "Blocking QSBR check");
367 test_rcu_qsbr_synchronize_reader(void *arg)
369 uint32_t lcore_id = rte_lcore_id();
372 /* Register and become online */
373 rte_rcu_qsbr_thread_register(t[0], lcore_id);
374 rte_rcu_qsbr_thread_online(t[0], lcore_id);
377 rte_rcu_qsbr_quiescent(t[0], lcore_id);
379 rte_rcu_qsbr_thread_offline(t[0], lcore_id);
380 rte_rcu_qsbr_thread_unregister(t[0], lcore_id);
386 * rte_rcu_qsbr_synchronize: Wait till all the reader threads have entered
387 * the queiscent state.
390 test_rcu_qsbr_synchronize(void)
394 printf("\nTest rte_rcu_qsbr_synchronize()\n");
396 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
398 /* Test if the API returns when there are no threads reporting
399 * QS on the variable.
401 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
403 /* Test if the API returns when there are threads registered
406 for (i = 0; i < RTE_MAX_LCORE; i++)
407 rte_rcu_qsbr_thread_register(t[0], i);
408 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
410 /* Test if the API returns when the caller is also
411 * reporting the QS status.
413 rte_rcu_qsbr_thread_online(t[0], 0);
414 rte_rcu_qsbr_synchronize(t[0], 0);
415 rte_rcu_qsbr_thread_offline(t[0], 0);
417 /* Check the other boundary */
418 rte_rcu_qsbr_thread_online(t[0], RTE_MAX_LCORE - 1);
419 rte_rcu_qsbr_synchronize(t[0], RTE_MAX_LCORE - 1);
420 rte_rcu_qsbr_thread_offline(t[0], RTE_MAX_LCORE - 1);
422 /* Test if the API returns after unregisterng all the threads */
423 for (i = 0; i < RTE_MAX_LCORE; i++)
424 rte_rcu_qsbr_thread_unregister(t[0], i);
425 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
427 /* Test if the API returns with the live threads */
429 for (i = 0; i < num_cores; i++)
430 rte_eal_remote_launch(test_rcu_qsbr_synchronize_reader,
431 NULL, enabled_core_ids[i]);
432 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
433 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
434 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
435 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
436 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
439 rte_eal_mp_wait_lcore();
445 * rte_rcu_qsbr_thread_online: Add a registered reader thread, to
446 * the list of threads reporting their quiescent state on a QS variable.
449 test_rcu_qsbr_thread_online(void)
454 printf("Test rte_rcu_qsbr_thread_online()\n");
456 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
458 /* Register 2 threads to validate that only the
459 * online thread is waited upon.
461 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
462 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[1]);
464 /* Use qsbr_start to verify that the thread_online API
467 token = rte_rcu_qsbr_start(t[0]);
469 /* Make the thread online */
470 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
472 /* Check if the thread is online */
473 ret = rte_rcu_qsbr_check(t[0], token, true);
474 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
476 /* Check if the online thread, can report QS */
477 token = rte_rcu_qsbr_start(t[0]);
478 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
479 ret = rte_rcu_qsbr_check(t[0], token, true);
480 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
482 /* Make all the threads online */
483 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
484 token = rte_rcu_qsbr_start(t[0]);
485 for (i = 0; i < RTE_MAX_LCORE; i++) {
486 rte_rcu_qsbr_thread_register(t[0], i);
487 rte_rcu_qsbr_thread_online(t[0], i);
489 /* Check if all the threads are online */
490 ret = rte_rcu_qsbr_check(t[0], token, true);
491 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
492 /* Check if all the online threads can report QS */
493 token = rte_rcu_qsbr_start(t[0]);
494 for (i = 0; i < RTE_MAX_LCORE; i++)
495 rte_rcu_qsbr_quiescent(t[0], i);
496 ret = rte_rcu_qsbr_check(t[0], token, true);
497 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
503 * rte_rcu_qsbr_thread_offline: Remove a registered reader thread, from
504 * the list of threads reporting their quiescent state on a QS variable.
507 test_rcu_qsbr_thread_offline(void)
512 printf("\nTest rte_rcu_qsbr_thread_offline()\n");
514 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
516 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
518 /* Make the thread offline */
519 rte_rcu_qsbr_thread_offline(t[0], enabled_core_ids[0]);
521 /* Use qsbr_start to verify that the thread_offline API
524 token = rte_rcu_qsbr_start(t[0]);
525 /* Check if the thread is offline */
526 ret = rte_rcu_qsbr_check(t[0], token, true);
527 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread offline");
529 /* Bring an offline thread online and check if it can
532 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
533 /* Check if the online thread, can report QS */
534 token = rte_rcu_qsbr_start(t[0]);
535 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
536 ret = rte_rcu_qsbr_check(t[0], token, true);
537 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline to online");
540 * Check a sequence of online/status/offline/status/online/status
542 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
543 token = rte_rcu_qsbr_start(t[0]);
544 /* Make the threads online */
545 for (i = 0; i < RTE_MAX_LCORE; i++) {
546 rte_rcu_qsbr_thread_register(t[0], i);
547 rte_rcu_qsbr_thread_online(t[0], i);
550 /* Check if all the threads are online */
551 ret = rte_rcu_qsbr_check(t[0], token, true);
552 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
554 /* Check if all the online threads can report QS */
555 token = rte_rcu_qsbr_start(t[0]);
556 for (i = 0; i < RTE_MAX_LCORE; i++)
557 rte_rcu_qsbr_quiescent(t[0], i);
558 ret = rte_rcu_qsbr_check(t[0], token, true);
559 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "report QS");
561 /* Make all the threads offline */
562 for (i = 0; i < RTE_MAX_LCORE; i++)
563 rte_rcu_qsbr_thread_offline(t[0], i);
564 /* Make sure these threads are not being waited on */
565 token = rte_rcu_qsbr_start(t[0]);
566 ret = rte_rcu_qsbr_check(t[0], token, true);
567 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline QS");
569 /* Make the threads online */
570 for (i = 0; i < RTE_MAX_LCORE; i++)
571 rte_rcu_qsbr_thread_online(t[0], i);
572 /* Check if all the online threads can report QS */
573 token = rte_rcu_qsbr_start(t[0]);
574 for (i = 0; i < RTE_MAX_LCORE; i++)
575 rte_rcu_qsbr_quiescent(t[0], i);
576 ret = rte_rcu_qsbr_check(t[0], token, true);
577 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "online again");
583 * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file
586 test_rcu_qsbr_dump(void)
590 printf("\nTest rte_rcu_qsbr_dump()\n");
593 rte_rcu_qsbr_dump(NULL, t[0]);
594 rte_rcu_qsbr_dump(stdout, NULL);
595 rte_rcu_qsbr_dump(NULL, NULL);
597 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
598 rte_rcu_qsbr_init(t[1], RTE_MAX_LCORE);
600 /* QS variable with 0 core mask */
601 rte_rcu_qsbr_dump(stdout, t[0]);
603 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
605 for (i = 1; i < 3; i++)
606 rte_rcu_qsbr_thread_register(t[1], enabled_core_ids[i]);
608 rte_rcu_qsbr_dump(stdout, t[0]);
609 rte_rcu_qsbr_dump(stdout, t[1]);
615 test_rcu_qsbr_reader(void *arg)
617 struct rte_rcu_qsbr *temp;
618 struct rte_hash *hash = NULL;
620 uint32_t lcore_id = rte_lcore_id();
621 struct test_rcu_thread_info *ti;
624 ti = (struct test_rcu_thread_info *)arg;
629 rte_rcu_qsbr_thread_register(temp, lcore_id);
630 rte_rcu_qsbr_thread_online(temp, lcore_id);
631 for (i = 0; i < TOTAL_ENTRY; i++) {
632 rte_rcu_qsbr_lock(temp, lcore_id);
633 if (rte_hash_lookup_data(hash, keys+i,
634 (void **)&pdata) != -ENOENT) {
636 while (pdata[lcore_id] < COUNTER_VALUE)
639 rte_rcu_qsbr_unlock(temp, lcore_id);
641 /* Update quiescent state counter */
642 rte_rcu_qsbr_quiescent(temp, lcore_id);
643 rte_rcu_qsbr_thread_offline(temp, lcore_id);
644 rte_rcu_qsbr_thread_unregister(temp, lcore_id);
645 } while (!writer_done);
651 test_rcu_qsbr_writer(void *arg)
656 struct rte_rcu_qsbr *temp;
657 struct rte_hash *hash = NULL;
658 struct test_rcu_thread_info *ti;
660 ti = (struct test_rcu_thread_info *)arg;
664 /* Delete element from the shared data structure */
665 del = rte_lcore_id() % TOTAL_ENTRY;
666 pos = rte_hash_del_key(hash, keys + del);
668 printf("Delete key failed #%d\n", keys[del]);
671 /* Start the quiescent state query process */
672 token = rte_rcu_qsbr_start(temp);
673 /* Check the quiescent state status */
674 rte_rcu_qsbr_check(temp, token, true);
675 for (i = 0; i < 2; i++) {
676 c = hash_data[ti->ih][del][ti->r_core_ids[i]];
677 if (c != COUNTER_VALUE && c != 0) {
678 printf("Reader lcore id %u did not complete = %u\t",
684 if (rte_hash_free_key_with_position(hash, pos) < 0) {
685 printf("Failed to free the key #%d\n", keys[del]);
688 rte_free(hash_data[ti->ih][del]);
689 hash_data[ti->ih][del] = NULL;
694 static struct rte_hash *
695 init_hash(int hash_id)
698 struct rte_hash *h = NULL;
700 sprintf(hash_name[hash_id], "hash%d", hash_id);
701 struct rte_hash_parameters hash_params = {
702 .entries = TOTAL_ENTRY,
703 .key_len = sizeof(uint32_t),
704 .hash_func_init_val = 0,
705 .socket_id = rte_socket_id(),
706 .hash_func = rte_hash_crc,
708 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
709 .name = hash_name[hash_id],
712 h = rte_hash_create(&hash_params);
714 printf("Hash create Failed\n");
718 for (i = 0; i < TOTAL_ENTRY; i++) {
719 hash_data[hash_id][i] =
720 rte_zmalloc(NULL, sizeof(uint32_t) * RTE_MAX_LCORE, 0);
721 if (hash_data[hash_id][i] == NULL) {
722 printf("No memory\n");
726 keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);
728 printf("No memory\n");
732 for (i = 0; i < TOTAL_ENTRY; i++)
735 for (i = 0; i < TOTAL_ENTRY; i++) {
736 if (rte_hash_add_key_data(h, keys + i,
737 (void *)((uintptr_t)hash_data[hash_id][i]))
739 printf("Hash key add Failed #%d\n", i);
748 * Single writer, Single QS variable, simultaneous QSBR Queries
751 test_rcu_qsbr_sw_sv_3qs(void)
760 printf("Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\n");
762 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
764 /* Shared data structure created */
767 printf("Hash init failed\n");
771 /* No need to fill the registered core IDs as the writer
772 * thread is not launched.
774 thread_info[0].ir = 0;
775 thread_info[0].ih = 0;
777 /* Reader threads are launched */
778 for (i = 0; i < 4; i++)
779 rte_eal_remote_launch(test_rcu_qsbr_reader, &thread_info[0],
780 enabled_core_ids[i]);
782 /* Delete element from the shared data structure */
783 pos[0] = rte_hash_del_key(h[0], keys + 0);
785 printf("Delete key failed #%d\n", keys[0]);
788 /* Start the quiescent state query process */
789 token[0] = rte_rcu_qsbr_start(t[0]);
791 /* Delete element from the shared data structure */
792 pos[1] = rte_hash_del_key(h[0], keys + 3);
794 printf("Delete key failed #%d\n", keys[3]);
797 /* Start the quiescent state query process */
798 token[1] = rte_rcu_qsbr_start(t[0]);
800 /* Delete element from the shared data structure */
801 pos[2] = rte_hash_del_key(h[0], keys + 6);
803 printf("Delete key failed #%d\n", keys[6]);
806 /* Start the quiescent state query process */
807 token[2] = rte_rcu_qsbr_start(t[0]);
809 /* Check the quiescent state status */
810 rte_rcu_qsbr_check(t[0], token[0], true);
811 for (i = 0; i < 4; i++) {
812 c = hash_data[0][0][enabled_core_ids[i]];
813 if (c != COUNTER_VALUE && c != 0) {
814 printf("Reader lcore %d did not complete #0 = %d\n",
815 enabled_core_ids[i], c);
820 if (rte_hash_free_key_with_position(h[0], pos[0]) < 0) {
821 printf("Failed to free the key #%d\n", keys[0]);
824 rte_free(hash_data[0][0]);
825 hash_data[0][0] = NULL;
827 /* Check the quiescent state status */
828 rte_rcu_qsbr_check(t[0], token[1], true);
829 for (i = 0; i < 4; i++) {
830 c = hash_data[0][3][enabled_core_ids[i]];
831 if (c != COUNTER_VALUE && c != 0) {
832 printf("Reader lcore %d did not complete #3 = %d\n",
833 enabled_core_ids[i], c);
838 if (rte_hash_free_key_with_position(h[0], pos[1]) < 0) {
839 printf("Failed to free the key #%d\n", keys[3]);
842 rte_free(hash_data[0][3]);
843 hash_data[0][3] = NULL;
845 /* Check the quiescent state status */
846 rte_rcu_qsbr_check(t[0], token[2], true);
847 for (i = 0; i < 4; i++) {
848 c = hash_data[0][6][enabled_core_ids[i]];
849 if (c != COUNTER_VALUE && c != 0) {
850 printf("Reader lcore %d did not complete #6 = %d\n",
851 enabled_core_ids[i], c);
856 if (rte_hash_free_key_with_position(h[0], pos[2]) < 0) {
857 printf("Failed to free the key #%d\n", keys[6]);
860 rte_free(hash_data[0][6]);
861 hash_data[0][6] = NULL;
865 /* Wait and check return value from reader threads */
866 for (i = 0; i < 4; i++)
867 if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
876 /* Wait until all readers have exited */
877 rte_eal_mp_wait_lcore();
881 for (i = 0; i < TOTAL_ENTRY; i++)
882 rte_free(hash_data[0][i]);
888 * Multi writer, Multiple QS variable, simultaneous QSBR queries
891 test_rcu_qsbr_mw_mv_mqs(void)
894 unsigned int test_cores;
897 test_cores = num_cores / 4;
898 test_cores = test_cores * 4;
900 printf("Test: %d writers, %d QSBR variable, simultaneous QSBR queries\n",
901 test_cores / 2, test_cores / 4);
903 for (i = 0; i < test_cores / 4; i++) {
905 rte_rcu_qsbr_init(t[i], RTE_MAX_LCORE);
908 printf("Hash init failed\n");
911 thread_info[i].ir = i;
912 thread_info[i].ih = i;
913 thread_info[i].r_core_ids[0] = enabled_core_ids[j];
914 thread_info[i].r_core_ids[1] = enabled_core_ids[j + 1];
916 /* Reader threads are launched */
917 rte_eal_remote_launch(test_rcu_qsbr_reader,
918 (void *)&thread_info[i],
919 enabled_core_ids[j]);
920 rte_eal_remote_launch(test_rcu_qsbr_reader,
921 (void *)&thread_info[i],
922 enabled_core_ids[j + 1]);
924 /* Writer threads are launched */
925 rte_eal_remote_launch(test_rcu_qsbr_writer,
926 (void *)&thread_info[i],
927 enabled_core_ids[j + 2]);
928 rte_eal_remote_launch(test_rcu_qsbr_writer,
929 (void *)&thread_info[i],
930 enabled_core_ids[j + 3]);
933 /* Wait and check return value from writer threads */
934 for (i = 0; i < test_cores / 4; i++) {
936 if (rte_eal_wait_lcore(enabled_core_ids[j + 2]) < 0)
939 if (rte_eal_wait_lcore(enabled_core_ids[j + 3]) < 0)
944 /* Wait and check return value from reader threads */
945 for (i = 0; i < test_cores / 4; i++) {
947 if (rte_eal_wait_lcore(enabled_core_ids[j]) < 0)
950 if (rte_eal_wait_lcore(enabled_core_ids[j + 1]) < 0)
954 for (i = 0; i < test_cores / 4; i++)
963 /* Wait until all readers and writers have exited */
964 rte_eal_mp_wait_lcore();
966 for (i = 0; i < test_cores / 4; i++)
969 for (j = 0; j < test_cores / 4; j++)
970 for (i = 0; i < TOTAL_ENTRY; i++)
971 rte_free(hash_data[j][i]);
977 test_rcu_qsbr_main(void)
981 if (rte_lcore_count() < 5) {
982 printf("Not enough cores for rcu_qsbr_autotest, expecting at least 5\n");
987 RTE_LCORE_FOREACH_SLAVE(core_id) {
988 enabled_core_ids[num_cores] = core_id;
992 /* Error-checking test cases */
993 if (test_rcu_qsbr_get_memsize() < 0)
996 if (test_rcu_qsbr_init() < 0)
1001 if (test_rcu_qsbr_thread_register() < 0)
1004 if (test_rcu_qsbr_thread_unregister() < 0)
1007 if (test_rcu_qsbr_start() < 0)
1010 if (test_rcu_qsbr_check() < 0)
1013 if (test_rcu_qsbr_synchronize() < 0)
1016 if (test_rcu_qsbr_dump() < 0)
1019 if (test_rcu_qsbr_thread_online() < 0)
1022 if (test_rcu_qsbr_thread_offline() < 0)
1025 printf("\nFunctional tests\n");
1027 if (test_rcu_qsbr_sw_sv_3qs() < 0)
1030 if (test_rcu_qsbr_mw_mv_mqs() < 0)
1044 REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main);