test/crypto: remove illegal PMD header include
[dpdk.git] / app / test / test_mcslock.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Arm Limited
3  */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <inttypes.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <sys/queue.h>
11
12 #include <rte_common.h>
13 #include <rte_memory.h>
14 #include <rte_per_lcore.h>
15 #include <rte_launch.h>
16 #include <rte_eal.h>
17 #include <rte_lcore.h>
18 #include <rte_cycles.h>
19 #include <rte_mcslock.h>
20
21 #include "test.h"
22
23 /*
24  * RTE MCS lock test
25  * =================
26  *
27  * These tests are derived from spin lock test cases.
28  *
29  * - The functional test takes all of these locks and launches the
30  *   ''test_mcslock_per_core()'' function on each core (except the main).
31  *
32  *   - The function takes the global lock, display something, then releases
33  *     the global lock on each core.
34  *
35  * - A load test is carried out, with all cores attempting to lock a single
36  *   lock multiple times.
37  */
38
39 rte_mcslock_t *p_ml;
40 rte_mcslock_t *p_ml_try;
41 rte_mcslock_t *p_ml_perf;
42
43 static unsigned int count;
44
45 static uint32_t synchro;
46
47 static int
48 test_mcslock_per_core(__rte_unused void *arg)
49 {
50         /* Per core me node. */
51         rte_mcslock_t ml_me;
52
53         rte_mcslock_lock(&p_ml, &ml_me);
54         printf("MCS lock taken on core %u\n", rte_lcore_id());
55         rte_mcslock_unlock(&p_ml, &ml_me);
56         printf("MCS lock released on core %u\n", rte_lcore_id());
57
58         return 0;
59 }
60
61 static uint64_t time_count[RTE_MAX_LCORE] = {0};
62
63 #define MAX_LOOP 1000000
64
65 static int
66 load_loop_fn(void *func_param)
67 {
68         uint64_t time_diff = 0, begin;
69         uint64_t hz = rte_get_timer_hz();
70         volatile uint64_t lcount = 0;
71         const int use_lock = *(int *)func_param;
72         const unsigned int lcore = rte_lcore_id();
73
74         /**< Per core me node. */
75         rte_mcslock_t ml_perf_me;
76
77         /* wait synchro */
78         rte_wait_until_equal_32(&synchro, 1, __ATOMIC_RELAXED);
79
80         begin = rte_get_timer_cycles();
81         while (lcount < MAX_LOOP) {
82                 if (use_lock)
83                         rte_mcslock_lock(&p_ml_perf, &ml_perf_me);
84
85                 lcount++;
86                 if (use_lock)
87                         rte_mcslock_unlock(&p_ml_perf, &ml_perf_me);
88         }
89         time_diff = rte_get_timer_cycles() - begin;
90         time_count[lcore] = time_diff * 1000000 / hz;
91         return 0;
92 }
93
94 static int
95 test_mcslock_perf(void)
96 {
97         unsigned int i;
98         uint64_t total = 0;
99         int lock = 0;
100         const unsigned int lcore = rte_lcore_id();
101
102         printf("\nTest with no lock on single core...\n");
103         __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
104         load_loop_fn(&lock);
105         printf("Core [%u] Cost Time = %"PRIu64" us\n",
106                         lcore, time_count[lcore]);
107         memset(time_count, 0, sizeof(time_count));
108
109         printf("\nTest with lock on single core...\n");
110         __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
111         lock = 1;
112         load_loop_fn(&lock);
113         printf("Core [%u] Cost Time = %"PRIu64" us\n",
114                         lcore, time_count[lcore]);
115         memset(time_count, 0, sizeof(time_count));
116
117         printf("\nTest with lock on %u cores...\n", (rte_lcore_count()));
118
119         __atomic_store_n(&synchro, 0, __ATOMIC_RELAXED);
120         rte_eal_mp_remote_launch(load_loop_fn, &lock, SKIP_MAIN);
121
122         /* start synchro and launch test on main */
123         __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED);
124         load_loop_fn(&lock);
125
126         rte_eal_mp_wait_lcore();
127
128         RTE_LCORE_FOREACH(i) {
129                 printf("Core [%u] Cost Time = %"PRIu64" us\n",
130                                 i, time_count[i]);
131                 total += time_count[i];
132         }
133
134         printf("Total Cost Time = %"PRIu64" us\n", total);
135
136         return 0;
137 }
138
139 /*
140  * Use rte_mcslock_trylock() to trylock a mcs lock object,
141  * If it could not lock the object successfully, it would
142  * return immediately.
143  */
144 static int
145 test_mcslock_try(__rte_unused void *arg)
146 {
147         /**< Per core me node. */
148         rte_mcslock_t ml_me;
149         rte_mcslock_t ml_try_me;
150
151         /* Locked ml_try in the main lcore, so it should fail
152          * when trying to lock it in the worker lcore.
153          */
154         if (rte_mcslock_trylock(&p_ml_try, &ml_try_me) == 0) {
155                 rte_mcslock_lock(&p_ml, &ml_me);
156                 count++;
157                 rte_mcslock_unlock(&p_ml, &ml_me);
158         }
159
160         return 0;
161 }
162
163
164 /*
165  * Test rte_eal_get_lcore_state() in addition to mcs locks
166  * as we have "waiting" then "running" lcores.
167  */
168 static int
169 test_mcslock(void)
170 {
171         int ret = 0;
172         int i;
173
174         /* Define per core me node. */
175         rte_mcslock_t ml_me;
176         rte_mcslock_t ml_try_me;
177
178         /*
179          * Test mcs lock & unlock on each core
180          */
181
182         /* worker cores should be waiting: print it */
183         RTE_LCORE_FOREACH_WORKER(i) {
184                 printf("lcore %d state: %d\n", i,
185                                 (int) rte_eal_get_lcore_state(i));
186         }
187
188         rte_mcslock_lock(&p_ml, &ml_me);
189
190         RTE_LCORE_FOREACH_WORKER(i) {
191                 rte_eal_remote_launch(test_mcslock_per_core, NULL, i);
192         }
193
194         /* worker cores should be busy: print it */
195         RTE_LCORE_FOREACH_WORKER(i) {
196                 printf("lcore %d state: %d\n", i,
197                                 (int) rte_eal_get_lcore_state(i));
198         }
199
200         rte_mcslock_unlock(&p_ml, &ml_me);
201
202         rte_eal_mp_wait_lcore();
203
204         /*
205          * Test if it could return immediately from try-locking a locked object.
206          * Here it will lock the mcs lock object first, then launch all the
207          * worker lcores to trylock the same mcs lock object.
208          * All the worker lcores should give up try-locking a locked object and
209          * return immediately, and then increase the "count" initialized with
210          * zero by one per times.
211          * We can check if the "count" is finally equal to the number of all
212          * worker lcores to see if the behavior of try-locking a locked
213          * mcslock object is correct.
214          */
215         if (rte_mcslock_trylock(&p_ml_try, &ml_try_me) == 0)
216                 return -1;
217
218         count = 0;
219         RTE_LCORE_FOREACH_WORKER(i) {
220                 rte_eal_remote_launch(test_mcslock_try, NULL, i);
221         }
222         rte_eal_mp_wait_lcore();
223         rte_mcslock_unlock(&p_ml_try, &ml_try_me);
224
225         /* Test is_locked API */
226         if (rte_mcslock_is_locked(p_ml)) {
227                 printf("mcslock is locked but it should not be\n");
228                 return -1;
229         }
230
231         /* Counting the locked times in each core */
232         rte_mcslock_lock(&p_ml, &ml_me);
233         if (count != (rte_lcore_count() - 1))
234                 ret = -1;
235         rte_mcslock_unlock(&p_ml, &ml_me);
236
237         /* mcs lock perf test */
238         if (test_mcslock_perf() < 0)
239                 return -1;
240
241         return ret;
242 }
243
244 REGISTER_TEST_COMMAND(mcslock_autotest, test_mcslock);