Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2019 Intel Corporation
3 : : */
4 : :
5 : : #include "test.h"
6 : :
7 : : #include <stdio.h>
8 : : #include <stdint.h>
9 : : #include <string.h>
10 : : #include <stdarg.h>
11 : : #include <errno.h>
12 : : #include <stdlib.h>
13 : : #ifndef RTE_EXEC_ENV_WINDOWS
14 : : #include <sys/mman.h>
15 : : #endif
16 : : #include <sys/queue.h>
17 : : #include <unistd.h>
18 : :
19 : : #include <rte_common.h>
20 : : #include <rte_memory.h>
21 : : #include <rte_per_lcore.h>
22 : : #include <rte_launch.h>
23 : : #include <rte_eal.h>
24 : : #include <rte_lcore.h>
25 : : #include <rte_malloc.h>
26 : : #include <rte_cycles.h>
27 : : #include <rte_random.h>
28 : : #include <rte_string_fns.h>
29 : :
30 : : #define N 10000
31 : :
32 : : static int
33 : : is_mem_on_socket(int32_t socket);
34 : :
35 : : static int32_t
36 : : addr_to_socket(void *addr);
37 : :
38 : : /*
39 : : * Malloc
40 : : * ======
41 : : *
42 : : * Allocate some dynamic memory from heap (3 areas). Check that areas
43 : : * don't overlap and that alignment constraints match. This test is
44 : : * done many times on different lcores simultaneously.
45 : : */
46 : :
47 : : /* Test if memory overlaps: return 1 if true, or 0 if false. */
48 : : static int
49 : : is_memory_overlap(void *p1, size_t len1, void *p2, size_t len2)
50 : : {
51 : 10030 : uintptr_t ptr1 = (uintptr_t)p1;
52 : 20060 : uintptr_t ptr2 = (uintptr_t)p2;
53 : :
54 [ - + - - : 30090 : if (ptr2 >= ptr1 && (ptr2 - ptr1) < len1)
- + - - -
+ - - - +
- - - + -
- - + -
- ]
55 : : return 1;
56 [ + - - + : 30090 : else if (ptr2 < ptr1 && (ptr1 - ptr2) < len2)
+ - - + +
- - + + -
- + + - -
+ + - -
+ ]
57 : : return 1;
58 : : return 0;
59 : : }
60 : :
61 : : static int
62 : : is_aligned(void *p, int align)
63 : : {
64 : : uintptr_t addr = (uintptr_t)p;
65 : : unsigned mask = align - 1;
66 : :
67 : : if (addr & mask)
68 : : return 0;
69 : : return 1;
70 : : }
71 : :
72 : : static int
73 : 1 : test_align_overlap_per_lcore(__rte_unused void *arg)
74 : : {
75 : : const unsigned align1 = 8,
76 : : align2 = 64,
77 : : align3 = 2048;
78 : : unsigned i,j;
79 : : void *p1 = NULL, *p2 = NULL, *p3 = NULL;
80 : : int ret = 0;
81 : :
82 [ + + ]: 10001 : for (i = 0; i < N; i++) {
83 : 10000 : p1 = rte_zmalloc("dummy", 1000, align1);
84 [ + - ]: 10000 : if (!p1){
85 : : printf("rte_zmalloc returned NULL (i=%u)\n", i);
86 : : ret = -1;
87 : 0 : break;
88 : : }
89 [ + + ]: 10010000 : for(j = 0; j < 1000 ; j++) {
90 [ - + ]: 10000000 : if( *(char *)p1 != 0) {
91 : : printf("rte_zmalloc didn't zero the allocated memory\n");
92 : : ret = -1;
93 : : }
94 : : }
95 : 10000 : p2 = rte_malloc("dummy", 1000, align2);
96 [ - + ]: 10000 : if (!p2){
97 : : printf("rte_malloc returned NULL (i=%u)\n", i);
98 : : ret = -1;
99 : 0 : rte_free(p1);
100 : 0 : break;
101 : : }
102 : 10000 : p3 = rte_malloc("dummy", 1000, align3);
103 [ - + ]: 10000 : if (!p3){
104 : : printf("rte_malloc returned NULL (i=%u)\n", i);
105 : : ret = -1;
106 : 0 : rte_free(p1);
107 : 0 : rte_free(p2);
108 : 0 : break;
109 : : }
110 : : if (is_memory_overlap(p1, 1000, p2, 1000)) {
111 : : printf("p1 and p2 overlaps\n");
112 : : ret = -1;
113 : : }
114 : : if (is_memory_overlap(p2, 1000, p3, 1000)) {
115 : : printf("p2 and p3 overlaps\n");
116 : : ret = -1;
117 : : }
118 : : if (is_memory_overlap(p1, 1000, p3, 1000)) {
119 : : printf("p1 and p3 overlaps\n");
120 : : ret = -1;
121 : : }
122 : : if (!is_aligned(p1, align1)) {
123 : : printf("p1 is not aligned\n");
124 : : ret = -1;
125 : : }
126 : : if (!is_aligned(p2, align2)) {
127 : : printf("p2 is not aligned\n");
128 : : ret = -1;
129 : : }
130 : : if (!is_aligned(p3, align3)) {
131 : : printf("p3 is not aligned\n");
132 : : ret = -1;
133 : : }
134 : 10000 : rte_free(p1);
135 : 10000 : rte_free(p2);
136 : 10000 : rte_free(p3);
137 : : }
138 : 1 : rte_malloc_dump_stats(stdout, "dummy");
139 : :
140 : 1 : return ret;
141 : : }
142 : :
143 : : static int
144 : 1 : test_reordered_free_per_lcore(__rte_unused void *arg)
145 : : {
146 : : const unsigned align1 = 8,
147 : : align2 = 64,
148 : : align3 = 2048;
149 : : unsigned i,j;
150 : : void *p1, *p2, *p3;
151 : : int ret = 0;
152 : :
153 [ + + ]: 31 : for (i = 0; i < 30; i++) {
154 : 30 : p1 = rte_zmalloc("dummy", 1000, align1);
155 [ + - ]: 30 : if (!p1){
156 : : printf("rte_zmalloc returned NULL (i=%u)\n", i);
157 : : ret = -1;
158 : 0 : break;
159 : : }
160 [ + + ]: 30030 : for(j = 0; j < 1000 ; j++) {
161 [ - + ]: 30000 : if( *(char *)p1 != 0) {
162 : : printf("rte_zmalloc didn't zero the allocated memory\n");
163 : : ret = -1;
164 : : }
165 : : }
166 : : /* use calloc to allocate 1000 16-byte items this time */
167 : 30 : p2 = rte_calloc("dummy", 1000, 16, align2);
168 : : /* for third request use regular malloc again */
169 : 30 : p3 = rte_malloc("dummy", 1000, align3);
170 [ - + ]: 30 : if (!p2 || !p3){
171 : : printf("rte_malloc returned NULL (i=%u)\n", i);
172 : : ret = -1;
173 : 0 : break;
174 : : }
175 : : if (is_memory_overlap(p1, 1000, p2, 1000)) {
176 : : printf("p1 and p2 overlaps\n");
177 : : ret = -1;
178 : : }
179 : : if (is_memory_overlap(p2, 1000, p3, 1000)) {
180 : : printf("p2 and p3 overlaps\n");
181 : : ret = -1;
182 : : }
183 : : if (is_memory_overlap(p1, 1000, p3, 1000)) {
184 : : printf("p1 and p3 overlaps\n");
185 : : ret = -1;
186 : : }
187 : : if (!is_aligned(p1, align1)) {
188 : : printf("p1 is not aligned\n");
189 : : ret = -1;
190 : : }
191 : : if (!is_aligned(p2, align2)) {
192 : : printf("p2 is not aligned\n");
193 : : ret = -1;
194 : : }
195 : : if (!is_aligned(p3, align3)) {
196 : : printf("p3 is not aligned\n");
197 : : ret = -1;
198 : : }
199 : : /* try freeing in every possible order */
200 [ + + + + : 30 : switch (i%6){
+ + ]
201 : 5 : case 0:
202 : 5 : rte_free(p1);
203 : 5 : rte_free(p2);
204 : 5 : rte_free(p3);
205 : 5 : break;
206 : 5 : case 1:
207 : 5 : rte_free(p1);
208 : 5 : rte_free(p3);
209 : 5 : rte_free(p2);
210 : 5 : break;
211 : 5 : case 2:
212 : 5 : rte_free(p2);
213 : 5 : rte_free(p1);
214 : 5 : rte_free(p3);
215 : 5 : break;
216 : 5 : case 3:
217 : 5 : rte_free(p2);
218 : 5 : rte_free(p3);
219 : 5 : rte_free(p1);
220 : 5 : break;
221 : 5 : case 4:
222 : 5 : rte_free(p3);
223 : 5 : rte_free(p1);
224 : 5 : rte_free(p2);
225 : 5 : break;
226 : 5 : case 5:
227 : 5 : rte_free(p3);
228 : 5 : rte_free(p2);
229 : 5 : rte_free(p1);
230 : 5 : break;
231 : : }
232 : : }
233 : 1 : rte_malloc_dump_stats(stdout, "dummy");
234 : :
235 : 1 : return ret;
236 : : }
237 : :
238 : : /* test function inside the malloc lib*/
239 : : static int
240 : 1 : test_str_to_size(void)
241 : : {
242 : : struct {
243 : : const char *str;
244 : : uint64_t value;
245 : 1 : } test_values[] =
246 : : {{ "5G", (uint64_t)5 * 1024 * 1024 *1024 },
247 : : {"0x20g", (uint64_t)0x20 * 1024 * 1024 *1024},
248 : : {"10M", 10 * 1024 * 1024},
249 : : {"050m", 050 * 1024 * 1024},
250 : : {"8K", 8 * 1024},
251 : : {"15k", 15 * 1024},
252 : : {"0200", 0200},
253 : : {"0x103", 0x103},
254 : : {"432", 432},
255 : : {"-1", 0}, /* negative values return 0 */
256 : : {" -2", 0},
257 : : {" -3MB", 0},
258 : : {"18446744073709551616", 0} /* ULLONG_MAX + 1 == out of range*/
259 : : };
260 : : unsigned i;
261 [ + + ]: 14 : for (i = 0; i < RTE_DIM(test_values); i++)
262 [ + - ]: 13 : if (rte_str_to_size(test_values[i].str) != test_values[i].value)
263 : : return -1;
264 : : return 0;
265 : : }
266 : :
267 : : static int
268 : 1 : test_multi_alloc_statistics(void)
269 : : {
270 : : int socket = 0;
271 : : struct rte_malloc_socket_stats pre_stats, post_stats ,first_stats, second_stats;
272 : : size_t size = 2048;
273 : : int align = 1024;
274 : : int overhead = 0;
275 : :
276 : : /* Dynamically calculate the overhead by allocating one cacheline and
277 : : * then comparing what was allocated from the heap.
278 : : */
279 : 1 : rte_malloc_get_socket_stats(socket, &pre_stats);
280 : :
281 : 1 : void *dummy = rte_malloc_socket(NULL, RTE_CACHE_LINE_SIZE, 0, socket);
282 [ + - ]: 1 : if (dummy == NULL)
283 : : return -1;
284 : :
285 : 1 : rte_malloc_get_socket_stats(socket, &post_stats);
286 : :
287 : : /* after subtracting cache line, remainder is overhead */
288 : 1 : overhead = post_stats.heap_allocsz_bytes - pre_stats.heap_allocsz_bytes;
289 : : overhead -= RTE_CACHE_LINE_SIZE;
290 : :
291 : 1 : rte_free(dummy);
292 : :
293 : : /* Now start the real tests */
294 : 1 : rte_malloc_get_socket_stats(socket, &pre_stats);
295 : :
296 : 1 : void *p1 = rte_malloc_socket("stats", size , align, socket);
297 [ + - ]: 1 : if (!p1)
298 : : return -1;
299 : 1 : rte_free(p1);
300 : 1 : rte_malloc_dump_stats(stdout, "stats");
301 : :
302 : 1 : rte_malloc_get_socket_stats(socket,&post_stats);
303 : : /* Check statistics reported are correct */
304 : : /* All post stats should be equal to pre stats after alloc freed */
305 [ + - ]: 1 : if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) ||
306 [ + - ]: 1 : (post_stats.heap_freesz_bytes != pre_stats.heap_freesz_bytes) ||
307 [ + - ]: 1 : (post_stats.heap_allocsz_bytes != pre_stats.heap_allocsz_bytes) ||
308 [ - + ]: 1 : (post_stats.alloc_count != pre_stats.alloc_count) ||
309 : : (post_stats.free_count != pre_stats.free_count)) {
310 : : printf("Malloc statistics are incorrect - freed alloc\n");
311 : 0 : return -1;
312 : : }
313 : : /* Check two consecutive allocations */
314 : : size = 1024;
315 : : align = 0;
316 : 1 : rte_malloc_get_socket_stats(socket,&pre_stats);
317 : 1 : void *p2 = rte_malloc_socket("add", size ,align, socket);
318 [ + - ]: 1 : if (!p2)
319 : : return -1;
320 : 1 : rte_malloc_get_socket_stats(socket,&first_stats);
321 : :
322 : 1 : void *p3 = rte_malloc_socket("add2", size,align, socket);
323 [ + - ]: 1 : if (!p3)
324 : : return -1;
325 : :
326 : 1 : rte_malloc_get_socket_stats(socket,&second_stats);
327 : :
328 : 1 : rte_free(p2);
329 : 1 : rte_free(p3);
330 : :
331 : : /* After freeing both allocations check stats return to original */
332 : 1 : rte_malloc_get_socket_stats(socket, &post_stats);
333 : :
334 [ - + ]: 1 : if(second_stats.heap_totalsz_bytes != first_stats.heap_totalsz_bytes) {
335 : : printf("Incorrect heap statistics: Total size \n");
336 : 0 : return -1;
337 : : }
338 : : /* Check allocated size is equal to two additions plus overhead */
339 : 1 : if(second_stats.heap_allocsz_bytes !=
340 [ - + ]: 1 : size + overhead + first_stats.heap_allocsz_bytes) {
341 : : printf("Incorrect heap statistics: Allocated size \n");
342 : 0 : return -1;
343 : : }
344 : : /* Check that allocation count increments correctly i.e. +1 */
345 [ - + ]: 1 : if (second_stats.alloc_count != first_stats.alloc_count + 1) {
346 : : printf("Incorrect heap statistics: Allocated count \n");
347 : 0 : return -1;
348 : : }
349 : :
350 [ - + ]: 1 : if (second_stats.free_count != first_stats.free_count){
351 : : printf("Incorrect heap statistics: Free count \n");
352 : 0 : return -1;
353 : : }
354 : :
355 : : /* Make sure that we didn't touch our greatest chunk: 2 * 11M) */
356 [ - + ]: 1 : if (post_stats.greatest_free_size != pre_stats.greatest_free_size) {
357 : : printf("Incorrect heap statistics: Greatest free size \n");
358 : 0 : return -1;
359 : : }
360 : : /* Free size must equal the original free size minus the new allocation*/
361 [ - + ]: 1 : if (first_stats.heap_freesz_bytes <= second_stats.heap_freesz_bytes) {
362 : : printf("Incorrect heap statistics: Free size \n");
363 : 0 : return -1;
364 : : }
365 : :
366 [ + - ]: 1 : if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) ||
367 [ + - ]: 1 : (post_stats.heap_freesz_bytes != pre_stats.heap_freesz_bytes) ||
368 [ + - ]: 1 : (post_stats.heap_allocsz_bytes != pre_stats.heap_allocsz_bytes) ||
369 [ - + ]: 1 : (post_stats.alloc_count != pre_stats.alloc_count) ||
370 : : (post_stats.free_count != pre_stats.free_count)) {
371 : : printf("Malloc statistics are incorrect - freed alloc\n");
372 : 0 : return -1;
373 : : }
374 : : return 0;
375 : : }
376 : :
377 : : #ifdef RTE_EXEC_ENV_WINDOWS
378 : : static int
379 : : test_realloc(void)
380 : : {
381 : : return TEST_SKIPPED;
382 : : }
383 : : #else
384 : :
385 : : static int
386 : 1 : test_realloc_socket(int socket)
387 : : {
388 : 1 : const char hello_str[] = "Hello, world!";
389 : : const unsigned size1 = 1024;
390 : : const unsigned size2 = size1 + 1024;
391 : : const unsigned size3 = size2;
392 : : const unsigned size4 = size3 + 1024;
393 : :
394 : : /* test data is the same even if element is moved*/
395 : 1 : char *ptr1 = rte_zmalloc_socket(
396 : : NULL, size1, RTE_CACHE_LINE_SIZE, socket);
397 [ - + ]: 1 : if (!ptr1){
398 : : printf("NULL pointer returned from rte_zmalloc\n");
399 : 0 : return -1;
400 : : }
401 : : strlcpy(ptr1, hello_str, size1);
402 : 1 : char *ptr2 = rte_realloc_socket(
403 : : ptr1, size2, RTE_CACHE_LINE_SIZE, socket);
404 [ - + ]: 1 : if (!ptr2){
405 : 0 : rte_free(ptr1);
406 : : printf("NULL pointer returned from rte_realloc\n");
407 : 0 : return -1;
408 : : }
409 [ - + ]: 1 : if (ptr1 == ptr2){
410 : : printf("unexpected - ptr1 == ptr2\n");
411 : : }
412 [ - + ]: 1 : if (strcmp(ptr2, hello_str) != 0){
413 : : printf("Error - lost data from pointed area\n");
414 : 0 : rte_free(ptr2);
415 : 0 : return -1;
416 : : }
417 : : unsigned i;
418 [ + + ]: 1012 : for (i = strnlen(hello_str, sizeof(hello_str)); i < size1; i++)
419 [ - + ]: 1011 : if (ptr2[i] != 0){
420 : : printf("Bad data in realloc\n");
421 : 0 : rte_free(ptr2);
422 : 0 : return -1;
423 : : }
424 : : /* now allocate third element, free the second
425 : : * and resize third. It should not move. (ptr1 is now invalid)
426 : : */
427 : 1 : char *ptr3 = rte_zmalloc_socket(
428 : : NULL, size3, RTE_CACHE_LINE_SIZE, socket);
429 [ - + ]: 1 : if (!ptr3){
430 : : printf("NULL pointer returned from rte_zmalloc\n");
431 : 0 : rte_free(ptr2);
432 : 0 : return -1;
433 : : }
434 [ + + ]: 2049 : for (i = 0; i < size3; i++)
435 [ - + ]: 2048 : if (ptr3[i] != 0){
436 : : printf("Bad data in zmalloc\n");
437 : 0 : rte_free(ptr3);
438 : 0 : rte_free(ptr2);
439 : 0 : return -1;
440 : : }
441 : 1 : rte_free(ptr2);
442 : : /* first resize to half the size of the freed block */
443 : 1 : char *ptr4 = rte_realloc_socket(
444 : : ptr3, size4, RTE_CACHE_LINE_SIZE, socket);
445 [ - + ]: 1 : if (!ptr4){
446 : : printf("NULL pointer returned from rte_realloc\n");
447 : 0 : rte_free(ptr3);
448 : 0 : return -1;
449 : : }
450 [ - + ]: 1 : if (ptr3 != ptr4){
451 : : printf("Unexpected - ptr4 != ptr3\n");
452 : 0 : rte_free(ptr4);
453 : 0 : return -1;
454 : : }
455 : : /* now resize again to the full size of the freed block */
456 : 1 : ptr4 = rte_realloc_socket(ptr3, size3 + size2 + size1,
457 : : RTE_CACHE_LINE_SIZE, socket);
458 [ - + ]: 1 : if (ptr3 != ptr4){
459 : : printf("Unexpected - ptr4 != ptr3 on second resize\n");
460 : 0 : rte_free(ptr4);
461 : 0 : return -1;
462 : : }
463 : 1 : rte_free(ptr4);
464 : :
465 : : /* now try a resize to a smaller size, see if it works */
466 : : const unsigned size5 = 1024;
467 : : const unsigned size6 = size5 / 2;
468 : 1 : char *ptr5 = rte_malloc_socket(
469 : : NULL, size5, RTE_CACHE_LINE_SIZE, socket);
470 [ - + ]: 1 : if (!ptr5){
471 : : printf("NULL pointer returned from rte_malloc\n");
472 : 0 : return -1;
473 : : }
474 : 1 : char *ptr6 = rte_realloc_socket(
475 : : ptr5, size6, RTE_CACHE_LINE_SIZE, socket);
476 [ - + ]: 1 : if (!ptr6){
477 : : printf("NULL pointer returned from rte_realloc\n");
478 : 0 : rte_free(ptr5);
479 : 0 : return -1;
480 : : }
481 [ - + ]: 1 : if (ptr5 != ptr6){
482 : : printf("Error, resizing to a smaller size moved data\n");
483 : 0 : rte_free(ptr6);
484 : 0 : return -1;
485 : : }
486 : 1 : rte_free(ptr6);
487 : :
488 : : /* check for behaviour changing alignment */
489 : : const unsigned size7 = 1024;
490 : : const unsigned orig_align = RTE_CACHE_LINE_SIZE;
491 : : unsigned new_align = RTE_CACHE_LINE_SIZE * 2;
492 : 1 : char *ptr7 = rte_malloc_socket(NULL, size7, orig_align, socket);
493 [ - + ]: 1 : if (!ptr7){
494 : : printf("NULL pointer returned from rte_malloc\n");
495 : 0 : return -1;
496 : : }
497 : : /* calc an alignment we don't already have */
498 [ + + ]: 5 : while(RTE_PTR_ALIGN(ptr7, new_align) == ptr7)
499 : 4 : new_align *= 2;
500 : 1 : char *ptr8 = rte_realloc_socket(ptr7, size7, new_align, socket);
501 [ - + ]: 1 : if (!ptr8){
502 : : printf("NULL pointer returned from rte_realloc\n");
503 : 0 : rte_free(ptr7);
504 : 0 : return -1;
505 : : }
506 [ - + ]: 1 : if (RTE_PTR_ALIGN(ptr8, new_align) != ptr8){
507 : : printf("Failure to re-align data\n");
508 : 0 : rte_free(ptr8);
509 : 0 : return -1;
510 : : }
511 : 1 : rte_free(ptr8);
512 : :
513 : : /* test behaviour when there is a free block after current one,
514 : : * but its not big enough
515 : : */
516 : : unsigned size9 = 1024, size10 = 1024;
517 : : unsigned size11 = size9 + size10 + 256;
518 : 1 : char *ptr9 = rte_malloc_socket(
519 : : NULL, size9, RTE_CACHE_LINE_SIZE, socket);
520 [ - + ]: 1 : if (!ptr9){
521 : : printf("NULL pointer returned from rte_malloc\n");
522 : 0 : return -1;
523 : : }
524 : 1 : char *ptr10 = rte_malloc_socket(
525 : : NULL, size10, RTE_CACHE_LINE_SIZE, socket);
526 [ - + ]: 1 : if (!ptr10){
527 : : printf("NULL pointer returned from rte_malloc\n");
528 : 0 : return -1;
529 : : }
530 : 1 : rte_free(ptr9);
531 : 1 : char *ptr11 = rte_realloc_socket(
532 : : ptr10, size11, RTE_CACHE_LINE_SIZE, socket);
533 [ - + ]: 1 : if (!ptr11){
534 : : printf("NULL pointer returned from rte_realloc\n");
535 : 0 : rte_free(ptr10);
536 : 0 : return -1;
537 : : }
538 [ - + ]: 1 : if (ptr11 == ptr10){
539 : : printf("Error, unexpected that realloc has not created new buffer\n");
540 : 0 : rte_free(ptr11);
541 : 0 : return -1;
542 : : }
543 : 1 : rte_free(ptr11);
544 : :
545 : : /* check we don't crash if we pass null to realloc
546 : : * We should get a malloc of the size requested*/
547 : : const size_t size12 = 1024;
548 : : size_t size12_check;
549 : 1 : char *ptr12 = rte_realloc_socket(
550 : : NULL, size12, RTE_CACHE_LINE_SIZE, socket);
551 [ - + ]: 1 : if (!ptr12){
552 : : printf("NULL pointer returned from rte_realloc\n");
553 : 0 : return -1;
554 : : }
555 [ + - ]: 1 : if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
556 [ - + ]: 1 : size12_check != size12){
557 : 0 : rte_free(ptr12);
558 : 0 : return -1;
559 : : }
560 : 1 : rte_free(ptr12);
561 : :
562 : : /* do the same, but for regular memory */
563 : 1 : ptr12 = rte_realloc(NULL, size12, RTE_CACHE_LINE_SIZE);
564 [ - + ]: 1 : if (!ptr12) {
565 : : printf("NULL pointer returned from rte_realloc\n");
566 : 0 : return -1;
567 : : }
568 [ + - ]: 1 : if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
569 [ - + ]: 1 : size12_check != size12) {
570 : 0 : rte_free(ptr12);
571 : 0 : return -1;
572 : : }
573 : 1 : rte_free(ptr12);
574 : :
575 : 1 : return 0;
576 : : }
577 : :
578 : : static int
579 : 1 : test_realloc_numa(void)
580 : : {
581 : : /* check realloc_socket part */
582 : : int32_t socket_count = 0, socket_allocated, socket;
583 : : void *ptr1, *ptr2;
584 : : int ret = -1;
585 : : size_t size = 1024;
586 : :
587 : : ptr1 = NULL;
588 [ + + ]: 33 : for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
589 [ + + ]: 32 : if (is_mem_on_socket(socket)) {
590 : : int j = 2;
591 : :
592 : 2 : socket_count++;
593 [ + + ]: 6 : while (j--) {
594 : : /* j == 1 -> resizing */
595 : 4 : ptr2 = rte_realloc_socket(ptr1, size,
596 : : RTE_CACHE_LINE_SIZE,
597 : : socket);
598 [ - + ]: 4 : if (ptr2 == NULL) {
599 : : printf("NULL pointer returned from rte_realloc_socket\n");
600 : 0 : goto end;
601 : : }
602 : :
603 : : ptr1 = ptr2;
604 : : socket_allocated = addr_to_socket(ptr2);
605 [ - + ]: 4 : if (socket_allocated != socket) {
606 : : printf("Requested socket (%d) doesn't mach allocated one (%d)\n",
607 : : socket, socket_allocated);
608 : 0 : goto end;
609 : : }
610 : 4 : size += RTE_CACHE_LINE_SIZE;
611 : : }
612 : : }
613 : : }
614 : :
615 : : /* Print warning if only a single socket, but don't fail the test */
616 [ - + ]: 1 : if (socket_count < 2)
617 : : printf("WARNING: realloc_socket test needs memory on multiple sockets!\n");
618 : :
619 : : ret = 0;
620 : 1 : end:
621 : 1 : rte_free(ptr1);
622 : 1 : return ret;
623 : : }
624 : :
625 : : static int
626 : 1 : test_realloc(void)
627 : : {
628 : : const char *heap_name = "realloc_heap";
629 : : int realloc_heap_socket;
630 : : unsigned int mem_sz = 1U << 13; /* 8K */
631 : 1 : unsigned int page_sz = sysconf(_SC_PAGESIZE);
632 : : void *mem;
633 : : int ret;
634 : :
635 : : /* page size may be bigger than total mem size, so adjust */
636 : 1 : mem_sz = RTE_MAX(mem_sz, page_sz);
637 : :
638 : : /*
639 : : * the realloc tests depend on specific layout of underlying memory, so
640 : : * to prevent accidental failures to do fragmented main heap, we will
641 : : * do all of our tests on an artificially created memory.
642 : : */
643 [ - + ]: 1 : if (rte_malloc_heap_create(heap_name) != 0) {
644 : : printf("Failed to create external heap\n");
645 : : ret = -1;
646 : 0 : goto end;
647 : : }
648 : 1 : realloc_heap_socket = rte_malloc_heap_get_socket(heap_name);
649 : :
650 : 1 : mem = mmap(NULL, mem_sz, PROT_READ | PROT_WRITE,
651 : : MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
652 [ - + ]: 1 : if (mem == MAP_FAILED) {
653 : : printf("Failed to allocate memory for external heap\n");
654 : : ret = -1;
655 : 0 : goto heap_destroy;
656 : : }
657 : :
658 [ - + ]: 1 : if (rte_malloc_heap_memory_add(
659 : : heap_name, mem, mem_sz, NULL, 0, page_sz) != 0) {
660 : : printf("Failed to add memory to external heap\n");
661 : : ret = -1;
662 : 0 : goto mem_free;
663 : : }
664 : :
665 : : /* run the socket-bound tests */
666 : 1 : ret = test_realloc_socket(realloc_heap_socket);
667 [ - + ]: 1 : if (ret != 0)
668 : 0 : goto mem_remove;
669 : :
670 : : /* now, run the NUMA node tests */
671 : 1 : ret = test_realloc_numa();
672 : :
673 : 1 : mem_remove:
674 : 1 : rte_malloc_heap_memory_remove(heap_name, mem, mem_sz);
675 : 1 : mem_free:
676 : 1 : munmap(mem, mem_sz);
677 : 1 : heap_destroy:
678 : 1 : rte_malloc_heap_destroy(heap_name);
679 : 1 : end:
680 : 1 : return ret;
681 : : }
682 : :
683 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
684 : :
685 : : static int
686 : 1 : test_random_alloc_free(void *_ __rte_unused)
687 : : {
688 : : struct mem_list {
689 : : struct mem_list *next;
690 : : char data[0];
691 : : } *list_head = NULL;
692 : : unsigned i;
693 : : unsigned count = 0;
694 : :
695 [ + + ]: 10001 : for (i = 0; i < N; i++){
696 : : unsigned free_mem = 0;
697 : : size_t allocated_size;
698 [ + + ]: 60929 : while (!free_mem){
699 : 50929 : const unsigned mem_size = sizeof(struct mem_list) + \
700 : 50929 : rte_rand() % (64 * 1024);
701 : 50929 : const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */
702 : 50929 : struct mem_list *entry = rte_malloc(NULL,
703 : : mem_size, align);
704 [ + - ]: 50929 : if (entry == NULL)
705 : 0 : return -1;
706 [ + - ]: 50929 : if (RTE_PTR_ALIGN(entry, align)!= entry)
707 : : return -1;
708 [ + - ]: 50929 : if (rte_malloc_validate(entry, &allocated_size) == -1
709 [ + - ]: 50929 : || allocated_size < mem_size)
710 : : return -1;
711 : 50929 : memset(entry->data, rte_lcore_id(),
712 : : mem_size - sizeof(*entry));
713 : 50929 : entry->next = list_head;
714 [ + - ]: 50929 : if (rte_malloc_validate(entry, NULL) == -1)
715 : : return -1;
716 : : list_head = entry;
717 : :
718 : 50929 : count++;
719 : : /* switch to freeing the memory with a 20% probability */
720 : 50929 : free_mem = ((rte_rand() % 10) >= 8);
721 : : }
722 [ + + ]: 60929 : while (list_head){
723 : : struct mem_list *entry = list_head;
724 : 50929 : list_head = list_head->next;
725 : 50929 : rte_free(entry);
726 : : }
727 : : }
728 : : printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count);
729 : 1 : return 0;
730 : : }
731 : :
732 : : #define err_return() do { \
733 : : printf("%s: %d - Error\n", __func__, __LINE__); \
734 : : goto err_return; \
735 : : } while (0)
736 : :
737 : : static int
738 : 1 : test_rte_malloc_validate(void)
739 : : {
740 : : const size_t request_size = 1024;
741 : : size_t allocated_size;
742 : 1 : char *data_ptr = rte_malloc(NULL, request_size, RTE_CACHE_LINE_SIZE);
743 : : #ifdef RTE_MALLOC_DEBUG
744 : : int retval;
745 : : char *over_write_vals = NULL;
746 : : #endif
747 : :
748 [ - + ]: 1 : if (data_ptr == NULL) {
749 : : printf("%s: %d - Allocation error\n", __func__, __LINE__);
750 : 0 : return -1;
751 : : }
752 : :
753 : : /* check that a null input returns -1 */
754 [ - + ]: 1 : if (rte_malloc_validate(NULL, NULL) != -1)
755 : 0 : err_return();
756 : :
757 : : /* check that we get ok on a valid pointer */
758 [ - + ]: 1 : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
759 : 0 : err_return();
760 : :
761 : : /* check that the returned size is ok */
762 [ - + ]: 1 : if (allocated_size < request_size)
763 : 0 : err_return();
764 : :
765 : : #ifdef RTE_MALLOC_DEBUG
766 : :
767 : : /****** change the header to be bad */
768 : : char save_buf[64];
769 : : over_write_vals = (char *)((uintptr_t)data_ptr - sizeof(save_buf));
770 : : /* first save the data as a backup before overwriting it */
771 : : memcpy(save_buf, over_write_vals, sizeof(save_buf));
772 : : memset(over_write_vals, 1, sizeof(save_buf));
773 : : /* then run validate */
774 : : retval = rte_malloc_validate(data_ptr, NULL);
775 : : /* finally restore the data again */
776 : : memcpy(over_write_vals, save_buf, sizeof(save_buf));
777 : : /* check we previously had an error */
778 : : if (retval != -1)
779 : : err_return();
780 : :
781 : : /* check all ok again */
782 : : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
783 : : err_return();
784 : :
785 : : /**** change the trailer to be bad */
786 : : over_write_vals = (char *)((uintptr_t)data_ptr + allocated_size);
787 : : /* first save the data as a backup before overwriting it */
788 : : memcpy(save_buf, over_write_vals, sizeof(save_buf));
789 : : memset(over_write_vals, 1, sizeof(save_buf));
790 : : /* then run validate */
791 : : retval = rte_malloc_validate(data_ptr, NULL);
792 : : /* finally restore the data again */
793 : : memcpy(over_write_vals, save_buf, sizeof(save_buf));
794 : : if (retval != -1)
795 : : err_return();
796 : :
797 : : /* check all ok again */
798 : : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
799 : : err_return();
800 : : #endif
801 : :
802 : 1 : rte_free(data_ptr);
803 : 1 : return 0;
804 : :
805 : 0 : err_return:
806 : : /*clean up */
807 : 0 : rte_free(data_ptr);
808 : 0 : return -1;
809 : : }
810 : :
811 : : static int
812 : 1 : test_zero_aligned_alloc(void)
813 : : {
814 : 1 : char *p1 = rte_malloc(NULL,1024, 0);
815 [ - + ]: 1 : if (!p1)
816 : 0 : goto err_return;
817 [ - + ]: 1 : if (!rte_is_aligned(p1, RTE_CACHE_LINE_SIZE))
818 : 0 : goto err_return;
819 : 1 : rte_free(p1);
820 : 1 : return 0;
821 : :
822 : 0 : err_return:
823 : : /*clean up */
824 : 0 : rte_free(p1);
825 : 0 : return -1;
826 : : }
827 : :
828 : : static int
829 : 1 : test_malloc_bad_params(void)
830 : : {
831 : : const char *type = NULL;
832 : : size_t size = 0;
833 : : unsigned align = RTE_CACHE_LINE_SIZE;
834 : :
835 : : /* rte_malloc expected to return null with inappropriate size */
836 : 1 : char *bad_ptr = rte_malloc(type, size, align);
837 [ - + ]: 1 : if (bad_ptr != NULL)
838 : 0 : goto err_return;
839 : :
840 : : /* rte_realloc expected to return null with inappropriate size */
841 : 1 : bad_ptr = rte_realloc(NULL, size, align);
842 [ - + ]: 1 : if (bad_ptr != NULL)
843 : 0 : goto err_return;
844 : :
845 : : /* rte_malloc expected to return null with inappropriate alignment */
846 : : align = 17;
847 : : size = 1024;
848 : :
849 : 1 : bad_ptr = rte_malloc(type, size, align);
850 [ - + ]: 1 : if (bad_ptr != NULL)
851 : 0 : goto err_return;
852 : :
853 : : /* rte_realloc expected to return null with inappropriate alignment */
854 : 1 : bad_ptr = rte_realloc(NULL, size, align);
855 [ - + ]: 1 : if (bad_ptr != NULL)
856 : 0 : goto err_return;
857 : :
858 : : #if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
859 : : /* this test can not be built, will get trapped at compile time! */
860 : : #else
861 : : /* rte_malloc expected to return null with size will cause overflow */
862 : : align = RTE_CACHE_LINE_SIZE;
863 : : size = (size_t)-8;
864 : :
865 : : bad_ptr = rte_malloc(type, size, align);
866 : : if (bad_ptr != NULL)
867 : : goto err_return;
868 : :
869 : : bad_ptr = rte_realloc(NULL, size, align);
870 : : if (bad_ptr != NULL)
871 : : goto err_return;
872 : : #endif
873 : : return 0;
874 : :
875 : 0 : err_return:
876 : : /* clean up pointer */
877 : 0 : rte_free(bad_ptr);
878 : 0 : return -1;
879 : : }
880 : :
881 : : static int
882 : 522 : check_socket_mem(const struct rte_memseg_list *msl, void *arg)
883 : : {
884 : : int32_t *socket = arg;
885 : :
886 [ + + ]: 522 : if (msl->external)
887 : : return 0;
888 : :
889 : 492 : return *socket == msl->socket_id;
890 : : }
891 : :
892 : : /* Check if memory is available on a specific socket */
893 : : static int
894 : : is_mem_on_socket(int32_t socket)
895 : : {
896 : 32 : return rte_memseg_list_walk(check_socket_mem, &socket);
897 : : }
898 : :
899 : :
900 : : /*
901 : : * Find what socket a memory address is on. Only works for addresses within
902 : : * memsegs, not heap or stack...
903 : : */
904 : : static int32_t
905 : : addr_to_socket(void * addr)
906 : : {
907 : 13 : const struct rte_memseg *ms = rte_mem_virt2memseg(addr, NULL);
908 [ + - + - : 13 : return ms == NULL ? -1 : ms->socket_id;
+ - + - ]
909 : :
910 : : }
911 : :
912 : : /* Test using rte_[c|m|zm]alloc_socket() on a specific socket */
913 : : static int
914 : 33 : test_alloc_single_socket(int32_t socket)
915 : : {
916 : : const char *type = NULL;
917 : : const size_t size = 10;
918 : : const unsigned align = 0;
919 : : char *mem = NULL;
920 : : int32_t desired_socket = (socket == SOCKET_ID_ANY) ?
921 [ + + ]: 33 : (int32_t)rte_socket_id() : socket;
922 : :
923 : : /* Test rte_calloc_socket() */
924 : 33 : mem = rte_calloc_socket(type, size, sizeof(char), align, socket);
925 [ + + ]: 33 : if (mem == NULL)
926 : : return -1;
927 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
928 : 0 : rte_free(mem);
929 : 0 : return -1;
930 : : }
931 : 3 : rte_free(mem);
932 : :
933 : : /* Test rte_malloc_socket() */
934 : 3 : mem = rte_malloc_socket(type, size, align, socket);
935 [ + - ]: 3 : if (mem == NULL)
936 : : return -1;
937 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
938 : 0 : rte_free(mem);
939 : 0 : return -1;
940 : : }
941 : 3 : rte_free(mem);
942 : :
943 : : /* Test rte_zmalloc_socket() */
944 : 3 : mem = rte_zmalloc_socket(type, size, align, socket);
945 [ + - ]: 3 : if (mem == NULL)
946 : : return -1;
947 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
948 : 0 : rte_free(mem);
949 : 0 : return -1;
950 : : }
951 : 3 : rte_free(mem);
952 : :
953 : 3 : return 0;
954 : : }
955 : :
956 : : static int
957 : 1 : test_alloc_socket(void)
958 : : {
959 : : unsigned socket_count = 0;
960 : : unsigned i;
961 : :
962 [ + - ]: 1 : if (test_alloc_single_socket(SOCKET_ID_ANY) < 0)
963 : : return -1;
964 : :
965 [ + + ]: 33 : for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
966 [ + + ]: 32 : if (is_mem_on_socket(i)) {
967 : 2 : socket_count++;
968 [ - + ]: 2 : if (test_alloc_single_socket(i) < 0) {
969 : : printf("Fail: rte_malloc_socket(..., %u) did not succeed\n",
970 : : i);
971 : 0 : return -1;
972 : : }
973 : : }
974 : : else {
975 [ - + ]: 30 : if (test_alloc_single_socket(i) == 0) {
976 : : printf("Fail: rte_malloc_socket(..., %u) succeeded\n",
977 : : i);
978 : 0 : return -1;
979 : : }
980 : : }
981 : : }
982 : :
983 : : /* Print warning if only a single socket, but don't fail the test */
984 [ - + ]: 1 : if (socket_count < 2) {
985 : : printf("WARNING: alloc_socket test needs memory on multiple sockets!\n");
986 : : }
987 : :
988 : : return 0;
989 : : }
990 : :
991 : : static int
992 : 1 : test_malloc(void)
993 : : {
994 : : unsigned lcore_id;
995 : : int ret = 0;
996 : :
997 [ - + ]: 1 : if (test_str_to_size() < 0){
998 : : printf("test_str_to_size() failed\n");
999 : 0 : return -1;
1000 : : }
1001 : : else printf("test_str_to_size() passed\n");
1002 : :
1003 [ - + ]: 1 : if (test_zero_aligned_alloc() < 0){
1004 : : printf("test_zero_aligned_alloc() failed\n");
1005 : 0 : return -1;
1006 : : }
1007 : : else printf("test_zero_aligned_alloc() passed\n");
1008 : :
1009 [ - + ]: 1 : if (test_malloc_bad_params() < 0){
1010 : : printf("test_malloc_bad_params() failed\n");
1011 : 0 : return -1;
1012 : : }
1013 : : else printf("test_malloc_bad_params() passed\n");
1014 : :
1015 [ - + ]: 1 : if (test_realloc() < 0){
1016 : : printf("test_realloc() failed\n");
1017 : 0 : return -1;
1018 : : }
1019 : : else printf("test_realloc() passed\n");
1020 : :
1021 : : /*----------------------------*/
1022 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1023 : 1 : rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id);
1024 : : }
1025 : :
1026 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1027 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
1028 : : ret = -1;
1029 : : }
1030 [ - + ]: 1 : if (ret < 0){
1031 : : printf("test_align_overlap_per_lcore() failed\n");
1032 : 0 : return ret;
1033 : : }
1034 : : else printf("test_align_overlap_per_lcore() passed\n");
1035 : :
1036 : : /*----------------------------*/
1037 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1038 : 1 : rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id);
1039 : : }
1040 : :
1041 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1042 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
1043 : : ret = -1;
1044 : : }
1045 [ - + ]: 1 : if (ret < 0){
1046 : : printf("test_reordered_free_per_lcore() failed\n");
1047 : 0 : return ret;
1048 : : }
1049 : : else printf("test_reordered_free_per_lcore() passed\n");
1050 : :
1051 : : /*----------------------------*/
1052 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1053 : 1 : rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id);
1054 : : }
1055 : :
1056 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1057 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
1058 : : ret = -1;
1059 : : }
1060 [ - + ]: 1 : if (ret < 0){
1061 : : printf("test_random_alloc_free() failed\n");
1062 : 0 : return ret;
1063 : : }
1064 : : else printf("test_random_alloc_free() passed\n");
1065 : :
1066 : : /*----------------------------*/
1067 : 1 : ret = test_rte_malloc_validate();
1068 [ - + ]: 1 : if (ret < 0){
1069 : : printf("test_rte_malloc_validate() failed\n");
1070 : 0 : return ret;
1071 : : }
1072 : : else printf("test_rte_malloc_validate() passed\n");
1073 : :
1074 : 1 : ret = test_alloc_socket();
1075 [ - + ]: 1 : if (ret < 0){
1076 : : printf("test_alloc_socket() failed\n");
1077 : 0 : return ret;
1078 : : }
1079 : : else printf("test_alloc_socket() passed\n");
1080 : :
1081 : 1 : ret = test_multi_alloc_statistics();
1082 [ - + ]: 1 : if (ret < 0) {
1083 : : printf("test_multi_alloc_statistics() failed\n");
1084 : 0 : return ret;
1085 : : }
1086 : : else
1087 : : printf("test_multi_alloc_statistics() passed\n");
1088 : :
1089 : 1 : return 0;
1090 : : }
1091 : :
1092 : 251 : REGISTER_FAST_TEST(malloc_autotest, false, true, test_malloc);
|