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