67a48ba38a958489b1adfc12566cebe55620af36
[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/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 < RTE_DIM(test_values); 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);