xref: /dpdk/app/test/test_malloc.c (revision da7e701151ea8b742d4c38ace3e4fefd1b4507fc)
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 	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
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 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
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
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
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
379 test_realloc(void)
380 {
381 	return TEST_SKIPPED;
382 }
383 #else
384 
385 static int
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
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
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
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 	rte_srand((unsigned)rte_rdtsc());
696 
697 	for (i = 0; i < N; i++){
698 		unsigned free_mem = 0;
699 		size_t allocated_size;
700 		while (!free_mem){
701 			const unsigned mem_size = sizeof(struct mem_list) + \
702 					rte_rand() % (64 * 1024);
703 			const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */
704 			struct mem_list *entry = rte_malloc(NULL,
705 					mem_size, align);
706 			if (entry == NULL)
707 				return -1;
708 			if (RTE_PTR_ALIGN(entry, align)!= entry)
709 				return -1;
710 			if (rte_malloc_validate(entry, &allocated_size) == -1
711 					|| allocated_size < mem_size)
712 				return -1;
713 			memset(entry->data, rte_lcore_id(),
714 					mem_size - sizeof(*entry));
715 			entry->next = list_head;
716 			if (rte_malloc_validate(entry, NULL) == -1)
717 				return -1;
718 			list_head = entry;
719 
720 			count++;
721 			/* switch to freeing the memory with a 20% probability */
722 			free_mem = ((rte_rand() % 10) >= 8);
723 		}
724 		while (list_head){
725 			struct mem_list *entry = list_head;
726 			list_head = list_head->next;
727 			rte_free(entry);
728 		}
729 	}
730 	printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count);
731 	return 0;
732 }
733 
734 #define err_return() do { \
735 	printf("%s: %d - Error\n", __func__, __LINE__); \
736 	goto err_return; \
737 } while (0)
738 
739 static int
740 test_rte_malloc_validate(void)
741 {
742 	const size_t request_size = 1024;
743 	size_t allocated_size;
744 	char *data_ptr = rte_malloc(NULL, request_size, RTE_CACHE_LINE_SIZE);
745 #ifdef RTE_MALLOC_DEBUG
746 	int retval;
747 	char *over_write_vals = NULL;
748 #endif
749 
750 	if (data_ptr == NULL) {
751 		printf("%s: %d - Allocation error\n", __func__, __LINE__);
752 		return -1;
753 	}
754 
755 	/* check that a null input returns -1 */
756 	if (rte_malloc_validate(NULL, NULL) != -1)
757 		err_return();
758 
759 	/* check that we get ok on a valid pointer */
760 	if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
761 		err_return();
762 
763 	/* check that the returned size is ok */
764 	if (allocated_size < request_size)
765 		err_return();
766 
767 #ifdef RTE_MALLOC_DEBUG
768 
769 	/****** change the header to be bad */
770 	char save_buf[64];
771 	over_write_vals = (char *)((uintptr_t)data_ptr - sizeof(save_buf));
772 	/* first save the data as a backup before overwriting it */
773 	memcpy(save_buf, over_write_vals, sizeof(save_buf));
774 	memset(over_write_vals, 1, sizeof(save_buf));
775 	/* then run validate */
776 	retval = rte_malloc_validate(data_ptr, NULL);
777 	/* finally restore the data again */
778 	memcpy(over_write_vals, save_buf, sizeof(save_buf));
779 	/* check we previously had an error */
780 	if (retval != -1)
781 		err_return();
782 
783 	/* check all ok again */
784 	if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
785 		err_return();
786 
787 	/**** change the trailer to be bad */
788 	over_write_vals = (char *)((uintptr_t)data_ptr + allocated_size);
789 	/* first save the data as a backup before overwriting it */
790 	memcpy(save_buf, over_write_vals, sizeof(save_buf));
791 	memset(over_write_vals, 1, sizeof(save_buf));
792 	/* then run validate */
793 	retval = rte_malloc_validate(data_ptr, NULL);
794 	/* finally restore the data again */
795 	memcpy(over_write_vals, save_buf, sizeof(save_buf));
796 	if (retval != -1)
797 		err_return();
798 
799 	/* check all ok again */
800 	if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
801 		err_return();
802 #endif
803 
804 	rte_free(data_ptr);
805 	return 0;
806 
807 err_return:
808 	/*clean up */
809 	rte_free(data_ptr);
810 	return -1;
811 }
812 
813 static int
814 test_zero_aligned_alloc(void)
815 {
816 	char *p1 = rte_malloc(NULL,1024, 0);
817 	if (!p1)
818 		goto err_return;
819 	if (!rte_is_aligned(p1, RTE_CACHE_LINE_SIZE))
820 		goto err_return;
821 	rte_free(p1);
822 	return 0;
823 
824 err_return:
825 	/*clean up */
826 	rte_free(p1);
827 	return -1;
828 }
829 
830 static int
831 test_malloc_bad_params(void)
832 {
833 	const char *type = NULL;
834 	size_t size = 0;
835 	unsigned align = RTE_CACHE_LINE_SIZE;
836 
837 	/* rte_malloc expected to return null with inappropriate size */
838 	char *bad_ptr = rte_malloc(type, size, align);
839 	if (bad_ptr != NULL)
840 		goto err_return;
841 
842 	/* rte_realloc expected to return null with inappropriate size */
843 	bad_ptr = rte_realloc(NULL, size, align);
844 	if (bad_ptr != NULL)
845 		goto err_return;
846 
847 	/* rte_malloc expected to return null with inappropriate alignment */
848 	align = 17;
849 	size = 1024;
850 
851 	bad_ptr = rte_malloc(type, size, align);
852 	if (bad_ptr != NULL)
853 		goto err_return;
854 
855 	/* rte_realloc expected to return null with inappropriate alignment */
856 	bad_ptr = rte_realloc(NULL, size, align);
857 	if (bad_ptr != NULL)
858 		goto err_return;
859 
860 #if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
861 	/* this test can not be built, will get trapped at compile time! */
862 #else
863 	/* rte_malloc expected to return null with size will cause overflow */
864 	align = RTE_CACHE_LINE_SIZE;
865 	size = (size_t)-8;
866 
867 	bad_ptr = rte_malloc(type, size, align);
868 	if (bad_ptr != NULL)
869 		goto err_return;
870 
871 	bad_ptr = rte_realloc(NULL, size, align);
872 	if (bad_ptr != NULL)
873 		goto err_return;
874 #endif
875 	return 0;
876 
877 err_return:
878 	/* clean up pointer */
879 	rte_free(bad_ptr);
880 	return -1;
881 }
882 
883 static int
884 check_socket_mem(const struct rte_memseg_list *msl, void *arg)
885 {
886 	int32_t *socket = arg;
887 
888 	if (msl->external)
889 		return 0;
890 
891 	return *socket == msl->socket_id;
892 }
893 
894 /* Check if memory is available on a specific socket */
895 static int
896 is_mem_on_socket(int32_t socket)
897 {
898 	return rte_memseg_list_walk(check_socket_mem, &socket);
899 }
900 
901 
902 /*
903  * Find what socket a memory address is on. Only works for addresses within
904  * memsegs, not heap or stack...
905  */
906 static int32_t
907 addr_to_socket(void * addr)
908 {
909 	const struct rte_memseg *ms = rte_mem_virt2memseg(addr, NULL);
910 	return ms == NULL ? -1 : ms->socket_id;
911 
912 }
913 
914 /* Test using rte_[c|m|zm]alloc_socket() on a specific socket */
915 static int
916 test_alloc_single_socket(int32_t socket)
917 {
918 	const char *type = NULL;
919 	const size_t size = 10;
920 	const unsigned align = 0;
921 	char *mem = NULL;
922 	int32_t desired_socket = (socket == SOCKET_ID_ANY) ?
923 			(int32_t)rte_socket_id() : socket;
924 
925 	/* Test rte_calloc_socket() */
926 	mem = rte_calloc_socket(type, size, sizeof(char), align, socket);
927 	if (mem == NULL)
928 		return -1;
929 	if (addr_to_socket(mem) != desired_socket) {
930 		rte_free(mem);
931 		return -1;
932 	}
933 	rte_free(mem);
934 
935 	/* Test rte_malloc_socket() */
936 	mem = rte_malloc_socket(type, size, align, socket);
937 	if (mem == NULL)
938 		return -1;
939 	if (addr_to_socket(mem) != desired_socket) {
940 		rte_free(mem);
941 		return -1;
942 	}
943 	rte_free(mem);
944 
945 	/* Test rte_zmalloc_socket() */
946 	mem = rte_zmalloc_socket(type, size, align, socket);
947 	if (mem == NULL)
948 		return -1;
949 	if (addr_to_socket(mem) != desired_socket) {
950 		rte_free(mem);
951 		return -1;
952 	}
953 	rte_free(mem);
954 
955 	return 0;
956 }
957 
958 static int
959 test_alloc_socket(void)
960 {
961 	unsigned socket_count = 0;
962 	unsigned i;
963 
964 	if (test_alloc_single_socket(SOCKET_ID_ANY) < 0)
965 		return -1;
966 
967 	for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
968 		if (is_mem_on_socket(i)) {
969 			socket_count++;
970 			if (test_alloc_single_socket(i) < 0) {
971 				printf("Fail: rte_malloc_socket(..., %u) did not succeed\n",
972 						i);
973 				return -1;
974 			}
975 		}
976 		else {
977 			if (test_alloc_single_socket(i) == 0) {
978 				printf("Fail: rte_malloc_socket(..., %u) succeeded\n",
979 						i);
980 				return -1;
981 			}
982 		}
983 	}
984 
985 	/* Print warning if only a single socket, but don't fail the test */
986 	if (socket_count < 2) {
987 		printf("WARNING: alloc_socket test needs memory on multiple sockets!\n");
988 	}
989 
990 	return 0;
991 }
992 
993 static int
994 test_malloc(void)
995 {
996 	unsigned lcore_id;
997 	int ret = 0;
998 
999 	if (test_str_to_size() < 0){
1000 		printf("test_str_to_size() failed\n");
1001 		return -1;
1002 	}
1003 	else printf("test_str_to_size() passed\n");
1004 
1005 	if (test_zero_aligned_alloc() < 0){
1006 		printf("test_zero_aligned_alloc() failed\n");
1007 		return -1;
1008 	}
1009 	else printf("test_zero_aligned_alloc() passed\n");
1010 
1011 	if (test_malloc_bad_params() < 0){
1012 		printf("test_malloc_bad_params() failed\n");
1013 		return -1;
1014 	}
1015 	else printf("test_malloc_bad_params() passed\n");
1016 
1017 	if (test_realloc() < 0){
1018 		printf("test_realloc() failed\n");
1019 		return -1;
1020 	}
1021 	else printf("test_realloc() passed\n");
1022 
1023 	/*----------------------------*/
1024 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1025 		rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id);
1026 	}
1027 
1028 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1029 		if (rte_eal_wait_lcore(lcore_id) < 0)
1030 			ret = -1;
1031 	}
1032 	if (ret < 0){
1033 		printf("test_align_overlap_per_lcore() failed\n");
1034 		return ret;
1035 	}
1036 	else printf("test_align_overlap_per_lcore() passed\n");
1037 
1038 	/*----------------------------*/
1039 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1040 		rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id);
1041 	}
1042 
1043 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1044 		if (rte_eal_wait_lcore(lcore_id) < 0)
1045 			ret = -1;
1046 	}
1047 	if (ret < 0){
1048 		printf("test_reordered_free_per_lcore() failed\n");
1049 		return ret;
1050 	}
1051 	else printf("test_reordered_free_per_lcore() passed\n");
1052 
1053 	/*----------------------------*/
1054 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1055 		rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id);
1056 	}
1057 
1058 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1059 		if (rte_eal_wait_lcore(lcore_id) < 0)
1060 			ret = -1;
1061 	}
1062 	if (ret < 0){
1063 		printf("test_random_alloc_free() failed\n");
1064 		return ret;
1065 	}
1066 	else printf("test_random_alloc_free() passed\n");
1067 
1068 	/*----------------------------*/
1069 	ret = test_rte_malloc_validate();
1070 	if (ret < 0){
1071 		printf("test_rte_malloc_validate() failed\n");
1072 		return ret;
1073 	}
1074 	else printf("test_rte_malloc_validate() passed\n");
1075 
1076 	ret = test_alloc_socket();
1077 	if (ret < 0){
1078 		printf("test_alloc_socket() failed\n");
1079 		return ret;
1080 	}
1081 	else printf("test_alloc_socket() passed\n");
1082 
1083 	ret = test_multi_alloc_statistics();
1084 	if (ret < 0) {
1085 		printf("test_multi_alloc_statistics() failed\n");
1086 		return ret;
1087 	}
1088 	else
1089 		printf("test_multi_alloc_statistics() passed\n");
1090 
1091 	return 0;
1092 }
1093 
1094 REGISTER_FAST_TEST(malloc_autotest, false, true, test_malloc);
1095