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