Commit 37f99463 authored by ggaren@apple.com's avatar ggaren@apple.com

Substantially reduced VM thrash in the GC heap.

        
Patch by Geoffrey Garen <ggaren@apple.com> on 2009-08-24
Reviewed by Oliver Hunt.

1.08x faster on v8 (1.60x faster on v8-splay).
        
1.40x faster on bench-alloc-nonretained.
        
1.90x faster on bench-alloc-retained.
        
SunSpider says no change.
        
* runtime/Collector.cpp:
(JSC::Heap::heapAllocate): Fixed a long-standing bug: update a few local
variables unconditionally after calling collect(), since they may be used
even if we don't "goto scan". (In the bug I saw, usedBlocks got out of
sync with heap.usedBlocks).
(JSC::Heap::sweep): Keep enough free heap space to accomodate 
the number of objects we'll allocate before the next GC, plus 25%, for
good measure.
* runtime/Collector.h: Bumped the block size to 256k. This seems to give
the best cache performance, and it prevents us from initiating lots of
VM traffic to recover very small chunks of memory.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@47739 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 1050f79b
2009-08-24 Geoffrey Garen <ggaren@apple.com>
Reviewed by Oliver Hunt.
Substantially reduced VM thrash in the GC heap.
1.08x faster on v8 (1.60x faster on v8-splay).
1.40x faster on bench-alloc-nonretained.
1.90x faster on bench-alloc-retained.
SunSpider says no change.
* runtime/Collector.cpp:
(JSC::Heap::heapAllocate): Fixed a long-standing bug: update a few local
variables unconditionally after calling collect(), since they may be used
even if we don't "goto scan". (In the bug I saw, usedBlocks got out of
sync with heap.usedBlocks).
(JSC::Heap::sweep): Keep enough free heap space to accomodate
the number of objects we'll allocate before the next GC, plus 25%, for
good measure.
* runtime/Collector.h: Bumped the block size to 256k. This seems to give
the best cache performance, and it prevents us from initiating lots of
VM traffic to recover very small chunks of memory.
2009-08-24 Gavin Barraclough <barraclough@apple.com>
Reviewed by Oliver Adler & Darin Hunt.
......
......@@ -101,7 +101,6 @@ namespace JSC {
// tunable parameters
const size_t SPARE_EMPTY_BLOCKS = 2;
const size_t GROWTH_FACTOR = 2;
const size_t LOW_WATER_FACTOR = 4;
const size_t ALLOCATIONS_PER_COLLECTION = 4000;
......@@ -385,16 +384,15 @@ collect:
#ifndef NDEBUG
heap.operationInProgress = NoOperation;
#endif
bool collected = collect();
bool foundGarbage = collect();
numLiveObjects = heap.numLiveObjects;
usedBlocks = heap.usedBlocks;
i = heap.firstBlockWithPossibleSpace;
#ifndef NDEBUG
heap.operationInProgress = Allocation;
#endif
if (collected) {
numLiveObjects = heap.numLiveObjects;
usedBlocks = heap.usedBlocks;
i = heap.firstBlockWithPossibleSpace;
if (foundGarbage)
goto scan;
}
}
// didn't find a block, and GC didn't reclaim anything, need to allocate a new block
......@@ -1084,31 +1082,44 @@ template <HeapType heapType> size_t Heap::sweep()
curBlock->freeList = freeList;
curBlock->marked.clearAll();
if (usedCells == 0) {
emptyBlocks++;
if (emptyBlocks > SPARE_EMPTY_BLOCKS) {
#if !DEBUG_COLLECTOR
freeBlock(reinterpret_cast<CollectorBlock*>(curBlock));
#endif
// swap with the last block so we compact as we go
heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];
heap.usedBlocks--;
block--; // Don't move forward a step in this case
if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) {
heap.numBlocks = heap.numBlocks / GROWTH_FACTOR;
heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*)));
}
}
}
if (!usedCells)
++emptyBlocks;
}
if (heap.numLiveObjects != numLiveObjects)
heap.firstBlockWithPossibleSpace = 0;
heap.numLiveObjects = numLiveObjects;
heap.numLiveObjectsAtLastCollect = numLiveObjects;
heap.extraCost = 0;
if (!emptyBlocks)
return numLiveObjects;
size_t neededCells = 1.25 * (numLiveObjects + max(ALLOCATIONS_PER_COLLECTION, numLiveObjects));
size_t neededBlocks = (neededCells + HeapConstants<heapType>::cellsPerBlock - 1) / HeapConstants<heapType>::cellsPerBlock;
for (size_t block = 0; block < heap.usedBlocks; block++) {
if (heap.usedBlocks <= neededBlocks)
break;
Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]);
if (curBlock->usedCells)
continue;
#if !DEBUG_COLLECTOR
freeBlock(reinterpret_cast<CollectorBlock*>(curBlock));
#endif
// swap with the last block so we compact as we go
heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];
heap.usedBlocks--;
block--; // Don't move forward a step in this case
if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) {
heap.numBlocks = heap.numBlocks / GROWTH_FACTOR;
heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*)));
}
}
return numLiveObjects;
}
......
......@@ -175,7 +175,7 @@ namespace JSC {
#endif
template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; };
const size_t BLOCK_SIZE = 16 * 4096; // 64k
const size_t BLOCK_SIZE = 64 * 4096; // 256k
// derived constants
const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment