]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/app/test/test_rcu_qsbr.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / seastar / dpdk / app / test / test_rcu_qsbr.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2018 Arm Limited
3 */
4
5 #include <stdio.h>
6 #include <stdbool.h>
7 #include <rte_pause.h>
8 #include <rte_rcu_qsbr.h>
9 #include <rte_hash.h>
10 #include <rte_hash_crc.h>
11 #include <rte_malloc.h>
12 #include <rte_cycles.h>
13 #include <unistd.h>
14
15 #include "test.h"
16
17 /* Check condition and return an error if true. */
18 #define TEST_RCU_QSBR_RETURN_IF_ERROR(cond, str, ...) do { \
19 if (cond) { \
20 printf("ERROR file %s, line %d: " str "\n", __FILE__, \
21 __LINE__, ##__VA_ARGS__); \
22 return -1; \
23 } \
24 } while (0)
25
26 /* Make sure that this has the same value as __RTE_QSBR_CNT_INIT */
27 #define TEST_RCU_QSBR_CNT_INIT 1
28
29 #define TEST_RCU_MAX_LCORE 128
30 uint16_t enabled_core_ids[TEST_RCU_MAX_LCORE];
31 uint8_t num_cores;
32
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;
38
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];
42
43 static inline int
44 get_enabled_cores_mask(void)
45 {
46 uint16_t core_id;
47 uint32_t max_cores = rte_lcore_count();
48
49 if (max_cores > TEST_RCU_MAX_LCORE) {
50 printf("Number of cores exceed %d\n", TEST_RCU_MAX_LCORE);
51 return -1;
52 }
53
54 core_id = 0;
55 num_cores = 0;
56 RTE_LCORE_FOREACH_SLAVE(core_id) {
57 enabled_core_ids[num_cores] = core_id;
58 num_cores++;
59 }
60
61 return 0;
62 }
63
64 static int
65 alloc_rcu(void)
66 {
67 int i;
68 uint32_t sz;
69
70 sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
71
72 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
73 t[i] = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz,
74 RTE_CACHE_LINE_SIZE);
75
76 return 0;
77 }
78
79 static int
80 free_rcu(void)
81 {
82 int i;
83
84 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
85 rte_free(t[i]);
86
87 return 0;
88 }
89
90 /*
91 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
92 * reporting their quiescent state on a QS variable.
93 */
94 static int
95 test_rcu_qsbr_get_memsize(void)
96 {
97 uint32_t sz;
98
99 printf("\nTest rte_rcu_qsbr_thread_register()\n");
100
101 sz = rte_rcu_qsbr_get_memsize(0);
102 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 1), "Get Memsize for 0 threads");
103
104 sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
105 /* For 128 threads,
106 * for machines with cache line size of 64B - 8384
107 * for machines with cache line size of 128 - 16768
108 */
109 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 8384 && sz != 16768),
110 "Get Memsize");
111
112 return 0;
113 }
114
115 /*
116 * rte_rcu_qsbr_init: Initialize a QSBR variable.
117 */
118 static int
119 test_rcu_qsbr_init(void)
120 {
121 int r;
122
123 printf("\nTest rte_rcu_qsbr_init()\n");
124
125 r = rte_rcu_qsbr_init(NULL, TEST_RCU_MAX_LCORE);
126 TEST_RCU_QSBR_RETURN_IF_ERROR((r != 1), "NULL variable");
127
128 return 0;
129 }
130
131 /*
132 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
133 * reporting their quiescent state on a QS variable.
134 */
135 static int
136 test_rcu_qsbr_thread_register(void)
137 {
138 int ret;
139
140 printf("\nTest rte_rcu_qsbr_thread_register()\n");
141
142 ret = rte_rcu_qsbr_thread_register(NULL, enabled_core_ids[0]);
143 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
144
145 ret = rte_rcu_qsbr_thread_register(NULL, 100000);
146 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
147 "NULL variable, invalid thread id");
148
149 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
150
151 /* Register valid thread id */
152 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
153 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Valid thread id");
154
155 /* Re-registering should not return error */
156 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
157 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
158 "Already registered thread id");
159
160 /* Register valid thread id - max allowed thread id */
161 ret = rte_rcu_qsbr_thread_register(t[0], TEST_RCU_MAX_LCORE - 1);
162 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Max thread id");
163
164 ret = rte_rcu_qsbr_thread_register(t[0], 100000);
165 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
166 "NULL variable, invalid thread id");
167
168 return 0;
169 }
170
171 /*
172 * rte_rcu_qsbr_thread_unregister: Remove a reader thread, from the list of
173 * threads reporting their quiescent state on a QS variable.
174 */
175 static int
176 test_rcu_qsbr_thread_unregister(void)
177 {
178 int i, j, ret;
179 uint64_t token;
180 uint8_t num_threads[3] = {1, TEST_RCU_MAX_LCORE, 1};
181
182 printf("\nTest rte_rcu_qsbr_thread_unregister()\n");
183
184 ret = rte_rcu_qsbr_thread_unregister(NULL, enabled_core_ids[0]);
185 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
186
187 ret = rte_rcu_qsbr_thread_unregister(NULL, 100000);
188 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
189 "NULL variable, invalid thread id");
190
191 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
192
193 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
194
195 ret = rte_rcu_qsbr_thread_unregister(t[0], 100000);
196 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
197 "NULL variable, invalid thread id");
198
199 /* Find first disabled core */
200 for (i = 0; i < TEST_RCU_MAX_LCORE; i++) {
201 if (enabled_core_ids[i] == 0)
202 break;
203 }
204 /* Test with disabled lcore */
205 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
206 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
207 "disabled thread id");
208 /* Unregister already unregistered core */
209 ret = rte_rcu_qsbr_thread_unregister(t[0], i);
210 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
211 "Already unregistered core");
212
213 /* Test with enabled lcore */
214 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
215 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
216 "enabled thread id");
217 /* Unregister already unregistered core */
218 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
219 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
220 "Already unregistered core");
221
222 /*
223 * Test with different thread_ids:
224 * 1 - thread_id = 0
225 * 2 - All possible thread_ids, from 0 to TEST_RCU_MAX_LCORE
226 * 3 - thread_id = TEST_RCU_MAX_LCORE - 1
227 */
228 for (j = 0; j < 3; j++) {
229 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
230
231 for (i = 0; i < num_threads[j]; i++)
232 rte_rcu_qsbr_thread_register(t[0],
233 (j == 2) ? (TEST_RCU_MAX_LCORE - 1) : i);
234
235 token = rte_rcu_qsbr_start(t[0]);
236 TEST_RCU_QSBR_RETURN_IF_ERROR(
237 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
238 /* Update quiescent state counter */
239 for (i = 0; i < num_threads[j]; i++) {
240 /* Skip one update */
241 if (i == (TEST_RCU_MAX_LCORE - 10))
242 continue;
243 rte_rcu_qsbr_quiescent(t[0],
244 (j == 2) ? (TEST_RCU_MAX_LCORE - 1) : i);
245 }
246
247 if (j == 1) {
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");
252 /* Update the previously skipped thread */
253 rte_rcu_qsbr_quiescent(t[0], TEST_RCU_MAX_LCORE - 10);
254 }
255
256 /* Validate the updates */
257 ret = rte_rcu_qsbr_check(t[0], token, false);
258 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
259 "Non-blocking QSBR check");
260
261 for (i = 0; i < num_threads[j]; i++)
262 rte_rcu_qsbr_thread_unregister(t[0],
263 (j == 2) ? (TEST_RCU_MAX_LCORE - 1) : i);
264
265 /* Check with no thread registered */
266 ret = rte_rcu_qsbr_check(t[0], token, true);
267 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
268 "Blocking QSBR check");
269 }
270 return 0;
271 }
272
273 /*
274 * rte_rcu_qsbr_start: Ask the worker threads to report the quiescent state
275 * status.
276 */
277 static int
278 test_rcu_qsbr_start(void)
279 {
280 uint64_t token;
281 int i;
282
283 printf("\nTest rte_rcu_qsbr_start()\n");
284
285 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
286
287 for (i = 0; i < 3; i++)
288 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
289
290 token = rte_rcu_qsbr_start(t[0]);
291 TEST_RCU_QSBR_RETURN_IF_ERROR(
292 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
293 return 0;
294 }
295
296 static int
297 test_rcu_qsbr_check_reader(void *arg)
298 {
299 struct rte_rcu_qsbr *temp;
300 uint8_t read_type = (uint8_t)((uintptr_t)arg);
301
302 temp = t[read_type];
303
304 /* Update quiescent state counter */
305 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[0]);
306 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[1]);
307 rte_rcu_qsbr_thread_unregister(temp, enabled_core_ids[2]);
308 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[3]);
309 return 0;
310 }
311
312 /*
313 * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis-
314 * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API.
315 */
316 static int
317 test_rcu_qsbr_check(void)
318 {
319 int i, ret;
320 uint64_t token;
321
322 printf("\nTest rte_rcu_qsbr_check()\n");
323
324 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
325
326 token = rte_rcu_qsbr_start(t[0]);
327 TEST_RCU_QSBR_RETURN_IF_ERROR(
328 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
329
330
331 ret = rte_rcu_qsbr_check(t[0], 0, false);
332 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Token = 0");
333
334 ret = rte_rcu_qsbr_check(t[0], token, true);
335 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
336
337 for (i = 0; i < 3; i++)
338 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
339
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");
343
344 token = rte_rcu_qsbr_start(t[0]);
345 TEST_RCU_QSBR_RETURN_IF_ERROR(
346 (token != (TEST_RCU_QSBR_CNT_INIT + 2)), "QSBR Start");
347
348 ret = rte_rcu_qsbr_check(t[0], token, false);
349 /* Threads are offline, hence this should pass */
350 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
351
352 for (i = 0; i < 3; i++)
353 rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[i]);
354
355 ret = rte_rcu_qsbr_check(t[0], token, true);
356 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
357
358 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
359
360 for (i = 0; i < 4; i++)
361 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
362
363 token = rte_rcu_qsbr_start(t[0]);
364 TEST_RCU_QSBR_RETURN_IF_ERROR(
365 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
366
367 rte_eal_remote_launch(test_rcu_qsbr_check_reader, NULL,
368 enabled_core_ids[0]);
369
370 rte_eal_mp_wait_lcore();
371 ret = rte_rcu_qsbr_check(t[0], token, true);
372 TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "Blocking QSBR check");
373
374 return 0;
375 }
376
377 static int
378 test_rcu_qsbr_synchronize_reader(void *arg)
379 {
380 uint32_t lcore_id = rte_lcore_id();
381 (void)arg;
382
383 /* Register and become online */
384 rte_rcu_qsbr_thread_register(t[0], lcore_id);
385 rte_rcu_qsbr_thread_online(t[0], lcore_id);
386
387 while (!writer_done)
388 rte_rcu_qsbr_quiescent(t[0], lcore_id);
389
390 rte_rcu_qsbr_thread_offline(t[0], lcore_id);
391 rte_rcu_qsbr_thread_unregister(t[0], lcore_id);
392
393 return 0;
394 }
395
396 /*
397 * rte_rcu_qsbr_synchronize: Wait till all the reader threads have entered
398 * the queiscent state.
399 */
400 static int
401 test_rcu_qsbr_synchronize(void)
402 {
403 int i;
404
405 printf("\nTest rte_rcu_qsbr_synchronize()\n");
406
407 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
408
409 /* Test if the API returns when there are no threads reporting
410 * QS on the variable.
411 */
412 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
413
414 /* Test if the API returns when there are threads registered
415 * but not online.
416 */
417 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
418 rte_rcu_qsbr_thread_register(t[0], i);
419 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
420
421 /* Test if the API returns when the caller is also
422 * reporting the QS status.
423 */
424 rte_rcu_qsbr_thread_online(t[0], 0);
425 rte_rcu_qsbr_synchronize(t[0], 0);
426 rte_rcu_qsbr_thread_offline(t[0], 0);
427
428 /* Check the other boundary */
429 rte_rcu_qsbr_thread_online(t[0], TEST_RCU_MAX_LCORE - 1);
430 rte_rcu_qsbr_synchronize(t[0], TEST_RCU_MAX_LCORE - 1);
431 rte_rcu_qsbr_thread_offline(t[0], TEST_RCU_MAX_LCORE - 1);
432
433 /* Test if the API returns after unregisterng all the threads */
434 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
435 rte_rcu_qsbr_thread_unregister(t[0], i);
436 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
437
438 /* Test if the API returns with the live threads */
439 writer_done = 0;
440 for (i = 0; i < num_cores; i++)
441 rte_eal_remote_launch(test_rcu_qsbr_synchronize_reader,
442 NULL, enabled_core_ids[i]);
443 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
444 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
445 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
446 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
447 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
448
449 writer_done = 1;
450 rte_eal_mp_wait_lcore();
451
452 return 0;
453 }
454
455 /*
456 * rte_rcu_qsbr_thread_online: Add a registered reader thread, to
457 * the list of threads reporting their quiescent state on a QS variable.
458 */
459 static int
460 test_rcu_qsbr_thread_online(void)
461 {
462 int i, ret;
463 uint64_t token;
464
465 printf("Test rte_rcu_qsbr_thread_online()\n");
466
467 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
468
469 /* Register 2 threads to validate that only the
470 * online thread is waited upon.
471 */
472 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
473 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[1]);
474
475 /* Use qsbr_start to verify that the thread_online API
476 * succeeded.
477 */
478 token = rte_rcu_qsbr_start(t[0]);
479
480 /* Make the thread online */
481 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
482
483 /* Check if the thread is online */
484 ret = rte_rcu_qsbr_check(t[0], token, true);
485 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
486
487 /* Check if the online thread, can report QS */
488 token = rte_rcu_qsbr_start(t[0]);
489 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
490 ret = rte_rcu_qsbr_check(t[0], token, true);
491 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
492
493 /* Make all the threads online */
494 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
495 token = rte_rcu_qsbr_start(t[0]);
496 for (i = 0; i < TEST_RCU_MAX_LCORE; i++) {
497 rte_rcu_qsbr_thread_register(t[0], i);
498 rte_rcu_qsbr_thread_online(t[0], i);
499 }
500 /* Check if all the threads are online */
501 ret = rte_rcu_qsbr_check(t[0], token, true);
502 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
503 /* Check if all the online threads can report QS */
504 token = rte_rcu_qsbr_start(t[0]);
505 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
506 rte_rcu_qsbr_quiescent(t[0], i);
507 ret = rte_rcu_qsbr_check(t[0], token, true);
508 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
509
510 return 0;
511 }
512
513 /*
514 * rte_rcu_qsbr_thread_offline: Remove a registered reader thread, from
515 * the list of threads reporting their quiescent state on a QS variable.
516 */
517 static int
518 test_rcu_qsbr_thread_offline(void)
519 {
520 int i, ret;
521 uint64_t token;
522
523 printf("\nTest rte_rcu_qsbr_thread_offline()\n");
524
525 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
526
527 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
528
529 /* Make the thread offline */
530 rte_rcu_qsbr_thread_offline(t[0], enabled_core_ids[0]);
531
532 /* Use qsbr_start to verify that the thread_offline API
533 * succeeded.
534 */
535 token = rte_rcu_qsbr_start(t[0]);
536 /* Check if the thread is offline */
537 ret = rte_rcu_qsbr_check(t[0], token, true);
538 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread offline");
539
540 /* Bring an offline thread online and check if it can
541 * report QS.
542 */
543 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
544 /* Check if the online thread, can report QS */
545 token = rte_rcu_qsbr_start(t[0]);
546 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
547 ret = rte_rcu_qsbr_check(t[0], token, true);
548 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline to online");
549
550 /*
551 * Check a sequence of online/status/offline/status/online/status
552 */
553 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
554 token = rte_rcu_qsbr_start(t[0]);
555 /* Make the threads online */
556 for (i = 0; i < TEST_RCU_MAX_LCORE; i++) {
557 rte_rcu_qsbr_thread_register(t[0], i);
558 rte_rcu_qsbr_thread_online(t[0], i);
559 }
560
561 /* Check if all the threads are online */
562 ret = rte_rcu_qsbr_check(t[0], token, true);
563 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
564
565 /* Check if all the online threads can report QS */
566 token = rte_rcu_qsbr_start(t[0]);
567 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
568 rte_rcu_qsbr_quiescent(t[0], i);
569 ret = rte_rcu_qsbr_check(t[0], token, true);
570 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "report QS");
571
572 /* Make all the threads offline */
573 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
574 rte_rcu_qsbr_thread_offline(t[0], i);
575 /* Make sure these threads are not being waited on */
576 token = rte_rcu_qsbr_start(t[0]);
577 ret = rte_rcu_qsbr_check(t[0], token, true);
578 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline QS");
579
580 /* Make the threads online */
581 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
582 rte_rcu_qsbr_thread_online(t[0], i);
583 /* Check if all the online threads can report QS */
584 token = rte_rcu_qsbr_start(t[0]);
585 for (i = 0; i < TEST_RCU_MAX_LCORE; i++)
586 rte_rcu_qsbr_quiescent(t[0], i);
587 ret = rte_rcu_qsbr_check(t[0], token, true);
588 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "online again");
589
590 return 0;
591 }
592
593 /*
594 * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file
595 */
596 static int
597 test_rcu_qsbr_dump(void)
598 {
599 int i;
600
601 printf("\nTest rte_rcu_qsbr_dump()\n");
602
603 /* Negative tests */
604 rte_rcu_qsbr_dump(NULL, t[0]);
605 rte_rcu_qsbr_dump(stdout, NULL);
606 rte_rcu_qsbr_dump(NULL, NULL);
607
608 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
609 rte_rcu_qsbr_init(t[1], TEST_RCU_MAX_LCORE);
610
611 /* QS variable with 0 core mask */
612 rte_rcu_qsbr_dump(stdout, t[0]);
613
614 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
615
616 for (i = 1; i < 3; i++)
617 rte_rcu_qsbr_thread_register(t[1], enabled_core_ids[i]);
618
619 rte_rcu_qsbr_dump(stdout, t[0]);
620 rte_rcu_qsbr_dump(stdout, t[1]);
621 printf("\n");
622 return 0;
623 }
624
625 static int
626 test_rcu_qsbr_reader(void *arg)
627 {
628 struct rte_rcu_qsbr *temp;
629 struct rte_hash *hash = NULL;
630 int i;
631 uint32_t lcore_id = rte_lcore_id();
632 uint8_t read_type = (uint8_t)((uintptr_t)arg);
633 uint32_t *pdata;
634
635 temp = t[read_type];
636 hash = h[read_type];
637
638 do {
639 rte_rcu_qsbr_thread_register(temp, lcore_id);
640 rte_rcu_qsbr_thread_online(temp, lcore_id);
641 for (i = 0; i < TOTAL_ENTRY; i++) {
642 rte_rcu_qsbr_lock(temp, lcore_id);
643 if (rte_hash_lookup_data(hash, keys+i,
644 (void **)&pdata) != -ENOENT) {
645 *pdata = 0;
646 while (*pdata < COUNTER_VALUE)
647 ++*pdata;
648 }
649 rte_rcu_qsbr_unlock(temp, lcore_id);
650 }
651 /* Update quiescent state counter */
652 rte_rcu_qsbr_quiescent(temp, lcore_id);
653 rte_rcu_qsbr_thread_offline(temp, lcore_id);
654 rte_rcu_qsbr_thread_unregister(temp, lcore_id);
655 } while (!writer_done);
656
657 return 0;
658 }
659
660 static int
661 test_rcu_qsbr_writer(void *arg)
662 {
663 uint64_t token;
664 int32_t pos;
665 struct rte_rcu_qsbr *temp;
666 struct rte_hash *hash = NULL;
667 uint8_t writer_type = (uint8_t)((uintptr_t)arg);
668
669 temp = t[(writer_type/2) % TEST_RCU_MAX_LCORE];
670 hash = h[(writer_type/2) % TEST_RCU_MAX_LCORE];
671
672 /* Delete element from the shared data structure */
673 pos = rte_hash_del_key(hash, keys + (writer_type % TOTAL_ENTRY));
674 if (pos < 0) {
675 printf("Delete key failed #%d\n",
676 keys[writer_type % TOTAL_ENTRY]);
677 return -1;
678 }
679 /* Start the quiescent state query process */
680 token = rte_rcu_qsbr_start(temp);
681 /* Check the quiescent state status */
682 rte_rcu_qsbr_check(temp, token, true);
683 if (*hash_data[(writer_type/2) % TEST_RCU_MAX_LCORE]
684 [writer_type % TOTAL_ENTRY] != COUNTER_VALUE &&
685 *hash_data[(writer_type/2) % TEST_RCU_MAX_LCORE]
686 [writer_type % TOTAL_ENTRY] != 0) {
687 printf("Reader did not complete #%d = %d\t", writer_type,
688 *hash_data[(writer_type/2) % TEST_RCU_MAX_LCORE]
689 [writer_type % TOTAL_ENTRY]);
690 return -1;
691 }
692
693 if (rte_hash_free_key_with_position(hash, pos) < 0) {
694 printf("Failed to free the key #%d\n",
695 keys[writer_type % TOTAL_ENTRY]);
696 return -1;
697 }
698 rte_free(hash_data[(writer_type/2) % TEST_RCU_MAX_LCORE]
699 [writer_type % TOTAL_ENTRY]);
700 hash_data[(writer_type/2) % TEST_RCU_MAX_LCORE]
701 [writer_type % TOTAL_ENTRY] = NULL;
702
703 return 0;
704 }
705
706 static struct rte_hash *
707 init_hash(int hash_id)
708 {
709 int i;
710 struct rte_hash *h = NULL;
711
712 sprintf(hash_name[hash_id], "hash%d", hash_id);
713 struct rte_hash_parameters hash_params = {
714 .entries = TOTAL_ENTRY,
715 .key_len = sizeof(uint32_t),
716 .hash_func_init_val = 0,
717 .socket_id = rte_socket_id(),
718 .hash_func = rte_hash_crc,
719 .extra_flag =
720 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
721 .name = hash_name[hash_id],
722 };
723
724 h = rte_hash_create(&hash_params);
725 if (h == NULL) {
726 printf("Hash create Failed\n");
727 return NULL;
728 }
729
730 for (i = 0; i < TOTAL_ENTRY; i++) {
731 hash_data[hash_id][i] = rte_zmalloc(NULL, sizeof(uint32_t), 0);
732 if (hash_data[hash_id][i] == NULL) {
733 printf("No memory\n");
734 return NULL;
735 }
736 }
737 keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);
738 if (keys == NULL) {
739 printf("No memory\n");
740 return NULL;
741 }
742
743 for (i = 0; i < TOTAL_ENTRY; i++)
744 keys[i] = i;
745
746 for (i = 0; i < TOTAL_ENTRY; i++) {
747 if (rte_hash_add_key_data(h, keys + i,
748 (void *)((uintptr_t)hash_data[hash_id][i]))
749 < 0) {
750 printf("Hash key add Failed #%d\n", i);
751 return NULL;
752 }
753 }
754 return h;
755 }
756
757 /*
758 * Functional test:
759 * Single writer, Single QS variable, simultaneous QSBR Queries
760 */
761 static int
762 test_rcu_qsbr_sw_sv_3qs(void)
763 {
764 uint64_t token[3];
765 int i;
766 int32_t pos[3];
767
768 writer_done = 0;
769
770 printf("Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\n");
771
772 rte_rcu_qsbr_init(t[0], TEST_RCU_MAX_LCORE);
773
774 /* Shared data structure created */
775 h[0] = init_hash(0);
776 if (h[0] == NULL) {
777 printf("Hash init failed\n");
778 goto error;
779 }
780
781 /* Reader threads are launched */
782 for (i = 0; i < 4; i++)
783 rte_eal_remote_launch(test_rcu_qsbr_reader, NULL,
784 enabled_core_ids[i]);
785
786 /* Delete element from the shared data structure */
787 pos[0] = rte_hash_del_key(h[0], keys + 0);
788 if (pos[0] < 0) {
789 printf("Delete key failed #%d\n", keys[0]);
790 goto error;
791 }
792 /* Start the quiescent state query process */
793 token[0] = rte_rcu_qsbr_start(t[0]);
794
795 /* Delete element from the shared data structure */
796 pos[1] = rte_hash_del_key(h[0], keys + 3);
797 if (pos[1] < 0) {
798 printf("Delete key failed #%d\n", keys[3]);
799 goto error;
800 }
801 /* Start the quiescent state query process */
802 token[1] = rte_rcu_qsbr_start(t[0]);
803
804 /* Delete element from the shared data structure */
805 pos[2] = rte_hash_del_key(h[0], keys + 6);
806 if (pos[2] < 0) {
807 printf("Delete key failed #%d\n", keys[6]);
808 goto error;
809 }
810 /* Start the quiescent state query process */
811 token[2] = rte_rcu_qsbr_start(t[0]);
812
813 /* Check the quiescent state status */
814 rte_rcu_qsbr_check(t[0], token[0], true);
815 if (*hash_data[0][0] != COUNTER_VALUE && *hash_data[0][0] != 0) {
816 printf("Reader did not complete #0 = %d\n", *hash_data[0][0]);
817 goto error;
818 }
819
820 if (rte_hash_free_key_with_position(h[0], pos[0]) < 0) {
821 printf("Failed to free the key #%d\n", keys[0]);
822 goto error;
823 }
824 rte_free(hash_data[0][0]);
825 hash_data[0][0] = NULL;
826
827 /* Check the quiescent state status */
828 rte_rcu_qsbr_check(t[0], token[1], true);
829 if (*hash_data[0][3] != COUNTER_VALUE && *hash_data[0][3] != 0) {
830 printf("Reader did not complete #3 = %d\n", *hash_data[0][3]);
831 goto error;
832 }
833
834 if (rte_hash_free_key_with_position(h[0], pos[1]) < 0) {
835 printf("Failed to free the key #%d\n", keys[3]);
836 goto error;
837 }
838 rte_free(hash_data[0][3]);
839 hash_data[0][3] = NULL;
840
841 /* Check the quiescent state status */
842 rte_rcu_qsbr_check(t[0], token[2], true);
843 if (*hash_data[0][6] != COUNTER_VALUE && *hash_data[0][6] != 0) {
844 printf("Reader did not complete #6 = %d\n", *hash_data[0][6]);
845 goto error;
846 }
847
848 if (rte_hash_free_key_with_position(h[0], pos[2]) < 0) {
849 printf("Failed to free the key #%d\n", keys[6]);
850 goto error;
851 }
852 rte_free(hash_data[0][6]);
853 hash_data[0][6] = NULL;
854
855 writer_done = 1;
856 /* Wait until all readers have exited */
857 rte_eal_mp_wait_lcore();
858 /* Check return value from threads */
859 for (i = 0; i < 4; i++)
860 if (lcore_config[enabled_core_ids[i]].ret < 0)
861 goto error;
862 rte_hash_free(h[0]);
863 rte_free(keys);
864
865 return 0;
866
867 error:
868 writer_done = 1;
869 /* Wait until all readers have exited */
870 rte_eal_mp_wait_lcore();
871
872 rte_hash_free(h[0]);
873 rte_free(keys);
874 for (i = 0; i < TOTAL_ENTRY; i++)
875 rte_free(hash_data[0][i]);
876
877 return -1;
878 }
879
880 /*
881 * Multi writer, Multiple QS variable, simultaneous QSBR queries
882 */
883 static int
884 test_rcu_qsbr_mw_mv_mqs(void)
885 {
886 int i, j;
887 uint8_t test_cores;
888
889 writer_done = 0;
890 test_cores = num_cores / 4;
891 test_cores = test_cores * 4;
892
893 printf("Test: %d writers, %d QSBR variable, simultaneous QSBR queries\n"
894 , test_cores / 2, test_cores / 4);
895
896 for (i = 0; i < num_cores / 4; i++) {
897 rte_rcu_qsbr_init(t[i], TEST_RCU_MAX_LCORE);
898 h[i] = init_hash(i);
899 if (h[i] == NULL) {
900 printf("Hash init failed\n");
901 goto error;
902 }
903 }
904
905 /* Reader threads are launched */
906 for (i = 0; i < test_cores / 2; i++)
907 rte_eal_remote_launch(test_rcu_qsbr_reader,
908 (void *)(uintptr_t)(i / 2),
909 enabled_core_ids[i]);
910
911 /* Writer threads are launched */
912 for (; i < test_cores; i++)
913 rte_eal_remote_launch(test_rcu_qsbr_writer,
914 (void *)(uintptr_t)(i - (test_cores / 2)),
915 enabled_core_ids[i]);
916 /* Wait for writers to complete */
917 for (i = test_cores / 2; i < test_cores; i++)
918 rte_eal_wait_lcore(enabled_core_ids[i]);
919
920 writer_done = 1;
921 /* Wait for readers to complete */
922 rte_eal_mp_wait_lcore();
923
924 /* Check return value from threads */
925 for (i = 0; i < test_cores; i++)
926 if (lcore_config[enabled_core_ids[i]].ret < 0)
927 goto error;
928
929 for (i = 0; i < num_cores / 4; i++)
930 rte_hash_free(h[i]);
931
932 rte_free(keys);
933
934 return 0;
935
936 error:
937 writer_done = 1;
938 /* Wait until all readers have exited */
939 rte_eal_mp_wait_lcore();
940
941 for (i = 0; i < num_cores / 4; i++)
942 rte_hash_free(h[i]);
943 rte_free(keys);
944 for (j = 0; j < TEST_RCU_MAX_LCORE; j++)
945 for (i = 0; i < TOTAL_ENTRY; i++)
946 rte_free(hash_data[j][i]);
947
948 return -1;
949 }
950
951 static int
952 test_rcu_qsbr_main(void)
953 {
954 if (get_enabled_cores_mask() != 0)
955 return -1;
956
957 if (num_cores < 4) {
958 printf("Test failed! Need 4 or more cores\n");
959 goto test_fail;
960 }
961
962 /* Error-checking test cases */
963 if (test_rcu_qsbr_get_memsize() < 0)
964 goto test_fail;
965
966 if (test_rcu_qsbr_init() < 0)
967 goto test_fail;
968
969 alloc_rcu();
970
971 if (test_rcu_qsbr_thread_register() < 0)
972 goto test_fail;
973
974 if (test_rcu_qsbr_thread_unregister() < 0)
975 goto test_fail;
976
977 if (test_rcu_qsbr_start() < 0)
978 goto test_fail;
979
980 if (test_rcu_qsbr_check() < 0)
981 goto test_fail;
982
983 if (test_rcu_qsbr_synchronize() < 0)
984 goto test_fail;
985
986 if (test_rcu_qsbr_dump() < 0)
987 goto test_fail;
988
989 if (test_rcu_qsbr_thread_online() < 0)
990 goto test_fail;
991
992 if (test_rcu_qsbr_thread_offline() < 0)
993 goto test_fail;
994
995 printf("\nFunctional tests\n");
996
997 if (test_rcu_qsbr_sw_sv_3qs() < 0)
998 goto test_fail;
999
1000 if (test_rcu_qsbr_mw_mv_mqs() < 0)
1001 goto test_fail;
1002
1003 free_rcu();
1004
1005 printf("\n");
1006 return 0;
1007
1008 test_fail:
1009 free_rcu();
1010
1011 return -1;
1012 }
1013
1014 REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main);