Bug 1078437 - Prevent store buffer compaction from thrashing, r=terrence
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -92,17 +92,17 @@ void
StoreBuffer::MonoTypeBuffer<T>::handleOverflow(StoreBuffer *owner)
{
if (!owner->isAboutToOverflow()) {
/*
* Compact the buffer now, and if that fails to free enough space then
* trigger a minor collection.
*/
compact(owner);
- if (isAboutToOverflow())
+ if (isLowOnSpace())
owner->setAboutToOverflow();
} else {
/*
* A minor GC has already been triggered, so there's no point
* compacting unless the buffer is totally full.
*/
if (storage_->availableInCurrentChunk() < sizeof(T))
maybeCompact(owner);
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -73,17 +73,28 @@ static const size_t LifoAllocBlockSize =
* The StoreBuffer observes all writes that occur in the system and performs
* efficient filtering of them to derive a remembered set for nursery GC.
*/
class StoreBuffer
{
friend class mozilla::ReentrancyGuard;
/* The size at which a block is about to overflow. */
- static const size_t MinAvailableSize = (size_t)(LifoAllocBlockSize * 1.0 / 8.0);
+ static const size_t LowAvailableThreshold = (size_t)(LifoAllocBlockSize * 1.0 / 16.0);
+
+ /*
+ * If the space available in the store buffer hits the
+ * LowAvailableThreshold and gets compacted, but still doesn't have at
+ * least HighAvailableThreshold space available, then we will trigger a
+ * minor GC. HighAvailableThreshold should be set to provide enough space
+ * for the mutator to run for a while in between compactions. (If
+ * HighAvailableThreshold is too low, we will thrash and spend most of the
+ * time compacting. If it is too high, we will tenure things too early.)
+ */
+ static const size_t HighAvailableThreshold = (size_t)(LifoAllocBlockSize * 1.0 / 4.0);
/*
* This buffer holds only a single type of edge. Using this buffer is more
* efficient than the generic buffer when many writes will be to the same
* type of edge: e.g. Value or Cell*.
*/
template<typename T>
struct MonoTypeBuffer
@@ -105,17 +116,21 @@ class StoreBuffer
if (!storage_)
return;
storage_->used() ? storage_->releaseAll() : storage_->freeAll();
usedAtLastCompact_ = 0;
}
bool isAboutToOverflow() const {
- return !storage_->isEmpty() && storage_->availableInCurrentChunk() < MinAvailableSize;
+ return !storage_->isEmpty() && storage_->availableInCurrentChunk() < LowAvailableThreshold;
+ }
+
+ bool isLowOnSpace() const {
+ return !storage_->isEmpty() && storage_->availableInCurrentChunk() < HighAvailableThreshold;
}
void handleOverflow(StoreBuffer *owner);
/* Compaction algorithms. */
void compactRemoveDuplicates(StoreBuffer *owner);
/*
@@ -184,17 +199,17 @@ class StoreBuffer
void clear() {
if (!storage_)
return;
storage_->used() ? storage_->releaseAll() : storage_->freeAll();
}
bool isAboutToOverflow() const {
- return !storage_->isEmpty() && storage_->availableInCurrentChunk() < MinAvailableSize;
+ return !storage_->isEmpty() && storage_->availableInCurrentChunk() < LowAvailableThreshold;
}
/* Mark all generic edges. */
void mark(StoreBuffer *owner, JSTracer *trc);
template <typename T>
void put(StoreBuffer *owner, const T &t) {
MOZ_ASSERT(storage_);