Bug 1296639 - Remove SpiderMonkey's periodic full GC. r=sfink, a=ritu
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 22 Aug 2016 11:14:24 +0100
changeset 350429 1bff8281c912ae6f1efdc6545e73fea30dfc2376
parent 350428 d55458f5cabcc3e64a0e4ba36f0267d90e7cb04b
child 350430 0f6060afb0ed6f47cd4bddcf85d6fb01d9fed3f8
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink, ritu
bugs1296639
milestone50.0
Bug 1296639 - Remove SpiderMonkey's periodic full GC. r=sfink, a=ritu
js/public/GCAPI.h
js/src/gc/GCRuntime.h
js/src/jsapi.cpp
js/src/jsgc.cpp
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -60,17 +60,17 @@ namespace JS {
     D(ALLOC_TRIGGER)                            \
     D(DEBUG_GC)                                 \
     D(COMPARTMENT_REVIVED)                      \
     D(RESET)                                    \
     D(OUT_OF_NURSERY)                           \
     D(EVICT_NURSERY)                            \
     D(FULL_STORE_BUFFER)                        \
     D(SHARED_MEMORY_LIMIT)                      \
-    D(PERIODIC_FULL_GC)                         \
+    D(UNUSED1)                                  \
     D(INCREMENTAL_TOO_SLOW)                     \
     D(ABORT_GC)                                 \
                                                 \
     /* These are reserved for future use. */    \
     D(RESERVED0)                                \
     D(RESERVED1)                                \
     D(RESERVED2)                                \
     D(RESERVED3)                                \
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -454,24 +454,16 @@ class GCSchedulingTunables
  *      phase, we have a highFrequencyGCMode that ups the growth rate to 300%
  *      of the current size[retained] so that we'll do fewer longer GCs at the
  *      end of the mutator startup rather than more, smaller GCs.
  *
  *          Assumptions:
  *            -> Responsiveness is proportional to t[marking] + t[sweeping].
  *            -> size[retained] is proportional only to GC allocations.
  *
- *      PERIODIC_FULL_GC
- *      ----------------
- *      When we return to the event loop and it has been 20 seconds since we've
- *      done a GC, we start an incremenal, all-zones, shrinking GC.
- *
- *          Assumptions:
- *            -> Our triggers are incomplete.
- *
  *      ALLOC_TRIGGER (non-incremental)
  *      -------------------------------
  *      If we do not return to the event loop before getting all the way to our
  *      gc trigger bytes then MAYBEGC will never fire. To avoid OOMing, we
  *      succeed the current allocation and set the script interrupt so that we
  *      will (hopefully) do a GC before we overflow our max and have to raise
  *      an OOM exception for the script.
  *
@@ -618,18 +610,17 @@ class GCRuntime
 
     MOZ_MUST_USE bool setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock);
     uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
 
     MOZ_MUST_USE bool triggerGC(JS::gcreason::Reason reason);
     void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
     // The return value indicates if we were able to do the GC.
     bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason);
-    MOZ_MUST_USE bool maybeGC(Zone* zone);
-    void maybePeriodicFullGC();
+    void maybeGC(Zone* zone);
     void minorGC(JS::gcreason::Reason reason) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC);
         minorGCImpl(reason, nullptr);
     }
     void minorGC(JSContext* cx, JS::gcreason::Reason reason);
     void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_EVICT_NURSERY);
         minorGCImpl(reason, nullptr);
@@ -1078,17 +1069,16 @@ class GCRuntime
     /*
      * Number of the committed arenas in all GC chunks including empty chunks.
      */
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
     VerifyPreTracer* verifyPreData;
 
   private:
     bool chunkAllocationSinceLastGC;
-    int64_t nextFullGCTime;
     int64_t lastGCTime;
 
     JSGCMode mode;
 
     mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters;
 
     uint64_t decommitThreshold;
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1346,18 +1346,17 @@ JS_GC(JSContext* cx)
     JS::PrepareForFullGC(cx);
     cx->gc.gc(GC_NORMAL, JS::gcreason::API);
 }
 
 JS_PUBLIC_API(void)
 JS_MaybeGC(JSContext* cx)
 {
     GCRuntime& gc = cx->runtime()->gc;
-    if (!gc.maybeGC(cx->zone()))
-        gc.maybePeriodicFullGC();
+    gc.maybeGC(cx->zone());
 }
 
 JS_PUBLIC_API(void)
 JS_SetGCCallback(JSContext* cx, JSGCCallback cb, void* data)
 {
     AssertHeapIsIdle(cx);
     cx->gc.setGCCallback(cb, data);
 }
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -243,19 +243,16 @@ using namespace js::gc;
 
 using mozilla::ArrayLength;
 using mozilla::Get;
 using mozilla::Maybe;
 using mozilla::Swap;
 
 using JS::AutoGCRooter;
 
