OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 } | 211 } |
212 | 212 |
213 // Test some finer aspects of internal page transitions. | 213 // Test some finer aspects of internal page transitions. |
214 TEST(WTF_PartitionAlloc, PageTransitions) | 214 TEST(WTF_PartitionAlloc, PageTransitions) |
215 { | 215 { |
216 TestSetup(); | 216 TestSetup(); |
217 size_t bucketIdx = kTestAllocSize >> WTF::kBucketShift; | 217 size_t bucketIdx = kTestAllocSize >> WTF::kBucketShift; |
218 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; | 218 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; |
219 | 219 |
220 WTF::PartitionPageHeader* page1 = GetFullPage(kTestAllocSize); | 220 WTF::PartitionPageHeader* page1 = GetFullPage(kTestAllocSize); |
| 221 EXPECT_EQ(page1, bucket->currPage); |
| 222 EXPECT_EQ(page1, page1->next); |
| 223 EXPECT_EQ(page1, page1->prev); |
221 WTF::PartitionPageHeader* page2 = GetFullPage(kTestAllocSize); | 224 WTF::PartitionPageHeader* page2 = GetFullPage(kTestAllocSize); |
222 EXPECT_EQ(page2, bucket->currPage); | 225 EXPECT_EQ(page2, bucket->currPage); |
223 EXPECT_EQ(page1, page2->next); | 226 EXPECT_EQ(page2, page2->next); |
224 EXPECT_EQ(page1, page2->prev); | 227 EXPECT_EQ(page2, page2->prev); |
| 228 |
| 229 // Bounce page1 back into the non-full list then fill it up again. |
| 230 char* ptr = reinterpret_cast<char*>(page1) + sizeof(WTF::PartitionPageHeader
); |
| 231 partitionFree(ptr); |
| 232 (void) partitionAlloc(allocator.root(), kTestAllocSize); |
| 233 EXPECT_EQ(page1, bucket->currPage); |
| 234 |
225 // Allocating another page at this point should cause us to scan over page1 | 235 // Allocating another page at this point should cause us to scan over page1 |
226 // (which is both full and NOT our current page), and evict it from the | 236 // (which is both full and NOT our current page), and evict it from the |
227 // freelist. Older code had a O(n^2) condition due to failure to do this. | 237 // freelist. Older code had a O(n^2) condition due to failure to do this. |
228 WTF::PartitionPageHeader* page3 = GetFullPage(kTestAllocSize); | 238 WTF::PartitionPageHeader* page3 = GetFullPage(kTestAllocSize); |
229 EXPECT_EQ(page3, bucket->currPage); | 239 EXPECT_EQ(page3, bucket->currPage); |
230 EXPECT_EQ(page2, page3->next); | 240 EXPECT_EQ(page3, page3->next); |
231 EXPECT_EQ(page3, page2->next); | 241 EXPECT_EQ(page3, page3->next); |
232 | 242 |
233 // Work out a pointer into page2 and free it. | 243 // Work out a pointer into page2 and free it. |
234 char* ptr = reinterpret_cast<char*>(page2) + sizeof(WTF::PartitionPageHeader
); | 244 ptr = reinterpret_cast<char*>(page2) + sizeof(WTF::PartitionPageHeader); |
235 partitionFree(ptr); | 245 partitionFree(ptr); |
236 // Trying to allocate at this time should cause us to cycle around to page2 | 246 // Trying to allocate at this time should cause us to cycle around to page2 |
237 // and find the recently freed slot. | 247 // and find the recently freed slot. |
238 char* newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTes
tAllocSize)); | 248 char* newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTes
tAllocSize)); |
239 EXPECT_EQ(ptr, newPtr); | 249 EXPECT_EQ(ptr, newPtr); |
240 EXPECT_EQ(page2, bucket->currPage); | 250 EXPECT_EQ(page2, bucket->currPage); |
241 | 251 |
242 // Work out a pointer into page1 and free it. This should pull the page | 252 // Work out a pointer into page1 and free it. This should pull the page |
243 // back into the ring list of available pages. | 253 // back into the ring list of available pages. |
244 ptr = reinterpret_cast<char*>(page1) + sizeof(WTF::PartitionPageHeader); | 254 ptr = reinterpret_cast<char*>(page1) + sizeof(WTF::PartitionPageHeader); |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 void* ptr3 = partitionAlloc(allocator.root(), bigSize); | 472 void* ptr3 = partitionAlloc(allocator.root(), bigSize); |
463 EXPECT_TRUE(ptr3); | 473 EXPECT_TRUE(ptr3); |
464 EXPECT_EQ(0, page->freelistHead); | 474 EXPECT_EQ(0, page->freelistHead); |
465 EXPECT_EQ(3, page->numAllocatedSlots); | 475 EXPECT_EQ(3, page->numAllocatedSlots); |
466 | 476 |
467 void* ptr4 = partitionAlloc(allocator.root(), bigSize); | 477 void* ptr4 = partitionAlloc(allocator.root(), bigSize); |
468 EXPECT_TRUE(ptr4); | 478 EXPECT_TRUE(ptr4); |
469 WTF::PartitionPageHeader* page2 = reinterpret_cast<WTF::PartitionPageHeader*
>(reinterpret_cast<size_t>(ptr4) & WTF::kPartitionPageBaseMask); | 479 WTF::PartitionPageHeader* page2 = reinterpret_cast<WTF::PartitionPageHeader*
>(reinterpret_cast<size_t>(ptr4) & WTF::kPartitionPageBaseMask); |
470 EXPECT_EQ(1, page2->numAllocatedSlots); | 480 EXPECT_EQ(1, page2->numAllocatedSlots); |
471 | 481 |
| 482 // Churn things a little whilst there's a partial page freelist. |
| 483 partitionFree(ptr); |
| 484 ptr = partitionAlloc(allocator.root(), bigSize); |
| 485 void* ptr5 = partitionAlloc(allocator.root(), bigSize); |
| 486 |
472 partitionFree(ptr); | 487 partitionFree(ptr); |
473 partitionFree(ptr2); | 488 partitionFree(ptr2); |
474 partitionFree(ptr3); | 489 partitionFree(ptr3); |
475 partitionFree(ptr4); | 490 partitionFree(ptr4); |
| 491 partitionFree(ptr5); |
476 EXPECT_TRUE(bucket->freePages); | 492 EXPECT_TRUE(bucket->freePages); |
477 EXPECT_EQ(page, bucket->freePages->page); | 493 EXPECT_EQ(page, bucket->freePages->page); |
478 EXPECT_TRUE(page2->freelistHead); | 494 EXPECT_TRUE(page2->freelistHead); |
479 EXPECT_EQ(0, page2->numAllocatedSlots); | 495 EXPECT_EQ(0, page2->numAllocatedSlots); |
480 | 496 |
481 // And test a couple of sizes that do not cross kSubPartitionPageSize with a
single allocation. | 497 // And test a couple of sizes that do not cross kSubPartitionPageSize with a
single allocation. |
482 size_t mediumSize = WTF::kSubPartitionPageSize / 2; | 498 size_t mediumSize = WTF::kSubPartitionPageSize / 2; |
483 bucketIdx = mediumSize >> WTF::kBucketShift; | 499 bucketIdx = mediumSize >> WTF::kBucketShift; |
484 bucket = &allocator.root()->buckets()[bucketIdx]; | 500 bucket = &allocator.root()->buckets()[bucketIdx]; |
485 EXPECT_EQ(0, bucket->freePages); | 501 EXPECT_EQ(0, bucket->freePages); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 firstPageSlots = (WTF::kSubPartitionPageSize - sizeof(WTF::PartitionPageHead
er)) / verySmallSize; | 538 firstPageSlots = (WTF::kSubPartitionPageSize - sizeof(WTF::PartitionPageHead
er)) / verySmallSize; |
523 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); | 539 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); |
524 | 540 |
525 partitionFree(ptr); | 541 partitionFree(ptr); |
526 EXPECT_TRUE(page->freelistHead); | 542 EXPECT_TRUE(page->freelistHead); |
527 EXPECT_EQ(0, page->numAllocatedSlots); | 543 EXPECT_EQ(0, page->numAllocatedSlots); |
528 | 544 |
529 TestShutdown(); | 545 TestShutdown(); |
530 } | 546 } |
531 | 547 |
| 548 // Test some of the fragmentation-resistant properties of the allocator. |
| 549 TEST(WTF_PartitionAlloc, PageRefilling) |
| 550 { |
| 551 TestSetup(); |
| 552 size_t bucketIdx = kTestAllocSize >> WTF::kBucketShift; |
| 553 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; |
| 554 |
| 555 // Grab two full pages and a non-full page. |
| 556 WTF::PartitionPageHeader* page1 = GetFullPage(kTestAllocSize); |
| 557 WTF::PartitionPageHeader* page2 = GetFullPage(kTestAllocSize); |
| 558 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); |
| 559 EXPECT_TRUE(ptr); |
| 560 EXPECT_NE(page1, bucket->currPage); |
| 561 EXPECT_NE(page2, bucket->currPage); |
| 562 WTF::PartitionPageHeader* page = reinterpret_cast<WTF::PartitionPageHeader*>
(reinterpret_cast<size_t>(ptr) & WTF::kPartitionPageBaseMask); |
| 563 EXPECT_EQ(1, page->numAllocatedSlots); |
| 564 |
| 565 // Work out a pointer into page2 and free it; and then page1 and free it. |
| 566 char* ptr2 = reinterpret_cast<char*>(page1) + sizeof(WTF::PartitionPageHeade
r); |
| 567 partitionFree(ptr2); |
| 568 ptr2 = reinterpret_cast<char*>(page2) + sizeof(WTF::PartitionPageHeader); |
| 569 partitionFree(ptr2); |
| 570 |
| 571 // If we perform two allocations from the same bucket now, we expect to |
| 572 // refill both the nearly full pages. |
| 573 (void) partitionAlloc(allocator.root(), kTestAllocSize); |
| 574 (void) partitionAlloc(allocator.root(), kTestAllocSize); |
| 575 EXPECT_EQ(1, page->numAllocatedSlots); |
| 576 |
| 577 FreeFullPage(page2, kTestAllocSize); |
| 578 FreeFullPage(page1, kTestAllocSize); |
| 579 partitionFree(ptr); |
| 580 |
| 581 TestShutdown(); |
| 582 } |
| 583 |
532 #if OS(POSIX) | 584 #if OS(POSIX) |
533 | 585 |
534 // Test correct handling if our mapping collides with another. | 586 // Test correct handling if our mapping collides with another. |
535 TEST(WTF_PartitionAlloc, MappingCollision) | 587 TEST(WTF_PartitionAlloc, MappingCollision) |
536 { | 588 { |
537 TestSetup(); | 589 TestSetup(); |
538 // The -1 is because the first super page allocated with have its first part
ition page marked as a guard page. | 590 // The -1 is because the first super page allocated with have its first part
ition page marked as a guard page. |
539 size_t numPartitionPagesNeeded = (WTF::kSuperPageSize / WTF::kPartitionPageS
ize) - 1; | 591 size_t numPartitionPagesNeeded = (WTF::kSuperPageSize / WTF::kPartitionPageS
ize) - 1; |
540 OwnArrayPtr<WTF::PartitionPageHeader*> firstSuperPagePages = adoptArrayPtr(n
ew WTF::PartitionPageHeader*[numPartitionPagesNeeded]); | 592 OwnArrayPtr<WTF::PartitionPageHeader*> firstSuperPagePages = adoptArrayPtr(n
ew WTF::PartitionPageHeader*[numPartitionPagesNeeded]); |
541 OwnArrayPtr<WTF::PartitionPageHeader*> secondSuperPagePages = adoptArrayPtr(
new WTF::PartitionPageHeader*[numPartitionPagesNeeded]); | 593 OwnArrayPtr<WTF::PartitionPageHeader*> secondSuperPagePages = adoptArrayPtr(
new WTF::PartitionPageHeader*[numPartitionPagesNeeded]); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 } | 635 } |
584 | 636 |
585 TestShutdown(); | 637 TestShutdown(); |
586 } | 638 } |
587 | 639 |
588 #endif // OS(POSIX) | 640 #endif // OS(POSIX) |
589 | 641 |
590 } // namespace | 642 } // namespace |
591 | 643 |
592 #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 644 #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
OLD | NEW |