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

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

Issue 183113003: PartitionAlloc: support in-place resize of directly mapped allocation (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: addressing some more comments Created 6 years, 9 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
« no previous file with comments | « Source/wtf/PartitionAlloc.h ('k') | Source/wtf/PartitionAllocTest.cpp » ('j') | 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 29 matching lines...) Expand all
40 // Two partition pages are used as guard / metadata page so make sure the super 40 // Two partition pages are used as guard / metadata page so make sure the super
41 // page size is bigger. 41 // page size is bigger.
42 COMPILE_ASSERT(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, ok_super_page _size); 42 COMPILE_ASSERT(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, ok_super_page _size);
43 COMPILE_ASSERT(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), ok_super_page_m ultiple); 43 COMPILE_ASSERT(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), ok_super_page_m ultiple);
44 // Four system pages gives us room to hack out a still-guard-paged piece 44 // Four system pages gives us room to hack out a still-guard-paged piece
45 // of metadata in the middle of a guard partition page. 45 // of metadata in the middle of a guard partition page.
46 COMPILE_ASSERT(WTF::kSystemPageSize * 4 <= WTF::kPartitionPageSize, ok_partition _page_size); 46 COMPILE_ASSERT(WTF::kSystemPageSize * 4 <= WTF::kPartitionPageSize, ok_partition _page_size);
47 COMPILE_ASSERT(!(WTF::kPartitionPageSize % WTF::kSystemPageSize), ok_partition_p age_multiple); 47 COMPILE_ASSERT(!(WTF::kPartitionPageSize % WTF::kSystemPageSize), ok_partition_p age_multiple);
48 COMPILE_ASSERT(sizeof(WTF::PartitionPage) <= WTF::kPageMetadataSize, PartitionPa ge_not_too_big); 48 COMPILE_ASSERT(sizeof(WTF::PartitionPage) <= WTF::kPageMetadataSize, PartitionPa ge_not_too_big);
49 COMPILE_ASSERT(sizeof(WTF::PartitionSuperPageExtentEntry) <= WTF::kPageMetadataS ize, PartitionSuperPageExtentEntry_not_too_big); 49 COMPILE_ASSERT(sizeof(WTF::PartitionSuperPageExtentEntry) <= WTF::kPageMetadataS ize, PartitionSuperPageExtentEntry_not_too_big);
50 COMPILE_ASSERT(sizeof(WTF::PartitionBucket) <= WTF::kPageMetadataSize, Partition Bucket_not_too_big);
Chris Evans 2014/03/06 06:30:20 Nit: maybe put this directly under PartitionPa ge_
50 COMPILE_ASSERT(WTF::kPageMetadataSize * WTF::kNumPartitionPagesPerSuperPage <= W TF::kSystemPageSize, page_metadata_fits_in_hole); 51 COMPILE_ASSERT(WTF::kPageMetadataSize * WTF::kNumPartitionPagesPerSuperPage <= W TF::kSystemPageSize, page_metadata_fits_in_hole);
51 // Check that some of our zanier calculations worked out as expected. 52 // Check that some of our zanier calculations worked out as expected.
52 COMPILE_ASSERT(WTF::kGenericSmallestBucket == 8, generic_smallest_bucket); 53 COMPILE_ASSERT(WTF::kGenericSmallestBucket == 8, generic_smallest_bucket);
53 COMPILE_ASSERT(WTF::kGenericMaxBucketed == 983040, generic_max_bucketed); 54 COMPILE_ASSERT(WTF::kGenericMaxBucketed == 983040, generic_max_bucketed);
54 55
55 namespace WTF { 56 namespace WTF {
56 57
57 int PartitionRootBase::gInitializedLock = 0; 58 int PartitionRootBase::gInitializedLock = 0;
58 bool PartitionRootBase::gInitialized = false; 59 bool PartitionRootBase::gInitialized = false;
59 PartitionPage PartitionRootBase::gSeedPage; 60 PartitionPage PartitionRootBase::gSeedPage;
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 RELEASE_ASSERT(bucket->numFullPages); 518 RELEASE_ASSERT(bucket->numFullPages);
518 // Not necessary but might help stop accidents. 519 // Not necessary but might help stop accidents.
519 page->nextPage = 0; 520 page->nextPage = 0;
520 } 521 }
521 } 522 }
522 523
523 bucket->activePagesHead = 0; 524 bucket->activePagesHead = 0;
524 return false; 525 return false;
525 } 526 }
526 527
528 struct PartitionDirectMapExtent {
529 size_t mapSize; // Mapped size, not including guard pages and meta-data.
530 };
531
532 static ALWAYS_INLINE PartitionDirectMapExtent* partitionPageToDirectMapExtent(Pa rtitionPage* page)
533 {
534 ASSERT(partitionBucketIsDirectMapped(page->bucket));
535 return reinterpret_cast<PartitionDirectMapExtent*>(reinterpret_cast<char*>(p age) + 2 * kPageMetadataSize);
536 }
537
527 static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags , size_t size) 538 static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags , size_t size)
528 { 539 {
529 size = partitionDirectMapSize(size); 540 size = partitionDirectMapSize(size);
530 541
531 // Because we need to fake looking like a super page, We need to allocate 542 // Because we need to fake looking like a super page, We need to allocate
532 // a bunch of system pages more than "size": 543 // a bunch of system pages more than "size":
533 // - The first few system pages are the partition page in which the super 544 // - The first few system pages are the partition page in which the super
534 // page metadata is stored. We fault just one system page out of a partition 545 // page metadata is stored. We fault just one system page out of a partition
535 // page sized clump. 546 // page sized clump.
536 // - We add a trailing guard page. 547 // - We add a trailing guard page.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 page->numUnprovisionedSlots = 0; 585 page->numUnprovisionedSlots = 0;
575 page->pageOffset = 0; 586 page->pageOffset = 0;
576 page->freeCacheIndex = 0; 587 page->freeCacheIndex = 0;
577 588
578 bucket->activePagesHead = 0; 589 bucket->activePagesHead = 0;
579 bucket->freePagesHead = 0; 590 bucket->freePagesHead = 0;
580 bucket->slotSize = size; 591 bucket->slotSize = size;
581 bucket->numSystemPagesPerSlotSpan = 0; 592 bucket->numSystemPagesPerSlotSpan = 0;
582 bucket->numFullPages = 0; 593 bucket->numFullPages = 0;
583 594
595 PartitionDirectMapExtent* mapExtent = partitionPageToDirectMapExtent(page);
596 mapExtent->mapSize = mapSize - kPartitionPageSize - kSystemPageSize;
597
584 return ret; 598 return ret;
585 } 599 }
586 600
587 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) 601 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page)
588 { 602 {
589 size_t unmapSize = page->bucket->slotSize; 603 size_t unmapSize = partitionPageToDirectMapExtent(page)->mapSize;
604
590 // Add on the size of the trailing guard page and preceeding partition 605 // Add on the size of the trailing guard page and preceeding partition
591 // page, then round up to allocation granularity. 606 // page.
592 unmapSize += kPartitionPageSize + kSystemPageSize; 607 unmapSize += kPartitionPageSize + kSystemPageSize;
593 unmapSize += kPageAllocationGranularityOffsetMask; 608
594 unmapSize &= kPageAllocationGranularityBaseMask; 609 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask));
595 610
596 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); 611 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page));
597 // Account for the mapping starting a partition page before the actual 612 // Account for the mapping starting a partition page before the actual
598 // allocation address. 613 // allocation address.
599 ptr -= kPartitionPageSize; 614 ptr -= kPartitionPageSize;
600 615
601 freePages(ptr, unmapSize); 616 freePages(ptr, unmapSize);
602 } 617 }
603 618
604 void* partitionAllocSlowPath(PartitionRootBase* root, int flags, size_t size, Pa rtitionBucket* bucket) 619 void* partitionAllocSlowPath(PartitionRootBase* root, int flags, size_t size, Pa rtitionBucket* bucket)
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 page->nextPage = bucket->activePagesHead; 771 page->nextPage = bucket->activePagesHead;
757 bucket->activePagesHead = page; 772 bucket->activePagesHead = page;
758 --bucket->numFullPages; 773 --bucket->numFullPages;
759 // Special case: for a partition page with just a single slot, it may 774 // Special case: for a partition page with just a single slot, it may
760 // now be empty and we want to run it through the empty logic. 775 // now be empty and we want to run it through the empty logic.
761 if (UNLIKELY(page->numAllocatedSlots == 0)) 776 if (UNLIKELY(page->numAllocatedSlots == 0))
762 partitionFreeSlowPath(page); 777 partitionFreeSlowPath(page);
763 } 778 }
764 } 779 }
765 780
781 bool partitionReallocDirectMappedInPlace(PartitionRootGeneric* root, PartitionPa ge* page, size_t newSize)
782 {
783 newSize = partitionCookieSizeAdjustAdd(newSize);
784
785 // Note that the new size might be a bucketed size; this function is called
786 // whenever we're reallocating a direct mapped allocation.
787 newSize = partitionDirectMapSize(newSize);
788 if (newSize < kGenericMinDirectMappedDownsize)
789 return false;
790
791 ASSERT(partitionBucketIsDirectMapped(page->bucket));
Chris Evans 2014/03/06 06:30:20 Nit: maybe put the ASSERT at the top of the functi
792
793 // bucket->slotSize is the current size of the allocation.
794 size_t currentSize = page->bucket->slotSize;
795 if (newSize == currentSize)
796 return true;
797
798 char* charPtr = static_cast<char*>(partitionPageToPointer(page));
799
800 if (newSize < currentSize) {
801 // Shrink by decommitting unneeded pages and making them inaccessible.
802 size_t decommitSize = currentSize - newSize;
803 decommitSystemPages(charPtr + newSize, decommitSize);
804 setSystemPagesInaccessible(charPtr + newSize, decommitSize);
805 } else if (newSize <= partitionPageToDirectMapExtent(page)->mapSize) {
806 // Grow within the actually allocated memory. Just need to make the
807 // pages accessible again.
808 size_t recommitSize = newSize - currentSize;
809 setSystemPagesAccessible(charPtr + currentSize, recommitSize);
810
811 #ifndef NDEBUG
812 memset(charPtr + currentSize, kUninitializedByte, recommitSize);
813 #endif
814 } else {
815 // We can't perform the realloc in-place.
816 // TODO: support this too when possible.
817 return false;
818 }
819
820 #ifndef NDEBUG
821 // Write a new trailing cookie.
822 partitionCookieWriteValue(charPtr + newSize - kCookieSize);
823 #endif
824
825 page->bucket->slotSize = newSize;
826 return true;
827 }
828
766 void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS ize) 829 void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS ize)
767 { 830 {
768 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) 831 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
769 return realloc(ptr, newSize); 832 return realloc(ptr, newSize);
770 #else 833 #else
771 if (UNLIKELY(!ptr)) 834 if (UNLIKELY(!ptr))
772 return partitionAllocGeneric(root, newSize); 835 return partitionAllocGeneric(root, newSize);
773 if (UNLIKELY(!newSize)) { 836 if (UNLIKELY(!newSize)) {
774 partitionFreeGeneric(root, ptr); 837 partitionFreeGeneric(root, ptr);
775 return 0; 838 return 0;
776 } 839 }
777 840
841 RELEASE_ASSERT(newSize <= kGenericMaxDirectMapped);
842
778 ASSERT(partitionPointerIsValid(partitionCookieFreePointerAdjust(ptr))); 843 ASSERT(partitionPointerIsValid(partitionCookieFreePointerAdjust(ptr)));
779 844
845 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr));
846
847 if (partitionBucketIsDirectMapped(page->bucket)) {
Chris Evans 2014/03/06 06:31:23 Nit: could add UNLIKELY around this condition, as
848 // We may be able to perform the realloc in place by changing the
849 // accessibility of memory pages and, if reducing the size, decommitting
850 // them.
851 if (partitionReallocDirectMappedInPlace(root, page, newSize))
852 return ptr;
853 }
854
780 size_t actualNewSize = partitionAllocActualSize(root, newSize); 855 size_t actualNewSize = partitionAllocActualSize(root, newSize);
781 size_t actualOldSize = partitionAllocGetSize(ptr); 856 size_t actualOldSize = partitionAllocGetSize(ptr);
782 857
783 // TODO: note that tcmalloc will "ignore" a downsizing realloc() unless the 858 // TODO: note that tcmalloc will "ignore" a downsizing realloc() unless the
784 // new size is a significant percentage smaller. We could do the same if we 859 // new size is a significant percentage smaller. We could do the same if we
785 // determine it is a win. 860 // determine it is a win.
786 if (actualNewSize == actualOldSize) { 861 if (actualNewSize == actualOldSize) {
787 // Trying to allocate a block of size newSize would give us a block of 862 // Trying to allocate a block of size newSize would give us a block of
788 // the same size as the one we've already got, so no point in doing 863 // the same size as the one we've already got, so no point in doing
789 // anything here. 864 // anything here.
790 // TODO: for an upsize or downsize on a direct mapped allocation, we
791 // should really try and resize it in-place.
792 return ptr; 865 return ptr;
793 } 866 }
794 867
795 // This realloc cannot be resized in-place. Sadness. 868 // This realloc cannot be resized in-place. Sadness.
796 void* ret = partitionAllocGeneric(root, newSize); 869 void* ret = partitionAllocGeneric(root, newSize);
797 size_t copySize = actualOldSize; 870 size_t copySize = actualOldSize;
798 if (newSize < copySize) 871 if (newSize < copySize)
799 copySize = newSize; 872 copySize = newSize;
800 873
801 memcpy(ret, ptr, copySize); 874 memcpy(ret, ptr, copySize);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
855 printf("total live: %zu bytes\n", totalLive); 928 printf("total live: %zu bytes\n", totalLive);
856 printf("total resident: %zu bytes\n", totalResident); 929 printf("total resident: %zu bytes\n", totalResident);
857 printf("total freeable: %zu bytes\n", totalFreeable); 930 printf("total freeable: %zu bytes\n", totalFreeable);
858 fflush(stdout); 931 fflush(stdout);
859 } 932 }
860 933
861 #endif // !NDEBUG 934 #endif // !NDEBUG
862 935
863 } // namespace WTF 936 } // namespace WTF
864 937
OLDNEW
« no previous file with comments | « Source/wtf/PartitionAlloc.h ('k') | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698