Bug 618479 part 2. Use binary, not linear, search to determine timer insertion locations. r=brendan
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 13 Feb 2013 10:11:53 -0500 (2013-02-13)
changeset 121747 bffcfc510a9cac94f1a8700e327951a4019cd847
parent 121746 32b985353206dc8ee08ccf16794c5cbc65656327
child 121748 04f0afec7a035c8330a241eaffa02ea3707c1058
push id24307
push useremorley@mozilla.com
push dateThu, 14 Feb 2013 10:47:46 +0000 (2013-02-14)
treeherdermozilla-central@aceeea086ccb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbrendan
bugs618479
milestone21.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 618479 part 2. Use binary, not linear, search to determine timer insertion locations. r=brendan
xpcom/threads/TimerThread.cpp
xpcom/threads/TimerThread.h
xpcom/threads/nsTimerImpl.h
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -412,41 +412,26 @@ nsresult TimerThread::RemoveTimer(nsTime
 
 // This function must be called from within a lock
 int32_t TimerThread::AddTimerInternal(nsTimerImpl *aTimer)
 {
   if (mShutdown)
     return -1;
 
   TimeStamp now = TimeStamp::Now();
-  uint32_t count = mTimers.Length();
-  uint32_t i = 0;
-  for (; i < count; i++) {
-    nsTimerImpl *timer = mTimers[i];
-
-    // Don't break till we have skipped any overdue timers.
 
-    // XXXbz why?  Given our definition of overdue in terms of
-    // mTimeoutAdjustment, aTimer might be overdue already!  Why not
-    // just fire timers in order?
-
-    // XXX does this hold for TYPE_REPEATING_PRECISE?  /be
+  TimerAdditionComparator c(now, mTimeoutAdjustment, aTimer);
+  nsTimerImpl** insertSlot = mTimers.InsertElementSorted(aTimer, c);
 
-    if (now < timer->mTimeout + mTimeoutAdjustment &&
-        aTimer->mTimeout < timer->mTimeout) {
-      break;
-    }
-  }
-
-  if (!mTimers.InsertElementAt(i, aTimer))
+  if (!insertSlot)
     return -1;
 
   aTimer->mArmed = true;
   NS_ADDREF(aTimer);
-  return i;
+  return insertSlot - mTimers.Elements();
 }
 
 bool TimerThread::RemoveTimerInternal(nsTimerImpl *aTimer)
 {
   if (!mTimers.RemoveElement(aTimer))
     return false;
 
   ReleaseTimerInternal(aTimer);
--- a/xpcom/threads/TimerThread.h
+++ b/xpcom/threads/TimerThread.h
@@ -76,9 +76,44 @@ private:
 #define DELAY_LINE_LENGTH       (1u << DELAY_LINE_LENGTH_LOG2)
 
   int32_t  mDelayLine[DELAY_LINE_LENGTH]; // milliseconds
   uint32_t mDelayLineCounter;
   uint32_t mMinTimerPeriod;     // milliseconds
   TimeDuration mTimeoutAdjustment;
 };
 
+struct TimerAdditionComparator {
+  TimerAdditionComparator(const mozilla::TimeStamp &aNow,
+                          const mozilla::TimeDuration &aTimeoutAdjustment,
+                          nsTimerImpl *aTimerToInsert) :
+    now(aNow),
+    timeoutAdjustment(aTimeoutAdjustment)
+#ifdef DEBUG
+    , timerToInsert(aTimerToInsert)
+#endif
+  {}
+
+  PRBool LessThan(nsTimerImpl *fromArray, nsTimerImpl *newTimer) const {
+    NS_ABORT_IF_FALSE(newTimer == timerToInsert, "Unexpected timer ordering");
+
+    // Skip any overdue timers.
+
+    // XXXbz why?  Given our definition of overdue in terms of
+    // mTimeoutAdjustment, aTimer might be overdue already!  Why not
+    // just fire timers in order?
+    return now >= fromArray->mTimeout + timeoutAdjustment ||
+           fromArray->mTimeout <= newTimer->mTimeout;
+  }
+
+  PRBool Equals(nsTimerImpl* fromArray, nsTimerImpl* newTimer) const {
+    return PR_FALSE;
+  }
+
+private:
+  const mozilla::TimeStamp &now;
+  const mozilla::TimeDuration &timeoutAdjustment;
+#ifdef DEBUG
+  const nsTimerImpl * const timerToInsert;
+#endif
+};
+
 #endif /* TimerThread_h___ */
--- a/xpcom/threads/nsTimerImpl.h
+++ b/xpcom/threads/nsTimerImpl.h
@@ -47,16 +47,17 @@ public:
   typedef mozilla::TimeStamp TimeStamp;
 
   nsTimerImpl();
 
   static NS_HIDDEN_(nsresult) Startup();
   static NS_HIDDEN_(void) Shutdown();
 
   friend class TimerThread;
+  friend class TimerAdditionComparator;
 
   void Fire();
   nsresult PostTimerEvent();
   void SetDelayInternal(uint32_t aDelay);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMER