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