<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[209727] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/209727">209727</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-12-12 14:06:41 -0800 (Mon, 12 Dec 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>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:
* JavaScriptCore.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:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreheapSpaceTimeSchedulercpp">trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSpaceTimeSchedulerh">trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (209726 => 209727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2016-12-12 22:06:41 UTC (rev 209727)
</span><span class="lines">@@ -497,6 +497,7 @@
</span><span class="cx">     heap/MarkedSpace.cpp
</span><span class="cx">     heap/MutatorState.cpp
</span><span class="cx">     heap/SlotVisitor.cpp
</span><ins>+    heap/SpaceTimeScheduler.cpp
</ins><span class="cx">     heap/StopIfNecessaryTimer.cpp
</span><span class="cx">     heap/VisitRaceKey.cpp
</span><span class="cx">     heap/Weak.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (209726 => 209727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-12 22:06:41 UTC (rev 209727)
</span><span class="lines">@@ -1,3 +1,44 @@
</span><ins>+2016-12-12  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        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:
+        * JavaScriptCore.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:
+
</ins><span class="cx"> 2016-12-12  Michael Saboff  &lt;msaboff@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION(r209653): speedometer crashes making virtual slow path tailcalls
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (209726 => 209727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-12-12 22:06:41 UTC (rev 209727)
</span><span class="lines">@@ -753,6 +753,8 @@
</span><span class="cx">                 0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */; };
</span><span class="cx">                 0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; };
</span><span class="cx">                 0FDE87F91DFD0C760064C390 /* CellContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDE87F81DFD0C6D0064C390 /* CellContainer.cpp */; };
</span><ins>+                0FDE87FC1DFE6E510064C390 /* SpaceTimeScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */; };
+                0FDE87FD1DFE6E540064C390 /* SpaceTimeScheduler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */; };
</ins><span class="cx">                 0FDF67D21D9C6D27001B9825 /* B3Kind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDF67D11D9C6086001B9825 /* B3Kind.h */; };
</span><span class="cx">                 0FDF67D31D9C6D2A001B9825 /* B3Kind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF67D01D9C6086001B9825 /* B3Kind.cpp */; };
</span><span class="cx">                 0FDF67D61D9DC440001B9825 /* AirKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF67D41D9DC43E001B9825 /* AirKind.cpp */; };
</span><span class="lines">@@ -3181,6 +3183,8 @@
</span><span class="cx">                 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessDataDump.cpp; path = dfg/DFGVariableAccessDataDump.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDE87F81DFD0C6D0064C390 /* CellContainer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CellContainer.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpaceTimeScheduler.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpaceTimeScheduler.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0FDF67D01D9C6086001B9825 /* B3Kind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3Kind.cpp; path = b3/B3Kind.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDF67D11D9C6086001B9825 /* B3Kind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3Kind.h; path = b3/B3Kind.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDF67D41D9DC43E001B9825 /* AirKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirKind.cpp; path = b3/air/AirKind.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -5737,6 +5741,8 @@
</span><span class="cx">                                 C225494215F7DBAA0065E898 /* SlotVisitor.cpp */,
</span><span class="cx">                                 14BA78F013AAB88F005B7C2C /* SlotVisitor.h */,
</span><span class="cx">                                 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */,
</span><ins>+                                0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */,
+                                0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */,
</ins><span class="cx">                                 0F7CF9501DC027D70098CC12 /* StopIfNecessaryTimer.cpp */,
</span><span class="cx">                                 0F7CF9511DC027D70098CC12 /* StopIfNecessaryTimer.h */,
</span><span class="cx">                                 142E3132134FF0A600AFADB5 /* Strong.h */,
</span><span class="lines">@@ -8622,6 +8628,7 @@
</span><span class="cx">                                 BC18C4280E16F5CD00B34460 /* JSStringRef.h in Headers */,
</span><span class="cx">                                 43AB26C61C1A535900D82AE6 /* B3MathExtras.h in Headers */,
</span><span class="cx">                                 AD2FCBF31DB58DAD00B3E736 /* WebAssemblyInstancePrototype.h in Headers */,
</span><ins>+                                0FDE87FC1DFE6E510064C390 /* SpaceTimeScheduler.h in Headers */,
</ins><span class="cx">                                 BC18C4290E16F5CD00B34460 /* JSStringRefCF.h in Headers */,
</span><span class="cx">                                 E350708A1DC49BBF0089BCD6 /* DOMJITSignature.h in Headers */,
</span><span class="cx">                                 1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */,
</span><span class="lines">@@ -9792,6 +9799,7 @@
</span><span class="cx">                                 0FD8A32517D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.cpp in Sources */,
</span><span class="cx">                                 0FC09791146A6F7100CF2442 /* DFGOSRExit.cpp in Sources */,
</span><span class="cx">                                 0F235BEB17178E7300690C7F /* DFGOSRExitBase.cpp in Sources */,
</span><ins>+                                0FDE87FD1DFE6E540064C390 /* SpaceTimeScheduler.cpp in Sources */,
</ins><span class="cx">                                 0FC09792146A6F7300CF2442 /* DFGOSRExitCompiler.cpp in Sources */,
</span><span class="cx">                                 0F4DE1D11C4D764B004D6C11 /* B3OriginDump.cpp in Sources */,
</span><span class="cx">                                 FE3A06B11C10CB8400390FDD /* JITBitAndGenerator.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (209726 => 209727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2016-12-12 22:06:41 UTC (rev 209727)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx"> #include &quot;PreventCollectionScope.h&quot;
</span><span class="cx"> #include &quot;SamplingProfiler.h&quot;
</span><span class="cx"> #include &quot;ShadowChicken.h&quot;
</span><ins>+#include &quot;SpaceTimeScheduler.h&quot;
</ins><span class="cx"> #include &quot;SuperSampler.h&quot;
</span><span class="cx"> #include &quot;StopIfNecessaryTimer.h&quot;
</span><span class="cx"> #include &quot;TypeProfilerLog.h&quot;
</span><span class="lines">@@ -560,100 +561,11 @@
</span><span class="cx"> 
</span><span class="cx">     m_collectorSlotVisitor-&gt;didStartMarking();
</span><span class="cx"> 
</span><del>-    MonotonicTime initialTime = MonotonicTime::now();
</del><ins>+    SpaceTimeScheduler scheduler(*this);
</ins><span class="cx">     
</span><del>-    const Seconds period = Seconds::fromMilliseconds(Options::concurrentGCPeriodMS());
-    
-    const double bytesAllocatedThisCycleAtTheBeginning = m_bytesAllocatedThisCycle;
-    const double bytesAllocatedThisCycleAtTheEnd =
-        Options::concurrentGCMaxHeadroom() *
-        std::max(
-            bytesAllocatedThisCycleAtTheBeginning,
-            static_cast&lt;double&gt;(m_maxEdenSize));
-    double bytesAllocatedThisCycle;
-    MonotonicTime nowForScheduling;
-    
-    auto cacheSchedulingStats = [&amp;] () {
-        bytesAllocatedThisCycle = m_bytesAllocatedThisCycle;
-        nowForScheduling = MonotonicTime::now();
-    };
-    
-    cacheSchedulingStats();
-    
-    auto targetMutatorUtilization = [&amp;] () -&gt; 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 &gt;= 0))
-            headroomFullness = 0;
-        if (!(headroomFullness &lt;= 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 = [&amp;] () -&gt; double {
-        return 1 - targetMutatorUtilization();
-    };
-    
-    auto elapsedInPeriod = [&amp;] () -&gt; Seconds {
-        return (nowForScheduling - initialTime) % period;
-    };
-    
-    auto phase = [&amp;] () -&gt; double {
-        return elapsedInPeriod() / period;
-    };
-    
-    auto shouldBeResumed = [&amp;] () -&gt; bool {
-        if (Options::collectorShouldResumeFirst())
-            return phase() &lt;= targetMutatorUtilization();
-        return phase() &gt; targetCollectorUtilization();
-    };
-    
-    auto timeToResume = [&amp;] () -&gt; MonotonicTime {
-        ASSERT(!shouldBeResumed());
-        if (Options::collectorShouldResumeFirst())
-            return nowForScheduling - elapsedInPeriod() + period;
-        return nowForScheduling - elapsedInPeriod() + period * targetCollectorUtilization();
-    };
-    
-    auto timeToStop = [&amp;] () -&gt; 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(&quot;cr=&quot;, rateOfCollection, &quot; &quot;);
-    
-    // FIXME: Determine if this is useful or get rid of it.
-    // https://bugs.webkit.org/show_bug.cgi?id=164940
-    double extraPauseRatio = Options::initialExtraPauseRatio();
-    
</del><span class="cx">     for (unsigned iteration = 1; ; ++iteration) {
</span><span class="cx">         if (Options::logGC())
</span><span class="cx">             dataLog(&quot;i#&quot;, iteration, &quot; &quot;);
</span><del>-        MonotonicTime topOfLoop = MonotonicTime::now();
</del><span class="cx">         {
</span><span class="cx">             TimingScope preConvergenceTimingScope(*this, &quot;Heap::markToFixpoint conservative scan&quot;);
</span><span class="cx">             m_objectSpace.prepareForConservativeScan();
</span><span class="lines">@@ -716,8 +628,7 @@
</span><span class="cx">         bool shouldTerminate = m_collectorSlotVisitor-&gt;isEmpty() &amp;&amp; m_mutatorMarkStack-&gt;isEmpty();
</span><span class="cx">         
</span><span class="cx">         if (Options::logGC()) {
</span><del>-            cacheSchedulingStats();
-            dataLog(m_collectorSlotVisitor-&gt;collectorMarkStack().size(), &quot;+&quot;, m_mutatorMarkStack-&gt;size() + m_collectorSlotVisitor-&gt;mutatorMarkStack().size(), &quot;, a=&quot;, m_bytesAllocatedThisCycle / 1024, &quot; kb, b=&quot;, m_barriersExecuted, &quot;, mu=&quot;, targetMutatorUtilization(), &quot; &quot;);
</del><ins>+            dataLog(m_collectorSlotVisitor-&gt;collectorMarkStack().size(), &quot;+&quot;, m_mutatorMarkStack-&gt;size() + m_collectorSlotVisitor-&gt;mutatorMarkStack().size(), &quot;, a=&quot;, m_bytesAllocatedThisCycle / 1024, &quot; kb, b=&quot;, m_barriersExecuted, &quot;, mu=&quot;, scheduler.currentDecision().targetMutatorUtilization(), &quot; &quot;);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         // We want to do this to conservatively ensure that we rescan any code blocks that are
</span><span class="lines">@@ -739,31 +650,31 @@
</span><span class="cx">         if (Options::logGC() == GCLogging::Verbose)
</span><span class="cx">             dataLog(&quot;Live Weak Handles:\n&quot;, *m_collectorSlotVisitor);
</span><span class="cx">         
</span><del>-        MonotonicTime beforeConvergence = MonotonicTime::now();
-        
</del><span class="cx">         {
</span><span class="cx">             TimingScope traceTimingScope(*this, &quot;Heap::markToFixpoint tracing&quot;);
</span><span class="cx">             ParallelModeEnabler enabler(*m_collectorSlotVisitor);
</span><span class="cx">             
</span><span class="cx">             if (Options::useCollectorTimeslicing()) {
</span><del>-                // 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 &quot;mandatory&quot; pause
-                // completes.
</del><ins>+                scheduler.snapPhase();
</ins><span class="cx">                 
</span><span class="cx">                 SlotVisitor::SharedDrainResult drainResult;
</span><del>-                
-                Seconds extraPause = (beforeConvergence - topOfLoop) * extraPauseRatio;
-                initialTime = beforeConvergence + extraPause;
-                drainResult = m_collectorSlotVisitor-&gt;drainInParallel(initialTime);
-                
-                while (drainResult != SlotVisitor::SharedDrainResult::Done) {
-                    cacheSchedulingStats();
-                    if (shouldBeResumed()) {
</del><ins>+                do {
+                    auto decision = scheduler.currentDecision();
+                    if (decision.shouldBeResumed()) {
</ins><span class="cx">                         ResumeTheWorldScope resumeTheWorldScope(*this);
</span><del>-                        drainResult = m_collectorSlotVisitor-&gt;drainInParallelPassively(timeToStop());
</del><ins>+                        drainResult = m_collectorSlotVisitor-&gt;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());
+                        }
</ins><span class="cx">                     } else
</span><del>-                        drainResult = m_collectorSlotVisitor-&gt;drainInParallel(timeToResume());
-                }
</del><ins>+                        drainResult = m_collectorSlotVisitor-&gt;drainInParallel(decision.timeToResume());
+                } while (drainResult != SlotVisitor::SharedDrainResult::Done);
</ins><span class="cx">             } else {
</span><span class="cx">                 // Disabling collector timeslicing is meant to be used together with
</span><span class="cx">                 // --collectContinuously=true to maximize the opportunity for harmful races.
</span><span class="lines">@@ -771,8 +682,6 @@
</span><span class="cx">                 m_collectorSlotVisitor-&gt;drainInParallel();
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-        
-        extraPauseRatio *= Options::extraPauseRatioIterationGrowthRate();
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (209726 => 209727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2016-12-12 22:06:41 UTC (rev 209727)
</span><span class="lines">@@ -75,6 +75,7 @@
</span><span class="cx"> class MarkStackArray;
</span><span class="cx"> class MarkedArgumentBuffer;
</span><span class="cx"> class SlotVisitor;
</span><ins>+class SpaceTimeScheduler;
</ins><span class="cx"> class StopIfNecessaryTimer;
</span><span class="cx"> class VM;
</span><span class="cx"> 
</span><span class="lines">@@ -376,6 +377,7 @@
</span><span class="cx">     friend class MarkedAllocator;
</span><span class="cx">     friend class MarkedBlock;
</span><span class="cx">     friend class SlotVisitor;
</span><ins>+    friend class SpaceTimeScheduler;
</ins><span class="cx">     friend class IncrementalSweeper;
</span><span class="cx">     friend class HeapStatistics;
</span><span class="cx">     friend class VM;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSpaceTimeSchedulercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp (0 => 209727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp        2016-12-12 22:06:41 UTC (rev 209727)
</span><span class="lines">@@ -0,0 +1,129 @@
</span><ins>+/*
+ * 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 &quot;config.h&quot;
+#include &quot;SpaceTimeScheduler.h&quot;
+
+#include &quot;JSCInlines.h&quot;
+
+namespace JSC {
+
+double SpaceTimeScheduler::Decision::targetMutatorUtilization() const
+{
+    double bytesSinceBeginningOfCycle =
+        m_bytesAllocatedThisCycle - m_scheduler-&gt;m_bytesAllocatedThisCycleAtTheBeginning;
+    
+    double maxHeadroom =
+        m_scheduler-&gt;m_bytesAllocatedThisCycleAtTheEnd - m_scheduler-&gt;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 &gt;= 0))
+        headroomFullness = 0;
+    if (!(headroomFullness &lt;= 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-&gt;m_initialTime) % m_scheduler-&gt;m_period;
+}
+
+double SpaceTimeScheduler::Decision::phase() const
+{
+    return elapsedInPeriod() / m_scheduler-&gt;m_period;
+}
+
+bool SpaceTimeScheduler::Decision::shouldBeResumed() const
+{
+    if (Options::collectorShouldResumeFirst())
+        return phase() &lt;= targetMutatorUtilization();
+    return phase() &gt; targetCollectorUtilization();
+}
+
+MonotonicTime SpaceTimeScheduler::Decision::timeToResume() const
+{
+    ASSERT(!shouldBeResumed());
+    if (Options::collectorShouldResumeFirst())
+        return m_now - elapsedInPeriod() + m_scheduler-&gt;m_period;
+    return m_now - elapsedInPeriod() + m_scheduler-&gt;m_period * targetCollectorUtilization();
+}
+
+MonotonicTime SpaceTimeScheduler::Decision::timeToStop() const
+{
+    ASSERT(shouldBeResumed());
+    if (Options::collectorShouldResumeFirst())
+        return m_now - elapsedInPeriod() + m_scheduler-&gt;m_period * targetMutatorUtilization();
+    return m_now - elapsedInPeriod() + m_scheduler-&gt;m_period;
+}
+
+SpaceTimeScheduler::SpaceTimeScheduler(Heap&amp; heap)
+    : m_heap(heap)
+    , m_period(Seconds::fromMilliseconds(Options::concurrentGCPeriodMS()))
+    , m_bytesAllocatedThisCycleAtTheBeginning(heap.m_bytesAllocatedThisCycle)
+    , m_bytesAllocatedThisCycleAtTheEnd(
+        Options::concurrentGCMaxHeadroom() *
+        std::max&lt;double&gt;(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
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSpaceTimeSchedulerh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h (0 => 209727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h        2016-12-12 22:06:41 UTC (rev 209727)
</span><span class="lines">@@ -0,0 +1,78 @@
</span><ins>+/*
+ * 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 &lt;wtf/MonotonicTime.h&gt;
+#include &lt;wtf/Seconds.h&gt;
+
+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&amp;);
+    
+    // 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&amp; m_heap;
+    Seconds m_period;
+    double m_bytesAllocatedThisCycleAtTheBeginning;
+    double m_bytesAllocatedThisCycleAtTheEnd;
+    MonotonicTime m_initialTime;
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (209726 => 209727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2016-12-12 21:49:53 UTC (rev 209726)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2016-12-12 22:06:41 UTC (rev 209727)
</span><span class="lines">@@ -202,9 +202,8 @@
</span><span class="cx">     v(double, maximumMutatorUtilization, 0.7, Normal, nullptr) \
</span><span class="cx">     v(double, concurrentGCMaxHeadroom, 1.5, Normal, nullptr) \
</span><span class="cx">     v(double, concurrentGCPeriodMS, 2, Normal, nullptr) \
</span><del>-    v(double, initialExtraPauseRatio, 0, Normal, nullptr) \
-    v(double, extraPauseRatioIterationGrowthRate, 1.1, Normal, nullptr) \
</del><span class="cx">     v(bool, collectorShouldResumeFirst, false, Normal, nullptr) \
</span><ins>+    v(double, collectorPermittedIdleRatio, 1, Normal, nullptr) \
</ins><span class="cx">     v(bool, scribbleFreeCells, false, Normal, nullptr) \
</span><span class="cx">     v(double, sizeClassProgression, 1.4, Normal, nullptr) \
</span><span class="cx">     v(unsigned, largeAllocationCutoff, 100000, Normal, nullptr) \
</span></span></pre>
</div>
</div>

</body>
</html>