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