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 rte_srand((unsigned)rte_rdtsc()); 696 697 for (i = 0; i < N; i++){ 698 unsigned free_mem = 0; 699 size_t allocated_size; 700 while (!free_mem){ 701 const unsigned mem_size = sizeof(struct mem_list) + \ 702 rte_rand() % (64 * 1024); 703 const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */ 704 struct mem_list *entry = rte_malloc(NULL, 705 mem_size, align); 706 if (entry == NULL) 707 return -1; 708 if (RTE_PTR_ALIGN(entry, align)!= entry) 709 return -1; 710 if (rte_malloc_validate(entry, &allocated_size) == -1 711 || allocated_size < mem_size) 712 return -1; 713 memset(entry->data, rte_lcore_id(), 714 mem_size - sizeof(*entry)); 715 entry->next = list_head; 716 if (rte_malloc_validate(entry, NULL) == -1) 717 return -1; 718 list_head = entry; 719 720 count++; 721 /* switch to freeing the memory with a 20% probability */ 722 free_mem = ((rte_rand() % 10) >= 8); 723 } 724 while (list_head){ 725 struct mem_list *entry = list_head; 726 list_head = list_head->next; 727 rte_free(entry); 728 } 729 } 730 printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count); 731 return 0; 732 } 733 734 #define err_return() do { \ 735 printf("%s: %d - Error\n", __func__, __LINE__); \ 736 goto err_return; \ 737 } while (0) 738 739 static int 740 test_rte_malloc_validate(void) 741 { 742 const size_t request_size = 1024; 743 size_t allocated_size; 744 char *data_ptr = rte_malloc(NULL, request_size, RTE_CACHE_LINE_SIZE); 745 #ifdef RTE_MALLOC_DEBUG 746 int retval; 747 char *over_write_vals = NULL; 748 #endif 749 750 if (data_ptr == NULL) { 751 printf("%s: %d - Allocation error\n", __func__, __LINE__); 752 return -1; 753 } 754 755 /* check that a null input returns -1 */ 756 if (rte_malloc_validate(NULL, NULL) != -1) 757 err_return(); 758 759 /* check that we get ok on a valid pointer */ 760 if (rte_malloc_validate(data_ptr, &allocated_size) < 0) 761 err_return(); 762 763 /* check that the returned size is ok */ 764 if (allocated_size < request_size) 765 err_return(); 766 767 #ifdef RTE_MALLOC_DEBUG 768 769 /****** change the header to be bad */ 770 char save_buf[64]; 771 over_write_vals = (char *)((uintptr_t)data_ptr - sizeof(save_buf)); 772 /* first save the data as a backup before overwriting it */ 773 memcpy(save_buf, over_write_vals, sizeof(save_buf)); 774 memset(over_write_vals, 1, sizeof(save_buf)); 775 /* then run validate */ 776 retval = rte_malloc_validate(data_ptr, NULL); 777 /* finally restore the data again */ 778 memcpy(over_write_vals, save_buf, sizeof(save_buf)); 779 /* check we previously had an error */ 780 if (retval != -1) 781 err_return(); 782 783 /* check all ok again */ 784 if (rte_malloc_validate(data_ptr, &allocated_size) < 0) 785 err_return(); 786 787 /**** change the trailer to be bad */ 788 over_write_vals = (char *)((uintptr_t)data_ptr + allocated_size); 789 /* first save the data as a backup before overwriting it */ 790 memcpy(save_buf, over_write_vals, sizeof(save_buf)); 791 memset(over_write_vals, 1, sizeof(save_buf)); 792 /* then run validate */ 793 retval = rte_malloc_validate(data_ptr, NULL); 794 /* finally restore the data again */ 795 memcpy(over_write_vals, save_buf, sizeof(save_buf)); 796 if (retval != -1) 797 err_return(); 798 799 /* check all ok again */ 800 if (rte_malloc_validate(data_ptr, &allocated_size) < 0) 801 err_return(); 802 #endif 803 804 rte_free(data_ptr); 805 return 0; 806 807 err_return: 808 /*clean up */ 809 rte_free(data_ptr); 810 return -1; 811 } 812 813 static int 814 test_zero_aligned_alloc(void) 815 { 816 char *p1 = rte_malloc(NULL,1024, 0); 817 if (!p1) 818 goto err_return; 819 if (!rte_is_aligned(p1, RTE_CACHE_LINE_SIZE)) 820 goto err_return; 821 rte_free(p1); 822 return 0; 823 824 err_return: 825 /*clean up */ 826 if (p1) rte_free(p1); 827 return -1; 828 } 829 830 static int 831 test_malloc_bad_params(void) 832 { 833 const char *type = NULL; 834 size_t size = 0; 835 unsigned align = RTE_CACHE_LINE_SIZE; 836 837 /* rte_malloc expected to return null with inappropriate size */ 838 char *bad_ptr = rte_malloc(type, size, align); 839 if (bad_ptr != NULL) 840 goto err_return; 841 842 /* rte_realloc expected to return null with inappropriate size */ 843 bad_ptr = rte_realloc(NULL, size, align); 844 if (bad_ptr != NULL) 845 goto err_return; 846 847 /* rte_malloc expected to return null with inappropriate alignment */ 848 align = 17; 849 size = 1024; 850 851 bad_ptr = rte_malloc(type, size, align); 852 if (bad_ptr != NULL) 853 goto err_return; 854 855 /* rte_realloc expected to return null with inappropriate alignment */ 856 bad_ptr = rte_realloc(NULL, size, align); 857 if (bad_ptr != NULL) 858 goto err_return; 859 860 #if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG) 861 /* this test can not be built, will get trapped at compile time! */ 862 #else 863 /* rte_malloc expected to return null with size will cause overflow */ 864 align = RTE_CACHE_LINE_SIZE; 865 size = (size_t)-8; 866 867 bad_ptr = rte_malloc(type, size, align); 868 if (bad_ptr != NULL) 869 goto err_return; 870 871 bad_ptr = rte_realloc(NULL, size, align); 872 if (bad_ptr != NULL) 873 goto err_return; 874 #endif 875 return 0; 876 877 err_return: 878 /* clean up pointer */ 879 if (bad_ptr) 880 rte_free(bad_ptr); 881 return -1; 882 } 883 884 static int 885 check_socket_mem(const struct rte_memseg_list *msl, void *arg) 886 { 887 int32_t *socket = arg; 888 889 if (msl->external) 890 return 0; 891 892 return *socket == msl->socket_id; 893 } 894 895 /* Check if memory is available on a specific socket */ 896 static int 897 is_mem_on_socket(int32_t socket) 898 { 899 return rte_memseg_list_walk(check_socket_mem, &socket); 900 } 901 902 903 /* 904 * Find what socket a memory address is on. Only works for addresses within 905 * memsegs, not heap or stack... 906 */ 907 static int32_t 908 addr_to_socket(void * addr) 909 { 910 const struct rte_memseg *ms = rte_mem_virt2memseg(addr, NULL); 911 return ms == NULL ? -1 : ms->socket_id; 912 913 } 914 915 /* Test using rte_[c|m|zm]alloc_socket() on a specific socket */ 916 static int 917 test_alloc_single_socket(int32_t socket) 918 { 919 const char *type = NULL; 920 const size_t size = 10; 921 const unsigned align = 0; 922 char *mem = NULL; 923 int32_t desired_socket = (socket == SOCKET_ID_ANY) ? 924 (int32_t)rte_socket_id() : socket; 925 926 /* Test rte_calloc_socket() */ 927 mem = rte_calloc_socket(type, size, sizeof(char), align, socket); 928 if (mem == NULL) 929 return -1; 930 if (addr_to_socket(mem) != desired_socket) { 931 rte_free(mem); 932 return -1; 933 } 934 rte_free(mem); 935 936 /* Test rte_malloc_socket() */ 937 mem = rte_malloc_socket(type, size, align, socket); 938 if (mem == NULL) 939 return -1; 940 if (addr_to_socket(mem) != desired_socket) { 941 return -1; 942 } 943 rte_free(mem); 944 945 /* Test rte_zmalloc_socket() */ 946 mem = rte_zmalloc_socket(type, size, align, socket); 947 if (mem == NULL) 948 return -1; 949 if (addr_to_socket(mem) != desired_socket) { 950 rte_free(mem); 951 return -1; 952 } 953 rte_free(mem); 954 955 return 0; 956 } 957 958 static int 959 test_alloc_socket(void) 960 { 961 unsigned socket_count = 0; 962 unsigned i; 963 964 if (test_alloc_single_socket(SOCKET_ID_ANY) < 0) 965 return -1; 966 967 for (i = 0; i < RTE_MAX_NUMA_NODES; i++) { 968 if (is_mem_on_socket(i)) { 969 socket_count++; 970 if (test_alloc_single_socket(i) < 0) { 971 printf("Fail: rte_malloc_socket(..., %u) did not succeed\n", 972 i); 973 return -1; 974 } 975 } 976 else { 977 if (test_alloc_single_socket(i) == 0) { 978 printf("Fail: rte_malloc_socket(..., %u) succeeded\n", 979 i); 980 return -1; 981 } 982 } 983 } 984 985 /* Print warning if only a single socket, but don't fail the test */ 986 if (socket_count < 2) { 987 printf("WARNING: alloc_socket test needs memory on multiple sockets!\n"); 988 } 989 990 return 0; 991 } 992 993 static int 994 test_malloc(void) 995 { 996 unsigned lcore_id; 997 int ret = 0; 998 999 if (test_str_to_size() < 0){ 1000 printf("test_str_to_size() failed\n"); 1001 return -1; 1002 } 1003 else printf("test_str_to_size() passed\n"); 1004 1005 if (test_zero_aligned_alloc() < 0){ 1006 printf("test_zero_aligned_alloc() failed\n"); 1007 return -1; 1008 } 1009 else printf("test_zero_aligned_alloc() passed\n"); 1010 1011 if (test_malloc_bad_params() < 0){ 1012 printf("test_malloc_bad_params() failed\n"); 1013 return -1; 1014 } 1015 else printf("test_malloc_bad_params() passed\n"); 1016 1017 if (test_realloc() < 0){ 1018 printf("test_realloc() failed\n"); 1019 return -1; 1020 } 1021 else printf("test_realloc() passed\n"); 1022 1023 /*----------------------------*/ 1024 RTE_LCORE_FOREACH_WORKER(lcore_id) { 1025 rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id); 1026 } 1027 1028 RTE_LCORE_FOREACH_WORKER(lcore_id) { 1029 if (rte_eal_wait_lcore(lcore_id) < 0) 1030 ret = -1; 1031 } 1032 if (ret < 0){ 1033 printf("test_align_overlap_per_lcore() failed\n"); 1034 return ret; 1035 } 1036 else printf("test_align_overlap_per_lcore() passed\n"); 1037 1038 /*----------------------------*/ 1039 RTE_LCORE_FOREACH_WORKER(lcore_id) { 1040 rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id); 1041 } 1042 1043 RTE_LCORE_FOREACH_WORKER(lcore_id) { 1044 if (rte_eal_wait_lcore(lcore_id) < 0) 1045 ret = -1; 1046 } 1047 if (ret < 0){ 1048 printf("test_reordered_free_per_lcore() failed\n"); 1049 return ret; 1050 } 1051 else printf("test_reordered_free_per_lcore() passed\n"); 1052 1053 /*----------------------------*/ 1054 RTE_LCORE_FOREACH_WORKER(lcore_id) { 1055 rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id); 1056 } 1057 1058 RTE_LCORE_FOREACH_WORKER(lcore_id) { 1059 if (rte_eal_wait_lcore(lcore_id) < 0) 1060 ret = -1; 1061 } 1062 if (ret < 0){ 1063 printf("test_random_alloc_free() failed\n"); 1064 return ret; 1065 } 1066 else printf("test_random_alloc_free() passed\n"); 1067 1068 /*----------------------------*/ 1069 ret = test_rte_malloc_validate(); 1070 if (ret < 0){ 1071 printf("test_rte_malloc_validate() failed\n"); 1072 return ret; 1073 } 1074 else printf("test_rte_malloc_validate() passed\n"); 1075 1076 ret = test_alloc_socket(); 1077 if (ret < 0){ 1078 printf("test_alloc_socket() failed\n"); 1079 return ret; 1080 } 1081 else printf("test_alloc_socket() passed\n"); 1082 1083 ret = test_multi_alloc_statistics(); 1084 if (ret < 0) { 1085 printf("test_multi_alloc_statistics() failed\n"); 1086 return ret; 1087 } 1088 else 1089 printf("test_multi_alloc_statistics() passed\n"); 1090 1091 return 0; 1092 } 1093 1094 REGISTER_TEST_COMMAND(malloc_autotest, test_malloc); 1095