Bug 1433007 - (part 4) Perform nursery resize calculation in bytes r=sfink
authorPaul Bone <pbone@mozilla.com>
Fri, 15 Feb 2019 04:30:02 +0000
changeset 459495 d6ef554aa023f5fd53f64ddac770d4d332552566
parent 459494 54066b2f1a730885bb97a8dc2600276dc2be69cc
child 459496 cd3427c916a4d424e46f999089db29f3825fbec9
push id111964
push usercsabou@mozilla.com
push dateFri, 15 Feb 2019 18:54:44 +0000
treeherdermozilla-inbound@db3c4f905082 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1433007
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1433007 - (part 4) Perform nursery resize calculation in bytes r=sfink Differential Revision: https://phabricator.services.mozilla.com/D19347
js/src/gc/Nursery.cpp
js/src/gc/Nursery.h
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -1138,17 +1138,19 @@ void js::Nursery::maybeResizeNursery(JS:
 #endif
 
   newMaxNurseryChunks = tunables().gcMaxNurseryBytes() >> ChunkShift;
   if (newMaxNurseryChunks != chunkCountLimit_) {
     chunkCountLimit_ = newMaxNurseryChunks;
     /* The configured maximum nursery size is changing */
     if (maxChunkCount() > newMaxNurseryChunks) {
       /* We need to shrink the nursery */
-      shrinkAllocableSpace(newMaxNurseryChunks);
+      static_assert(NurseryChunkUsableSize < ChunkSize,
+          "Usable size must be smaller than total size or this calculation might overflow");
+      shrinkAllocableSpace(newMaxNurseryChunks * NurseryChunkUsableSize);
       return;
     }
   }
 
   /*
    * This incorrect promotion rate results in better nursery sizing
    * decisions, however we should to better tuning based on the real
    * promotion rate in the future.
@@ -1157,59 +1159,61 @@ void js::Nursery::maybeResizeNursery(JS:
       float(previousGC.tenuredBytes) / float(previousGC.nurseryCapacity);
 
   /*
    * Object lifetimes arn't going to behave linearly, but a better
    * relationship that works for all programs and can be predicted in
    * advance doesn't exist.
    */
   const float factor = promotionRate / PromotionGoal;
-  const unsigned newChunkCount = round(float(maxChunkCount()) * factor);
+  const unsigned newCapacity = unsigned(float(capacity()) * factor);
 
   // If one of these conditions is true then we always shrink or grow the
   // nursery.  This way the thresholds still have an effect even if the goal
   // seeking says the current size is ideal.
   if (maxChunkCount() < chunkCountLimit() && promotionRate > GrowThreshold) {
-    unsigned lowLimit = maxChunkCount() + 1;
-    unsigned highLimit = Min(chunkCountLimit(), maxChunkCount() * 2);
+    unsigned lowLimit = (maxChunkCount() + 1) * NurseryChunkUsableSize;
+    unsigned highLimit = Min(chunkCountLimit() * NurseryChunkUsableSize, capacity() * 2);
 
-    growAllocableSpace(mozilla::Clamp(newChunkCount, lowLimit, highLimit));
+    growAllocableSpace(mozilla::Clamp(newCapacity, lowLimit, highLimit));
   } else if (maxChunkCount() > 1 && promotionRate < ShrinkThreshold) {
-    unsigned lowLimit = Max(1u, maxChunkCount() / 2);
-    unsigned highLimit = maxChunkCount() - 1u;
+    unsigned lowLimit = Max(NurseryChunkUsableSize, capacity() / 2);
+    unsigned highLimit = (maxChunkCount() - 1) * NurseryChunkUsableSize;
 
-    shrinkAllocableSpace(mozilla::Clamp(newChunkCount, lowLimit, highLimit));
+    shrinkAllocableSpace(mozilla::Clamp(newCapacity, lowLimit, highLimit));
   }
 }
 
-void js::Nursery::growAllocableSpace(unsigned newCount) {
-  MOZ_ASSERT(newCount > currentChunk_);
-  capacity_ = newCount * NurseryChunkUsableSize;
-  MOZ_ASSERT(newCount <= chunkCountLimit_);
+void js::Nursery::growAllocableSpace(unsigned newCapacity) {
+  MOZ_ASSERT(newCapacity > currentChunk_ * NurseryChunkUsableSize);
+  // round up to whole chunk.
+  capacity_ = JS_ROUNDUP(newCapacity, NurseryChunkUsableSize);
   MOZ_ASSERT(capacity_ <= chunkCountLimit_ * NurseryChunkUsableSize);
 }
 
 void js::Nursery::freeChunksFrom(unsigned firstFreeChunk) {
   MOZ_ASSERT(firstFreeChunk < chunks_.length());
   {
     AutoLockGC lock(runtime());
     for (unsigned i = firstFreeChunk; i < chunks_.length(); i++) {
       runtime()->gc.recycleChunk(chunk(i).toChunk(runtime()), lock);
     }
   }
   chunks_.shrinkTo(firstFreeChunk);
 }
 
-void js::Nursery::shrinkAllocableSpace(unsigned newCount) {
+void js::Nursery::shrinkAllocableSpace(unsigned newCapacity) {
 #ifdef JS_GC_ZEAL
   if (runtime()->hasZealMode(ZealMode::GenerationalGC)) {
     return;
   }
 #endif
 
+  unsigned newCount = newCapacity / NurseryChunkUsableSize;
+
   // Don't shrink the nursery to zero (use Nursery::disable() instead)
   MOZ_ASSERT(newCount != 0);
 
   // Don't attempt to shrink it to the same size.
   if (newCount == maxChunkCount()) {
     return;
   }
 
@@ -1217,17 +1221,17 @@ void js::Nursery::shrinkAllocableSpace(u
 
   if (newCount < allocatedChunkCount()) {
     freeChunksFrom(newCount);
   }
 
   capacity_ = newCount * NurseryChunkUsableSize;
 }
 
-void js::Nursery::minimizeAllocableSpace() { shrinkAllocableSpace(1); }
+void js::Nursery::minimizeAllocableSpace() { shrinkAllocableSpace(NurseryChunkUsableSize); }
 
 bool js::Nursery::queueDictionaryModeObjectToSweep(NativeObject* obj) {
   MOZ_ASSERT(IsInsideNursery(obj));
   return dictionaryModeObjects_.append(obj);
 }
 
 uintptr_t js::Nursery::currentEnd() const {
   MOZ_ASSERT(currentEnd_ == chunk(currentChunk_).end());
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -607,18 +607,18 @@ class Nursery {
    */
   void clear();
 
   void sweepDictionaryModeObjects();
   void sweepMapAndSetObjects();
 
   /* Change the allocable space provided by the nursery. */
   void maybeResizeNursery(JS::GCReason reason);
-  void growAllocableSpace(unsigned newCount);
-  void shrinkAllocableSpace(unsigned newCount);
+  void growAllocableSpace(unsigned newCapacity);
+  void shrinkAllocableSpace(unsigned newCapacity);
   void minimizeAllocableSpace();
 
   // Free the chunks starting at firstFreeChunk until the end of the chunks
   // vector. Shrinks the vector but does not update maxChunkCount().
   void freeChunksFrom(unsigned firstFreeChunk);
 
   /* Profile recording and printing. */
   void maybeClearProfileDurations();