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