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