Bug 1336822 Optimize ResetTimesForTHrottleReduction() for common case. r=ehsan a=lizzard
authorBen Kelly <ben@wanderview.com>
Mon, 13 Feb 2017 15:02:30 -0500
changeset 376137 a453af7168f3290b05e01aca27dbda196d5da62a
parent 376136 08243c8a96514bb8de3e655170c023790af54549
child 376138 c234f1f1ed00994e018b49bfabedd104dbfa173a
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, lizzard
bugs1336822
milestone53.0a2
Bug 1336822 Optimize ResetTimesForTHrottleReduction() for common case. r=ehsan a=lizzard
dom/base/TimeoutManager.cpp
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -844,28 +844,38 @@ TimeoutManager::Timeouts::ResetTimersFor
 
       // Since we reset When() we need to move |timeout| to the right
       // place in the list so that it remains sorted by When().
 
       // Get the pointer to the next timeout now, before we move the
       // current timeout in the list.
       Timeout* nextTimeout = timeout->getNext();
 
-      // It is safe to remove and re-insert because When() is now
-      // strictly smaller than it used to be, so we know we'll insert
-      // |timeout| before nextTimeout.
-      NS_ASSERTION(!nextTimeout ||
-                   timeout->When() < nextTimeout->When(), "How did that happen?");
-      timeout->remove();
-      // Insert() will addref |timeout| and reset mFiringDepth.  Make sure to
-      // undo that after calling it.
-      uint32_t firingDepth = timeout->mFiringDepth;
-      Insert(timeout, aSortBy);
-      timeout->mFiringDepth = firingDepth;
-      timeout->Release();
+      // Since we are only reducing intervals in this method we can
+      // make an optimization here.  If the reduction does not cause us
+      // to fall before our previous timeout then we do not have to
+      // remove and re-insert the current timeout.  This is important
+      // because re-insertion makes this algorithm O(n^2).  Since we
+      // will typically be shifting a lot of timers at once this
+      // optimization saves us a lot of work.
+      Timeout* prevTimeout = timeout->getPrevious();
+      if (prevTimeout && prevTimeout->When() > timeout->When()) {
+        // It is safe to remove and re-insert because When() is now
+        // strictly smaller than it used to be, so we know we'll insert
+        // |timeout| before nextTimeout.
+        NS_ASSERTION(!nextTimeout ||
+                     timeout->When() < nextTimeout->When(), "How did that happen?");
+        timeout->remove();
+        // Insert() will addref |timeout| and reset mFiringDepth.  Make sure to
+        // undo that after calling it.
+        uint32_t firingDepth = timeout->mFiringDepth;
+        Insert(timeout, aSortBy);
+        timeout->mFiringDepth = firingDepth;
+        timeout->Release();
+      }
 
       nsresult rv = timeout->InitTimer(aQueue, delay.ToMilliseconds());
 
       if (NS_FAILED(rv)) {
         NS_WARNING("Error resetting non background timer for DOM timeout!");
         return rv;
       }