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