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