xref: /dpdk/app/test/test_lcore_var.c (revision b0faa8330bfdc919c6591850e883b57304bd0fbe)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2024 Ericsson AB
3  */
4 
5 #include <inttypes.h>
6 #include <stdio.h>
7 #include <string.h>
8 
9 #include <rte_launch.h>
10 #include <rte_lcore_var.h>
11 #include <rte_random.h>
12 
13 #include "test.h"
14 
15 #define MIN_LCORES 2
16 
17 RTE_LCORE_VAR_HANDLE(int, test_int);
18 RTE_LCORE_VAR_HANDLE(char, test_char);
19 RTE_LCORE_VAR_HANDLE(long, test_long_sized);
20 RTE_LCORE_VAR_HANDLE(short, test_short);
21 RTE_LCORE_VAR_HANDLE(long, test_long_sized_aligned);
22 
23 struct int_checker_state {
24 	int old_value;
25 	int new_value;
26 	bool success;
27 };
28 
29 static void
30 rand_blk(void *blk, size_t size)
31 {
32 	size_t i;
33 
34 	for (i = 0; i < size; i++)
35 		((unsigned char *)blk)[i] = (unsigned char)rte_rand();
36 }
37 
38 static bool
39 is_ptr_aligned(const void *ptr, size_t align)
40 {
41 	return ptr != NULL ? (uintptr_t)ptr % align == 0 : false;
42 }
43 
44 static int
45 check_int(void *arg)
46 {
47 	struct int_checker_state *state = arg;
48 
49 	int *ptr = RTE_LCORE_VAR(test_int);
50 
51 	bool naturally_aligned = is_ptr_aligned(ptr, sizeof(int));
52 
53 	bool equal = *(RTE_LCORE_VAR(test_int)) == state->old_value;
54 
55 	state->success = equal && naturally_aligned;
56 
57 	*ptr = state->new_value;
58 
59 	return 0;
60 }
61 
62 RTE_LCORE_VAR_INIT(test_int);
63 RTE_LCORE_VAR_INIT(test_char);
64 RTE_LCORE_VAR_INIT_SIZE(test_long_sized, 32);
65 RTE_LCORE_VAR_INIT(test_short);
66 RTE_LCORE_VAR_INIT_SIZE_ALIGN(test_long_sized_aligned, sizeof(long), RTE_CACHE_LINE_SIZE);
67 
68 static int
69 test_int_lvar(void)
70 {
71 	unsigned int lcore_id;
72 
73 	struct int_checker_state states[RTE_MAX_LCORE] = {};
74 
75 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
76 		struct int_checker_state *state = &states[lcore_id];
77 
78 		state->old_value = (int)rte_rand();
79 		state->new_value = (int)rte_rand();
80 
81 		*RTE_LCORE_VAR_LCORE(lcore_id, test_int) = state->old_value;
82 	}
83 
84 	RTE_LCORE_FOREACH_WORKER(lcore_id)
85 		rte_eal_remote_launch(check_int, &states[lcore_id], lcore_id);
86 
87 	rte_eal_mp_wait_lcore();
88 
89 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
90 		struct int_checker_state *state = &states[lcore_id];
91 		int value;
92 
93 		TEST_ASSERT(state->success,
94 				"Unexpected value encountered on lcore %d", lcore_id);
95 
96 		value = *RTE_LCORE_VAR_LCORE(lcore_id, test_int);
97 		TEST_ASSERT_EQUAL(state->new_value, value,
98 				"Lcore %d failed to update int", lcore_id);
99 	}
100 
101 	/* take the opportunity to test the foreach macro */
102 	int *v;
103 	unsigned int i = 0;
104 	RTE_LCORE_VAR_FOREACH(lcore_id, v, test_int) {
105 		TEST_ASSERT_EQUAL(i, lcore_id,
106 				"Encountered lcore id %d while expecting %d during iteration",
107 				lcore_id, i);
108 		TEST_ASSERT_EQUAL(states[lcore_id].new_value, *v,
109 				"Unexpected value on lcore %d during iteration", lcore_id);
110 		i++;
111 	}
112 
113 	return TEST_SUCCESS;
114 }
115 
116 static int
117 test_sized_alignment(void)
118 {
119 	unsigned int lcore_id;
120 	long *v;
121 
122 	RTE_LCORE_VAR_FOREACH(lcore_id, v, test_long_sized) {
123 		TEST_ASSERT(is_ptr_aligned(v, alignof(long)), "Type-derived alignment failed");
124 	}
125 
126 	RTE_LCORE_VAR_FOREACH(lcore_id, v, test_long_sized_aligned) {
127 		TEST_ASSERT(is_ptr_aligned(v, RTE_CACHE_LINE_SIZE), "Explicit alignment failed");
128 	}
129 
130 	return TEST_SUCCESS;
131 }
132 
133 /* private, larger, struct */
134 #define TEST_STRUCT_DATA_SIZE 1234
135 
136 struct test_struct {
137 	uint8_t data[TEST_STRUCT_DATA_SIZE];
138 };
139 
140 static RTE_LCORE_VAR_HANDLE(char, before_struct);
141 static RTE_LCORE_VAR_HANDLE(struct test_struct, test_struct);
142 static RTE_LCORE_VAR_HANDLE(char, after_struct);
143 
144 struct struct_checker_state {
145 	struct test_struct old_value;
146 	struct test_struct new_value;
147 	bool success;
148 };
149 
150 static int check_struct(void *arg)
151 {
152 	struct struct_checker_state *state = arg;
153 
154 	struct test_struct *lcore_struct = RTE_LCORE_VAR(test_struct);
155 
156 	bool properly_aligned = is_ptr_aligned(test_struct, alignof(struct test_struct));
157 
158 	bool equal = memcmp(lcore_struct->data, state->old_value.data, TEST_STRUCT_DATA_SIZE) == 0;
159 
160 	state->success = equal && properly_aligned;
161 
162 	memcpy(lcore_struct->data, state->new_value.data, TEST_STRUCT_DATA_SIZE);
163 
164 	return 0;
165 }
166 
167 static int
168 test_struct_lvar(void)
169 {
170 	unsigned int lcore_id;
171 
172 	RTE_LCORE_VAR_ALLOC(before_struct);
173 	RTE_LCORE_VAR_ALLOC(test_struct);
174 	RTE_LCORE_VAR_ALLOC(after_struct);
175 
176 	struct struct_checker_state states[RTE_MAX_LCORE];
177 
178 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
179 		struct struct_checker_state *state = &states[lcore_id];
180 
181 		rand_blk(state->old_value.data, TEST_STRUCT_DATA_SIZE);
182 		rand_blk(state->new_value.data, TEST_STRUCT_DATA_SIZE);
183 
184 		memcpy(RTE_LCORE_VAR_LCORE(lcore_id, test_struct)->data,
185 				state->old_value.data, TEST_STRUCT_DATA_SIZE);
186 	}
187 
188 	RTE_LCORE_FOREACH_WORKER(lcore_id)
189 		rte_eal_remote_launch(check_struct, &states[lcore_id], lcore_id);
190 
191 	rte_eal_mp_wait_lcore();
192 
193 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
194 		struct struct_checker_state *state = &states[lcore_id];
195 		struct test_struct *lstruct = RTE_LCORE_VAR_LCORE(lcore_id, test_struct);
196 
197 		TEST_ASSERT(state->success, "Unexpected value encountered on lcore %d", lcore_id);
198 
199 		bool equal = memcmp(lstruct->data, state->new_value.data,
200 				TEST_STRUCT_DATA_SIZE) == 0;
201 
202 		TEST_ASSERT(equal, "Lcore %d failed to update struct", lcore_id);
203 	}
204 
205 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
206 		char before = *RTE_LCORE_VAR_LCORE(lcore_id, before_struct);
207 		char after = *RTE_LCORE_VAR_LCORE(lcore_id, after_struct);
208 
209 		TEST_ASSERT_EQUAL(before, 0,
210 				"Lcore variable before test struct was modified on lcore %d",
211 				lcore_id);
212 		TEST_ASSERT_EQUAL(after, 0,
213 				"Lcore variable after test struct was modified on lcore %d",
214 				lcore_id);
215 	}
216 
217 	return TEST_SUCCESS;
218 }
219 
220 #define TEST_ARRAY_SIZE 99
221 
222 typedef uint16_t test_array_t[TEST_ARRAY_SIZE];
223 
224 static void test_array_init_rand(test_array_t a)
225 {
226 	size_t i;
227 	for (i = 0; i < TEST_ARRAY_SIZE; i++)
228 		a[i] = (uint16_t)rte_rand();
229 }
230 
231 static bool test_array_equal(test_array_t a, test_array_t b)
232 {
233 	size_t i;
234 	for (i = 0; i < TEST_ARRAY_SIZE; i++) {
235 		if (a[i] != b[i])
236 			return false;
237 	}
238 	return true;
239 }
240 
241 static void test_array_copy(test_array_t dst, const test_array_t src)
242 {
243 	size_t i;
244 	for (i = 0; i < TEST_ARRAY_SIZE; i++)
245 		dst[i] = src[i];
246 }
247 
248 static RTE_LCORE_VAR_HANDLE(char, before_array);
249 static RTE_LCORE_VAR_HANDLE(test_array_t, test_array);
250 static RTE_LCORE_VAR_HANDLE(char, after_array);
251 
252 struct array_checker_state {
253 	test_array_t old_value;
254 	test_array_t new_value;
255 	bool success;
256 };
257 
258 static int check_array(void *arg)
259 {
260 	struct array_checker_state *state = arg;
261 
262 	test_array_t *lcore_array = RTE_LCORE_VAR(test_array);
263 
264 	bool properly_aligned = is_ptr_aligned(lcore_array, alignof(test_array_t));
265 
266 	bool equal = test_array_equal(*lcore_array, state->old_value);
267 
268 	state->success = equal && properly_aligned;
269 
270 	test_array_copy(*lcore_array, state->new_value);
271 
272 	return 0;
273 }
274 
275 static int
276 test_array_lvar(void)
277 {
278 	unsigned int lcore_id;
279 
280 	RTE_LCORE_VAR_ALLOC(before_array);
281 	RTE_LCORE_VAR_ALLOC(test_array);
282 	RTE_LCORE_VAR_ALLOC(after_array);
283 
284 	struct array_checker_state states[RTE_MAX_LCORE];
285 
286 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
287 		struct array_checker_state *state = &states[lcore_id];
288 
289 		test_array_init_rand(state->new_value);
290 		test_array_init_rand(state->old_value);
291 
292 		test_array_copy(*RTE_LCORE_VAR_LCORE(lcore_id, test_array), state->old_value);
293 	}
294 
295 	RTE_LCORE_FOREACH_WORKER(lcore_id)
296 		rte_eal_remote_launch(check_array, &states[lcore_id], lcore_id);
297 
298 	rte_eal_mp_wait_lcore();
299 
300 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
301 		struct array_checker_state *state = &states[lcore_id];
302 		test_array_t *larray = RTE_LCORE_VAR_LCORE(lcore_id, test_array);
303 
304 		TEST_ASSERT(state->success, "Unexpected value encountered on lcore %d", lcore_id);
305 
306 		bool equal = test_array_equal(*larray, state->new_value);
307 
308 		TEST_ASSERT(equal, "Lcore %d failed to update array", lcore_id);
309 	}
310 
311 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
312 		char before = *RTE_LCORE_VAR_LCORE(lcore_id, before_array);
313 		char after = *RTE_LCORE_VAR_LCORE(lcore_id, after_array);
314 
315 		TEST_ASSERT_EQUAL(before, 0,
316 				"Lcore variable before test array was modified on lcore %d",
317 				lcore_id);
318 		TEST_ASSERT_EQUAL(after, 0,
319 				"Lcore variable after test array was modified on lcore %d",
320 				lcore_id);
321 	}
322 
323 	return TEST_SUCCESS;
324 }
325 
326 #define MANY_LVARS (2 * RTE_MAX_LCORE_VAR / sizeof(uint32_t))
327 
328 static int
329 test_many_lvars(void)
330 {
331 	uint32_t **handlers = malloc(sizeof(uint32_t *) * MANY_LVARS);
332 	unsigned int i;
333 
334 	TEST_ASSERT(handlers != NULL, "Unable to allocate memory");
335 
336 	for (i = 0; i < MANY_LVARS; i++) {
337 		unsigned int lcore_id;
338 
339 		RTE_LCORE_VAR_ALLOC(handlers[i]);
340 
341 		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
342 			uint32_t *v = RTE_LCORE_VAR_LCORE(lcore_id, handlers[i]);
343 			*v = (uint32_t)(i * lcore_id);
344 		}
345 	}
346 
347 	for (i = 0; i < MANY_LVARS; i++) {
348 		unsigned int lcore_id;
349 
350 		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
351 			uint32_t v = *RTE_LCORE_VAR_LCORE(lcore_id, handlers[i]);
352 			TEST_ASSERT_EQUAL((uint32_t)(i * lcore_id), v,
353 					"Unexpected lcore variable value on lcore %d",
354 					lcore_id);
355 		}
356 	}
357 
358 	free(handlers);
359 
360 	return TEST_SUCCESS;
361 }
362 
363 static int
364 test_large_lvar(void)
365 {
366 	RTE_LCORE_VAR_HANDLE(unsigned char, large);
367 	unsigned int lcore_id;
368 
369 	RTE_LCORE_VAR_ALLOC_SIZE(large, RTE_MAX_LCORE_VAR);
370 
371 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
372 		unsigned char *ptr = RTE_LCORE_VAR_LCORE(lcore_id, large);
373 
374 		memset(ptr, (unsigned char)lcore_id, RTE_MAX_LCORE_VAR);
375 	}
376 
377 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
378 		unsigned char *ptr = RTE_LCORE_VAR_LCORE(lcore_id, large);
379 		size_t i;
380 
381 		for (i = 0; i < RTE_MAX_LCORE_VAR; i++)
382 			TEST_ASSERT_EQUAL(ptr[i], (unsigned char)lcore_id,
383 					"Large lcore variable value is corrupted on lcore %d.",
384 					lcore_id);
385 	}
386 
387 	return TEST_SUCCESS;
388 }
389 
390 static struct unit_test_suite lcore_var_testsuite = {
391 	.suite_name = "lcore variable autotest",
392 	.unit_test_cases = {
393 		TEST_CASE(test_int_lvar),
394 		TEST_CASE(test_sized_alignment),
395 		TEST_CASE(test_struct_lvar),
396 		TEST_CASE(test_array_lvar),
397 		TEST_CASE(test_many_lvars),
398 		TEST_CASE(test_large_lvar),
399 		TEST_CASES_END()
400 	},
401 };
402 
403 static int test_lcore_var(void)
404 {
405 	if (rte_lcore_count() < MIN_LCORES) {
406 		printf("Not enough cores for lcore_var_autotest; expecting at least %d.\n",
407 				MIN_LCORES);
408 		return TEST_SKIPPED;
409 	}
410 
411 	return unit_test_suite_runner(&lcore_var_testsuite);
412 }
413 
414 REGISTER_FAST_TEST(lcore_var_autotest, true, false, test_lcore_var);
415