- Revision
- 120149
- Author
- [email protected]
- Date
- 2012-06-12 19:06:50 -0700 (Tue, 12 Jun 2012)
Log Message
GC should be 1.7X faster
https://bugs.webkit.org/show_bug.cgi?id=88840
Reviewed by Oliver Hunt.
I profiled, and removed anything that showed up as a concurrency
bottleneck. Then, I added 3 threads to our max thread count, since we
can scale up to more threads now.
* heap/BlockAllocator.cpp:
(JSC::BlockAllocator::BlockAllocator):
(JSC::BlockAllocator::~BlockAllocator):
(JSC::BlockAllocator::releaseFreeBlocks):
(JSC::BlockAllocator::waitForRelativeTimeWhileHoldingLock):
(JSC::BlockAllocator::waitForRelativeTime):
(JSC::BlockAllocator::blockFreeingThreadMain):
* heap/BlockAllocator.h:
(BlockAllocator):
(JSC::BlockAllocator::allocate):
(JSC::BlockAllocator::deallocate): Use a spin lock for the common case
where we're just popping a linked list. (A pthread mutex would sleep our
thread even if the lock were only contended for a microsecond.)
Scope the lock to avoid holding it while allocating VM, since that's a
slow activity and it doesn't modify any of our data structures.
We still use a pthread mutex to handle our condition variable since we
have to, and it's not a hot path.
* heap/CopiedSpace.cpp:
(JSC::CopiedSpace::CopiedSpace):
(JSC::CopiedSpace::doneFillingBlock):
* heap/CopiedSpace.h:
(JSC::CopiedSpace::CopiedSpace): Use a spin lock for the to space lock,
since it just guards linked list and hash table manipulation.
* heap/MarkStack.cpp:
(JSC::MarkStackSegmentAllocator::MarkStackSegmentAllocator):
(JSC::MarkStackSegmentAllocator::allocate):
(JSC::MarkStackSegmentAllocator::release):
(JSC::MarkStackSegmentAllocator::shrinkReserve): Use a spin lock, since
we're just managing a linked list.
(JSC::MarkStackArray::donateSomeCellsTo): Changed donation to be proportional
to our current stack size. This fixes cases where we used to donate too
much. Interestingly, donating too much was starving the donor (when it
ran out of work later) *and* the recipient (since it had to wait on a
long donation operation to complete before it could acquire the lock).
In the worst case, we're still guaranteed to donate N cells in roughly log N time.
This change also fixes cases where we used to donate too little, since
we would always keep a fixed minimum number of cells. In the worst case,
with N marking threads, would could have N large object graph roots in
our stack for the duration of GC, and scale to only 1 thread.
It's an interesting observation that a single object in the mark stack
might represent an arbitrarily large object graph -- and only the act
of marking can find out.
(JSC::MarkStackArray::stealSomeCellsFrom): Steal in proportion to idle
threads. Once again, this fixes cases where constants could cause us
to steal too much or too little.
(JSC::SlotVisitor::donateKnownParallel): Always wake up other threads
if they're idle. We can afford to do this because we're conservative
about when we donate.
(JSC::SlotVisitor::drainFromShared):
* heap/MarkStack.h:
(MarkStackSegmentAllocator):
(MarkStackArray):
(JSC):
* heap/SlotVisitor.h: Merged the "should I donate?" decision into a
single function, for simplicity.
* runtime/Options.cpp:
(minimumNumberOfScansBetweenRebalance): Reduced the delay before donation
a lot. We can afford to do this because, in the common case, donation is
a single branch that decides not to donate.
(cpusToUse): Use more CPUs now, since we scale better now.
* runtime/Options.h:
(Options): Removed now-unused variables.
Modified Paths
Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (120148 => 120149)
--- trunk/Source/_javascript_Core/ChangeLog 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-06-13 02:06:50 UTC (rev 120149)
@@ -1,3 +1,91 @@
+2012-06-11 Geoffrey Garen <[email protected]>
+
+ GC should be 1.7X faster
+ https://bugs.webkit.org/show_bug.cgi?id=88840
+
+ Reviewed by Oliver Hunt.
+
+ I profiled, and removed anything that showed up as a concurrency
+ bottleneck. Then, I added 3 threads to our max thread count, since we
+ can scale up to more threads now.
+
+ * heap/BlockAllocator.cpp:
+ (JSC::BlockAllocator::BlockAllocator):
+ (JSC::BlockAllocator::~BlockAllocator):
+ (JSC::BlockAllocator::releaseFreeBlocks):
+ (JSC::BlockAllocator::waitForRelativeTimeWhileHoldingLock):
+ (JSC::BlockAllocator::waitForRelativeTime):
+ (JSC::BlockAllocator::blockFreeingThreadMain):
+ * heap/BlockAllocator.h:
+ (BlockAllocator):
+ (JSC::BlockAllocator::allocate):
+ (JSC::BlockAllocator::deallocate): Use a spin lock for the common case
+ where we're just popping a linked list. (A pthread mutex would sleep our
+ thread even if the lock were only contended for a microsecond.)
+
+ Scope the lock to avoid holding it while allocating VM, since that's a
+ slow activity and it doesn't modify any of our data structures.
+
+ We still use a pthread mutex to handle our condition variable since we
+ have to, and it's not a hot path.
+
+ * heap/CopiedSpace.cpp:
+ (JSC::CopiedSpace::CopiedSpace):
+ (JSC::CopiedSpace::doneFillingBlock):
+ * heap/CopiedSpace.h:
+ (JSC::CopiedSpace::CopiedSpace): Use a spin lock for the to space lock,
+ since it just guards linked list and hash table manipulation.
+
+ * heap/MarkStack.cpp:
+ (JSC::MarkStackSegmentAllocator::MarkStackSegmentAllocator):
+ (JSC::MarkStackSegmentAllocator::allocate):
+ (JSC::MarkStackSegmentAllocator::release):
+ (JSC::MarkStackSegmentAllocator::shrinkReserve): Use a spin lock, since
+ we're just managing a linked list.
+
+ (JSC::MarkStackArray::donateSomeCellsTo): Changed donation to be proportional
+ to our current stack size. This fixes cases where we used to donate too
+ much. Interestingly, donating too much was starving the donor (when it
+ ran out of work later) *and* the recipient (since it had to wait on a
+ long donation operation to complete before it could acquire the lock).
+
+ In the worst case, we're still guaranteed to donate N cells in roughly log N time.
+
+ This change also fixes cases where we used to donate too little, since
+ we would always keep a fixed minimum number of cells. In the worst case,
+ with N marking threads, would could have N large object graph roots in
+ our stack for the duration of GC, and scale to only 1 thread.
+
+ It's an interesting observation that a single object in the mark stack
+ might represent an arbitrarily large object graph -- and only the act
+ of marking can find out.
+
+ (JSC::MarkStackArray::stealSomeCellsFrom): Steal in proportion to idle
+ threads. Once again, this fixes cases where constants could cause us
+ to steal too much or too little.
+
+ (JSC::SlotVisitor::donateKnownParallel): Always wake up other threads
+ if they're idle. We can afford to do this because we're conservative
+ about when we donate.
+
+ (JSC::SlotVisitor::drainFromShared):
+ * heap/MarkStack.h:
+ (MarkStackSegmentAllocator):
+ (MarkStackArray):
+ (JSC):
+ * heap/SlotVisitor.h: Merged the "should I donate?" decision into a
+ single function, for simplicity.
+
+ * runtime/Options.cpp:
+ (minimumNumberOfScansBetweenRebalance): Reduced the delay before donation
+ a lot. We can afford to do this because, in the common case, donation is
+ a single branch that decides not to donate.
+
+ (cpusToUse): Use more CPUs now, since we scale better now.
+
+ * runtime/Options.h:
+ (Options): Removed now-unused variables.
+
2012-06-12 Filip Pizlo <[email protected]>
REGRESSION(120121): inspector tests crash in DFG
Modified: trunk/Source/_javascript_Core/heap/BlockAllocator.cpp (120148 => 120149)
--- trunk/Source/_javascript_Core/heap/BlockAllocator.cpp 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/heap/BlockAllocator.cpp 2012-06-13 02:06:50 UTC (rev 120149)
@@ -37,13 +37,15 @@
, m_blockFreeingThread(createThread(blockFreeingThreadStartFunc, this, "_javascript_Core::BlockFree"))
{
ASSERT(m_blockFreeingThread);
+ m_freeBlockLock.Init();
}
BlockAllocator::~BlockAllocator()
{
releaseFreeBlocks();
{
- MutexLocker locker(m_freeBlockLock);
+ MutexLocker locker(m_freeBlockConditionLock);
+
m_blockFreeingThreadShouldQuit = true;
m_freeBlockCondition.broadcast();
}
@@ -55,7 +57,7 @@
while (true) {
HeapBlock* block;
{
- MutexLocker locker(m_freeBlockLock);
+ SpinLockHolder locker(&m_freeBlockLock);
if (!m_numberOfFreeBlocks)
block = 0;
else {
@@ -76,7 +78,8 @@
{
if (m_blockFreeingThreadShouldQuit)
return;
- m_freeBlockCondition.timedWait(m_freeBlockLock, currentTime() + relative);
+
+ m_freeBlockCondition.timedWait(m_freeBlockConditionLock, currentTime() + relative);
}
void BlockAllocator::waitForRelativeTime(double relative)
@@ -85,7 +88,7 @@
// frequently. It would only be a bug if this function failed to return
// when it was asked to do so.
- MutexLocker locker(m_freeBlockLock);
+ MutexLocker locker(m_freeBlockConditionLock);
waitForRelativeTimeWhileHoldingLock(relative);
}
@@ -120,7 +123,7 @@
while (!m_blockFreeingThreadShouldQuit) {
HeapBlock* block;
{
- MutexLocker locker(m_freeBlockLock);
+ SpinLockHolder locker(&m_freeBlockLock);
if (m_numberOfFreeBlocks <= desiredNumberOfFreeBlocks)
block = 0;
else {
Modified: trunk/Source/_javascript_Core/heap/BlockAllocator.h (120148 => 120149)
--- trunk/Source/_javascript_Core/heap/BlockAllocator.h 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/heap/BlockAllocator.h 2012-06-13 02:06:50 UTC (rev 120149)
@@ -30,6 +30,7 @@
#include <wtf/DoublyLinkedList.h>
#include <wtf/Forward.h>
#include <wtf/PageAllocationAligned.h>
+#include <wtf/TCSpinLock.h>
#include <wtf/Threading.h>
namespace JSC {
@@ -58,19 +59,22 @@
size_t m_numberOfFreeBlocks;
bool m_isCurrentlyAllocating;
bool m_blockFreeingThreadShouldQuit;
- Mutex m_freeBlockLock;
+ SpinLock m_freeBlockLock;
+ Mutex m_freeBlockConditionLock;
ThreadCondition m_freeBlockCondition;
ThreadIdentifier m_blockFreeingThread;
};
inline PageAllocationAligned BlockAllocator::allocate()
{
- MutexLocker locker(m_freeBlockLock);
- m_isCurrentlyAllocating = true;
- if (m_numberOfFreeBlocks) {
- ASSERT(!m_freeBlocks.isEmpty());
- m_numberOfFreeBlocks--;
- return m_freeBlocks.removeHead()->m_allocation;
+ {
+ SpinLockHolder locker(&m_freeBlockLock);
+ m_isCurrentlyAllocating = true;
+ if (m_numberOfFreeBlocks) {
+ ASSERT(!m_freeBlocks.isEmpty());
+ m_numberOfFreeBlocks--;
+ return m_freeBlocks.removeHead()->m_allocation;
+ }
}
ASSERT(m_freeBlocks.isEmpty());
@@ -82,7 +86,7 @@
inline void BlockAllocator::deallocate(PageAllocationAligned allocation)
{
- MutexLocker locker(m_freeBlockLock);
+ SpinLockHolder locker(&m_freeBlockLock);
HeapBlock* heapBlock = new(NotNull, allocation.base()) HeapBlock(allocation);
m_freeBlocks.push(heapBlock);
m_numberOfFreeBlocks++;
Modified: trunk/Source/_javascript_Core/heap/CopiedSpace.cpp (120148 => 120149)
--- trunk/Source/_javascript_Core/heap/CopiedSpace.cpp 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/heap/CopiedSpace.cpp 2012-06-13 02:06:50 UTC (rev 120149)
@@ -38,6 +38,7 @@
, m_inCopyingPhase(false)
, m_numberOfLoanedBlocks(0)
{
+ m_toSpaceLock.Init();
}
CopiedSpace::~CopiedSpace()
@@ -168,7 +169,7 @@
}
{
- MutexLocker locker(m_toSpaceLock);
+ SpinLockHolder locker(&m_toSpaceLock);
m_toSpace->push(block);
m_blockSet.add(block);
m_blockFilter.add(reinterpret_cast<Bits>(block));
Modified: trunk/Source/_javascript_Core/heap/CopiedSpace.h (120148 => 120149)
--- trunk/Source/_javascript_Core/heap/CopiedSpace.h 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/heap/CopiedSpace.h 2012-06-13 02:06:50 UTC (rev 120149)
@@ -37,6 +37,7 @@
#include <wtf/PageAllocationAligned.h>
#include <wtf/PageBlock.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/TCSpinLock.h>
#include <wtf/ThreadingPrimitives.h>
namespace JSC {
@@ -100,7 +101,7 @@
TinyBloomFilter m_blockFilter;
HashSet<CopiedBlock*> m_blockSet;
- Mutex m_toSpaceLock;
+ SpinLock m_toSpaceLock;
DoublyLinkedList<HeapBlock>* m_toSpace;
DoublyLinkedList<HeapBlock>* m_fromSpace;
Modified: trunk/Source/_javascript_Core/heap/ListableHandler.h (120148 => 120149)
--- trunk/Source/_javascript_Core/heap/ListableHandler.h 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/heap/ListableHandler.h 2012-06-13 02:06:50 UTC (rev 120149)
@@ -24,6 +24,7 @@
#include <wtf/Locker.h>
#include <wtf/Noncopyable.h>
#include <wtf/ThreadingPrimitives.h>
+#include <wtf/TCSpinlock.h>
namespace JSC {
@@ -60,15 +61,12 @@
List()
: m_first(0)
{
+ m_lock.Init();
}
void addThreadSafe(T* handler)
{
- // NOTE: If we ever want this to be faster, we could turn it into
- // a CAS loop, since this is a singly-linked-list that, in parallel
- // tracing mode, can only grow. I.e. we don't have to worry about
- // any ABA problems.
- MutexLocker locker(m_lock);
+ SpinLockHolder locker(&m_lock);
addNotThreadSafe(handler);
}
@@ -106,7 +104,7 @@
m_first = handler;
}
- Mutex m_lock;
+ SpinLock m_lock;
T* m_first;
};
Modified: trunk/Source/_javascript_Core/heap/MarkStack.cpp (120148 => 120149)
--- trunk/Source/_javascript_Core/heap/MarkStack.cpp 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/heap/MarkStack.cpp 2012-06-13 02:06:50 UTC (rev 120149)
@@ -46,6 +46,7 @@
MarkStackSegmentAllocator::MarkStackSegmentAllocator()
: m_nextFreeSegment(0)
{
+ m_lock.Init();
}
MarkStackSegmentAllocator::~MarkStackSegmentAllocator()
@@ -56,7 +57,7 @@
MarkStackSegment* MarkStackSegmentAllocator::allocate()
{
{
- MutexLocker locker(m_lock);
+ SpinLockHolder locker(&m_lock);
if (m_nextFreeSegment) {
MarkStackSegment* result = m_nextFreeSegment;
m_nextFreeSegment = result->m_previous;
@@ -69,7 +70,7 @@
void MarkStackSegmentAllocator::release(MarkStackSegment* segment)
{
- MutexLocker locker(m_lock);
+ SpinLockHolder locker(&m_lock);
segment->m_previous = m_nextFreeSegment;
m_nextFreeSegment = segment;
}
@@ -78,7 +79,7 @@
{
MarkStackSegment* segments;
{
- MutexLocker locker(m_lock);
+ SpinLockHolder locker(&m_lock);
segments = m_nextFreeSegment;
m_nextFreeSegment = 0;
}
@@ -142,23 +143,31 @@
return true;
}
-bool MarkStackArray::donateSomeCellsTo(MarkStackArray& other)
+void MarkStackArray::donateSomeCellsTo(MarkStackArray& other)
{
+ // Try to donate about 1 / 2 of our cells. To reduce copying costs,
+ // we prefer donating whole segments over donating individual cells,
+ // even if this skews away from our 1 / 2 target.
+
ASSERT(m_segmentCapacity == other.m_segmentCapacity);
+
+ size_t segmentsToDonate = (m_numberOfPreviousSegments + 2 - 1) / 2; // Round up to donate 1 / 1 previous segments.
+
+ if (!segmentsToDonate) {
+ size_t cellsToDonate = m_top / 2; // Round down to donate 0 / 1 cells.
+ while (cellsToDonate--) {
+ ASSERT(m_top);
+ other.append(removeLast());
+ }
+ return;
+ }
+
validatePrevious();
other.validatePrevious();
-
- // Fast check: see if the other mark stack already has enough segments.
- if (other.m_numberOfPreviousSegments + 1 >= Options::maximumNumberOfSharedSegments)
- return false;
-
- size_t numberOfCellsToKeep = Options::minimumNumberOfCellsToKeep;
- ASSERT(m_top > numberOfCellsToKeep || m_topSegment->m_previous);
-
- // Looks like we should donate! Give the other mark stack all of our
- // previous segments, and then top it off.
+
MarkStackSegment* previous = m_topSegment->m_previous;
- while (previous) {
+ while (segmentsToDonate--) {
+ ASSERT(previous);
ASSERT(m_numberOfPreviousSegments);
MarkStackSegment* current = previous;
@@ -170,23 +179,18 @@
m_numberOfPreviousSegments--;
other.m_numberOfPreviousSegments++;
}
- ASSERT(!m_numberOfPreviousSegments);
- m_topSegment->m_previous = 0;
+ m_topSegment->m_previous = previous;
+
validatePrevious();
other.validatePrevious();
-
- // Now top off. We want to keep at a minimum numberOfCellsToKeep, but if
- // we really have a lot of work, we give up half.
- if (m_top > numberOfCellsToKeep * 2)
- numberOfCellsToKeep = m_top / 2;
- while (m_top > numberOfCellsToKeep)
- other.append(removeLast());
-
- return true;
}
-void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other)
+void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other, size_t idleThreadCount)
{
+ // Try to steal 1 / Nth of the shared array, where N is the number of idle threads.
+ // To reduce copying costs, we prefer stealing a whole segment over stealing
+ // individual cells, even if this skews away from our 1 / N target.
+
ASSERT(m_segmentCapacity == other.m_segmentCapacity);
validatePrevious();
other.validatePrevious();
@@ -211,10 +215,8 @@
other.validatePrevious();
return;
}
-
- // Otherwise drain 1/Nth of the shared array where N is the number of
- // workers, or Options::minimumNumberOfCellsToKeep, whichever is bigger.
- size_t numberOfCellsToSteal = std::max((size_t)Options::minimumNumberOfCellsToKeep, other.size() / Options::numberOfGCMarkers);
+
+ size_t numberOfCellsToSteal = (other.size() + idleThreadCount - 1) / idleThreadCount; // Round up to steal 1 / 1.
while (numberOfCellsToSteal-- > 0 && other.canRemoveLast())
append(other.removeLast());
}
@@ -343,18 +345,31 @@
cell->methodTable()->visitChildren(const_cast<JSCell*>(cell), visitor);
}
-void SlotVisitor::donateSlow()
+void SlotVisitor::donateKnownParallel()
{
- // Refuse to donate if shared has more entries than I do.
- if (m_shared.m_sharedMarkStack.size() > m_stack.size())
+ // NOTE: Because we re-try often, we can afford to be conservative, and
+ // assume that donating is not profitable.
+
+ // Avoid locking when a thread reaches a dead end in the object graph.
+ if (m_stack.size() < 2)
return;
- MutexLocker locker(m_shared.m_markingLock);
- if (m_stack.donateSomeCellsTo(m_shared.m_sharedMarkStack)) {
- // Only wake up threads if the shared stack is big enough; otherwise assume that
- // it's more profitable for us to just scan this ourselves later.
- if (m_shared.m_sharedMarkStack.size() >= Options::sharedStackWakeupThreshold)
- m_shared.m_markingCondition.broadcast();
- }
+
+ // If there's already some shared work queued up, be conservative and assume
+ // that donating more is not profitable.
+ if (m_shared.m_sharedMarkStack.size())
+ return;
+
+ // If we're contending on the lock, be conservative and assume that another
+ // thread is already donating.
+ MutexTryLocker locker(m_shared.m_markingLock);
+ if (!locker.locked())
+ return;
+
+ // Otherwise, assume that a thread will go idle soon, and donate.
+ m_stack.donateSomeCellsTo(m_shared.m_sharedMarkStack);
+
+ if (m_shared.m_numberOfActiveParallelMarkers < Options::numberOfGCMarkers)
+ m_shared.m_markingCondition.broadcast();
}
void SlotVisitor::drain()
@@ -454,7 +469,8 @@
}
}
- m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack);
+ size_t idleThreadCount = Options::numberOfGCMarkers - m_shared.m_numberOfActiveParallelMarkers;
+ m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack, idleThreadCount);
m_shared.m_numberOfActiveParallelMarkers++;
}
Modified: trunk/Source/_javascript_Core/heap/MarkStack.h (120148 => 120149)
--- trunk/Source/_javascript_Core/heap/MarkStack.h 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/heap/MarkStack.h 2012-06-13 02:06:50 UTC (rev 120149)
@@ -28,8 +28,8 @@
#include "CopiedSpace.h"
#include "HandleTypes.h"
-#include "Options.h"
#include "JSValue.h"
+#include "Options.h"
#include "Register.h"
#include "UnconditionalFinalizer.h"
#include "VTableSpectrum.h"
@@ -38,11 +38,12 @@
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
-#include <wtf/Vector.h>
#include <wtf/Noncopyable.h>
#include <wtf/OSAllocator.h>
#include <wtf/PageBlock.h>
+#include <wtf/TCSpinLock.h>
#include <wtf/text/StringHash.h>
+#include <wtf/Vector.h>
#if ENABLE(OBJECT_MARK_LOGGING)
#define MARK_LOG_MESSAGE0(message) dataLog(message)
@@ -112,7 +113,7 @@
void shrinkReserve();
private:
- Mutex m_lock;
+ SpinLock m_lock;
MarkStackSegment* m_nextFreeSegment;
};
@@ -129,10 +130,9 @@
bool isEmpty();
- bool canDonateSomeCells(); // Returns false if you should definitely not call doanteSomeCellsTo().
- bool donateSomeCellsTo(MarkStackArray& other); // Returns true if some cells were donated.
+ void donateSomeCellsTo(MarkStackArray& other);
- void stealSomeCellsFrom(MarkStackArray& other);
+ void stealSomeCellsFrom(MarkStackArray& other, size_t idleThreadCount);
size_t size();
@@ -414,22 +414,6 @@
return true;
}
- inline bool MarkStackArray::canDonateSomeCells()
- {
- size_t numberOfCellsToKeep = Options::minimumNumberOfCellsToKeep;
- // Another check: see if we have enough cells to warrant donation.
- if (m_top <= numberOfCellsToKeep) {
- // This indicates that we might not want to donate anything; check if we have
- // another full segment. If not, then don't donate.
- if (!m_topSegment->m_previous)
- return false;
-
- ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity);
- }
-
- return true;
- }
-
inline size_t MarkStackArray::size()
{
return m_top + m_segmentCapacity * m_numberOfPreviousSegments;
Modified: trunk/Source/_javascript_Core/heap/SlotVisitor.h (120148 => 120149)
--- trunk/Source/_javascript_Core/heap/SlotVisitor.h 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/heap/SlotVisitor.h 2012-06-13 02:06:50 UTC (rev 120149)
@@ -68,15 +68,8 @@
private:
void* allocateNewSpace(void*, size_t);
- void donateSlow();
-
- void donateKnownParallel()
- {
- if (!m_stack.canDonateSomeCells())
- return;
- donateSlow();
- }
-
+ void donateKnownParallel();
+
CopiedBlock* m_copyBlock;
};
Modified: trunk/Source/_javascript_Core/runtime/Options.cpp (120148 => 120149)
--- trunk/Source/_javascript_Core/runtime/Options.cpp 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/runtime/Options.cpp 2012-06-13 02:06:50 UTC (rev 120149)
@@ -89,9 +89,6 @@
unsigned minimumNumberOfScansBetweenRebalance;
unsigned gcMarkStackSegmentSize;
-unsigned minimumNumberOfCellsToKeep;
-unsigned maximumNumberOfSharedSegments;
-unsigned sharedStackWakeupThreshold;
unsigned numberOfGCMarkers;
unsigned opaqueRootMergeThreshold;
@@ -145,6 +142,22 @@
#define SET(variable, value) variable = value
#endif
+static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers)
+{
+ int cpusToUse = 1;
+
+#if ENABLE(PARALLEL_GC)
+ cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfGCMarkers);
+
+ // Be paranoid, it is the OS we're dealing with, after all.
+ ASSERT(cpusToUse >= 1);
+ if (cpusToUse < 1)
+ cpusToUse = 1;
+#endif
+
+ return cpusToUse;
+}
+
void initializeOptions()
{
SET(useJIT, true);
@@ -188,26 +201,11 @@
SET(doubleVoteRatioForDoubleFormat, 2);
- SET(minimumNumberOfScansBetweenRebalance, 10000);
+ SET(minimumNumberOfScansBetweenRebalance, 100);
SET(gcMarkStackSegmentSize, pageSize());
- SET(minimumNumberOfCellsToKeep, 10);
- SET(maximumNumberOfSharedSegments, 3);
- SET(sharedStackWakeupThreshold, 1);
SET(opaqueRootMergeThreshold, 1000);
+ SET(numberOfGCMarkers, computeNumberOfGCMarkers(7)); // We don't scale so well beyond 7.
- int cpusToUse = 1;
-#if ENABLE(PARALLEL_GC)
- cpusToUse = WTF::numberOfProcessorCores();
-#endif
- // We don't scale so well beyond 4.
- if (cpusToUse > 4)
- cpusToUse = 4;
- // Be paranoid, it is the OS we're dealing with, after all.
- if (cpusToUse < 1)
- cpusToUse = 1;
-
- SET(numberOfGCMarkers, cpusToUse);
-
ASSERT(thresholdForOptimizeAfterLongWarmUp >= thresholdForOptimizeAfterWarmUp);
ASSERT(thresholdForOptimizeAfterWarmUp >= thresholdForOptimizeSoon);
ASSERT(thresholdForOptimizeAfterWarmUp >= 0);
Modified: trunk/Source/_javascript_Core/runtime/Options.h (120148 => 120149)
--- trunk/Source/_javascript_Core/runtime/Options.h 2012-06-13 01:29:07 UTC (rev 120148)
+++ trunk/Source/_javascript_Core/runtime/Options.h 2012-06-13 02:06:50 UTC (rev 120149)
@@ -75,9 +75,6 @@
extern unsigned minimumNumberOfScansBetweenRebalance;
extern unsigned gcMarkStackSegmentSize;
-extern unsigned minimumNumberOfCellsToKeep;
-extern unsigned maximumNumberOfSharedSegments;
-extern unsigned sharedStackWakeupThreshold;
JS_EXPORTDATA extern unsigned numberOfGCMarkers;
JS_EXPORTDATA extern unsigned opaqueRootMergeThreshold;