xref: /dpdk/app/test/test_malloc.c (revision 2a454f84f715608ee709a4c6ba00edf2e4b62b69)
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
is_memory_overlap(void * p1,size_t len1,void * p2,size_t len2)49 is_memory_overlap(void *p1, size_t len1, void *p2, size_t len2)
50 {
51 	uintptr_t ptr1 = (uintptr_t)p1;
52 	uintptr_t ptr2 = (uintptr_t)p2;
53 
54 	if (ptr2 >= ptr1 && (ptr2 - ptr1) < len1)
55 		return 1;
56 	else if (ptr2 < ptr1 && (ptr1 - ptr2) < len2)
57 		return 1;
58 	return 0;
59 }
60 
61 static int
is_aligned(void * p,int align)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
test_align_overlap_per_lcore(__rte_unused void * arg)73 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 	for (i = 0; i < N; i++) {
83 		p1 = rte_zmalloc("dummy", 1000, align1);
84 		if (!p1){
85 			printf("rte_zmalloc returned NULL (i=%u)\n", i);
86 			ret = -1;
87 			break;
88 		}
89 		for(j = 0; j < 1000 ; j++) {
90 			if( *(char *)p1 != 0) {
91 				printf("rte_zmalloc didn't zero the allocated memory\n");
92 				ret = -1;
93 			}
94 		}
95 		p2 = rte_malloc("dummy", 1000, align2);
96 		if (!p2){
97 			printf("rte_malloc returned NULL (i=%u)\n", i);
98 			ret = -1;
99 			rte_free(p1);
100 			break;
101 		}
102 		p3 = rte_malloc("dummy", 1000, align3);
103 		if (!p3){
104 			printf("rte_malloc returned NULL (i=%u)\n", i);
105 			ret = -1;
106 			rte_free(p1);
107 			rte_free(p2);
108 			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 		rte_free(p1);
135 		rte_free(p2);
136 		rte_free(p3);
137 	}
138 	rte_malloc_dump_stats(stdout, "dummy");
139 
140 	return ret;
141 }
142 
143 static int
test_reordered_free_per_lcore(__rte_unused void * arg)144 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 	for (i = 0; i < 30; i++) {
154 		p1 = rte_zmalloc("dummy", 1000, align1);
155 		if (!p1){
156 			printf("rte_zmalloc returned NULL (i=%u)\n", i);
157 			ret = -1;
158 			break;
159 		}
160 		for(j = 0; j < 1000 ; j++) {
161 			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 		p2 = rte_calloc("dummy", 1000, 16, align2);
168 		/* for third request use regular malloc again */
169 		p3 = rte_malloc("dummy", 1000, align3);
170 		if (!p2 || !p3){
171 			printf("rte_malloc returned NULL (i=%u)\n", i);
172 			ret = -1;
173 			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 		switch (i%6){
201 		case 0:
202 			rte_free(p1);
203 			rte_free(p2);
204 			rte_free(p3);
205 			break;
206 		case 1:
207 			rte_free(p1);
208 			rte_free(p3);
209 			rte_free(p2);
210 			break;
211 		case 2:
212 			rte_free(p2);
213 			rte_free(p1);
214 			rte_free(p3);
215 			break;
216 		case 3:
217 			rte_free(p2);
218 			rte_free(p3);
219 			rte_free(p1);
220 			break;
221 		case 4:
222 			rte_free(p3);
223 			rte_free(p1);
224 			rte_free(p2);
225 			break;
226 		case 5:
227 			rte_free(p3);
228 			rte_free(p2);
229 			rte_free(p1);
230 			break;
231 		}
232 	}
233 	rte_malloc_dump_stats(stdout, "dummy");
234 
235 	return ret;
236 }
237 
238 /* test function inside the malloc lib*/
239 static int
test_str_to_size(void)240 test_str_to_size(void)
241 {
242 	struct {
243 		const char *str;
244 		uint64_t value;
245 	} 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 	for (i = 0; i < RTE_DIM(test_values); i++)
262 		if (rte_str_to_size(test_values[i].str) != test_values[i].value)
263 			return -1;
264 	return 0;
265 }
266 
267 static int
test_multi_alloc_statistics(void)268 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 	rte_malloc_get_socket_stats(socket, &pre_stats);
280 
281 	void *dummy = rte_malloc_socket(NULL, RTE_CACHE_LINE_SIZE, 0, socket);
282 	if (dummy == NULL)
283 		return -1;
284 
285 	rte_malloc_get_socket_stats(socket, &post_stats);
286 
287 	/* after subtracting cache line, remainder is overhead */
288 	overhead = post_stats.heap_allocsz_bytes - pre_stats.heap_allocsz_bytes;
289 	overhead -= RTE_CACHE_LINE_SIZE;
290 
291 	rte_free(dummy);
292 
293 	/* Now start the real tests */
294 	rte_malloc_get_socket_stats(socket, &pre_stats);
295 
296 	void *p1 = rte_malloc_socket("stats", size , align, socket);
297 	if (!p1)
298 		return -1;
299 	rte_free(p1);
300 	rte_malloc_dump_stats(stdout, "stats");
301 
302 	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 	if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) ||
306 			(post_stats.heap_freesz_bytes != pre_stats.heap_freesz_bytes) ||
307 			(post_stats.heap_allocsz_bytes != pre_stats.heap_allocsz_bytes) ||
308 			(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 		return -1;
312 	}
313 	/* Check two consecutive allocations */
314 	size = 1024;
315 	align = 0;
316 	rte_malloc_get_socket_stats(socket,&pre_stats);
317 	void *p2 = rte_malloc_socket("add", size ,align, socket);
318 	if (!p2)
319 		return -1;
320 	rte_malloc_get_socket_stats(socket,&first_stats);
321 
322 	void *p3 = rte_malloc_socket("add2", size,align, socket);
323 	if (!p3)
324 		return -1;
325 
326 	rte_malloc_get_socket_stats(socket,&second_stats);
327 
328 	rte_free(p2);
329 	rte_free(p3);
330 
331 	/* After freeing both allocations check stats return to original */
332 	rte_malloc_get_socket_stats(socket, &post_stats);
333 
334 	if(second_stats.heap_totalsz_bytes != first_stats.heap_totalsz_bytes) {
335 		printf("Incorrect heap statistics: Total size \n");
336 		return -1;
337 	}
338 	/* Check allocated size is equal to two additions plus overhead */
339 	if(second_stats.heap_allocsz_bytes !=
340 			size + overhead + first_stats.heap_allocsz_bytes) {
341 		printf("Incorrect heap statistics: Allocated size \n");
342 		return -1;
343 	}
344 	/* Check that allocation count increments correctly i.e. +1 */
345 	if (second_stats.alloc_count != first_stats.alloc_count + 1) {
346 		printf("Incorrect heap statistics: Allocated count \n");
347 		return -1;
348 	}
349 
350 	if (second_stats.free_count != first_stats.free_count){
351 		printf("Incorrect heap statistics: Free count \n");
352 		return -1;
353 	}
354 
355 	/* Make sure that we didn't touch our greatest chunk: 2 * 11M)  */
356 	if (post_stats.greatest_free_size != pre_stats.greatest_free_size) {
357 		printf("Incorrect heap statistics: Greatest free size \n");
358 		return -1;
359 	}
360 	/* Free size must equal the original free size minus the new allocation*/
361 	if (first_stats.heap_freesz_bytes <= second_stats.heap_freesz_bytes) {
362 		printf("Incorrect heap statistics: Free size \n");
363 		return -1;
364 	}
365 
366 	if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) ||
367 			(post_stats.heap_freesz_bytes != pre_stats.heap_freesz_bytes) ||
368 			(post_stats.heap_allocsz_bytes != pre_stats.heap_allocsz_bytes) ||
369 			(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 		return -1;
373 	}
374 	return 0;
375 }
376 
377 #ifdef RTE_EXEC_ENV_WINDOWS
378 static int
test_realloc(void)379 test_realloc(void)
380 {
381 	return TEST_SKIPPED;
382 }
383 #else
384 
385 static int
test_realloc_socket(int socket)386 test_realloc_socket(int socket)
387 {
388 	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 	char *ptr1 = rte_zmalloc_socket(
396 			NULL, size1, RTE_CACHE_LINE_SIZE, socket);
397 	if (!ptr1){
398 		printf("NULL pointer returned from rte_zmalloc\n");
399 		return -1;
400 	}
401 	strlcpy(ptr1, hello_str, size1);
402 	char *ptr2 = rte_realloc_socket(
403 			ptr1, size2, RTE_CACHE_LINE_SIZE, socket);
404 	if (!ptr2){
405 		rte_free(ptr1);
406 		printf("NULL pointer returned from rte_realloc\n");
407 		return -1;
408 	}
409 	if (ptr1 == ptr2){
410 		printf("unexpected - ptr1 == ptr2\n");
411 	}
412 	if (strcmp(ptr2, hello_str) != 0){
413 		printf("Error - lost data from pointed area\n");
414 		rte_free(ptr2);
415 		return -1;
416 	}
417 	unsigned i;
418 	for (i = strnlen(hello_str, sizeof(hello_str)); i < size1; i++)
419 		if (ptr2[i] != 0){
420 			printf("Bad data in realloc\n");
421 			rte_free(ptr2);
422 			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 	char *ptr3 = rte_zmalloc_socket(
428 			NULL, size3, RTE_CACHE_LINE_SIZE, socket);
429 	if (!ptr3){
430 		printf("NULL pointer returned from rte_zmalloc\n");
431 		rte_free(ptr2);
432 		return -1;
433 	}
434 	for (i = 0; i < size3; i++)
435 		if (ptr3[i] != 0){
436 			printf("Bad data in zmalloc\n");
437 			rte_free(ptr3);
438 			rte_free(ptr2);
439 			return -1;
440 		}
441 	rte_free(ptr2);
442 	/* first resize to half the size of the freed block */
443 	char *ptr4 = rte_realloc_socket(
444 			ptr3, size4, RTE_CACHE_LINE_SIZE, socket);
445 	if (!ptr4){
446 		printf("NULL pointer returned from rte_realloc\n");
447 		rte_free(ptr3);
448 		return -1;
449 	}
450 	if (ptr3 != ptr4){
451 		printf("Unexpected - ptr4 != ptr3\n");
452 		rte_free(ptr4);
453 		return -1;
454 	}
455 	/* now resize again to the full size of the freed block */
456 	ptr4 = rte_realloc_socket(ptr3, size3 + size2 + size1,
457 			RTE_CACHE_LINE_SIZE, socket);
458 	if (ptr3 != ptr4){
459 		printf("Unexpected - ptr4 != ptr3 on second resize\n");
460 		rte_free(ptr4);
461 		return -1;
462 	}
463 	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 	char *ptr5 = rte_malloc_socket(
469 			NULL, size5, RTE_CACHE_LINE_SIZE, socket);
470 	if (!ptr5){
471 		printf("NULL pointer returned from rte_malloc\n");
472 		return -1;
473 	}
474 	char *ptr6 = rte_realloc_socket(
475 			ptr5, size6, RTE_CACHE_LINE_SIZE, socket);
476 	if (!ptr6){
477 		printf("NULL pointer returned from rte_realloc\n");
478 		rte_free(ptr5);
479 		return -1;
480 	}
481 	if (ptr5 != ptr6){
482 		printf("Error, resizing to a smaller size moved data\n");
483 		rte_free(ptr6);
484 		return -1;
485 	}
486 	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 	char *ptr7 = rte_malloc_socket(NULL, size7, orig_align, socket);
493 	if (!ptr7){
494 		printf("NULL pointer returned from rte_malloc\n");
495 		return -1;
496 	}
497 	/* calc an alignment we don't already have */
498 	while(RTE_PTR_ALIGN(ptr7, new_align) == ptr7)
499 		new_align *= 2;
500 	char *ptr8 = rte_realloc_socket(ptr7, size7, new_align, socket);
501 	if (!ptr8){
502 		printf("NULL pointer returned from rte_realloc\n");
503 		rte_free(ptr7);
504 		return -1;
505 	}
506 	if (RTE_PTR_ALIGN(ptr8, new_align) != ptr8){
507 		printf("Failure to re-align data\n");
508 		rte_free(ptr8);
509 		return -1;
510 	}
511 	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 	char *ptr9 = rte_malloc_socket(
519 			NULL, size9, RTE_CACHE_LINE_SIZE, socket);
520 	if (!ptr9){
521 		printf("NULL pointer returned from rte_malloc\n");
522 		return -1;
523 	}
524 	char *ptr10 = rte_malloc_socket(
525 			NULL, size10, RTE_CACHE_LINE_SIZE, socket);
526 	if (!ptr10){
527 		printf("NULL pointer returned from rte_malloc\n");
528 		return -1;
529 	}
530 	rte_free(ptr9);
531 	char *ptr11 = rte_realloc_socket(
532 			ptr10, size11, RTE_CACHE_LINE_SIZE, socket);
533 	if (!ptr11){
534 		printf("NULL pointer returned from rte_realloc\n");
535 		rte_free(ptr10);
536 		return -1;
537 	}
538 	if (ptr11 == ptr10){
539 		printf("Error, unexpected that realloc has not created new buffer\n");
540 		rte_free(ptr11);
541 		return -1;
542 	}
543 	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 	char *ptr12 = rte_realloc_socket(
550 			NULL, size12, RTE_CACHE_LINE_SIZE, socket);
551 	if (!ptr12){
552 		printf("NULL pointer returned from rte_realloc\n");
553 		return -1;
554 	}
555 	if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
556 			size12_check != size12){
557 		rte_free(ptr12);
558 		return -1;
559 	}
560 	rte_free(ptr12);
561 
562 	/* do the same, but for regular memory */
563 	ptr12 = rte_realloc(NULL, size12, RTE_CACHE_LINE_SIZE);
564 	if (!ptr12) {
565 		printf("NULL pointer returned from rte_realloc\n");
566 		return -1;
567 	}
568 	if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
569 			size12_check != size12) {
570 		rte_free(ptr12);
571 		return -1;
572 	}
573 	rte_free(ptr12);
574 
575 	return 0;
576 }
577 
578 static int
test_realloc_numa(void)579 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 	for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
589 		if (is_mem_on_socket(socket)) {
590 			int j = 2;
591 
592 			socket_count++;
593 			while (j--) {
594 				/* j == 1 -> resizing */
595 				ptr2 = rte_realloc_socket(ptr1, size,
596 							  RTE_CACHE_LINE_SIZE,
597 							  socket);
598 				if (ptr2 == NULL) {
599 					printf("NULL pointer returned from rte_realloc_socket\n");
600 					goto end;
601 				}
602 
603 				ptr1 = ptr2;
604 				socket_allocated = addr_to_socket(ptr2);
605 				if (socket_allocated != socket) {
606 					printf("Requested socket (%d) doesn't mach allocated one (%d)\n",
607 					       socket, socket_allocated);
608 					goto end;
609 				}
610 				size += RTE_CACHE_LINE_SIZE;
611 			}
612 		}
613 	}
614 
615 	/* Print warning if only a single socket, but don't fail the test */
616 	if (socket_count < 2)
617 		printf("WARNING: realloc_socket test needs memory on multiple sockets!\n");
618 
619 	ret = 0;
620 end:
621 	rte_free(ptr1);
622 	return ret;
623 }
624 
625 static int
test_realloc(void)626 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 	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 	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 	if (rte_malloc_heap_create(heap_name) != 0) {
644 		printf("Failed to create external heap\n");
645 		ret = -1;
646 		goto end;
647 	}
648 	realloc_heap_socket = rte_malloc_heap_get_socket(heap_name);
649 
650 	mem = mmap(NULL, mem_sz, PROT_READ | PROT_WRITE,
651 			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
652 	if (mem == MAP_FAILED) {
653 		printf("Failed to allocate memory for external heap\n");
654 		ret = -1;
655 		goto heap_destroy;
656 	}
657 
658 	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 		goto mem_free;
663 	}
664 
665 	/* run the socket-bound tests */
666 	ret = test_realloc_socket(realloc_heap_socket);
667 	if (ret != 0)
668 		goto mem_remove;
669 
670 	/* now, run the NUMA node tests */
671 	ret = test_realloc_numa();
672 
673 mem_remove:
674 	rte_malloc_heap_memory_remove(heap_name, mem, mem_sz);
675 mem_free:
676 	munmap(mem, mem_sz);
677 heap_destroy:
678 	rte_malloc_heap_destroy(heap_name);
679 end:
680 	return ret;
681 }
682 
683 #endif /* !RTE_EXEC_ENV_WINDOWS */
684 
685 static int
test_random_alloc_free(void * _ __rte_unused)686 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 	for (i = 0; i < N; i++){
696 		unsigned free_mem = 0;
697 		size_t allocated_size;
698 		while (!free_mem){
699 			const unsigned mem_size = sizeof(struct mem_list) + \
700 					rte_rand() % (64 * 1024);
701 			const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */
702 			struct mem_list *entry = rte_malloc(NULL,
703 					mem_size, align);
704 			if (entry == NULL)
705 				return -1;
706 			if (RTE_PTR_ALIGN(entry, align)!= entry)
707 				return -1;
708 			if (rte_malloc_validate(entry, &allocated_size) == -1
709 					|| allocated_size < mem_size)
710 				return -1;
711 			memset(entry->data, rte_lcore_id(),
712 					mem_size - sizeof(*entry));
713 			entry->next = list_head;
714 			if (rte_malloc_validate(entry, NULL) == -1)
715 				return -1;
716 			list_head = entry;
717 
718 			count++;
719 			/* switch to freeing the memory with a 20% probability */
720 			free_mem = ((rte_rand() % 10) >= 8);
721 		}
722 		while (list_head){
723 			struct mem_list *entry = list_head;
724 			list_head = list_head->next;
725 			rte_free(entry);
726 		}
727 	}
728 	printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count);
729 	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
test_rte_malloc_validate(void)738 test_rte_malloc_validate(void)
739 {
740 	const size_t request_size = 1024;
741 	size_t allocated_size;
742 	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 	if (data_ptr == NULL) {
749 		printf("%s: %d - Allocation error\n", __func__, __LINE__);
750 		return -1;
751 	}
752 
753 	/* check that a null input returns -1 */
754 	if (rte_malloc_validate(NULL, NULL) != -1)
755 		err_return();
756 
757 	/* check that we get ok on a valid pointer */
758 	if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
759 		err_return();
760 
761 	/* check that the returned size is ok */
762 	if (allocated_size < request_size)
763 		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 	rte_free(data_ptr);
803 	return 0;
804 
805 err_return:
806 	/*clean up */
807 	rte_free(data_ptr);
808 	return -1;
809 }
810 
811 static int
test_zero_aligned_alloc(void)812 test_zero_aligned_alloc(void)
813 {
814 	char *p1 = rte_malloc(NULL,1024, 0);
815 	if (!p1)
816 		goto err_return;
817 	if (!rte_is_aligned(p1, RTE_CACHE_LINE_SIZE))
818 		goto err_return;
819 	rte_free(p1);
820 	return 0;
821 
822 err_return:
823 	/*clean up */
824 	rte_free(p1);
825 	return -1;
826 }
827 
828 static int
test_malloc_bad_params(void)829 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 	char *bad_ptr = rte_malloc(type, size, align);
837 	if (bad_ptr != NULL)
838 		goto err_return;
839 
840 	/* rte_realloc expected to return null with inappropriate size */
841 	bad_ptr = rte_realloc(NULL, size, align);
842 	if (bad_ptr != NULL)
843 		goto err_return;
844 
845 	/* rte_malloc expected to return null with inappropriate alignment */
846 	align = 17;
847 	size = 1024;
848 
849 	bad_ptr = rte_malloc(type, size, align);
850 	if (bad_ptr != NULL)
851 		goto err_return;
852 
853 	/* rte_realloc expected to return null with inappropriate alignment */
854 	bad_ptr = rte_realloc(NULL, size, align);
855 	if (bad_ptr != NULL)
856 		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 err_return:
876 	/* clean up pointer */
877 	rte_free(bad_ptr);
878 	return -1;
879 }
880 
881 static int
check_socket_mem(const struct rte_memseg_list * msl,void * arg)882 check_socket_mem(const struct rte_memseg_list *msl, void *arg)
883 {
884 	int32_t *socket = arg;
885 
886 	if (msl->external)
887 		return 0;
888 
889 	return *socket == msl->socket_id;
890 }
891 
892 /* Check if memory is available on a specific socket */
893 static int
is_mem_on_socket(int32_t socket)894 is_mem_on_socket(int32_t socket)
895 {
896 	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
addr_to_socket(void * addr)905 addr_to_socket(void * addr)
906 {
907 	const struct rte_memseg *ms = rte_mem_virt2memseg(addr, NULL);
908 	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
test_alloc_single_socket(int32_t socket)914 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 			(int32_t)rte_socket_id() : socket;
922 
923 	/* Test rte_calloc_socket() */
924 	mem = rte_calloc_socket(type, size, sizeof(char), align, socket);
925 	if (mem == NULL)
926 		return -1;
927 	if (addr_to_socket(mem) != desired_socket) {
928 		rte_free(mem);
929 		return -1;
930 	}
931 	rte_free(mem);
932 
933 	/* Test rte_malloc_socket() */
934 	mem = rte_malloc_socket(type, size, align, socket);
935 	if (mem == NULL)
936 		return -1;
937 	if (addr_to_socket(mem) != desired_socket) {
938 		rte_free(mem);
939 		return -1;
940 	}
941 	rte_free(mem);
942 
943 	/* Test rte_zmalloc_socket() */
944 	mem = rte_zmalloc_socket(type, size, align, socket);
945 	if (mem == NULL)
946 		return -1;
947 	if (addr_to_socket(mem) != desired_socket) {
948 		rte_free(mem);
949 		return -1;
950 	}
951 	rte_free(mem);
952 
953 	return 0;
954 }
955 
956 static int
test_alloc_socket(void)957 test_alloc_socket(void)
958 {
959 	unsigned socket_count = 0;
960 	unsigned i;
961 
962 	if (test_alloc_single_socket(SOCKET_ID_ANY) < 0)
963 		return -1;
964 
965 	for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
966 		if (is_mem_on_socket(i)) {
967 			socket_count++;
968 			if (test_alloc_single_socket(i) < 0) {
969 				printf("Fail: rte_malloc_socket(..., %u) did not succeed\n",
970 						i);
971 				return -1;
972 			}
973 		}
974 		else {
975 			if (test_alloc_single_socket(i) == 0) {
976 				printf("Fail: rte_malloc_socket(..., %u) succeeded\n",
977 						i);
978 				return -1;
979 			}
980 		}
981 	}
982 
983 	/* Print warning if only a single socket, but don't fail the test */
984 	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
test_malloc(void)992 test_malloc(void)
993 {
994 	unsigned lcore_id;
995 	int ret = 0;
996 
997 	if (test_str_to_size() < 0){
998 		printf("test_str_to_size() failed\n");
999 		return -1;
1000 	}
1001 	else printf("test_str_to_size() passed\n");
1002 
1003 	if (test_zero_aligned_alloc() < 0){
1004 		printf("test_zero_aligned_alloc() failed\n");
1005 		return -1;
1006 	}
1007 	else printf("test_zero_aligned_alloc() passed\n");
1008 
1009 	if (test_malloc_bad_params() < 0){
1010 		printf("test_malloc_bad_params() failed\n");
1011 		return -1;
1012 	}
1013 	else printf("test_malloc_bad_params() passed\n");
1014 
1015 	if (test_realloc() < 0){
1016 		printf("test_realloc() failed\n");
1017 		return -1;
1018 	}
1019 	else printf("test_realloc() passed\n");
1020 
1021 	/*----------------------------*/
1022 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1023 		rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id);
1024 	}
1025 
1026 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1027 		if (rte_eal_wait_lcore(lcore_id) < 0)
1028 			ret = -1;
1029 	}
1030 	if (ret < 0){
1031 		printf("test_align_overlap_per_lcore() failed\n");
1032 		return ret;
1033 	}
1034 	else printf("test_align_overlap_per_lcore() passed\n");
1035 
1036 	/*----------------------------*/
1037 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1038 		rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id);
1039 	}
1040 
1041 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1042 		if (rte_eal_wait_lcore(lcore_id) < 0)
1043 			ret = -1;
1044 	}
1045 	if (ret < 0){
1046 		printf("test_reordered_free_per_lcore() failed\n");
1047 		return ret;
1048 	}
1049 	else printf("test_reordered_free_per_lcore() passed\n");
1050 
1051 	/*----------------------------*/
1052 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1053 		rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id);
1054 	}
1055 
1056 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1057 		if (rte_eal_wait_lcore(lcore_id) < 0)
1058 			ret = -1;
1059 	}
1060 	if (ret < 0){
1061 		printf("test_random_alloc_free() failed\n");
1062 		return ret;
1063 	}
1064 	else printf("test_random_alloc_free() passed\n");
1065 
1066 	/*----------------------------*/
1067 	ret = test_rte_malloc_validate();
1068 	if (ret < 0){
1069 		printf("test_rte_malloc_validate() failed\n");
1070 		return ret;
1071 	}
1072 	else printf("test_rte_malloc_validate() passed\n");
1073 
1074 	ret = test_alloc_socket();
1075 	if (ret < 0){
1076 		printf("test_alloc_socket() failed\n");
1077 		return ret;
1078 	}
1079 	else printf("test_alloc_socket() passed\n");
1080 
1081 	ret = test_multi_alloc_statistics();
1082 	if (ret < 0) {
1083 		printf("test_multi_alloc_statistics() failed\n");
1084 		return ret;
1085 	}
1086 	else
1087 		printf("test_multi_alloc_statistics() passed\n");
1088 
1089 	return 0;
1090 }
1091 
1092 REGISTER_FAST_TEST(malloc_autotest, false, true, test_malloc);
1093