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