xref: /dpdk/app/test/test_malloc.c (revision fc1f2750a3ec6da919e3c86e59d56f34ec97154b)
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 and 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 may increase, or may 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_totalsz_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 			post_stats.free_count != pre_stats.free_count - 1) {
341 		printf("Malloc statistics are incorrect - free_count\n");
342 		return -1;
343 	}
344 
345 	rte_free(p1);
346 	return 0;
347 }
348 
349 static int
350 test_multi_alloc_statistics(void)
351 {
352 	int socket = 0;
353 	struct rte_malloc_socket_stats pre_stats, post_stats ,first_stats, second_stats;
354 	size_t size = 2048;
355 	int align = 1024;
356 #ifndef RTE_LIBRTE_MALLOC_DEBUG
357 	int trailer_size = 0;
358 #else
359 	int trailer_size = 64;
360 #endif
361 	int overhead = 64 + trailer_size;
362 
363 	rte_malloc_get_socket_stats(socket, &pre_stats);
364 
365 	void *p1 = rte_malloc_socket("stats", size , align, socket);
366 	if (!p1)
367 		return -1;
368 	rte_free(p1);
369 	rte_malloc_dump_stats(stdout, "stats");
370 
371 	rte_malloc_get_socket_stats(socket,&post_stats);
372 	/* Check statistics reported are correct */
373 	/* All post stats should be equal to pre stats after alloc freed */
374 	if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) &&
375 			(post_stats.heap_freesz_bytes!=pre_stats.heap_freesz_bytes) &&
376 			(post_stats.heap_allocsz_bytes!=pre_stats.heap_allocsz_bytes)&&
377 			(post_stats.alloc_count!=pre_stats.alloc_count)&&
378 			(post_stats.free_count!=pre_stats.free_count)) {
379 		printf("Malloc statistics are incorrect - freed alloc\n");
380 		return -1;
381 	}
382 	/* Check two consecutive allocations */
383 	size = 1024;
384 	align = 0;
385 	rte_malloc_get_socket_stats(socket,&pre_stats);
386 	void *p2 = rte_malloc_socket("add", size ,align, socket);
387 	if (!p2)
388 		return -1;
389 	rte_malloc_get_socket_stats(socket,&first_stats);
390 
391 	void *p3 = rte_malloc_socket("add2", size,align, socket);
392 	if (!p3)
393 		return -1;
394 
395 	rte_malloc_get_socket_stats(socket,&second_stats);
396 
397 	rte_free(p2);
398 	rte_free(p3);
399 
400 	/* After freeing both allocations check stats return to original */
401 	rte_malloc_get_socket_stats(socket, &post_stats);
402 
403 	/*
404 	 * Check that no new blocks added after small allocations
405 	 * i.e. < RTE_MALLOC_MEMZONE_SIZE
406 	 */
407 	if(second_stats.heap_totalsz_bytes != first_stats.heap_totalsz_bytes) {
408 		printf("Incorrect heap statistics: Total size \n");
409 		return -1;
410 	}
411 	/* Check allocated size is equal to two additions plus overhead */
412 	if(second_stats.heap_allocsz_bytes !=
413 			size + overhead + first_stats.heap_allocsz_bytes) {
414 		printf("Incorrect heap statistics: Allocated size \n");
415 		return -1;
416 	}
417 	/* Check that allocation count increments correctly i.e. +1 */
418 	if (second_stats.alloc_count != first_stats.alloc_count + 1) {
419 		printf("Incorrect heap statistics: Allocated count \n");
420 		return -1;
421 	}
422 
423 	if (second_stats.free_count != first_stats.free_count){
424 		printf("Incorrect heap statistics: Free count \n");
425 		return -1;
426 	}
427 
428 	/* Make sure that we didn't touch our greatest chunk: 2 * 11M)  */
429 	if (post_stats.greatest_free_size != pre_stats.greatest_free_size) {
430 		printf("Incorrect heap statistics: Greatest free size \n");
431 		return -1;
432 	}
433 	/* Free size must equal the original free size minus the new allocation*/
434 	if (first_stats.heap_freesz_bytes <= second_stats.heap_freesz_bytes) {
435 		printf("Incorrect heap statistics: Free size \n");
436 		return -1;
437 	}
438 
439 	if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) &&
440 			(post_stats.heap_freesz_bytes!=pre_stats.heap_freesz_bytes) &&
441 			(post_stats.heap_allocsz_bytes!=pre_stats.heap_allocsz_bytes)&&
442 			(post_stats.alloc_count!=pre_stats.alloc_count)&&
443 			(post_stats.free_count!=pre_stats.free_count)) {
444 		printf("Malloc statistics are incorrect - freed alloc\n");
445 		return -1;
446 	}
447 	return 0;
448 }
449 
450 static int
451 test_memzone_size_alloc(void)
452 {
453 	void *p1 = rte_malloc("BIG", (size_t)(rte_str_to_size(MALLOC_MEMZONE_SIZE) - 128), 64);
454 	if (!p1)
455 		return -1;
456 	rte_free(p1);
457 	/* one extra check - check no crashes if free(NULL) */
458 	rte_free(NULL);
459 	return 0;
460 }
461 
462 static int
463 test_rte_malloc_type_limits(void)
464 {
465 	/* The type-limits functionality is not yet implemented,
466 	 * so always return 0 no matter what the retval.
467 	 */
468 	const char *typename = "limit_test";
469 	rte_malloc_set_limit(typename, 64 * 1024);
470 	rte_malloc_dump_stats(stdout, typename);
471 	return 0;
472 }
473 
474 static int
475 test_realloc(void)
476 {
477 	const char hello_str[] = "Hello, world!";
478 	const unsigned size1 = 1024;
479 	const unsigned size2 = size1 + 1024;
480 	const unsigned size3 = size2;
481 	const unsigned size4 = size3 + 1024;
482 
483 	/* test data is the same even if element is moved*/
484 	char *ptr1 = rte_zmalloc(NULL, size1, CACHE_LINE_SIZE);
485 	if (!ptr1){
486 		printf("NULL pointer returned from rte_zmalloc\n");
487 		return -1;
488 	}
489 	snprintf(ptr1, size1, "%s" ,hello_str);
490 	char *ptr2 = rte_realloc(ptr1, size2, CACHE_LINE_SIZE);
491 	if (!ptr2){
492 		rte_free(ptr1);
493 		printf("NULL pointer returned from rte_realloc\n");
494 		return -1;
495 	}
496 	if (ptr1 == ptr2){
497 		printf("unexpected - ptr1 == ptr2\n");
498 	}
499 	if (strcmp(ptr2, hello_str) != 0){
500 		printf("Error - lost data from pointed area\n");
501 		rte_free(ptr2);
502 		return -1;
503 	}
504 	unsigned i;
505 	for (i = strnlen(hello_str, sizeof(hello_str)); i < size1; i++)
506 		if (ptr2[i] != 0){
507 			printf("Bad data in realloc\n");
508 			rte_free(ptr2);
509 			return -1;
510 		}
511 	/* now allocate third element, free the second
512 	 * and resize third. It should not move. (ptr1 is now invalid)
513 	 */
514 	char *ptr3 = rte_zmalloc(NULL, size3, CACHE_LINE_SIZE);
515 	if (!ptr3){
516 		printf("NULL pointer returned from rte_zmalloc\n");
517 		rte_free(ptr2);
518 		return -1;
519 	}
520 	for (i = 0; i < size3; i++)
521 		if (ptr3[i] != 0){
522 			printf("Bad data in zmalloc\n");
523 			rte_free(ptr3);
524 			rte_free(ptr2);
525 			return -1;
526 		}
527 	rte_free(ptr2);
528 	/* first resize to half the size of the freed block */
529 	char *ptr4 = rte_realloc(ptr3, size4, CACHE_LINE_SIZE);
530 	if (!ptr4){
531 		printf("NULL pointer returned from rte_realloc\n");
532 		rte_free(ptr3);
533 		return -1;
534 	}
535 	if (ptr3 != ptr4){
536 		printf("Unexpected - ptr4 != ptr3\n");
537 		rte_free(ptr4);
538 		return -1;
539 	}
540 	/* now resize again to the full size of the freed block */
541 	ptr4 = rte_realloc(ptr3, size3 + size2 + size1, CACHE_LINE_SIZE);
542 	if (ptr3 != ptr4){
543 		printf("Unexpected - ptr4 != ptr3 on second resize\n");
544 		rte_free(ptr4);
545 		return -1;
546 	}
547 	rte_free(ptr4);
548 
549 	/* now try a resize to a smaller size, see if it works */
550 	const unsigned size5 = 1024;
551 	const unsigned size6 = size5 / 2;
552 	char *ptr5 = rte_malloc(NULL, size5, CACHE_LINE_SIZE);
553 	if (!ptr5){
554 		printf("NULL pointer returned from rte_malloc\n");
555 		return -1;
556 	}
557 	char *ptr6 = rte_realloc(ptr5, size6, CACHE_LINE_SIZE);
558 	if (!ptr6){
559 		printf("NULL pointer returned from rte_realloc\n");
560 		rte_free(ptr5);
561 		return -1;
562 	}
563 	if (ptr5 != ptr6){
564 		printf("Error, resizing to a smaller size moved data\n");
565 		rte_free(ptr6);
566 		return -1;
567 	}
568 	rte_free(ptr6);
569 
570 	/* check for behaviour changing alignment */
571 	const unsigned size7 = 1024;
572 	const unsigned orig_align = CACHE_LINE_SIZE;
573 	unsigned new_align = CACHE_LINE_SIZE * 2;
574 	char *ptr7 = rte_malloc(NULL, size7, orig_align);
575 	if (!ptr7){
576 		printf("NULL pointer returned from rte_malloc\n");
577 		return -1;
578 	}
579 	/* calc an alignment we don't already have */
580 	while(RTE_PTR_ALIGN(ptr7, new_align) == ptr7)
581 		new_align *= 2;
582 	char *ptr8 = rte_realloc(ptr7, size7, new_align);
583 	if (!ptr8){
584 		printf("NULL pointer returned from rte_realloc\n");
585 		rte_free(ptr7);
586 		return -1;
587 	}
588 	if (RTE_PTR_ALIGN(ptr8, new_align) != ptr8){
589 		printf("Failure to re-align data\n");
590 		rte_free(ptr8);
591 		return -1;
592 	}
593 	rte_free(ptr8);
594 
595 	/* test behaviour when there is a free block after current one,
596 	 * but its not big enough
597 	 */
598 	unsigned size9 = 1024, size10 = 1024;
599 	unsigned size11 = size9 + size10 + 256;
600 	char *ptr9 = rte_malloc(NULL, size9, CACHE_LINE_SIZE);
601 	if (!ptr9){
602 		printf("NULL pointer returned from rte_malloc\n");
603 		return -1;
604 	}
605 	char *ptr10 = rte_malloc(NULL, size10, CACHE_LINE_SIZE);
606 	if (!ptr10){
607 		printf("NULL pointer returned from rte_malloc\n");
608 		return -1;
609 	}
610 	rte_free(ptr9);
611 	char *ptr11 = rte_realloc(ptr10, size11, CACHE_LINE_SIZE);
612 	if (!ptr11){
613 		printf("NULL pointer returned from rte_realloc\n");
614 		rte_free(ptr10);
615 		return -1;
616 	}
617 	if (ptr11 == ptr10){
618 		printf("Error, unexpected that realloc has not created new buffer\n");
619 		rte_free(ptr11);
620 		return -1;
621 	}
622 	rte_free(ptr11);
623 
624 	/* check we don't crash if we pass null to realloc
625 	 * We should get a malloc of the size requested*/
626 	const size_t size12 = 1024;
627 	size_t size12_check;
628 	char *ptr12 = rte_realloc(NULL, size12, CACHE_LINE_SIZE);
629 	if (!ptr12){
630 		printf("NULL pointer returned from rte_realloc\n");
631 		return -1;
632 	}
633 	if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
634 			size12_check != size12){
635 		rte_free(ptr12);
636 		return -1;
637 	}
638 	rte_free(ptr12);
639 	return 0;
640 }
641 
642 static int
643 test_random_alloc_free(void *_ __attribute__((unused)))
644 {
645 	struct mem_list {
646 		struct mem_list *next;
647 		char data[0];
648 	} *list_head = NULL;
649 	unsigned i;
650 	unsigned count = 0;
651 
652 	rte_srand((unsigned)rte_rdtsc());
653 
654 	for (i = 0; i < N; i++){
655 		unsigned free_mem = 0;
656 		size_t allocated_size;
657 		while (!free_mem){
658 			const unsigned mem_size = sizeof(struct mem_list) + \
659 					rte_rand() % (64 * 1024);
660 			const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */
661 			struct mem_list *entry = rte_malloc(NULL,
662 					mem_size, align);
663 			if (entry == NULL)
664 				return -1;
665 			if (RTE_PTR_ALIGN(entry, align)!= entry)
666 				return -1;
667 			if (rte_malloc_validate(entry, &allocated_size) == -1
668 					|| allocated_size < mem_size)
669 				return -1;
670 			memset(entry->data, rte_lcore_id(),
671 					mem_size - sizeof(*entry));
672 			entry->next = list_head;
673 			if (rte_malloc_validate(entry, NULL) == -1)
674 				return -1;
675 			list_head = entry;
676 
677 			count++;
678 			/* switch to freeing the memory with a 20% probability */
679 			free_mem = ((rte_rand() % 10) >= 8);
680 		}
681 		while (list_head){
682 			struct mem_list *entry = list_head;
683 			list_head = list_head->next;
684 			rte_free(entry);
685 		}
686 	}
687 	printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count);
688 	return 0;
689 }
690 
691 #define err_return() do { \
692 	printf("%s: %d - Error\n", __func__, __LINE__); \
693 	goto err_return; \
694 } while (0)
695 
696 static int
697 test_rte_malloc_validate(void)
698 {
699 	const size_t request_size = 1024;
700 	size_t allocated_size;
701 	char *data_ptr = rte_malloc(NULL, request_size, CACHE_LINE_SIZE);
702 #ifdef RTE_LIBRTE_MALLOC_DEBUG
703 	int retval;
704 	char *over_write_vals = NULL;
705 #endif
706 
707 	if (data_ptr == NULL) {
708 		printf("%s: %d - Allocation error\n", __func__, __LINE__);
709 		return -1;
710 	}
711 
712 	/* check that a null input returns -1 */
713 	if (rte_malloc_validate(NULL, NULL) != -1)
714 		err_return();
715 
716 	/* check that we get ok on a valid pointer */
717 	if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
718 		err_return();
719 
720 	/* check that the returned size is ok */
721 	if (allocated_size < request_size)
722 		err_return();
723 
724 #ifdef RTE_LIBRTE_MALLOC_DEBUG
725 
726 	/****** change the header to be bad */
727 	char save_buf[64];
728 	over_write_vals = (char *)((uintptr_t)data_ptr - sizeof(save_buf));
729 	/* first save the data as a backup before overwriting it */
730 	memcpy(save_buf, over_write_vals, sizeof(save_buf));
731 	memset(over_write_vals, 1, sizeof(save_buf));
732 	/* then run validate */
733 	retval = rte_malloc_validate(data_ptr, NULL);
734 	/* finally restore the data again */
735 	memcpy(over_write_vals, save_buf, sizeof(save_buf));
736 	/* check we previously had an error */
737 	if (retval != -1)
738 		err_return();
739 
740 	/* check all ok again */
741 	if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
742 		err_return();
743 
744 	/**** change the trailer to be bad */
745 	over_write_vals = (char *)((uintptr_t)data_ptr + allocated_size);
746 	/* first save the data as a backup before overwriting it */
747 	memcpy(save_buf, over_write_vals, sizeof(save_buf));
748 	memset(over_write_vals, 1, sizeof(save_buf));
749 	/* then run validate */
750 	retval = rte_malloc_validate(data_ptr, NULL);
751 	/* finally restore the data again */
752 	memcpy(over_write_vals, save_buf, sizeof(save_buf));
753 	if (retval != -1)
754 		err_return();
755 
756 	/* check all ok again */
757 	if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
758 		err_return();
759 #endif
760 
761 	rte_free(data_ptr);
762 	return 0;
763 
764 err_return:
765 	/*clean up */
766 	rte_free(data_ptr);
767 	return -1;
768 }
769 
770 static int
771 test_zero_aligned_alloc(void)
772 {
773 	char *p1 = rte_malloc(NULL,1024, 0);
774 	if (!p1)
775 		goto err_return;
776 	if (!rte_is_aligned(p1, CACHE_LINE_SIZE))
777 		goto err_return;
778 	rte_free(p1);
779 	return 0;
780 
781 err_return:
782 	/*clean up */
783 	if (p1) rte_free(p1);
784 	return -1;
785 }
786 
787 static int
788 test_malloc_bad_params(void)
789 {
790 	const char *type = NULL;
791 	size_t size = 0;
792 	unsigned align = CACHE_LINE_SIZE;
793 
794 	/* rte_malloc expected to return null with inappropriate size */
795 	char *bad_ptr = rte_malloc(type, size, align);
796 	if (bad_ptr != NULL)
797 		goto err_return;
798 
799 	/* rte_malloc expected to return null with inappropriate alignment */
800 	align = 17;
801 	size = 1024;
802 
803 	bad_ptr = rte_malloc(type, size, align);
804 	if (bad_ptr != NULL)
805 		goto err_return;
806 
807 	return 0;
808 
809 err_return:
810 	/* clean up pointer */
811 	if (bad_ptr)
812 		rte_free(bad_ptr);
813 	return -1;
814 }
815 
816 /* Check if memory is avilable on a specific socket */
817 static int
818 is_mem_on_socket(int32_t socket)
819 {
820 	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
821 	unsigned i;
822 
823 	for (i = 0; i < RTE_MAX_MEMSEG; i++) {
824 		if (socket == ms[i].socket_id)
825 			return 1;
826 	}
827 	return 0;
828 }
829 
830 /*
831  * Find what socket a memory address is on. Only works for addresses within
832  * memsegs, not heap or stack...
833  */
834 static int32_t
835 addr_to_socket(void * addr)
836 {
837 	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
838 	unsigned i;
839 
840 	for (i = 0; i < RTE_MAX_MEMSEG; i++) {
841 		if ((ms[i].addr <= addr) &&
842 				((uintptr_t)addr <
843 				((uintptr_t)ms[i].addr + (uintptr_t)ms[i].len)))
844 			return ms[i].socket_id;
845 	}
846 	return -1;
847 }
848 
849 /* Test using rte_[c|m|zm]alloc_socket() on a specific socket */
850 static int
851 test_alloc_single_socket(int32_t socket)
852 {
853 	const char *type = NULL;
854 	const size_t size = 10;
855 	const unsigned align = 0;
856 	char *mem = NULL;
857 	int32_t desired_socket = (socket == SOCKET_ID_ANY) ?
858 			(int32_t)rte_socket_id() : socket;
859 
860 	/* Test rte_calloc_socket() */
861 	mem = rte_calloc_socket(type, size, sizeof(char), align, socket);
862 	if (mem == NULL)
863 		return -1;
864 	if (addr_to_socket(mem) != desired_socket) {
865 		rte_free(mem);
866 		return -1;
867 	}
868 	rte_free(mem);
869 
870 	/* Test rte_malloc_socket() */
871 	mem = rte_malloc_socket(type, size, align, socket);
872 	if (mem == NULL)
873 		return -1;
874 	if (addr_to_socket(mem) != desired_socket) {
875 		return -1;
876 	}
877 	rte_free(mem);
878 
879 	/* Test rte_zmalloc_socket() */
880 	mem = rte_zmalloc_socket(type, size, align, socket);
881 	if (mem == NULL)
882 		return -1;
883 	if (addr_to_socket(mem) != desired_socket) {
884 		rte_free(mem);
885 		return -1;
886 	}
887 	rte_free(mem);
888 
889 	return 0;
890 }
891 
892 static int
893 test_alloc_socket(void)
894 {
895 	unsigned socket_count = 0;
896 	unsigned i;
897 
898 	if (test_alloc_single_socket(SOCKET_ID_ANY) < 0)
899 		return -1;
900 
901 	for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
902 		if (is_mem_on_socket(i)) {
903 			socket_count++;
904 			if (test_alloc_single_socket(i) < 0) {
905 				printf("Fail: rte_malloc_socket(..., %u) did not succeed\n",
906 						i);
907 				return -1;
908 			}
909 		}
910 		else {
911 			if (test_alloc_single_socket(i) == 0) {
912 				printf("Fail: rte_malloc_socket(..., %u) succeeded\n",
913 						i);
914 				return -1;
915 			}
916 		}
917 	}
918 
919 	/* Print warnign if only a single socket, but don't fail the test */
920 	if (socket_count < 2) {
921 		printf("WARNING: alloc_socket test needs memory on multiple sockets!\n");
922 	}
923 
924 	return 0;
925 }
926 
927 static int
928 test_malloc(void)
929 {
930 	unsigned lcore_id;
931 	int ret = 0;
932 
933 	if (test_str_to_size() < 0){
934 		printf("test_str_to_size() failed\n");
935 		return -1;
936 	}
937 	else printf("test_str_to_size() passed\n");
938 
939 	if (test_memzone_size_alloc() < 0){
940 		printf("test_memzone_size_alloc() failed\n");
941 		return -1;
942 	}
943 	else printf("test_memzone_size_alloc() passed\n");
944 
945 	if (test_big_alloc() < 0){
946 		printf("test_big_alloc() failed\n");
947 		return -1;
948 	}
949 	else printf("test_big_alloc() passed\n");
950 
951 	if (test_zero_aligned_alloc() < 0){
952 		printf("test_zero_aligned_alloc() failed\n");
953 		return -1;
954 	}
955 	else printf("test_zero_aligned_alloc() passed\n");
956 
957 	if (test_malloc_bad_params() < 0){
958 		printf("test_malloc_bad_params() failed\n");
959 		return -1;
960 	}
961 	else printf("test_malloc_bad_params() passed\n");
962 
963 	if (test_realloc() < 0){
964 		printf("test_realloc() failed\n");
965 		return -1;
966 	}
967 	else printf("test_realloc() passed\n");
968 
969 	/*----------------------------*/
970 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
971 		rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id);
972 	}
973 
974 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
975 		if (rte_eal_wait_lcore(lcore_id) < 0)
976 			ret = -1;
977 	}
978 	if (ret < 0){
979 		printf("test_align_overlap_per_lcore() failed\n");
980 		return ret;
981 	}
982 	else printf("test_align_overlap_per_lcore() passed\n");
983 
984 	/*----------------------------*/
985 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
986 		rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id);
987 	}
988 
989 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
990 		if (rte_eal_wait_lcore(lcore_id) < 0)
991 			ret = -1;
992 	}
993 	if (ret < 0){
994 		printf("test_reordered_free_per_lcore() failed\n");
995 		return ret;
996 	}
997 	else printf("test_reordered_free_per_lcore() passed\n");
998 
999 	/*----------------------------*/
1000 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
1001 		rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id);
1002 	}
1003 
1004 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
1005 		if (rte_eal_wait_lcore(lcore_id) < 0)
1006 			ret = -1;
1007 	}
1008 	if (ret < 0){
1009 		printf("test_random_alloc_free() failed\n");
1010 		return ret;
1011 	}
1012 	else printf("test_random_alloc_free() passed\n");
1013 
1014 	/*----------------------------*/
1015 	ret = test_rte_malloc_type_limits();
1016 	if (ret < 0){
1017 		printf("test_rte_malloc_type_limits() failed\n");
1018 		return ret;
1019 	}
1020 	/* TODO: uncomment following line once type limits are valid */
1021 	/*else printf("test_rte_malloc_type_limits() passed\n");*/
1022 
1023 	/*----------------------------*/
1024 	ret = test_rte_malloc_validate();
1025 	if (ret < 0){
1026 		printf("test_rte_malloc_validate() failed\n");
1027 		return ret;
1028 	}
1029 	else printf("test_rte_malloc_validate() passed\n");
1030 
1031 	ret = test_alloc_socket();
1032 	if (ret < 0){
1033 		printf("test_alloc_socket() failed\n");
1034 		return ret;
1035 	}
1036 	else printf("test_alloc_socket() passed\n");
1037 
1038 	ret = test_multi_alloc_statistics();
1039 	if (ret < 0) {
1040 		printf("test_multi_alloc_statistics() failed\n");
1041 		return ret;
1042 	}
1043 	else
1044 		printf("test_multi_alloc_statistics() passed\n");
1045 
1046 	return 0;
1047 }
1048 
1049 static struct test_command malloc_cmd = {
1050 	.command = "malloc_autotest",
1051 	.callback = test_malloc,
1052 };
1053 REGISTER_TEST_COMMAND(malloc_cmd);
1054