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