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