Bug 1298085 - Don't unthrottle the refresh driver after 200ms when waiting for compositor transactions. r=mchang
☠☠ backed out by f19715529c24 ☠ ☠
authorNicolas Silva <nsilva@mozilla.com>
Fri, 09 Sep 2016 12:06:29 +0200
changeset 354709 96e65eb8c47237e91ceee9f4565d6856baa33862
parent 354708 02824c83b371ab04aa7cb5d35c569d668cc299e6
child 354710 2ed4423183bde2957b5c12fb5f92b82723fb0aa8
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmchang
bugs1298085
milestone51.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 1298085 - Don't unthrottle the refresh driver after 200ms when waiting for compositor transactions. r=mchang
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1004,23 +1004,23 @@ nsRefreshDriver::nsRefreshDriver(nsPresC
     mThrottled(false),
     mNeedToRecomputeVisibility(false),
     mTestControllingRefreshes(false),
     mViewManagerFlushIsPending(false),
     mRequestedHighPrecision(false),
     mInRefresh(false),
     mWaitingForTransaction(false),
     mSkippedPaints(false),
-    mResizeSuppressed(false)
+    mResizeSuppressed(false),
+    mWarningThreshold(1)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mPresContext,
              "Need a pres context to tell us to call Disconnect() later "
              "and decrement sRefreshDriverCount.");
-
   mMostRecentRefreshEpochTime = JS_Now();
   mMostRecentRefresh = TimeStamp::Now();
   mMostRecentTick = mMostRecentRefresh;
   mNextThrottledFrameRequestTick = mMostRecentTick;
   mNextRecomputeVisibilityTick = mMostRecentTick;
 
   ++sRefreshDriverCount;
 }
@@ -1060,16 +1060,17 @@ nsRefreshDriver::AdvanceTimeAndRefresh(i
     mMostRecentRefreshEpochTime = JS_Now();
     mMostRecentRefresh = TimeStamp::Now();
 
     mTestControllingRefreshes = true;
     if (mWaitingForTransaction) {
       // Disable any refresh driver throttling when entering test mode
       mWaitingForTransaction = false;
       mSkippedPaints = false;
+      mWarningThreshold = 1;
     }
   }
 
   mMostRecentRefreshEpochTime += aMilliseconds * 1000;
   mMostRecentRefresh += TimeDuration::FromMilliseconds((double) aMilliseconds);
 
   mozilla::dom::AutoNoJSAPI nojsapi;
   DoTick();
@@ -1650,16 +1651,17 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
     return;
   }
   mMostRecentTick = aNowTime;
   if (mRootRefresh) {
     mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
     mRootRefresh = nullptr;
   }
   mSkippedPaints = false;
+  mWarningThreshold = 1;
 
   nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
   if (!presShell || (ObserverCount() == 0 && ImageRequestCount() == 0)) {
     // Things are being destroyed, or we no longer have any observers.
     // We don't want to stop the timer when observers are initially
     // removed, because sometimes observers can be added and removed
     // often depending on what other things are going on and in that
     // situation we don't want to thrash our timer.  So instead we
@@ -1987,28 +1989,30 @@ nsRefreshDriver::FinishedWaitingForTrans
   if (mSkippedPaints &&
       !IsInRefresh() &&
       (ObserverCount() || ImageRequestCount())) {
     profiler_tracing("Paint", "RD", TRACING_INTERVAL_START);
     DoRefresh();
     profiler_tracing("Paint", "RD", TRACING_INTERVAL_END);
   }
   mSkippedPaints = false;
+  mWarningThreshold = 1;
 }
 
 uint64_t
 nsRefreshDriver::GetTransactionId()
 {
   ++mPendingTransaction;
 
   if (mPendingTransaction >= mCompletedTransaction + 2 &&
       !mWaitingForTransaction &&
       !mTestControllingRefreshes) {
     mWaitingForTransaction = true;
     mSkippedPaints = false;
+    mWarningThreshold = 1;
   }
 
   return mPendingTransaction;
 }
 
 uint64_t
 nsRefreshDriver::LastTransactionId() const
 {
@@ -2058,27 +2062,24 @@ nsRefreshDriver::WillRefresh(mozilla::Ti
 }
 
 bool
 nsRefreshDriver::IsWaitingForPaint(mozilla::TimeStamp aTime)
 {
   if (mTestControllingRefreshes) {
     return false;
   }
-  // If we've skipped too many ticks then it's possible
-  // that something went wrong and we're waiting on
-  // a notification that will never arrive.
-  if (aTime > (mMostRecentTick + TimeDuration::FromMilliseconds(200))) {
-    mSkippedPaints = false;
-    mWaitingForTransaction = false;
-    if (mRootRefresh) {
-      mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
-    }
-    return false;
+
+  if (aTime > (mMostRecentTick + TimeDuration::FromMilliseconds(mWarningThreshold * 1000))) {
+    gfxCriticalNote << "Refresh driver waiting for the compositor for"
+                    << (aTime - mMostRecentTick).ToSeconds()
+                    << " seconds.";
+    mWarningThreshold *= 2;
   }
+
   if (mWaitingForTransaction) {
     mSkippedPaints = true;
     return true;
   }
 
   // Try find the 'root' refresh driver for the current window and check
   // if that is waiting for a paint.
   nsPresContext *rootContext = PresContext()->GetRootPresContext();
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -419,16 +419,20 @@ private:
   bool mSkippedPaints;
 
   // True if view managers should delay any resize request until the
   // next tick by the refresh driver. This flag will be reset at the
   // start of every tick.
   bool mResizeSuppressed;
 
   int64_t mMostRecentRefreshEpochTime;
+  // Number of seconds that the refresh driver is blocked waiting for a compositor
+  // transaction to be completed before we append a note to the gfx critical log.
+  // The number is doubled every time the threshold is hit.
+  uint64_t mWarningThreshold;
   mozilla::TimeStamp mMostRecentRefresh;
   mozilla::TimeStamp mMostRecentTick;
   mozilla::TimeStamp mTickStart;
   mozilla::TimeStamp mNextThrottledFrameRequestTick;
   mozilla::TimeStamp mNextRecomputeVisibilityTick;
 
   // separate arrays for each flush type we support
   ObserverArray mObservers[3];