Bug 1078437 - Prevent store buffer compaction from thrashing, r=terrence
authorSteve Fink <sfink@mozilla.com>
Tue, 14 Oct 2014 13:19:28 -0700
changeset 210450 713b9fa30f62b47d811adc4f190b07b22cae2eb4
parent 210449 8d3304b7e0e0b2b8fd607c8320436b415e8d4cae
child 210451 52fd69cc794c89cc87b9b893fec53786a9574886
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersterrence
bugs1078437
milestone36.0a1
Bug 1078437 - Prevent store buffer compaction from thrashing, r=terrence
js/src/gc/StoreBuffer.cpp
js/src/gc/StoreBuffer.h
--- 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_);