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

Unified Diff: Source/wtf/PartitionAlloc.cpp

Issue 1203893002: PartitionAlloc: make PartitionPurgeDiscardUnusedSystemPages discard more. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@discard
Patch Set: Compile fix. Created 5 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/wtf/PartitionAlloc.cpp
diff --git a/Source/wtf/PartitionAlloc.cpp b/Source/wtf/PartitionAlloc.cpp
index 1d63350968a24f6a6c42f342729bf910fa089009..6bb40ca415759074f391eb2df45b1a0b864b451d 100644
--- a/Source/wtf/PartitionAlloc.cpp
+++ b/Source/wtf/PartitionAlloc.cpp
@@ -1080,10 +1080,11 @@ void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS
#endif
}
-static size_t partitionPurgePage(const PartitionPage* page, bool discard)
+static size_t partitionPurgePage(PartitionPage* page, bool discard)
{
const PartitionBucket* bucket = page->bucket;
- if (bucket->slotSize < kSystemPageSize || !page->numAllocatedSlots)
+ size_t slotSize = bucket->slotSize;
+ if (slotSize < kSystemPageSize || !page->numAllocatedSlots)
return 0;
size_t bucketNumSlots = partitionBucketSlots(bucket);
@@ -1103,16 +1104,18 @@ static size_t partitionPurgePage(const PartitionPage* page, bool discard)
const size_t maxSlotCount = (kPartitionPageSize * kMaxPartitionPagesPerSlotSpan) / kSystemPageSize;
ASSERT(bucketNumSlots <= maxSlotCount);
+ ASSERT(page->numUnprovisionedSlots < bucketNumSlots);
+ size_t numSlots = bucketNumSlots - page->numUnprovisionedSlots;
char slotUsage[maxSlotCount];
size_t lastSlot = static_cast<size_t>(-1);
- memset(slotUsage, 1, sizeof(slotUsage));
+ memset(slotUsage, 1, numSlots);
char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page));
PartitionFreelistEntry* entry = page->freelistHead;
// First, walk the freelist for this page and make a bitmap of which slots
// are not in use.
while (entry) {
- size_t slotIndex = (reinterpret_cast<char*>(entry) - ptr) / bucket->slotSize;
- ASSERT(slotIndex < bucketNumSlots);
+ size_t slotIndex = (reinterpret_cast<char*>(entry) - ptr) / slotSize;
+ ASSERT(slotIndex < numSlots);
slotUsage[slotIndex] = 0;
entry = partitionFreelistMask(entry->next);
// If we have a slot where the masked freelist entry is 0, we can
@@ -1123,21 +1126,68 @@ static size_t partitionPurgePage(const PartitionPage* page, bool discard)
if (!partitionFreelistMask(entry))
lastSlot = slotIndex;
}
+
+ // If the slot(s) at the end of the slot span are not in used, we can
+ // truncate them entirely and rewrite the freelist.
+ size_t truncatedSlots = 0;
+ while (!slotUsage[numSlots - 1]) {
+ truncatedSlots++;
+ numSlots--;
+ ASSERT(numSlots);
+ }
+ // First, do the work of calculating the discardable bytes. Don't actually
+ // discard anything unless the discard flag was passed in.
+ char* beginPtr = nullptr;
+ char* endPtr = nullptr;
+ size_t unprovisionedBytes = 0;
+ if (truncatedSlots) {
+ beginPtr = ptr + (numSlots * slotSize);
+ endPtr = beginPtr + (slotSize * truncatedSlots);
+ beginPtr = reinterpret_cast<char*>(partitionRoundUpToSystemPage(reinterpret_cast<size_t>(beginPtr)));
+ // We round the end pointer here up and not down because we're at the
+ // end of a slot span, so we "own" all the way up the page boundary.
+ endPtr = reinterpret_cast<char*>(partitionRoundUpToSystemPage(reinterpret_cast<size_t>(endPtr)));
+ ASSERT(endPtr <= ptr + partitionBucketBytes(bucket));
+ if (beginPtr < endPtr) {
+ unprovisionedBytes = endPtr - beginPtr;
+ discardableBytes += unprovisionedBytes;
+ }
+ }
+ if (unprovisionedBytes && discard) {
+ ASSERT(truncatedSlots > 0);
+ size_t numNewEntries = 0;
+ page->numUnprovisionedSlots += truncatedSlots;
+ // Rewrite the freelist.
+ PartitionFreelistEntry** entryPtr = &page->freelistHead;
+ for (size_t slotIndex = 0; slotIndex < numSlots; ++slotIndex) {
+ if (slotUsage[slotIndex])
+ continue;
+ PartitionFreelistEntry* entry = reinterpret_cast<PartitionFreelistEntry*>(ptr + (slotSize * slotIndex));
+ *entryPtr = partitionFreelistMask(entry);
+ entryPtr = reinterpret_cast<PartitionFreelistEntry**>(entry);
+ numNewEntries++;
+ }
+ // Terminate the freelist chain.
+ *entryPtr = nullptr;
+ // The freelist head is stored unmasked.
+ page->freelistHead = partitionFreelistMask(page->freelistHead);
+ ASSERT(numNewEntries == numSlots - page->numAllocatedSlots);
+ // Discard the memory.
+ discardSystemPages(beginPtr, unprovisionedBytes);
+ }
+
// Next, walk the slots and for any not in use, consider where the system
// page boundaries occur. We can release any system pages back to the
// system as long as we don't interfere with a freelist pointer or an
// adjacent slot.
- // TODO(cevans): I think we can "truncate" the page, i.e. increase the
- // value of page->numUnprovisionedSlots and rewrite(!) the freelist, if
- // we find that to be a win too.
- for (size_t i = 0; i < bucketNumSlots; ++i) {
+ for (size_t i = 0; i < numSlots; ++i) {
if (slotUsage[i])
continue;
// The first address we can safely discard is just after the freelist
// pointer. There's one quirk: if the freelist pointer is actually a
// null, we can discard that pointer value too.
- char* beginPtr = ptr + (i * bucket->slotSize);
- char* endPtr = beginPtr + bucket->slotSize;
+ char* beginPtr = ptr + (i * slotSize);
+ char* endPtr = beginPtr + slotSize;
if (i != lastSlot)
beginPtr += sizeof(PartitionFreelistEntry);
beginPtr = reinterpret_cast<char*>(partitionRoundUpToSystemPage(reinterpret_cast<size_t>(beginPtr)));
@@ -1152,10 +1202,10 @@ static size_t partitionPurgePage(const PartitionPage* page, bool discard)
return discardableBytes;
}
-static void partitionPurgeBucket(const PartitionBucket* bucket)
+static void partitionPurgeBucket(PartitionBucket* bucket)
{
if (bucket->activePagesHead != &PartitionRootGeneric::gSeedPage) {
- for (const PartitionPage* page = bucket->activePagesHead; page; page = page->nextPage) {
+ for (PartitionPage* page = bucket->activePagesHead; page; page = page->nextPage) {
ASSERT(page != &PartitionRootGeneric::gSeedPage);
(void) partitionPurgePage(page, true);
}
@@ -1179,7 +1229,7 @@ void partitionPurgeMemoryGeneric(PartitionRootGeneric* root, int flags)
partitionDecommitEmptyPages(root);
if (flags & PartitionPurgeDiscardUnusedSystemPages) {
for (size_t i = 0; i < kGenericNumBuckets; ++i) {
- const PartitionBucket* bucket = &root->buckets[i];
+ PartitionBucket* bucket = &root->buckets[i];
if (bucket->slotSize >= kSystemPageSize)
partitionPurgeBucket(bucket);
}
@@ -1196,7 +1246,7 @@ static void partitionDumpPageStats(PartitionBucketMemoryStats* statsOut, const P
return;
}
- statsOut->discardableBytes += partitionPurgePage(page, false);
+ statsOut->discardableBytes += partitionPurgePage(const_cast<PartitionPage*>(page), false);
size_t rawSize = partitionPageGetRawSize(const_cast<PartitionPage*>(page));
if (rawSize)
« no previous file with comments | « no previous file | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698