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