Title: [209727] trunk/Source/_javascript_Core
Revision
209727
Author
[email protected]
Date
2016-12-12 14:06:41 -0800 (Mon, 12 Dec 2016)

Log Message

GC scheduler should avoid consecutive pauses
https://bugs.webkit.org/show_bug.cgi?id=165758

Reviewed by Michael Saboff.
        
This factors out the scheduler from lambdas in Heap::markToFixpoint to an actual class.
It's called the SpaceTimeScheduler because it is a linear controller that ties the
amount of time you spend on things to the amount of space you are using.
        
This patch uses this refactoring to fix a bug where the GC would pause even though we
still had time during a mutator timeslice. This is a 15% improvement on
JetStream/splay-latency. Seems neutral on everything else. However, it's not at all
clear if this is the right policy or not since retreating wavefront can sometimes be so
sensitive to scheduling decisions. For this reason, there is a tunable option that lets
you decide how long the GC will sit idle before the start of its timeslice.
        
So, we can revert this policy change in this patch without reverting the patch.

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
* heap/Heap.cpp:
(JSC::Heap::markToFixpoint):
* heap/Heap.h:
* heap/SpaceTimeScheduler.cpp: Added.
(JSC::SpaceTimeScheduler::Decision::targetMutatorUtilization):
(JSC::SpaceTimeScheduler::Decision::targetCollectorUtilization):
(JSC::SpaceTimeScheduler::Decision::elapsedInPeriod):
(JSC::SpaceTimeScheduler::Decision::phase):
(JSC::SpaceTimeScheduler::Decision::shouldBeResumed):
(JSC::SpaceTimeScheduler::Decision::timeToResume):
(JSC::SpaceTimeScheduler::Decision::timeToStop):
(JSC::SpaceTimeScheduler::SpaceTimeScheduler):
(JSC::SpaceTimeScheduler::snapPhase):
(JSC::SpaceTimeScheduler::currentDecision):
* heap/SpaceTimeScheduler.h: Added.
(JSC::SpaceTimeScheduler::Decision::Decision):
(JSC::SpaceTimeScheduler::Decision::operator bool):
* runtime/Options.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (209726 => 209727)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2016-12-12 22:06:41 UTC (rev 209727)
@@ -497,6 +497,7 @@
     heap/MarkedSpace.cpp
     heap/MutatorState.cpp
     heap/SlotVisitor.cpp
+    heap/SpaceTimeScheduler.cpp
     heap/StopIfNecessaryTimer.cpp
     heap/VisitRaceKey.cpp
     heap/Weak.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (209726 => 209727)


--- trunk/Source/_javascript_Core/ChangeLog	2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-12-12 22:06:41 UTC (rev 209727)
@@ -1,3 +1,44 @@
+2016-12-12  Filip Pizlo  <[email protected]>
+
+        GC scheduler should avoid consecutive pauses
+        https://bugs.webkit.org/show_bug.cgi?id=165758
+
+        Reviewed by Michael Saboff.
+        
+        This factors out the scheduler from lambdas in Heap::markToFixpoint to an actual class.
+        It's called the SpaceTimeScheduler because it is a linear controller that ties the
+        amount of time you spend on things to the amount of space you are using.
+        
+        This patch uses this refactoring to fix a bug where the GC would pause even though we
+        still had time during a mutator timeslice. This is a 15% improvement on
+        JetStream/splay-latency. Seems neutral on everything else. However, it's not at all
+        clear if this is the right policy or not since retreating wavefront can sometimes be so
+        sensitive to scheduling decisions. For this reason, there is a tunable option that lets
+        you decide how long the GC will sit idle before the start of its timeslice.
+        
+        So, we can revert this policy change in this patch without reverting the patch.
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * heap/Heap.cpp:
+        (JSC::Heap::markToFixpoint):
+        * heap/Heap.h:
+        * heap/SpaceTimeScheduler.cpp: Added.
+        (JSC::SpaceTimeScheduler::Decision::targetMutatorUtilization):
+        (JSC::SpaceTimeScheduler::Decision::targetCollectorUtilization):
+        (JSC::SpaceTimeScheduler::Decision::elapsedInPeriod):
+        (JSC::SpaceTimeScheduler::Decision::phase):
+        (JSC::SpaceTimeScheduler::Decision::shouldBeResumed):
+        (JSC::SpaceTimeScheduler::Decision::timeToResume):
+        (JSC::SpaceTimeScheduler::Decision::timeToStop):
+        (JSC::SpaceTimeScheduler::SpaceTimeScheduler):
+        (JSC::SpaceTimeScheduler::snapPhase):
+        (JSC::SpaceTimeScheduler::currentDecision):
+        * heap/SpaceTimeScheduler.h: Added.
+        (JSC::SpaceTimeScheduler::Decision::Decision):
+        (JSC::SpaceTimeScheduler::Decision::operator bool):
+        * runtime/Options.h:
+
 2016-12-12  Michael Saboff  <[email protected]>
 
         REGRESSION(r209653): speedometer crashes making virtual slow path tailcalls

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (209726 => 209727)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-12-12 22:06:41 UTC (rev 209727)
@@ -753,6 +753,8 @@
 		0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */; };
 		0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; };
 		0FDE87F91DFD0C760064C390 /* CellContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDE87F81DFD0C6D0064C390 /* CellContainer.cpp */; };
