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