Bug 1363829 P13 Use the nsITimer::InitHighResolutionWithCallback() instead of rounding. r=ehsan
authorBen Kelly <ben@wanderview.com>
Wed, 31 May 2017 17:13:19 -0700
changeset 409866 1c99a1222200ff65e731534083b57f83ddc8d041
parent 409865 79c1d7e0d539953a9d40820d243a8b892cd47fcc
child 409867 9b5fb2901eac7ccd48c7c0bb58ea229f817e963b
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1363829
milestone55.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 1363829 P13 Use the nsITimer::InitHighResolutionWithCallback() instead of rounding. r=ehsan
dom/base/TimeoutExecutor.cpp
--- a/dom/base/TimeoutExecutor.cpp
+++ b/dom/base/TimeoutExecutor.cpp
@@ -56,28 +56,36 @@ TimeoutExecutor::ScheduleDelayed(const T
   // Always call Cancel() in case we are re-using a timer.  Otherwise
   // the subsequent SetTarget() may fail.
   rv = mTimer->Cancel();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mTimer->SetTarget(mOwner->EventTarget());
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Convert the precise delay to integral milliseconds for nsITimer.  We
-  // favor rounding down here.  If we fire early we will simply be rescheduled
-  // for an immediate runnable or a 0-ms timer.  This ends up giving us the
-  // most accurate firing time at the cost of a few more runnables.  This cost
-  // is only incurred when the browser is idle, though.  When the busy main
-  // thread is busy there will be a delay and we won't actually be early.
-  // TODO: In the future we could pass a precision argument in and round
-  //       up here for low-precision background timers.  We don't really care
-  //       if those timers fire late.
-  TimeDuration delay(aDeadline - aNow - TimeDuration::FromMilliseconds(0.1));
-  rv = mTimer->InitWithCallback(this, delay.ToMilliseconds(),
-                                nsITimer::TYPE_ONE_SHOT);
+  // Note, we cannot use the normal nsITimer init methods that take
+  // integer milliseconds.  We need higher precision.  Consider this
+  // situation:
+  //
+  // 1. setTimeout(f, 1);
+  // 2. do some work for 500us
+  // 3. setTimeout(g, 1);
+  //
+  // This should fire f() and g() 500us apart.
+  //
+  // In the past worked because each setTimeout() got its own nsITimer.  The 1ms
+  // was preserved and passed through to nsITimer which converted it to a
+  // TimeStamp, etc.
+  //
+  // Now, however, there is only one nsITimer.  We fire f() and then try to
+  // schedule a new nsITimer for g().  Its only 500us in the future, though.  We
+  // must be able to pass this fractional value to nsITimer in order to get an
+  // accurate wakeup time.
+  rv = mTimer->InitHighResolutionWithCallback(this, aDeadline - aNow,
+                                              nsITimer::TYPE_ONE_SHOT);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mMode = Mode::Delayed;
   mDeadline = aDeadline;
 
   return NS_OK;
 }