+		0FDE87FC1DFE6E510064C390 /* SpaceTimeScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */; };
+		0FDE87FD1DFE6E540064C390 /* SpaceTimeScheduler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */; };
 		0FDF67D21D9C6D27001B9825 /* B3Kind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDF67D11D9C6086001B9825 /* B3Kind.h */; };
 		0FDF67D31D9C6D2A001B9825 /* B3Kind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF67D01D9C6086001B9825 /* B3Kind.cpp */; };
 		0FDF67D61D9DC440001B9825 /* AirKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF67D41D9DC43E001B9825 /* AirKind.cpp */; };
@@ -3181,6 +3183,8 @@
 		0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessDataDump.cpp; path = dfg/DFGVariableAccessDataDump.cpp; sourceTree = "<group>"; };
 		0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = "<group>"; };
 		0FDE87F81DFD0C6D0064C390 /* CellContainer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CellContainer.cpp; sourceTree = "<group>"; };
+		0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpaceTimeScheduler.cpp; sourceTree = "<group>"; };
+		0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpaceTimeScheduler.h; sourceTree = "<group>"; };
 		0FDF67D01D9C6086001B9825 /* B3Kind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3Kind.cpp; path = b3/B3Kind.cpp; sourceTree = "<group>"; };
 		0FDF67D11D9C6086001B9825 /* B3Kind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3Kind.h; path = b3/B3Kind.h; sourceTree = "<group>"; };
 		0FDF67D41D9DC43E001B9825 /* AirKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirKind.cpp; path = b3/air/AirKind.cpp; sourceTree = "<group>"; };
@@ -5737,6 +5741,8 @@
 				C225494215F7DBAA0065E898 /* SlotVisitor.cpp */,
 				14BA78F013AAB88F005B7C2C /* SlotVisitor.h */,
 				0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */,
+				0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */,
+				0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */,
 				0F7CF9501DC027D70098CC12 /* StopIfNecessaryTimer.cpp */,
 				0F7CF9511DC027D70098CC12 /* StopIfNecessaryTimer.h */,
 				142E3132134FF0A600AFADB5 /* Strong.h */,
@@ -8622,6 +8628,7 @@
 				BC18C4280E16F5CD00B34460 /* JSStringRef.h in Headers */,
 				43AB26C61C1A535900D82AE6 /* B3MathExtras.h in Headers */,
 				AD2FCBF31DB58DAD00B3E736 /* WebAssemblyInstancePrototype.h in Headers */,
+				0FDE87FC1DFE6E510064C390 /* SpaceTimeScheduler.h in Headers */,
 				BC18C4290E16F5CD00B34460 /* JSStringRefCF.h in Headers */,
 				E350708A1DC49BBF0089BCD6 /* DOMJITSignature.h in Headers */,
 				1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */,
@@ -9792,6 +9799,7 @@
 				0FD8A32517D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.cpp in Sources */,
 				0FC09791146A6F7100CF2442 /* DFGOSRExit.cpp in Sources */,
 				0F235BEB17178E7300690C7F /* DFGOSRExitBase.cpp in Sources */,
