Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: Source/wtf/PartitionAllocTest.cpp

Issue 26196002: Improve partitionAlloc's resistance to fragmentation. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/wtf/PartitionAlloc.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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)
OLDNEW
« no previous file with comments | « Source/wtf/PartitionAlloc.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698