-/* Perform a Full GC every 20 seconds if MaybeGC is called */
-static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
-
 /* Increase the IGC marking slice time if we are in highFrequencyGC mode. */
 static const int IGC_MARK_SLICE_MULTIPLIER = 2;
 
 const AllocKind gc::slotsToThingKind[] = {
     /*  0 */ AllocKind::OBJECT0,  AllocKind::OBJECT2,  AllocKind::OBJECT2,  AllocKind::OBJECT4,
     /*  4 */ AllocKind::OBJECT4,  AllocKind::OBJECT8,  AllocKind::OBJECT8,  AllocKind::OBJECT8,
     /*  8 */ AllocKind::OBJECT8,  AllocKind::OBJECT12, AllocKind::OBJECT12, AllocKind::OBJECT12,
     /* 12 */ AllocKind::OBJECT12, AllocKind::OBJECT16, AllocKind::OBJECT16, AllocKind::OBJECT16,
@@ -800,17 +797,16 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
     marker(rt),
     usage(nullptr),
     mMemProfiler(rt),
     maxMallocBytes(0),
     nextCellUniqueId_(LargestTaggedNullCellPointer + 1), // Ensure disjoint from null tagged pointers.
     numArenasFreeCommitted(0),
     verifyPreData(nullptr),
     chunkAllocationSinceLastGC(false),
-    nextFullGCTime(0),
     lastGCTime(PRMJ_Now()),
     mode(JSGC_MODE_INCREMENTAL),
     numActiveZoneIters(0),
     decommitThreshold(32 * 1024 * 1024),
     cleanUpEverything(false),
     grayBufferState(GCRuntime::GrayBufferState::Unused),
     grayBitsValid(false),
     majorGCTriggerReason(JS::gcreason::NO_REASON),
@@ -3046,70 +3042,40 @@ GCRuntime::triggerZoneGC(Zone* zone, JS:
         return true;
     }
 
     PrepareZoneForGC(zone);
     requestMajorGC(reason);
     return true;
 }
 
-bool
+void
 GCRuntime::maybeGC(Zone* zone)
 {
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
 #ifdef JS_GC_ZEAL
     if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::Poke)) {
         JS::PrepareForFullGC(rt->contextFromMainThread());
         gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
-        return true;
+        return;
     }
 #endif
 
     if (gcIfRequested())
-        return true;
+        return;
 
     if (zone->usage.gcBytes() > 1024 * 1024 &&
         zone->usage.gcBytes() >= zone->threshold.allocTrigger(schedulingState.inHighFrequencyGCMode()) &&
         !isIncrementalGCInProgress() &&
         !isBackgroundSweeping())
     {
         PrepareZoneForGC(zone);
         startGC(GC_NORMAL, JS::gcreason::EAGER_ALLOC_TRIGGER);
-        return true;
-    }
-
-    return false;
-}
-
-void
-GCRuntime::maybePeriodicFullGC()
-{
-    /*
-     * Trigger a periodic full GC.
-     *
-     * This is a source of non-determinism, but is not called from the shell.
-     *
-     * Access to the counters and, on 32 bit, setting gcNextFullGCTime below
-     * is not atomic and a race condition could trigger or suppress the GC. We
-     * tolerate this.
-     */
-#ifndef JS_MORE_DETERMINISTIC
-    int64_t now = PRMJ_Now();
-    if (nextFullGCTime && nextFullGCTime <= now && !isIncrementalGCInProgress()) {
-        if (chunkAllocationSinceLastGC ||
-            numArenasFreeCommitted > decommitThreshold)
-        {
-            JS::PrepareForFullGC(rt->contextFromMainThread());
-            startGC(GC_SHRINK, JS::gcreason::PERIODIC_FULL_GC);
-        } else {
-            nextFullGCTime = now + GC_IDLE_FULL_SPAN;
-        }
-    }
-#endif
+    }
 }
 
 // Do all possible decommit immediately from the current thread without
 // releasing the GC lock or allocating any memory.
 void
 GCRuntime::decommitAllWithoutUnlocking(const AutoLockGC& lock)
 {
     MOZ_ASSERT(emptyChunks(lock).count() == 0);
@@ -6151,20 +6117,16 @@ GCRuntime::gcCycle(bool nonincrementalBy
     /* The GC was reset, so we need a do-over. */
     if (prevState != State::NotActive && !isIncrementalGCInProgress())
         return true;
 
     TraceMajorGCStart();
 
     incrementalCollectSlice(budget, reason, session.lock);
 
-#ifndef JS_MORE_DETERMINISTIC
-    nextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN;
-#endif
-
     chunkAllocationSinceLastGC = false;
 
 #ifdef JS_GC_ZEAL
     /* Keeping these around after a GC is dangerous. */
     clearSelectedForMarking();
 #endif
 
     /* Clear gcMallocBytes for all zones. */