Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <string.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <stdint.h>
9 : : #include <inttypes.h>
10 : : #include <stdarg.h>
11 : : #include <errno.h>
12 : : #include <sys/queue.h>
13 : :
14 : : #include <rte_common.h>
15 : : #include <rte_log.h>
16 : : #include <rte_debug.h>
17 : : #include <rte_memory.h>
18 : : #include <rte_launch.h>
19 : : #include <rte_cycles.h>
20 : : #include <rte_eal.h>
21 : : #include <rte_per_lcore.h>
22 : : #include <rte_lcore.h>
23 : : #include <rte_branch_prediction.h>
24 : : #include <rte_ring.h>
25 : : #include <rte_mempool.h>
26 : : #include <rte_spinlock.h>
27 : : #include <rte_malloc.h>
28 : :
29 : : #ifdef RTE_LIB_HASH
30 : : #include <rte_hash.h>
31 : : #include <rte_fbk_hash.h>
32 : : #include <rte_jhash.h>
33 : : #endif /* RTE_LIB_HASH */
34 : :
35 : : #ifdef RTE_LIB_LPM
36 : : #include <rte_lpm.h>
37 : : #endif /* RTE_LIB_LPM */
38 : :
39 : : #include <rte_string_fns.h>
40 : :
41 : : #include "test.h"
42 : :
43 : : typedef int (*case_func_t)(void* arg);
44 : : typedef void (*case_clean_t)(unsigned lcore_id);
45 : :
46 : : #define MAX_STRING_SIZE (256)
47 : : #define MAX_ITER_MULTI (16)
48 : : #define MAX_ITER_ONCE (4)
49 : : #define MAX_LPM_ITER_TIMES (6)
50 : :
51 : : #define MEMPOOL_ELT_SIZE (sizeof(uint32_t))
52 : : #define MEMPOOL_SIZE (4)
53 : :
54 : : #define MAX_LCORES (rte_memzone_max_get() / (MAX_ITER_MULTI * 4U))
55 : :
56 : : static RTE_ATOMIC(uint32_t) obj_count;
57 : : static RTE_ATOMIC(uint32_t) synchro;
58 : :
59 : : #define WAIT_SYNCHRO_FOR_WORKERS() do { \
60 : : if (lcore_self != rte_get_main_lcore()) \
61 : : rte_wait_until_equal_32((uint32_t *)(uintptr_t)&synchro, 1, \
62 : : rte_memory_order_relaxed); \
63 : : } while(0)
64 : :
65 : : /*
66 : : * rte_eal_init only init once
67 : : */
68 : : static int
69 : 2 : test_eal_init_once(void *arg)
70 : : {
71 : : unsigned lcore_self = rte_lcore_id();
72 : 2 : char *argv[] = { arg, NULL };
73 : :
74 [ + + ]: 2 : WAIT_SYNCHRO_FOR_WORKERS();
75 : :
76 : : /* silent the check in the caller */
77 : 2 : rte_atomic_store_explicit(&obj_count, 1, rte_memory_order_relaxed);
78 [ - + ]: 2 : if (rte_eal_init(RTE_DIM(argv) - 1, argv) != -1)
79 : 0 : return -1;
80 : :
81 : : return 0;
82 : : }
83 : :
84 : : /*
85 : : * ring create/lookup reentrancy test
86 : : */
87 : : static void
88 : 2 : ring_clean(unsigned int lcore_id)
89 : : {
90 : : struct rte_ring *rp;
91 : : char ring_name[MAX_STRING_SIZE];
92 : : int i;
93 : :
94 : 2 : rp = rte_ring_lookup("fr_test_once");
95 : 2 : rte_ring_free(rp);
96 : :
97 [ + + ]: 34 : for (i = 0; i < MAX_ITER_MULTI; i++) {
98 : : snprintf(ring_name, sizeof(ring_name),
99 : : "fr_test_%d_%d", lcore_id, i);
100 : 32 : rp = rte_ring_lookup(ring_name);
101 : 32 : rte_ring_free(rp);
102 : : }
103 : 2 : }
104 : :
105 : : static int
106 : 2 : ring_create_lookup(__rte_unused void *arg)
107 : : {
108 : : unsigned lcore_self = rte_lcore_id();
109 : : struct rte_ring * rp;
110 : : char ring_name[MAX_STRING_SIZE];
111 : : int i;
112 : :
113 [ + + ]: 2 : WAIT_SYNCHRO_FOR_WORKERS();
114 : :
115 : : /* create the same ring simultaneously on all threads */
116 [ + + ]: 10 : for (i = 0; i < MAX_ITER_ONCE; i++) {
117 : 8 : rp = rte_ring_create("fr_test_once", 4096, SOCKET_ID_ANY, 0);
118 [ + + ]: 8 : if (rp != NULL)
119 : 1 : rte_atomic_fetch_add_explicit(&obj_count, 1, rte_memory_order_relaxed);
120 : : }
121 : :
122 : : /* create/lookup new ring several times */
123 [ + + ]: 34 : for (i = 0; i < MAX_ITER_MULTI; i++) {
124 : : snprintf(ring_name, sizeof(ring_name), "fr_test_%d_%d", lcore_self, i);
125 : 32 : rp = rte_ring_create(ring_name, 4096, SOCKET_ID_ANY, 0);
126 [ + - ]: 32 : if (NULL == rp)
127 : : return -1;
128 [ + - ]: 32 : if (rte_ring_lookup(ring_name) != rp)
129 : : return -1;
130 : :
131 : : /* verify all ring created successful */
132 [ + - ]: 32 : if (rte_ring_lookup(ring_name) == NULL)
133 : : return -1;
134 : : }
135 : :
136 : : return 0;
137 : : }
138 : :
139 : : static void
140 : 132 : my_obj_init(struct rte_mempool *mp, __rte_unused void *arg,
141 : : void *obj, unsigned i)
142 : : {
143 : : uint32_t *objnum = obj;
144 : 132 : memset(obj, 0, mp->elt_size);
145 : 132 : *objnum = i;
146 : 132 : }
147 : :
148 : : static void
149 : 2 : mempool_clean(unsigned int lcore_id)
150 : : {
151 : : struct rte_mempool *mp;
152 : : char mempool_name[MAX_STRING_SIZE];
153 : : int i;
154 : :
155 : 2 : mp = rte_mempool_lookup("fr_test_once");
156 : 2 : rte_mempool_free(mp);
157 : :
158 [ + + ]: 34 : for (i = 0; i < MAX_ITER_MULTI; i++) {
159 : : snprintf(mempool_name, sizeof(mempool_name), "fr_test_%d_%d",
160 : : lcore_id, i);
161 : 32 : mp = rte_mempool_lookup(mempool_name);
162 : 32 : rte_mempool_free(mp);
163 : : }
164 : 2 : }
165 : :
166 : : static int
167 : 2 : mempool_create_lookup(__rte_unused void *arg)
168 : : {
169 : : unsigned lcore_self = rte_lcore_id();
170 : : struct rte_mempool * mp;
171 : : char mempool_name[MAX_STRING_SIZE];
172 : : int i;
173 : :
174 [ + + ]: 2 : WAIT_SYNCHRO_FOR_WORKERS();
175 : :
176 : : /* create the same mempool simultaneously on all threads */
177 [ + + ]: 9 : for (i = 0; i < MAX_ITER_ONCE; i++) {
178 : 7 : mp = rte_mempool_create("fr_test_once", MEMPOOL_SIZE,
179 : : MEMPOOL_ELT_SIZE, 0, 0,
180 : : NULL, NULL,
181 : : my_obj_init, NULL,
182 : : SOCKET_ID_ANY, 0);
183 [ + + ]: 8 : if (mp != NULL)
184 : 1 : rte_atomic_fetch_add_explicit(&obj_count, 1, rte_memory_order_relaxed);
185 : : }
186 : :
187 : : /* create/lookup new ring several times */
188 [ + + ]: 34 : for (i = 0; i < MAX_ITER_MULTI; i++) {
189 : : snprintf(mempool_name, sizeof(mempool_name), "fr_test_%d_%d", lcore_self, i);
190 : 32 : mp = rte_mempool_create(mempool_name, MEMPOOL_SIZE,
191 : : MEMPOOL_ELT_SIZE, 0, 0,
192 : : NULL, NULL,
193 : : my_obj_init, NULL,
194 : : SOCKET_ID_ANY, 0);
195 [ + - ]: 32 : if (NULL == mp)
196 : : return -1;
197 [ + - ]: 32 : if (rte_mempool_lookup(mempool_name) != mp)
198 : : return -1;
199 : :
200 : : /* verify all ring created successful */
201 [ + - ]: 32 : if (rte_mempool_lookup(mempool_name) == NULL)
202 : : return -1;
203 : : }
204 : :
205 : : return 0;
206 : : }
207 : :
208 : : #ifdef RTE_LIB_HASH
209 : : static void
210 : 2 : hash_clean(unsigned lcore_id)
211 : : {
212 : : char hash_name[MAX_STRING_SIZE];
213 : : struct rte_hash *handle;
214 : : int i;
215 : :
216 : 2 : handle = rte_hash_find_existing("fr_test_once");
217 : 2 : rte_hash_free(handle);
218 : :
219 [ + + ]: 34 : for (i = 0; i < MAX_ITER_MULTI; i++) {
220 : : snprintf(hash_name, sizeof(hash_name), "fr_test_%d_%d", lcore_id, i);
221 : :
222 [ - + ]: 32 : if ((handle = rte_hash_find_existing(hash_name)) != NULL)
223 : 0 : rte_hash_free(handle);
224 : : }
225 : 2 : }
226 : :
227 : : static int
228 : 2 : hash_create_free(__rte_unused void *arg)
229 : : {
230 : : unsigned lcore_self = rte_lcore_id();
231 : : struct rte_hash *handle;
232 : : char hash_name[MAX_STRING_SIZE];
233 : : int i;
234 : 2 : struct rte_hash_parameters hash_params = {
235 : : .name = NULL,
236 : : .entries = 16,
237 : : .key_len = 4,
238 : : .hash_func = (rte_hash_function)rte_jhash_32b,
239 : : .hash_func_init_val = 0,
240 : : .socket_id = 0,
241 : : };
242 : :
243 [ + + ]: 2 : WAIT_SYNCHRO_FOR_WORKERS();
244 : :
245 : : /* create the same hash simultaneously on all threads */
246 : 2 : hash_params.name = "fr_test_once";
247 [ + + ]: 10 : for (i = 0; i < MAX_ITER_ONCE; i++) {
248 : 8 : handle = rte_hash_create(&hash_params);
249 [ + + ]: 8 : if (handle != NULL)
250 : 1 : rte_atomic_fetch_add_explicit(&obj_count, 1, rte_memory_order_relaxed);
251 : : }
252 : :
253 : : /* create multiple times simultaneously */
254 [ + + ]: 34 : for (i = 0; i < MAX_ITER_MULTI; i++) {
255 : : snprintf(hash_name, sizeof(hash_name), "fr_test_%d_%d", lcore_self, i);
256 : 32 : hash_params.name = hash_name;
257 : :
258 : 32 : handle = rte_hash_create(&hash_params);
259 [ + - ]: 32 : if (NULL == handle)
260 : : return -1;
261 : :
262 : : /* verify correct existing and then free all */
263 [ + - ]: 32 : if (handle != rte_hash_find_existing(hash_name))
264 : : return -1;
265 : :
266 : 32 : rte_hash_free(handle);
267 : :
268 : : /* verify free correct */
269 [ + - ]: 32 : if (NULL != rte_hash_find_existing(hash_name))
270 : : return -1;
271 : : }
272 : :
273 : : return 0;
274 : : }
275 : :
276 : : static void
277 : 2 : fbk_clean(unsigned lcore_id)
278 : : {
279 : : char fbk_name[MAX_STRING_SIZE];
280 : : struct rte_fbk_hash_table *handle;
281 : : int i;
282 : :
283 : 2 : handle = rte_fbk_hash_find_existing("fr_test_once");
284 : 2 : rte_fbk_hash_free(handle);
285 : :
286 [ + + ]: 34 : for (i = 0; i < MAX_ITER_MULTI; i++) {
287 : : snprintf(fbk_name, sizeof(fbk_name), "fr_test_%d_%d", lcore_id, i);
288 : :
289 [ - + ]: 32 : if ((handle = rte_fbk_hash_find_existing(fbk_name)) != NULL)
290 : 0 : rte_fbk_hash_free(handle);
291 : : }
292 : 2 : }
293 : :
294 : : static int
295 : 2 : fbk_create_free(__rte_unused void *arg)
296 : : {
297 : : unsigned lcore_self = rte_lcore_id();
298 : : struct rte_fbk_hash_table *handle;
299 : : char fbk_name[MAX_STRING_SIZE];
300 : : int i;
301 : 2 : struct rte_fbk_hash_params fbk_params = {
302 : : .name = NULL,
303 : : .entries = 4,
304 : : .entries_per_bucket = 4,
305 : : .socket_id = 0,
306 : : .hash_func = rte_jhash_1word,
307 : : .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
308 : : };
309 : :
310 [ + + ]: 2 : WAIT_SYNCHRO_FOR_WORKERS();
311 : :
312 : : /* create the same fbk hash table simultaneously on all threads */
313 : 2 : fbk_params.name = "fr_test_once";
314 [ + + ]: 10 : for (i = 0; i < MAX_ITER_ONCE; i++) {
315 : 8 : handle = rte_fbk_hash_create(&fbk_params);
316 [ + + ]: 8 : if (handle != NULL)
317 : 1 : rte_atomic_fetch_add_explicit(&obj_count, 1, rte_memory_order_relaxed);
318 : : }
319 : :
320 : : /* create multiple fbk tables simultaneously */
321 [ + + ]: 34 : for (i = 0; i < MAX_ITER_MULTI; i++) {
322 : : snprintf(fbk_name, sizeof(fbk_name), "fr_test_%d_%d", lcore_self, i);
323 : 32 : fbk_params.name = fbk_name;
324 : :
325 : 32 : handle = rte_fbk_hash_create(&fbk_params);
326 [ + - ]: 32 : if (NULL == handle)
327 : : return -1;
328 : :
329 : : /* verify correct existing and then free all */
330 [ + - ]: 32 : if (handle != rte_fbk_hash_find_existing(fbk_name))
331 : : return -1;
332 : :
333 : 32 : rte_fbk_hash_free(handle);
334 : :
335 : : /* verify free correct */
336 [ + - ]: 32 : if (NULL != rte_fbk_hash_find_existing(fbk_name))
337 : : return -1;
338 : : }
339 : :
340 : : return 0;
341 : : }
342 : : #endif /* RTE_LIB_HASH */
343 : :
344 : : #ifdef RTE_LIB_LPM
345 : : static void
346 : 2 : lpm_clean(unsigned int lcore_id)
347 : : {
348 : : char lpm_name[MAX_STRING_SIZE];
349 : : struct rte_lpm *lpm;
350 : : int i;
351 : :
352 : 2 : lpm = rte_lpm_find_existing("fr_test_once");
353 : 2 : rte_lpm_free(lpm);
354 : :
355 [ + + ]: 14 : for (i = 0; i < MAX_LPM_ITER_TIMES; i++) {
356 : : snprintf(lpm_name, sizeof(lpm_name), "fr_test_%d_%d", lcore_id, i);
357 : :
358 [ - + ]: 12 : if ((lpm = rte_lpm_find_existing(lpm_name)) != NULL)
359 : 0 : rte_lpm_free(lpm);
360 : : }
361 : 2 : }
362 : :
363 : : static int
364 : 2 : lpm_create_free(__rte_unused void *arg)
365 : : {
366 : : unsigned lcore_self = rte_lcore_id();
367 : : struct rte_lpm *lpm;
368 : : struct rte_lpm_config config;
369 : :
370 : 2 : config.max_rules = 4;
371 : 2 : config.number_tbl8s = 256;
372 : 2 : config.flags = 0;
373 : : char lpm_name[MAX_STRING_SIZE];
374 : : int i;
375 : :
376 [ + + ]: 2 : WAIT_SYNCHRO_FOR_WORKERS();
377 : :
378 : : /* create the same lpm simultaneously on all threads */
379 [ + + ]: 10 : for (i = 0; i < MAX_ITER_ONCE; i++) {
380 : 8 : lpm = rte_lpm_create("fr_test_once", SOCKET_ID_ANY, &config);
381 [ + + ]: 8 : if (lpm != NULL)
382 : 1 : rte_atomic_fetch_add_explicit(&obj_count, 1, rte_memory_order_relaxed);
383 : : }
384 : :
385 : : /* create multiple fbk tables simultaneously */
386 [ + + ]: 10 : for (i = 0; i < MAX_LPM_ITER_TIMES; i++) {
387 : : snprintf(lpm_name, sizeof(lpm_name), "fr_test_%d_%d", lcore_self, i);
388 : 9 : lpm = rte_lpm_create(lpm_name, SOCKET_ID_ANY, &config);
389 [ + - ]: 12 : if (NULL == lpm)
390 : : return -1;
391 : :
392 : : /* verify correct existing and then free all */
393 [ + - ]: 12 : if (lpm != rte_lpm_find_existing(lpm_name))
394 : : return -1;
395 : :
396 : 12 : rte_lpm_free(lpm);
397 : :
398 : : /* verify free correct */
399 [ + - ]: 12 : if (NULL != rte_lpm_find_existing(lpm_name))
400 : : return -1;
401 : : }
402 : :
403 : : return 0;
404 : : }
405 : : #endif /* RTE_LIB_LPM */
406 : :
407 : : struct test_case{
408 : : case_func_t func;
409 : : void* arg;
410 : : case_clean_t clean;
411 : : char name[MAX_STRING_SIZE];
412 : : };
413 : :
414 : : /* All test cases in the test suite */
415 : : struct test_case test_cases[] = {
416 : : { test_eal_init_once, NULL, NULL, "eal init once" },
417 : : { ring_create_lookup, NULL, ring_clean, "ring create/lookup" },
418 : : { mempool_create_lookup, NULL, mempool_clean,
419 : : "mempool create/lookup" },
420 : : #ifdef RTE_LIB_HASH
421 : : { hash_create_free, NULL, hash_clean, "hash create/free" },
422 : : { fbk_create_free, NULL, fbk_clean, "fbk create/free" },
423 : : #endif /* RTE_LIB_HASH */
424 : : #ifdef RTE_LIB_LPM
425 : : { lpm_create_free, NULL, lpm_clean, "lpm create/free" },
426 : : #endif /* RTE_LIB_LPM */
427 : : };
428 : :
429 : : /**
430 : : * launch test case in two separate thread
431 : : */
432 : : static int
433 : 6 : launch_test(struct test_case *pt_case)
434 : : {
435 : : unsigned int lcore_id;
436 : : unsigned int cores;
437 : : unsigned int count;
438 : : int ret = 0;
439 : :
440 [ + - ]: 6 : if (pt_case->func == NULL)
441 : : return -1;
442 : :
443 : 6 : rte_atomic_store_explicit(&obj_count, 0, rte_memory_order_relaxed);
444 : 6 : rte_atomic_store_explicit(&synchro, 0, rte_memory_order_relaxed);
445 : :
446 : 6 : cores = RTE_MIN(rte_lcore_count(), MAX_LCORES);
447 [ + + ]: 12 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
448 [ + - ]: 6 : if (cores == 1)
449 : : break;
450 : 6 : cores--;
451 : 6 : rte_eal_remote_launch(pt_case->func, pt_case->arg, lcore_id);
452 : : }
453 : :
454 : 6 : rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
455 : :
456 [ - + ]: 6 : if (pt_case->func(pt_case->arg) < 0)
457 : : ret = -1;
458 : :
459 [ + + ]: 12 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
460 [ - + ]: 6 : if (rte_eal_wait_lcore(lcore_id) < 0)
461 : : ret = -1;
462 : : }
463 : :
464 [ + + ]: 18 : RTE_LCORE_FOREACH(lcore_id) {
465 [ + + ]: 12 : if (pt_case->clean != NULL)
466 : 10 : pt_case->clean(lcore_id);
467 : : }
468 : :
469 : 6 : count = rte_atomic_load_explicit(&obj_count, rte_memory_order_relaxed);
470 [ - + ]: 6 : if (count != 1) {
471 : : printf("%s: common object allocated %d times (should be 1)\n",
472 : 0 : pt_case->name, count);
473 : : ret = -1;
474 : : }
475 : :
476 : : return ret;
477 : : }
478 : :
479 : : /**
480 : : * Main entry of func_reentrancy test
481 : : */
482 : : static int
483 : 1 : test_func_reentrancy(void)
484 : : {
485 : : uint32_t case_id;
486 : : struct test_case *pt_case = NULL;
487 : :
488 : : if (RTE_EXEC_ENV_IS_WINDOWS)
489 : : return TEST_SKIPPED;
490 : :
491 [ - + ]: 1 : if (rte_lcore_count() < 2) {
492 : : printf("Not enough cores for func_reentrancy_autotest, expecting at least 2\n");
493 : 0 : return TEST_SKIPPED;
494 : : }
495 [ - + ]: 1 : else if (rte_lcore_count() > MAX_LCORES)
496 : : printf("Too many lcores, some cores will be disabled\n");
497 : :
498 [ + + ]: 7 : for (case_id = 0; case_id < RTE_DIM(test_cases); case_id++) {
499 : 6 : pt_case = &test_cases[case_id];
500 [ - + ]: 6 : if (pt_case->func == NULL)
501 : 0 : continue;
502 : :
503 [ - + ]: 6 : if (launch_test(pt_case) < 0) {
504 : 0 : printf("Func-ReEnt CASE %"PRIu32": %s FAIL\n", case_id, pt_case->name);
505 : 0 : return -1;
506 : : }
507 : 6 : printf("Func-ReEnt CASE %"PRIu32": %s PASS\n", case_id, pt_case->name);
508 : : }
509 : :
510 : : return 0;
511 : : }
512 : :
513 : 253 : REGISTER_FAST_TEST(func_reentrancy_autotest, false, true, test_func_reentrancy);
|