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

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: fix various issues 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
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 506 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 RELEASE_ASSERT(bucket->numFullPages); 517 RELEASE_ASSERT(bucket->numFullPages);
518 // Not necessary but might help stop accidents. 518 // Not necessary but might help stop accidents.
519 page->nextPage = 0; 519 page->nextPage = 0;
520 } 520 }
521 } 521 }
522 522
523 bucket->activePagesHead = 0; 523 bucket->activePagesHead = 0;
524 return false; 524 return false;
525 } 525 }
526 526
527 static ALWAYS_INLINE size_t partitionDirectMapAvailableSize(PartitionPage* page)
Chris Evans 2014/03/05 07:57:04 This function seems a bit complicated, or at least
528 {
529 // Return the size of the mapping, *not* including space where meta-data is
530 // stored, and *not* including one trailing inaccessible system page; IOW
531 // the size of the area available for the actual allocation. Some of the
532 // pages at the end of this memory range may have been decommitted and made
533 // inaccessible by a partitionReallocGeneric() call.
534 //
535 // The value of bucket->slotSize is size of the current allocation.
536
537 PartitionBucket* bucket = page->bucket;
538
539 ASSERT(partitionBucketIsDirectMapped(bucket));
540 ASSERT(bucket != &PartitionRootBase::gPagedBucket);
541
542 char* ptr = static_cast<char*>(partitionPageToPointer(page));
543 char* endPtr = reinterpret_cast<char*>(bucket->freePagesHead) - kSystemPageS ize;
544
545 size_t size = endPtr - ptr;
546 ASSERT(bucket->slotSize <= size);
547 return size;
548 }
549
527 static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags , size_t size) 550 static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags , size_t size)
528 { 551 {
529 size = partitionDirectMapSize(size); 552 size = partitionDirectMapSize(size);
530 553
531 // Because we need to fake looking like a super page, We need to allocate 554 // Because we need to fake looking like a super page, We need to allocate
532 // a bunch of system pages more than "size": 555 // a bunch of system pages more than "size":
533 // - The first few system pages are the partition page in which the super 556 // - 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 557 // page metadata is stored. We fault just one system page out of a partition
535 // page sized clump. 558 // page sized clump.
536 // - We add a trailing guard page. 559 // - We add a trailing guard page.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 PartitionBucket* bucket = reinterpret_cast<PartitionBucket*>(reinterpret_cas t<char*>(page) + kPageMetadataSize); 592 PartitionBucket* bucket = reinterpret_cast<PartitionBucket*>(reinterpret_cas t<char*>(page) + kPageMetadataSize);
570 page->freelistHead = 0; 593 page->freelistHead = 0;
571 page->nextPage = 0; 594 page->nextPage = 0;
572 page->bucket = bucket; 595 page->bucket = bucket;
573 page->numAllocatedSlots = 1; 596 page->numAllocatedSlots = 1;
574 page->numUnprovisionedSlots = 0; 597 page->numUnprovisionedSlots = 0;
575 page->pageOffset = 0; 598 page->pageOffset = 0;
576 page->freeCacheIndex = 0; 599 page->freeCacheIndex = 0;
577 600
578 bucket->activePagesHead = 0; 601 bucket->activePagesHead = 0;
579 bucket->freePagesHead = 0; 602 bucket->freePagesHead = reinterpret_cast<PartitionPage*>(ptr + mapSize);
Chris Evans 2014/03/05 07:57:04 I'm not a huge fan of this. For each direct mappi
Jens Widell 2014/03/05 08:11:43 I certainly wasn't either. :-)
580 bucket->slotSize = size; 603 bucket->slotSize = size;
581 bucket->numSystemPagesPerSlotSpan = 0; 604 bucket->numSystemPagesPerSlotSpan = 0;
582 bucket->numFullPages = 0; 605 bucket->numFullPages = 0;
583 606
607 ASSERT(size <= partitionDirectMapAvailableSize(page));
608
584 return ret; 609 return ret;
585 } 610 }
586 611
587 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) 612 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page)
588 { 613 {
589 size_t unmapSize = page->bucket->slotSize; 614 size_t unmapSize = partitionDirectMapAvailableSize(page);
615
590 // Add on the size of the trailing guard page and preceeding partition 616 // Add on the size of the trailing guard page and preceeding partition
591 // page, then round up to allocation granularity. 617 // page.
592 unmapSize += kPartitionPageSize + kSystemPageSize; 618 unmapSize += kPartitionPageSize + kSystemPageSize;
593 unmapSize += kPageAllocationGranularityOffsetMask; 619
594 unmapSize &= kPageAllocationGranularityBaseMask; 620 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask));
595 621
596 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); 622 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page));
597 // Account for the mapping starting a partition page before the actual 623 // Account for the mapping starting a partition page before the actual
598 // allocation address. 624 // allocation address.
599 ptr -= kPartitionPageSize; 625 ptr -= kPartitionPageSize;
600 626
601 freePages(ptr, unmapSize); 627 freePages(ptr, unmapSize);
602 } 628 }
603 629
604 void* partitionAllocSlowPath(PartitionRootBase* root, int flags, size_t size, Pa rtitionBucket* bucket) 630 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; 782 page->nextPage = bucket->activePagesHead;
757 bucket->activePagesHead = page; 783 bucket->activePagesHead = page;
758 --bucket->numFullPages; 784 --bucket->numFullPages;
759 // Special case: for a partition page with just a single slot, it may 785 // 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. 786 // now be empty and we want to run it through the empty logic.
761 if (UNLIKELY(page->numAllocatedSlots == 0)) 787 if (UNLIKELY(page->numAllocatedSlots == 0))
762 partitionFreeSlowPath(page); 788 partitionFreeSlowPath(page);
763 } 789 }
764 } 790 }
765 791
792 bool partitionReallocDirectMappedInPlace(PartitionRootGeneric* root, void* ptr, size_t newSize)
793 {
794 newSize = partitionCookieSizeAdjustAdd(newSize);
795 ASSERT(partitionDirectMapSize(newSize) == newSize);
Chris Evans 2014/03/05 07:57:04 I think we also need newSize to be a multiple of k
Jens Widell 2014/03/05 08:11:43 The value returned by partitionDirectMapSize(size)
796
797 char* realPtr = static_cast<char*>(partitionCookieFreePointerAdjust(ptr));
798 PartitionPage* page = partitionPointerToPage(realPtr);
799 PartitionBucket* bucket = page->bucket;
800
801 // bucket->slotSize is the current size of the allocation.
802 // bucket->freePagesHead points to the first system page beyond what we
803 // first allocated; we can grow the allocation up to that point.
804
805 ASSERT(partitionBucketIsDirectMapped(bucket));
806 ASSERT(newSize != bucket->slotSize);
807
808 if (newSize < bucket->slotSize) {
809 // Shrink by decommitting unneeded pages and making them inaccessible.
810 // TODO: maybe refuse if the new size is too much smaller?
811 size_t decommitSize = bucket->slotSize - newSize;
812 decommitSystemPages(realPtr + newSize, decommitSize);
813 setSystemPagesInaccessible(realPtr + newSize, decommitSize);
814 } else if (newSize <= partitionDirectMapAvailableSize(page)) {
815 // Grow within the actually allocated memory. Just need to make the
816 // pages accessible again.
817 size_t recommitSize = newSize - bucket->slotSize;
818 setSystemPagesAccessible(realPtr + bucket->slotSize, recommitSize);
819
820 #ifndef NDEBUG
821 memset(realPtr + bucket->slotSize, kUninitializedByte, recommitSize);
822 #endif
823 } else {
824 // We can't perform the realloc in-place.
Chris Evans 2014/03/05 07:57:04 I think we can fill in this branch in the future (
825 return false;
826 }
827
828 #ifndef NDEBUG
829 // Write a new trailing cookie.
830 partitionCookieWriteValue(realPtr + newSize - kCookieSize);
831 #endif
832
833 bucket->slotSize = newSize;
834 return true;
835 }
836
766 void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS ize) 837 void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS ize)
767 { 838 {
768 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) 839 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
769 return realloc(ptr, newSize); 840 return realloc(ptr, newSize);
770 #else 841 #else
771 if (UNLIKELY(!ptr)) 842 if (UNLIKELY(!ptr))
772 return partitionAllocGeneric(root, newSize); 843 return partitionAllocGeneric(root, newSize);
773 if (UNLIKELY(!newSize)) { 844 if (UNLIKELY(!newSize)) {
774 partitionFreeGeneric(root, ptr); 845 partitionFreeGeneric(root, ptr);
775 return 0; 846 return 0;
776 } 847 }
Chris Evans 2014/03/05 07:57:04 Can we just put a no nonsense RELEASE_ASSERT here?
777 848
778 ASSERT(partitionPointerIsValid(partitionCookieFreePointerAdjust(ptr))); 849 ASSERT(partitionPointerIsValid(partitionCookieFreePointerAdjust(ptr)));
779 850
780 size_t actualNewSize = partitionAllocActualSize(root, newSize); 851 size_t actualNewSize = partitionAllocActualSize(root, newSize);
781 size_t actualOldSize = partitionAllocGetSize(ptr); 852 size_t actualOldSize = partitionAllocGetSize(ptr);
782 853
783 // TODO: note that tcmalloc will "ignore" a downsizing realloc() unless the 854 // 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 855 // new size is a significant percentage smaller. We could do the same if we
785 // determine it is a win. 856 // determine it is a win.
786 if (actualNewSize == actualOldSize) { 857 if (actualNewSize == actualOldSize) {
787 // Trying to allocate a block of size newSize would give us a block of 858 // 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 859 // the same size as the one we've already got, so no point in doing
789 // anything here. 860 // 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; 861 return ptr;
793 } 862 }
794 863
864 if (partitionSizeIsDirectMapped(actualOldSize) && partitionSizeIsDirectMappe d(actualNewSize)) {
Chris Evans 2014/03/05 07:57:04 I actually think we might want to relax the second
Jens Widell 2014/03/05 08:11:43 The reason I didn't do that was to avoid having an
865 // We may be able to perform the realloc in place by changing the
866 // accessibility of memory pages and, if reducing the size, decommitting
867 // them.
868 if (partitionReallocDirectMappedInPlace(root, ptr, actualNewSize))
869 return ptr;
870 }
871
795 // This realloc cannot be resized in-place. Sadness. 872 // This realloc cannot be resized in-place. Sadness.
796 void* ret = partitionAllocGeneric(root, newSize); 873 void* ret = partitionAllocGeneric(root, newSize);
797 size_t copySize = actualOldSize; 874 size_t copySize = actualOldSize;
798 if (newSize < copySize) 875 if (newSize < copySize)
799 copySize = newSize; 876 copySize = newSize;
800 877
801 memcpy(ret, ptr, copySize); 878 memcpy(ret, ptr, copySize);
802 partitionFreeGeneric(root, ptr); 879 partitionFreeGeneric(root, ptr);
803 return ret; 880 return ret;
804 #endif 881 #endif
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
855 printf("total live: %zu bytes\n", totalLive); 932 printf("total live: %zu bytes\n", totalLive);
856 printf("total resident: %zu bytes\n", totalResident); 933 printf("total resident: %zu bytes\n", totalResident);
857 printf("total freeable: %zu bytes\n", totalFreeable); 934 printf("total freeable: %zu bytes\n", totalFreeable);
858 fflush(stdout); 935 fflush(stdout);
859 } 936 }
860 937
861 #endif // !NDEBUG 938 #endif // !NDEBUG
862 939
863 } // namespace WTF 940 } // namespace WTF
864 941
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698