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