+				0FDE87FD1DFE6E540064C390 /* SpaceTimeScheduler.cpp in Sources */,
 				0FC09792146A6F7300CF2442 /* DFGOSRExitCompiler.cpp in Sources */,
 				0F4DE1D11C4D764B004D6C11 /* B3OriginDump.cpp in Sources */,
 				FE3A06B11C10CB8400390FDD /* JITBitAndGenerator.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (209726 => 209727)


--- trunk/Source/_javascript_Core/heap/Heap.cpp	2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp	2016-12-12 22:06:41 UTC (rev 209727)
@@ -52,6 +52,7 @@
 #include "PreventCollectionScope.h"
 #include "SamplingProfiler.h"
 #include "ShadowChicken.h"
+#include "SpaceTimeScheduler.h"
 #include "SuperSampler.h"
 #include "StopIfNecessaryTimer.h"
 #include "TypeProfilerLog.h"
@@ -560,100 +561,11 @@
 
     m_collectorSlotVisitor->didStartMarking();
 
-    MonotonicTime initialTime = MonotonicTime::now();
+    SpaceTimeScheduler scheduler(*this);
     
-    const Seconds period = Seconds::fromMilliseconds(Options::concurrentGCPeriodMS());
-    
-    const double bytesAllocatedThisCycleAtTheBeginning = m_bytesAllocatedThisCycle;
-    const double bytesAllocatedThisCycleAtTheEnd =
-        Options::concurrentGCMaxHeadroom() *
-        std::max(
-            bytesAllocatedThisCycleAtTheBeginning,
-            static_cast<double>(m_maxEdenSize));
-    double bytesAllocatedThisCycle;
-    MonotonicTime nowForScheduling;
-    
-    auto cacheSchedulingStats = [&] () {
-        bytesAllocatedThisCycle = m_bytesAllocatedThisCycle;
-        nowForScheduling = MonotonicTime::now();
-    };
-    
-    cacheSchedulingStats();
-    
-    auto targetMutatorUtilization = [&] () -> double {
-        double headroomFullness =
-            (bytesAllocatedThisCycle - bytesAllocatedThisCycleAtTheBeginning) /
-            (bytesAllocatedThisCycleAtTheEnd - bytesAllocatedThisCycleAtTheBeginning);
-        
-        // headroomFullness can be NaN and other interesting things if
-        // bytesAllocatedThisCycleAtTheBeginning is zero. We see that in debug tests. This code
-        // defends against all floating point dragons.
-        
-        if (!(headroomFullness >= 0))
-            headroomFullness = 0;
-        if (!(headroomFullness <= 1))
-            headroomFullness = 1;
-        
-        double mutatorUtilization = 1 - headroomFullness;
-        
-        // Scale the mutator utilization into the permitted window.
-        mutatorUtilization =
-            Options::minimumMutatorUtilization() +
-            mutatorUtilization * (
-                Options::maximumMutatorUtilization() -
-                Options::minimumMutatorUtilization());
-        
-        return mutatorUtilization;
-    };
-    
-    auto targetCollectorUtilization = [&] () -> double {
-        return 1 - targetMutatorUtilization();
-    };
-    
-    auto elapsedInPeriod = [&] () -> Seconds {
-        return (nowForScheduling - initialTime) % period;
-    };
-    
-    auto phase = [&] () -> double {
-        return elapsedInPeriod() / period;
-    };
-    
-    auto shouldBeResumed = [&] () -> bool {
-        if (Options::collectorShouldResumeFirst())
-            return phase() <= targetMutatorUtilization();
-        return phase() > targetCollectorUtilization();
-    };
-    
-    auto timeToResume = [&] () -> MonotonicTime {
-        ASSERT(!shouldBeResumed());
-        if (Options::collectorShouldResumeFirst())
-            return nowForScheduling - elapsedInPeriod() + period;
-        return nowForScheduling - elapsedInPeriod() + period * targetCollectorUtilization();
-    };
-    
-    auto timeToStop = [&] () -> MonotonicTime {
-        ASSERT(shouldBeResumed());
-        if (Options::collectorShouldResumeFirst())
-            return nowForScheduling - elapsedInPeriod() + period * targetMutatorUtilization();
-        return nowForScheduling - elapsedInPeriod() + period;
-    };
-    
-    // Adjust the target extra pause ratio as necessary.
-    double rateOfCollection =
-        (m_lastGCEndTime - m_lastGCStartTime) /
-        (m_currentGCStartTime - m_lastGCStartTime);
-    
-    if (Options::logGC())
-        dataLog("cr=", rateOfCollection, " ");
-    
-    // FIXME: Determine if this is useful or get rid of it.
-    // https://bugs.webkit.org/show_bug.cgi?id=164940
-    double extraPauseRatio = Options::initialExtraPauseRatio();
-    
     for (unsigned iteration = 1; ; ++iteration) {
         if (Options::logGC())
             dataLog("i#", iteration, " ");
-        MonotonicTime topOfLoop = MonotonicTime::now();
         {
             TimingScope preConvergenceTimingScope(*this, "Heap::markToFixpoint conservative scan");
             m_objectSpace.prepareForConservativeScan();
@@ -716,8 +628,7 @@
         bool shouldTerminate = m_collectorSlotVisitor->isEmpty() && m_mutatorMarkStack->isEmpty();
         
         if (Options::logGC()) {
-            cacheSchedulingStats();
-            dataLog(m_collectorSlotVisitor->collectorMarkStack().size(), "+", m_mutatorMarkStack->size() + m_collectorSlotVisitor->mutatorMarkStack().size(), ", a=", m_bytesAllocatedThisCycle / 1024, " kb, b=", m_barriersExecuted, ", mu=", targetMutatorUtilization(), " ");
+            dataLog(m_collectorSlotVisitor->collectorMarkStack().size(), "+", m_mutatorMarkStack->size() + m_collectorSlotVisitor->mutatorMarkStack().size(), ", a=", m_bytesAllocatedThisCycle / 1024, " kb, b=", m_barriersExecuted, ", mu=", scheduler.currentDecision().targetMutatorUtilization(), " ");
         }
         
         // We want to do this to conservatively ensure that we rescan any code blocks that are
@@ -739,31 +650,31 @@
         if (Options::logGC() == GCLogging::Verbose)
             dataLog("Live Weak Handles:\n", *m_collectorSlotVisitor);
         
-        MonotonicTime beforeConvergence = MonotonicTime::now();
-        
         {
             TimingScope traceTimingScope(*this, "Heap::markToFixpoint tracing");
             ParallelModeEnabler enabler(*m_collectorSlotVisitor);
             
             if (Options::useCollectorTimeslicing()) {
-                // Before we yield to the mutator, we should do GC work proportional to the time we
-                // spent paused. We initialize the timeslicer to start after this "mandatory" pause
-                // completes.
+                scheduler.snapPhase();
                 
                 SlotVisitor::SharedDrainResult drainResult;
-                
-                Seconds extraPause = (beforeConvergence - topOfLoop) * extraPauseRatio;
-                initialTime = beforeConvergence + extraPause;
-                drainResult = m_collectorSlotVisitor->drainInParallel(initialTime);
-                
-                while (drainResult != SlotVisitor::SharedDrainResult::Done) {
-                    cacheSchedulingStats();
-                    if (shouldBeResumed()) {
+                do {
+                    auto decision = scheduler.currentDecision();
+                    if (decision.shouldBeResumed()) {
                         ResumeTheWorldScope resumeTheWorldScope(*this);
-                        drainResult = m_collectorSlotVisitor->drainInParallelPassively(timeToStop());
+                        drainResult = m_collectorSlotVisitor->drainInParallelPassively(decision.timeToStop());
+                        if (drainResult == SlotVisitor::SharedDrainResult::Done) {
+                            // At this point we will stop. But maybe the scheduler does not want
+                            // that.
+                            Seconds scheduledIdle = decision.timeToStop() - MonotonicTime::now();
+                            // It's totally unclear what the value of collectPermittedIdleRatio
+                            // should be, other than it should be greater than 0. You could even
+                            // argue for it being greater than 1. We should tune it.
+                            sleep(scheduledIdle * Options::collectorPermittedIdleRatio());
+                        }
                     } else
-                        drainResult = m_collectorSlotVisitor->drainInParallel(timeToResume());
-                }
+                        drainResult = m_collectorSlotVisitor->drainInParallel(decision.timeToResume());
+                } while (drainResult != SlotVisitor::SharedDrainResult::Done);
             } else {
                 // Disabling collector timeslicing is meant to be used together with
                 // --collectContinuously=true to maximize the opportunity for harmful races.
@@ -771,8 +682,6 @@
                 m_collectorSlotVisitor->drainInParallel();
             }
         }
-        
-        extraPauseRatio *= Options::extraPauseRatioIterationGrowthRate();
     }
 
     {

Modified: trunk/Source/_javascript_Core/heap/Heap.h (209726 => 209727)


--- trunk/Source/_javascript_Core/heap/Heap.h	2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/_javascript_Core/heap/Heap.h	2016-12-12 22:06:41 UTC (rev 209727)
@@ -75,6 +75,7 @@
 class MarkStackArray;
 class MarkedArgumentBuffer;
 class SlotVisitor;
+class SpaceTimeScheduler;
 class StopIfNecessaryTimer;
 class VM;
 
@@ -376,6 +377,7 @@
     friend class MarkedAllocator;
     friend class MarkedBlock;
     friend class SlotVisitor;
+    friend class SpaceTimeScheduler;
     friend class IncrementalSweeper;
     friend class HeapStatistics;
     friend class VM;

Added: trunk/Source/_javascript_Core/heap/SpaceTimeScheduler.cpp (0 => 209727)


--- trunk/Source/_javascript_Core/heap/SpaceTimeScheduler.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/heap/SpaceTimeScheduler.cpp	2016-12-12 22:06:41 UTC (rev 209727)
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "SpaceTimeScheduler.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+double SpaceTimeScheduler::Decision::targetMutatorUtilization() const
+{
+    double bytesSinceBeginningOfCycle =
+        m_bytesAllocatedThisCycle - m_scheduler->m_bytesAllocatedThisCycleAtTheBeginning;
+    
+    double maxHeadroom =
+        m_scheduler->m_bytesAllocatedThisCycleAtTheEnd - m_scheduler->m_bytesAllocatedThisCycleAtTheBeginning;
+    
+    double headroomFullness =
+        bytesSinceBeginningOfCycle / maxHeadroom;
+    
+    // headroomFullness can be NaN and other interesting things if
+    // bytesAllocatedThisCycleAtTheBeginning is zero. We see that in debug tests. This code
+    // defends against all floating point dragons.
+    
+    if (!(headroomFullness >= 0))
+        headroomFullness = 0;
+    if (!(headroomFullness <= 1))
+        headroomFullness = 1;
+    
+    double mutatorUtilization = 1 - headroomFullness;
+    
+    // Scale the mutator utilization into the permitted window.
+    mutatorUtilization =
+        Options::minimumMutatorUtilization() +
+        mutatorUtilization * (
+            Options::maximumMutatorUtilization() -
+            Options::minimumMutatorUtilization());
+    
+    return mutatorUtilization;
+}
+
+double SpaceTimeScheduler::Decision::targetCollectorUtilization() const
+{
+    return 1 - targetMutatorUtilization();
+}
+
+Seconds SpaceTimeScheduler::Decision::elapsedInPeriod() const
+{
+    return (m_now - m_scheduler->m_initialTime) % m_scheduler->m_period;
+}
+
+double SpaceTimeScheduler::Decision::phase() const
+{
+    return elapsedInPeriod() / m_scheduler->m_period;
+}
+
+bool SpaceTimeScheduler::Decision::shouldBeResumed() const
+{
+    if (Options::collectorShouldResumeFirst())
+        return phase() <= targetMutatorUtilization();
+    return phase() > targetCollectorUtilization();
+}
+
+MonotonicTime SpaceTimeScheduler::Decision::timeToResume() const
+{
+    ASSERT(!shouldBeResumed());
+    if (Options::collectorShouldResumeFirst())
+        return m_now - elapsedInPeriod() + m_scheduler->m_period;
+    return m_now - elapsedInPeriod() + m_scheduler->m_period * targetCollectorUtilization();
+}
+
+MonotonicTime SpaceTimeScheduler::Decision::timeToStop() const
+{
+    ASSERT(shouldBeResumed());
+    if (Options::collectorShouldResumeFirst())
+        return m_now - elapsedInPeriod() + m_scheduler->m_period * targetMutatorUtilization();
+    return m_now - elapsedInPeriod() + m_scheduler->m_period;
+}
+
+SpaceTimeScheduler::SpaceTimeScheduler(Heap& heap)
+    : m_heap(heap)
+    , m_period(Seconds::fromMilliseconds(Options::concurrentGCPeriodMS()))
+    , m_bytesAllocatedThisCycleAtTheBeginning(heap.m_bytesAllocatedThisCycle)
+    , m_bytesAllocatedThisCycleAtTheEnd(
+        Options::concurrentGCMaxHeadroom() *
+        std::max<double>(m_bytesAllocatedThisCycleAtTheBeginning, heap.m_maxEdenSize))
+{
+    snapPhase();
+}
+
+void SpaceTimeScheduler::snapPhase()
+{
+    m_initialTime = MonotonicTime::now();
+}
+
+SpaceTimeScheduler::Decision SpaceTimeScheduler::currentDecision()
+{
+    Decision result;
+    result.m_scheduler = this;
+    result.m_bytesAllocatedThisCycle = m_heap.m_bytesAllocatedThisCycle;
+    result.m_now = MonotonicTime::now();
+    return result;
+}
+
+} // namespace JSC
+

Added: trunk/Source/_javascript_Core/heap/SpaceTimeScheduler.h (0 => 209727)


--- trunk/Source/_javascript_Core/heap/SpaceTimeScheduler.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/heap/SpaceTimeScheduler.h	2016-12-12 22:06:41 UTC (rev 209727)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#include <wtf/MonotonicTime.h>
+#include <wtf/Seconds.h>
+
+namespace JSC {
+
+class Heap;
+
+class SpaceTimeScheduler {
+public:
+    class Decision {
+    public:
+        explicit operator bool() const { return !!m_scheduler; }
+        
+        double targetMutatorUtilization() const;
+        double targetCollectorUtilization() const;
+        Seconds elapsedInPeriod() const;
+        double phase() const;
+        bool shouldBeResumed() const;
+        MonotonicTime timeToResume() const;
+        MonotonicTime timeToStop() const;
+        
+    private:
+        friend class SpaceTimeScheduler;
+
+        SpaceTimeScheduler* m_scheduler { nullptr };
+        double m_bytesAllocatedThisCycle { 0 };
+        MonotonicTime m_now;
+    };
+    
+    // Construct the scheduler at the start of a GC cycle.
+    SpaceTimeScheduler(Heap&);
+    
+    // Forces the next phase to start now.
+    void snapPhase();
+    
+    // Returns a snapshot of the current scheduling decision, which will be valid so long as
+    // SpaceTimeScheduler is live and you haven't called snapPhase().
+    Decision currentDecision();
+    
+private:
+    friend class Decision;
+
+    Heap& m_heap;
+    Seconds m_period;
+    double m_bytesAllocatedThisCycleAtTheBeginning;
+    double m_bytesAllocatedThisCycleAtTheEnd;
+    MonotonicTime m_initialTime;
+};
+
+} // namespace JSC
+

Modified: trunk/Source/_javascript_Core/runtime/Options.h (209726 => 209727)


--- trunk/Source/_javascript_Core/runtime/Options.h	2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/_javascript_Core/runtime/Options.h	2016-12-12 22:06:41 UTC (rev 209727)
@@ -202,9 +202,8 @@
     v(double, maximumMutatorUtilization, 0.7, Normal, nullptr) \
     v(double, concurrentGCMaxHeadroom, 1.5, Normal, nullptr) \
     v(double, concurrentGCPeriodMS, 2, Normal, nullptr) \
-    v(double, initialExtraPauseRatio, 0, Normal, nullptr) \
-    v(double, extraPauseRatioIterationGrowthRate, 1.1, Normal, nullptr) \
     v(bool, collectorShouldResumeFirst, false, Normal, nullptr) \
+    v(double, collectorPermittedIdleRatio, 1, Normal, nullptr) \
     v(bool, scribbleFreeCells, false, Normal, nullptr) \
     v(double, sizeClassProgression, 1.4, Normal, nullptr) \
     v(unsigned, largeAllocationCutoff, 100000, Normal, nullptr) \
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to