Title: [103070] trunk/Source
Revision
103070
Author
nd...@chromium.org
Date
2011-12-16 08:31:34 -0800 (Fri, 16 Dec 2011)

Log Message

[chromium] DelayBasedTimeSource should not change its timebase on late ticks
https://bugs.webkit.org/show_bug.cgi?id=74573

The original DelayBasedTimeSource was designed to shift its timebase
to the tick time when a tick came back "late." The rationale was that it is
better to just "start fresh" after a stutter. After profiling this,
this time-rebasing just destabilizes frame rate anytime the thread gets
loaded.  This patch keeps the timebase stationary, leading to vastly
smoother framerates when the message loop is under load.

Reviewed by James Robinson.

* platform/graphics/chromium/cc/CCDelayBasedTimeSource.cpp:
(WebCore::CCDelayBasedTimeSource::updateState):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (103069 => 103070)


--- trunk/Source/WebCore/ChangeLog	2011-12-16 14:58:49 UTC (rev 103069)
+++ trunk/Source/WebCore/ChangeLog	2011-12-16 16:31:34 UTC (rev 103070)
@@ -1,3 +1,20 @@
+2011-12-14  Nat Duca  <nd...@chromium.org>
+
+        [chromium] DelayBasedTimeSource should not change its timebase on late ticks
+        https://bugs.webkit.org/show_bug.cgi?id=74573
+
+        The original DelayBasedTimeSource was designed to shift its timebase
+        to the tick time when a tick came back "late." The rationale was that it is
+        better to just "start fresh" after a stutter. After profiling this,
+        this time-rebasing just destabilizes frame rate anytime the thread gets
+        loaded.  This patch keeps the timebase stationary, leading to vastly
+        smoother framerates when the message loop is under load.
+
+        Reviewed by James Robinson.
+
+        * platform/graphics/chromium/cc/CCDelayBasedTimeSource.cpp:
+        (WebCore::CCDelayBasedTimeSource::updateState):
+
 2011-12-16  Sheriff Bot  <webkit.review....@gmail.com>
 
         Unreviewed, rolling out r103062.

Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCDelayBasedTimeSource.cpp (103069 => 103070)


--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCDelayBasedTimeSource.cpp	2011-12-16 14:58:49 UTC (rev 103069)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCDelayBasedTimeSource.cpp	2011-12-16 16:31:34 UTC (rev 103070)
@@ -29,6 +29,7 @@
 #include "cc/CCThread.h"
 #include "cc/CCThreadTask.h"
 #include <wtf/CurrentTime.h>
+#include <wtf/MathExtras.h>
 
 namespace WebCore {
 
@@ -121,11 +122,8 @@
 //      now=18   tickTarget=16.667  newTarget=33.333   --> tick(), postDelayedTask(floor(33.333-18)) --> postDelayedTask(15)
 // This brings us back to 18+15 = 33, which was where we would have been if the task hadn't been late.
 //
-// For the really late delay, we fire a tick immediately reset the timebase from the current tim. E.g.:
-//      now=37   tickTarget=16.667  newTarget=53.6667   --> tick(), postDelayedTask(floor(53.667-37)) --> postDelayedTask(16)
-//
-// Here we realize we're more than a tick late. We adjust newTarget to be 16.667 from now, and post a task off that new
-// target.
+// For the really late delay, we we move to the next logical tick. The timebase is not reset.
+//      now=37   tickTarget=16.667  newTarget=50.000  --> tick(), postDelayedTask(floor(50.000-37)) --> postDelayedTask(13)
 void CCDelayBasedTimeSource::updateState()
 {
     if (m_state == STATE_INACTIVE)
@@ -138,18 +136,19 @@
         m_state = STATE_ACTIVE;
     }
 
-    const double maxLateBeforeResettingTimebase = 5.0;
+    int numIntervalsElapsed = static_cast<int>(floor((now - m_tickTarget) / m_intervalMs));
+    double lastEffectiveTick = m_tickTarget + m_intervalMs * numIntervalsElapsed;
+    double newTickTarget = lastEffectiveTick + m_intervalMs;
 
-    double newTickTarget = 0;
-    double amountLate = now - m_tickTarget;
-    if (amountLate <= maxLateBeforeResettingTimebase)
-        newTickTarget = m_tickTarget + m_intervalMs;
-    else
-        newTickTarget = now + m_intervalMs;
+    long long delay = static_cast<long long>(newTickTarget - now);
+    if (!delay) {
+        newTickTarget = newTickTarget + m_intervalMs;
+        delay = static_cast<long long>(newTickTarget - now);
+    }
 
     // Post another task *before* the tick and update state
     ASSERT(newTickTarget > now);
-    postTickTask(static_cast<long long>(newTickTarget - now));
+    postTickTask(delay);
     m_tickTarget = newTickTarget;
 
     // Fire the tick

Modified: trunk/Source/WebKit/chromium/tests/CCDelayBasedTimeSourceTest.cpp (103069 => 103070)


--- trunk/Source/WebKit/chromium/tests/CCDelayBasedTimeSourceTest.cpp	2011-12-16 14:58:49 UTC (rev 103069)
+++ trunk/Source/WebKit/chromium/tests/CCDelayBasedTimeSourceTest.cpp	2011-12-16 16:31:34 UTC (rev 103070)
@@ -92,6 +92,112 @@
     EXPECT_FALSE(thread.hasPendingTask());
 }
 
