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