Bug 1336598 P3 Add preferences to control timeout back pressure algorithm. r=smaug a=lizzard
authorBen Kelly <ben@wanderview.com>
Mon, 13 Feb 2017 15:02:30 -0500
changeset 378424 49a9d644f1e778fad84738c26acb4ec7377131d3
parent 378423 a07f4b1cef63068d31e8ea17130d5068cc8e05a3
child 378425 2476b831a480c8ab160281f8fb11e9cdc298ad26
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, lizzard
bugs1336598
milestone53.0a2
Bug 1336598 P3 Add preferences to control timeout back pressure algorithm. r=smaug a=lizzard
dom/base/TimeoutManager.cpp
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -58,52 +58,56 @@ static int32_t gTimeoutBucketingStrategy
 #define DOM_MAX_TIMEOUT_VALUE    DELAY_INTERVAL_LIMIT
 
 uint32_t TimeoutManager::sNestingLevel = 0;
 
 namespace {
 
 // The number of queued runnables within the TabGroup ThrottledEventQueue
 // at which to begin applying back pressure to the window.
-const uint32_t kThrottledEventQueueBackPressure = 5000;
+#define DEFAULT_THROTTLED_EVENT_QUEUE_BACK_PRESSURE 5000
+static uint32_t gThrottledEventQueueBackPressure;
 
 // The amount of delay to apply to timers when back pressure is triggered.
 // As the length of the ThrottledEventQueue grows delay is increased.  The
 // delay is scaled such that every kThrottledEventQueueBackPressure runnables
 // in the queue equates to an additional kBackPressureDelayMS.
-const double kBackPressureDelayMS = 250;
+#define DEFAULT_BACK_PRESSURE_DELAY_MS 250
+static uint32_t gBackPressureDelayMS;
 
 // This defines a limit for how much the delay must drop before we actually
 // reduce back pressure throttle amount.  This makes the throttle delay
 // a bit "sticky" once we enter back pressure.
-const double kBackPressureDelayReductionThresholdMS = 1000;
+#define DEFAULT_BACK_PRESSURE_DELAY_REDUCTION_THRESHOLD_MS 1000
+static uint32_t gBackPressureDelayReductionThresholdMS;
 
 // The minimum delay we can reduce back pressure to before we just floor
 // the value back to zero.  This allows us to ensure that we can exit
 // back pressure event if there are always a small number of runnables
 // queued up.
-const double kBackPressureDelayMinimumMS = 100;
+#define DEFAULT_BACK_PRESSURE_DELAY_MINIMUM_MS 100
+static uint32_t gBackPressureDelayMinimumMS;
 
 // Convert a ThrottledEventQueue length to a timer delay in milliseconds.
 // This will return a value between 0 and INT32_MAX.
 int32_t
 CalculateNewBackPressureDelayMS(uint32_t aBacklogDepth)
 {
   double multiplier = static_cast<double>(aBacklogDepth) /
-                      static_cast<double>(kThrottledEventQueueBackPressure);
-  double value = kBackPressureDelayMS * multiplier;
+                      static_cast<double>(gThrottledEventQueueBackPressure);
+  double value = static_cast<double>(gBackPressureDelayMS) * multiplier;
   // Avoid overflow
   if (value > INT32_MAX) {
     value = INT32_MAX;
   }
 
   // Once we get close to an empty queue just floor the delay back to zero.
   // We want to ensure we don't get stuck in a condition where there is a
   // small amount of delay remaining due to an active, but reasonable, queue.
-  else if (value < kBackPressureDelayMinimumMS) {
+  else if (value < static_cast<double>(gBackPressureDelayMinimumMS)) {
     value = 0;
   }
   return static_cast<int32_t>(value);
 }
 
 } // anonymous namespace
 
 TimeoutManager::TimeoutManager(nsGlobalWindow& aWindow)
@@ -131,16 +135,29 @@ TimeoutManager::Initialize()
                               "dom.min_tracking_timeout_value",
                               DEFAULT_MIN_TRACKING_TIMEOUT_VALUE);
   Preferences::AddIntVarCache(&gMinTrackingBackgroundTimeoutValue,
                               "dom.min_tracking_background_timeout_value",
                               DEFAULT_MIN_TRACKING_BACKGROUND_TIMEOUT_VALUE);
   Preferences::AddIntVarCache(&gTimeoutBucketingStrategy,
                               "dom.timeout_bucketing_strategy",
                               TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY);
