remove version in all files
[dpdk.git] / app / test / test_atomic.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without 
8  *   modification, are permitted provided that the following conditions 
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright 
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright 
14  *       notice, this list of conditions and the following disclaimer in 
15  *       the documentation and/or other materials provided with the 
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its 
18  *       contributors may be used to endorse or promote products derived 
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  * 
33  */
34
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <unistd.h>
38 #include <sys/queue.h>
39
40 #include <cmdline_parse.h>
41
42 #include <rte_memory.h>
43 #include <rte_memzone.h>
44 #include <rte_per_lcore.h>
45 #include <rte_launch.h>
46 #include <rte_atomic.h>
47 #include <rte_tailq.h>
48 #include <rte_eal.h>
49 #include <rte_per_lcore.h>
50 #include <rte_lcore.h>
51
52 #include "test.h"
53
54 /*
55  * Atomic Variables
56  * ================
57  *
58  * - The main test function performs three subtests. The first test
59  *   checks that the usual inc/dec/add/sub functions are working
60  *   correctly:
61  *
62  *   - Initialize 16-bit, 32-bit and 64-bit atomic variables to specific
63  *     values.
64  *
65  *   - These variables are incremented and decremented on each core at
66  *     the same time in ``test_atomic_usual()``.
67  *
68  *   - The function checks that once all lcores finish their function,
69  *     the value of the atomic variables are still the same.
70  *
71  * - The second test verifies the behavior of "test and set" functions.
72  *
73  *   - Initialize 16-bit, 32-bit and 64-bit atomic variables to zero.
74  *
75  *   - Invoke ``test_atomic_tas()`` on each lcore: before doing anything
76  *     else. The cores are waiting a synchro using ``while
77  *     (rte_atomic32_read(&val) == 0)`` which is triggered by the main test
78  *     function. Then all cores do a
79  *     ``rte_atomicXX_test_and_set()`` at the same time. If it is successful,
80  *     it increments another atomic counter.
81  *
82  *   - The main function checks that the atomic counter was incremented
83  *     twice only (one for 16-bit, one for 32-bit and one for 64-bit values).
84  *
85  * - Test "add/sub and return"
86  *
87  *   - Initialize 16-bit, 32-bit and 64-bit atomic variables to zero.
88  *
89  *   - Invoke ``test_atomic_addsub_return()`` on each lcore. Before doing
90  *     anything else, the cores are waiting a synchro. Each lcore does
91  *     this operation several times::
92  *
93  *       tmp = rte_atomicXX_add_return(&a, 1);
94  *       atomic_add(&count, tmp);
95  *       tmp = rte_atomicXX_sub_return(&a, 1);
96  *       atomic_sub(&count, tmp+1);
97  *
98  *   - At the end of the test, the *count* value must be 0.
99  */
100
101 #define NUM_ATOMIC_TYPES 3
102
103 #define N 10000
104
105 static rte_atomic16_t a16;
106 static rte_atomic32_t a32;
107 static rte_atomic64_t a64;
108 static rte_atomic32_t count;
109 static rte_atomic32_t synchro;
110
111 static int
112 test_atomic_usual(__attribute__((unused)) void *arg)
113 {
114         unsigned i;
115
116         while (rte_atomic32_read(&synchro) == 0)
117                 ;
118
119         for (i = 0; i < N; i++)
120                 rte_atomic16_inc(&a16);
121         for (i = 0; i < N; i++)
122                 rte_atomic16_dec(&a16);
123         for (i = 0; i < (N / 5); i++)
124                 rte_atomic16_add(&a16, 5);
125         for (i = 0; i < (N / 5); i++)
126                 rte_atomic16_sub(&a16, 5);
127
128         for (i = 0; i < N; i++)
129                 rte_atomic32_inc(&a32);
130         for (i = 0; i < N; i++)
131                 rte_atomic32_dec(&a32);
132         for (i = 0; i < (N / 5); i++)
133                 rte_atomic32_add(&a32, 5);
134         for (i = 0; i < (N / 5); i++)
135                 rte_atomic32_sub(&a32, 5);
136
137         for (i = 0; i < N; i++)
138                 rte_atomic64_inc(&a64);
139         for (i = 0; i < N; i++)
140                 rte_atomic64_dec(&a64);
141         for (i = 0; i < (N / 5); i++)
142                 rte_atomic64_add(&a64, 5);
143         for (i = 0; i < (N / 5); i++)
144                 rte_atomic64_sub(&a64, 5);
145
146         return 0;
147 }
148
149 static int
150 test_atomic_tas(__attribute__((unused)) void *arg)
151 {
152         while (rte_atomic32_read(&synchro) == 0)
153                 ;
154
155         if (rte_atomic16_test_and_set(&a16))
156                 rte_atomic32_inc(&count);
157         if (rte_atomic32_test_and_set(&a32))
158                 rte_atomic32_inc(&count);
159         if (rte_atomic64_test_and_set(&a64))
160                 rte_atomic32_inc(&count);
161
162         return 0;
163 }
164
165 static int
166 test_atomic_addsub_and_return(__attribute__((unused)) void *arg)
167 {
168         uint32_t tmp16;
169         uint32_t tmp32;
170         uint64_t tmp64;
171         unsigned i;
172
173         while (rte_atomic32_read(&synchro) == 0)
174                 ;
175
176         for (i = 0; i < N; i++) {
177                 tmp16 = rte_atomic16_add_return(&a16, 1);
178                 rte_atomic32_add(&count, tmp16);
179
180                 tmp16 = rte_atomic16_sub_return(&a16, 1);
181                 rte_atomic32_sub(&count, tmp16+1);
182
183                 tmp32 = rte_atomic32_add_return(&a32, 1);
184                 rte_atomic32_add(&count, tmp32);
185
186                 tmp32 = rte_atomic32_sub_return(&a32, 1);
187                 rte_atomic32_sub(&count, tmp32+1);
188
189                 tmp64 = rte_atomic64_add_return(&a64, 1);
190                 rte_atomic32_add(&count, tmp64);
191
192                 tmp64 = rte_atomic64_sub_return(&a64, 1);
193                 rte_atomic32_sub(&count, tmp64+1);
194         }
195
196         return 0;
197 }
198
199 /*
200  * rte_atomic32_inc_and_test() would increase a 32 bits counter by one and then
201  * test if that counter is equal to 0. It would return true if the counter is 0
202  * and false if the counter is not 0. rte_atomic64_inc_and_test() could do the
203  * same thing but for a 64 bits counter.
204  * Here checks that if the 32/64 bits counter is equal to 0 after being atomically
205  * increased by one. If it is, increase the variable of "count" by one which would
206  * be checked as the result later.
207  *
208  */
209 static int
210 test_atomic_inc_and_test(__attribute__((unused)) void *arg)
211 {
212         while (rte_atomic32_read(&synchro) == 0)
213                 ;
214
215         if (rte_atomic16_inc_and_test(&a16)) {
216                 rte_atomic32_inc(&count);
217         }
218         if (rte_atomic32_inc_and_test(&a32)) {
219                 rte_atomic32_inc(&count);
220         }
221         if (rte_atomic64_inc_and_test(&a64)) {
222                 rte_atomic32_inc(&count);
223         }
224
225         return 0;
226 }
227
228 /*
229  * rte_atomicXX_dec_and_test() should decrease a 32 bits counter by one and then
230  * test if that counter is equal to 0. It should return true if the counter is 0
231  * and false if the counter is not 0.
232  * This test checks if the counter is equal to 0 after being atomically
233  * decreased by one. If it is, increase the value of "count" by one which is to
234  * be checked as the result later.
235  */
236 static int
237 test_atomic_dec_and_test(__attribute__((unused)) void *arg)
238 {
239         while (rte_atomic32_read(&synchro) == 0)
240                 ;
241
242         if (rte_atomic16_dec_and_test(&a16))
243                 rte_atomic32_inc(&count);
244
245         if (rte_atomic32_dec_and_test(&a32))
246                 rte_atomic32_inc(&count);
247
248         if (rte_atomic64_dec_and_test(&a64))
249                 rte_atomic32_inc(&count);
250
251         return 0;
252 }
253
254 int
255 test_atomic(void)
256 {
257         rte_atomic16_init(&a16);
258         rte_atomic32_init(&a32);
259         rte_atomic64_init(&a64);
260         rte_atomic32_init(&count);
261         rte_atomic32_init(&synchro);
262
263         rte_atomic16_set(&a16, 1UL << 10);
264         rte_atomic32_set(&a32, 1UL << 10);
265         rte_atomic64_set(&a64, 1ULL << 33);
266
267         printf("usual inc/dec/add/sub functions\n");
268
269         rte_eal_mp_remote_launch(test_atomic_usual, NULL, SKIP_MASTER);
270         rte_atomic32_set(&synchro, 1);
271         rte_eal_mp_wait_lcore();
272         rte_atomic32_set(&synchro, 0);
273
274         if (rte_atomic16_read(&a16) != 1UL << 10) {
275                 printf("Atomic16 usual functions failed\n");
276                 return -1;
277         }
278
279         if (rte_atomic32_read(&a32) != 1UL << 10) {
280                 printf("Atomic32 usual functions failed\n");
281                 return -1;
282         }
283
284         if (rte_atomic64_read(&a64) != 1ULL << 33) {
285                 printf("Atomic64 usual functions failed\n");
286                 return -1;
287         }
288
289         printf("test and set\n");
290
291         rte_atomic64_set(&a64, 0);
292         rte_atomic32_set(&a32, 0);
293         rte_atomic16_set(&a16, 0);
294         rte_atomic32_set(&count, 0);
295         rte_eal_mp_remote_launch(test_atomic_tas, NULL, SKIP_MASTER);
296         rte_atomic32_set(&synchro, 1);
297         rte_eal_mp_wait_lcore();
298         rte_atomic32_set(&synchro, 0);
299
300         if (rte_atomic32_read(&count) != NUM_ATOMIC_TYPES) {
301                 printf("Atomic test and set failed\n");
302                 return -1;
303         }
304
305         printf("add/sub and return\n");
306
307         rte_atomic64_set(&a64, 0);
308         rte_atomic32_set(&a32, 0);
309         rte_atomic16_set(&a16, 0);
310         rte_atomic32_set(&count, 0);
311         rte_eal_mp_remote_launch(test_atomic_addsub_and_return, NULL,
312                                  SKIP_MASTER);
313         rte_atomic32_set(&synchro, 1);
314         rte_eal_mp_wait_lcore();
315         rte_atomic32_set(&synchro, 0);
316
317         if (rte_atomic32_read(&count) != 0) {
318                 printf("Atomic add/sub+return failed\n");
319                 return -1;
320         }
321
322         /*
323          * Set a64, a32 and a16 with the same value of minus "number of slave
324          * lcores", launch all slave lcores to atomically increase by one and
325          * test them respectively.
326          * Each lcore should have only one chance to increase a64 by one and
327          * then check if it is equal to 0, but there should be only one lcore
328          * that finds that it is 0. It is similar for a32 and a16.
329          * Then a variable of "count", initialized to zero, is increased by
330          * one if a64, a32 or a16 is 0 after being increased and tested
331          * atomically.
332          * We can check if "count" is finally equal to 3 to see if all slave
333          * lcores performed "atomic inc and test" right.
334          */
335         printf("inc and test\n");
336
337         rte_atomic64_clear(&a64);
338         rte_atomic32_clear(&a32);
339         rte_atomic16_clear(&a16);
340         rte_atomic32_clear(&synchro);
341         rte_atomic32_clear(&count);
342
343         rte_atomic64_set(&a64, (int64_t)(1 - (int64_t)rte_lcore_count()));
344         rte_atomic32_set(&a32, (int32_t)(1 - (int32_t)rte_lcore_count()));
345         rte_atomic16_set(&a16, (int16_t)(1 - (int16_t)rte_lcore_count()));
346         rte_eal_mp_remote_launch(test_atomic_inc_and_test, NULL, SKIP_MASTER);
347         rte_atomic32_set(&synchro, 1);
348         rte_eal_mp_wait_lcore();
349         rte_atomic32_clear(&synchro);
350
351         if (rte_atomic32_read(&count) != NUM_ATOMIC_TYPES) {
352                 printf("Atomic inc and test failed %d\n", count.cnt);
353                 return -1;
354         }
355
356         /*
357          * Same as above, but this time we set the values to "number of slave
358          * lcores", and decrement instead of increment.
359          */
360         printf("dec and test\n");
361
362         rte_atomic32_clear(&synchro);
363         rte_atomic32_clear(&count);
364
365         rte_atomic64_set(&a64, (int64_t)(rte_lcore_count() - 1));
366         rte_atomic32_set(&a32, (int32_t)(rte_lcore_count() - 1));
367         rte_atomic16_set(&a16, (int16_t)(rte_lcore_count() - 1));
368         rte_eal_mp_remote_launch(test_atomic_dec_and_test, NULL, SKIP_MASTER);
369         rte_atomic32_set(&synchro, 1);
370         rte_eal_mp_wait_lcore();
371         rte_atomic32_clear(&synchro);
372
373         if (rte_atomic32_read(&count) != NUM_ATOMIC_TYPES) {
374                 printf("Atomic dec and test failed\n");
375                 return -1;
376         }
377
378         return 0;
379 }
380