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