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