+// At 60Hz, when the tick returns at exactly the requested next time, make sure
+// a 16ms next delay is posted.
+TEST(CCDelayBasedTimeSource, NextDelaySaneWhenExactlyOnRequestedTime)
+{
+    FakeCCThread thread;
+    FakeCCTimeSourceClient client;
+    double interval = 1000.0 / 60.0;
+    RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
+    timer->setClient(&client);
+    timer->setActive(true);
+    // Run the first task, as that activates the timer and picks up a timebase.
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+
+    timer->setMonotonicallyIncreasingTimeMs(interval);
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+}
+
+// At 60Hz, when the tick returns at slightly after the requested next time, make sure
+// a 16ms next delay is posted.
+TEST(CCDelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterRequestedTime)
+{
+    FakeCCThread thread;
+    FakeCCTimeSourceClient client;
+    double interval = 1000.0 / 60.0;
+    RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
+    timer->setClient(&client);
+    timer->setActive(true);
+    // Run the first task, as that activates the timer and picks up a timebase.
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+
+    timer->setMonotonicallyIncreasingTimeMs(interval + 0.0001);
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+}
+
+// At 60Hz, when the tick returns at exactly 2*interval after the requested next time, make sure
+// a 16ms next delay is posted.
+TEST(CCDelayBasedTimeSource, NextDelaySaneWhenExactlyTwiceAfterRequestedTime)
+{
+    FakeCCThread thread;
+    FakeCCTimeSourceClient client;
+    double interval = 1000.0 / 60.0;
+    RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
+    timer->setClient(&client);
+    timer->setActive(true);
+    // Run the first task, as that activates the timer and picks up a timebase.
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+
+    timer->setMonotonicallyIncreasingTimeMs(2*interval);
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+}
+
+// At 60Hz, when the tick returns at 2*interval and a bit after the requested next time, make sure
+// a 16ms next delay is posted.
+TEST(CCDelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime)
+{
+    FakeCCThread thread;
+    FakeCCTimeSourceClient client;
+    double interval = 1000.0 / 60.0;
+    RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
+    timer->setClient(&client);
+    timer->setActive(true);
+    // Run the first task, as that activates the timer and picks up a timebase.
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+
+    timer->setMonotonicallyIncreasingTimeMs(2*interval + 0.0001);
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+}
+
+// At 60Hz, when the tick returns halfway to the next frame time, make sure
+// a correct next delay value is posted.
+TEST(CCDelayBasedTimeSource, NextDelaySaneWhenHalfAfterRequestedTime)
+{
+    FakeCCThread thread;
+    FakeCCTimeSourceClient client;
+    double interval = 1000.0 / 60.0;
+    RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
+    timer->setClient(&client);
+    timer->setActive(true);
+    // Run the first task, as that activates the timer and picks up a timebase.
+    thread.runPendingTask();
+
+    EXPECT_EQ(16, thread.pendingDelay());
+
+    timer->setMonotonicallyIncreasingTimeMs(interval + interval * 0.5);
+    thread.runPendingTask();
+
+    EXPECT_EQ(8, thread.pendingDelay());
+}
+
+
 TEST(CCDelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise)
 {
     int numIterations = 1000;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to