+
+  Preferences::AddUintVarCache(&gThrottledEventQueueBackPressure,
+                               "dom.timeout.throttled_event_queue_back_pressure",
+                               DEFAULT_THROTTLED_EVENT_QUEUE_BACK_PRESSURE);
+  Preferences::AddUintVarCache(&gBackPressureDelayMS,
+                               "dom.timeout.back_pressure_delay_ms",
+                               DEFAULT_BACK_PRESSURE_DELAY_MS);
+  Preferences::AddUintVarCache(&gBackPressureDelayReductionThresholdMS,
+                               "dom.timeout.back_pressure_delay_reduction_threshold_ms",
+                               DEFAULT_BACK_PRESSURE_DELAY_REDUCTION_THRESHOLD_MS);
+  Preferences::AddUintVarCache(&gBackPressureDelayMinimumMS,
+                               "dom.timeout.back_pressure_delay_minimum_ms",
+                               DEFAULT_BACK_PRESSURE_DELAY_MINIMUM_MS);
 }
 
 uint32_t
 TimeoutManager::GetTimeoutId(Timeout::Reason aReason)
 {
   switch (aReason) {
     case Timeout::Reason::eIdleCallbackTimeout:
       return ++mIdleCallbackTimeoutCounter;
@@ -594,17 +611,17 @@ TimeoutManager::MaybeApplyBackPressure()
     return;
   }
 
   // Only begin back pressure if the window has greatly fallen behind the main
   // thread.  This is a somewhat arbitrary threshold chosen such that it should
   // rarely fire under normaly circumstances.  Its low enough, though,
   // that we should have time to slow new runnables from being added before an
   // OOM occurs.
-  if (queue->Length() < kThrottledEventQueueBackPressure) {
+  if (queue->Length() < gThrottledEventQueueBackPressure) {
     return;
   }
 
   // First attempt to dispatch a runnable to update our back pressure state.  We
   // do this first in order to verify we can dispatch successfully before
   // entering the back pressure state.
   nsCOMPtr<nsIRunnable> r =
     NewNonOwningRunnableMethod<StoreRefPtrPassByPtr<nsGlobalWindow>>(this,
@@ -640,18 +657,18 @@ TimeoutManager::CancelOrUpdateBackPressu
 
   // If the delay has decreased, though, we only apply the new value if it has
   // reduced significantly.  This hysteresis avoids thrashing the back pressure
   // value back and forth rapidly.  This is important because reducing the
   // backpressure delay requires calling ResetTimerForThrottleReduction() which
   // can be quite expensive.  We only want to call that method if the back log
   // is really clearing.
   else if (newBackPressureDelayMS == 0 ||
-           (mBackPressureDelayMS >
-           (newBackPressureDelayMS + kBackPressureDelayReductionThresholdMS))) {
+           (static_cast<uint32_t>(mBackPressureDelayMS) >
+           (newBackPressureDelayMS + gBackPressureDelayReductionThresholdMS))) {
     int32_t oldBackPressureDelayMS = mBackPressureDelayMS;
     mBackPressureDelayMS = newBackPressureDelayMS;
 
     // If the back pressure delay has gone down we must reset any existing
     // timers to use the new value.  Otherwise we run the risk of executing
     // timer callbacks out-of-order.
     ResetTimersForThrottleReduction(oldBackPressureDelayMS);
   }