Bug 844970 - Use a grace period for all process priority downgrades. r=cjones
authorJustin Lebar <justin.lebar@gmail.com>
Wed, 27 Feb 2013 14:28:57 -0500
changeset 123201 d5cba11c8204b1edb64e62fdb95e11e727b8a424
parent 123200 f3476411480a383c84e017a99af2f9222cd5ab77
child 123202 7a79ddc7bedf213d15b67f052c7bb06d36fd275d
push id24373
push userryanvm@gmail.com
push dateThu, 28 Feb 2013 01:36:21 +0000
treeherdermozilla-central@8cb9d6981978 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs844970
milestone22.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 844970 - Use a grace period for all process priority downgrades. r=cjones
dom/ipc/ProcessPriorityManager.cpp
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -90,27 +90,16 @@ GetContentChildID()
   if (!contentChild) {
     return 0;
   }
 
   return contentChild->GetID();
 }
 
 /**
- * Determine if the priority is a backround priority.
- */
-bool
-IsBackgroundPriority(ProcessPriority aPriority)
-{
-  return (aPriority == PROCESS_PRIORITY_BACKGROUND ||
-          aPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN ||
-          aPriority == PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE);
-}
-
-/**
  * This class listens to various Gecko events and asks the hal back-end to
  * change this process's priority when it transitions between various states of
  * "importance".
  *
  * The process's priority determines its CPU priority and also how likely it is
  * to be killed when the system is running out of memory.
  *
  * The most basic dichotomy in the ProcessPriorityManager is between
@@ -156,31 +145,22 @@ public:
    * ProcessPriorityManager.h::TemporarilyLockProcessPriority().
    */
   void TemporarilyLockProcessPriority();
 
   /**
    * Recompute this process's priority and apply it, potentially after a brief
    * delay.
    *
-   * If we are transitioning to a priority that is "lower" than the current
-   * priority (as defined below), that transition happens after a grace period.
-   * Otherwise the transition happens immediately.
-   *
-   * For the purposes of deciding whether to apply a grace period, the
-   * hierarchy of priorities is
+   * If we are transitioning to a priority that is lower than the current
+   * priority, that transition happens after a grace period.  Otherwise the
+   * transition happens immediately.
    *
-   *  - UNKNOWN
-   *  - FOREGROUND_HIGH
-   *  - FOREGROUND
-   *  - BACKGROUND*
-   *
-   * So for example, a transition between any two BACKGROUND* priorites happens
-   * immediately, but a transition from UNKNOWN to FOREGROUND_HIGH happens
-   * after a grace period.
+   * Note that PROCESS_PRIORITY_UNKNOWN is considered the highest priority.
+   * Going from UNKNOWN to any other priority requires a grace period.
    */
   void ResetPriority();
 
   /**
    * Recompute this process's priority and apply it immediately.
    */
   void ResetPriorityNow();
 
@@ -189,57 +169,37 @@ private:
 
   /**
    * Is this process a "critical" process that's holding the "CPU" or
    * "high-priority" wake lock?
    */
   bool IsCriticalProcessWithWakeLock();
 
   /**
-   * If this process were in the foreground, what priority would it have?
-   */
-  ProcessPriority GetForegroundPriority();
-
-  /**
-   * If this process were in the foreground, what priority would it have?
-   */
-  ProcessPriority GetBackgroundPriority();
-
-  /**
    * Compute whether this process is in the foreground and return the result.
    */
   bool ComputeIsInForeground();
 
-
   /**
-   * Set this process's priority to the appropriate FOREGROUND* priority
-   * immediately if we're upgrading its priority, and after a grace period if
-   * we're downgrading it or if the current priority is unknown.
+   * Compute the priority this process ought to have, based on what we know at
+   * the moment.
    */
-  void SetIsForeground();
+  ProcessPriority ComputePriority();
 
   /**
-   * Set this process's priority to the appropriate FOREGROUND* priority
-   * immediately.
+   * Immediately set this process's priority to the given priority.
    */
-  void SetIsForegroundNow();
-
-  /**
-   * Set this process's priority to the appropriate BACKGROUND* priority
-   * immediately.
-   */
-  void SetIsBackgroundNow();
+  void SetPriorityNow(ProcessPriority aPriority);
 
   /**
    * If mResetPriorityTimer is null (i.e., not running), create a timer and set
    * it to invoke ResetPriorityNow() after
    * dom.ipc.processPriorityManager.aTimeoutPref ms.
    */
-  void
-  ScheduleResetPriority(const char* aTimeoutPref);
+  void ScheduleResetPriority(const char* aTimeoutPref);
 
   // Tracks whether this process holds the "cpu" lock.
   bool mHoldsCPUWakeLock;
 
   // Tracks whether this process holds the "high-priority" lock.
   bool mHoldsHighPriorityWakeLock;
 
   // mProcessPriority tracks the priority we've given this process in hal.
@@ -425,90 +385,45 @@ ProcessPriorityManager::IsCriticalProces
     if (appType.EqualsLiteral("critical")) {
       return true;
     }
   }
 
   return false;
 }
 
-ProcessPriority
-ProcessPriorityManager::GetForegroundPriority()
-{
-  return IsCriticalProcessWithWakeLock() ? PROCESS_PRIORITY_FOREGROUND_HIGH :
-                                           PROCESS_PRIORITY_FOREGROUND;
-}
-
-/**
- * Get the appropriate backround priority for this process.
- */
-ProcessPriority
-ProcessPriorityManager::GetBackgroundPriority()
-{
-  AudioChannelService* service = AudioChannelService::GetAudioChannelService();
-  if (service->ContentOrNormalChannelIsActive()) {
-    return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
-  }
-
-  bool isHomescreen = false;
-
-  ContentChild* contentChild = ContentChild::GetSingleton();
-  if (contentChild) {
-    const InfallibleTArray<PBrowserChild*>& browsers =
-      contentChild->ManagedPBrowserChild();
-    for (uint32_t i = 0; i < browsers.Length(); i++) {
-      nsAutoString appType;
-      static_cast<TabChild*>(browsers[i])->GetAppType(appType);
-      if (appType.EqualsLiteral("homescreen")) {
-        isHomescreen = true;
-        break;
-      }
-    }
-  }
-
-  return isHomescreen ?
-         PROCESS_PRIORITY_BACKGROUND_HOMESCREEN :
-         PROCESS_PRIORITY_BACKGROUND;
-}
-
-
 void
 ProcessPriorityManager::ResetPriority()
 {
   if (!mObservedTabChildCreated) {
     LOG("ResetPriority bailing because we haven't observed "
         "a tab-child-created event.");
     return;
   }
 
-  if (ComputeIsInForeground()) {
-    SetIsForeground();
-  } else if (IsBackgroundPriority(mProcessPriority)) {
-    // If we're already in the background, recompute our background priority
-    // and set it immediately.
-    SetIsBackgroundNow();
-  } else {
+  ProcessPriority processPriority = ComputePriority();
+  if (mProcessPriority == PROCESS_PRIORITY_UNKNOWN ||
+      mProcessPriority > processPriority) {
     ScheduleResetPriority("backgroundGracePeriodMS");
+    return;
   }
+
+  SetPriorityNow(processPriority);
 }
 
 void
 ProcessPriorityManager::ResetPriorityNow()
 {
   if (!mObservedTabChildCreated) {
     LOG("ResetPriorityNow bailing because we haven't observed "
         "a tab-child-created event.");
     return;
   }
 
-  if (ComputeIsInForeground()) {
-    SetIsForegroundNow();
-  } else {
-    SetIsBackgroundNow();
-  }
+  SetPriorityNow(ComputePriority());
 }
 
 bool
 ProcessPriorityManager::ComputeIsInForeground()
 {
   // Critical processes holding the CPU/high-priority wake lock are always
   // considered to be in the foreground.
   if (IsCriticalProcessWithWakeLock()) {
@@ -554,79 +469,94 @@ ProcessPriorityManager::ComputeIsInForeg
     // We could break out early from this loop if
     //   isActive && mProcessPriority == BACKGROUND,
     // but then we might not clean up all the weak refs.
   }
 
   return !allHidden;
 }
 
-void
-ProcessPriorityManager::SetIsForeground()
+ProcessPriority
+ProcessPriorityManager::ComputePriority()
 {
-  ProcessPriority foregroundPriority = GetForegroundPriority();
+  if (ComputeIsInForeground()) {
+    if (IsCriticalProcessWithWakeLock()) {
+      return PROCESS_PRIORITY_FOREGROUND_HIGH;
+    }
+    return PROCESS_PRIORITY_FOREGROUND;
+  }
+
+  AudioChannelService* service = AudioChannelService::GetAudioChannelService();
+  if (service->ContentOrNormalChannelIsActive()) {
+    return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
+  }
+
+  bool isHomescreen = false;
 
-  if (mProcessPriority == PROCESS_PRIORITY_UNKNOWN ||
-      foregroundPriority < mProcessPriority) {
-    LOG("Giving grace period to %s -> %s transition.",
-        ProcessPriorityToString(mProcessPriority),
-        ProcessPriorityToString(foregroundPriority));
-    ScheduleResetPriority("backgroundGracePeriodMS");
-  } else {
-    SetIsForegroundNow();
+  ContentChild* contentChild = ContentChild::GetSingleton();
+  if (contentChild) {
+    const InfallibleTArray<PBrowserChild*>& browsers =
+      contentChild->ManagedPBrowserChild();
+    for (uint32_t i = 0; i < browsers.Length(); i++) {
+      nsAutoString appType;
+      static_cast<TabChild*>(browsers[i])->GetAppType(appType);
+      if (appType.EqualsLiteral("homescreen")) {
+        isHomescreen = true;
+        break;
+      }
+    }
   }
+
+  return isHomescreen ?
+         PROCESS_PRIORITY_BACKGROUND_HOMESCREEN :
+         PROCESS_PRIORITY_BACKGROUND;
 }
 
 void
-ProcessPriorityManager::SetIsForegroundNow()
+ProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority)
 {
-  ProcessPriority foregroundPriority = GetForegroundPriority();
-  if (foregroundPriority == mProcessPriority) {
+  if (aPriority == PROCESS_PRIORITY_UNKNOWN) {
+    MOZ_ASSERT(false);
     return;
   }
 
-  // Cancel the memory minimization procedure we might have started.
-  nsCOMPtr<nsICancelableRunnable> runnable =
-    do_QueryReferent(mMemoryMinimizerRunnable);
-  if (runnable) {
-    runnable->Cancel();
-  }
-
-  mProcessPriority = foregroundPriority;
-  LOG("Setting priority to %s.", ProcessPriorityToString(mProcessPriority));
-  hal::SetProcessPriority(getpid(), mProcessPriority);
-}
-
-void
-ProcessPriorityManager::SetIsBackgroundNow()
-{
-  ProcessPriority backgroundPriority = GetBackgroundPriority();
-  if (mProcessPriority == backgroundPriority) {
+  if (mProcessPriority == aPriority) {
     return;
   }
 
-  mProcessPriority = backgroundPriority;
-  LOG("Setting priority to %s", ProcessPriorityToString(mProcessPriority));
+  LOG("Changing priority from %s to %s.",
+      ProcessPriorityToString(mProcessPriority),
+      ProcessPriorityToString(aPriority));
+  mProcessPriority = aPriority;
   hal::SetProcessPriority(getpid(), mProcessPriority);
 
-  // We're in the background; dump as much memory as we can.
-  nsCOMPtr<nsIMemoryReporterManager> mgr =
-    do_GetService("@mozilla.org/memory-reporter-manager;1");
-  if (mgr) {
+  if (aPriority >= PROCESS_PRIORITY_FOREGROUND) {
+    // Cancel the memory minimization procedure we might have started.
     nsCOMPtr<nsICancelableRunnable> runnable =
       do_QueryReferent(mMemoryMinimizerRunnable);
-
-    // Cancel the previous task if it's still pending
     if (runnable) {
       runnable->Cancel();
     }
+  } else {
+    // We're in the background; dump as much memory as we can.
+    nsCOMPtr<nsIMemoryReporterManager> mgr =
+      do_GetService("@mozilla.org/memory-reporter-manager;1");
+    if (mgr) {
+      nsCOMPtr<nsICancelableRunnable> runnable =
+        do_QueryReferent(mMemoryMinimizerRunnable);
 
-    mgr->MinimizeMemoryUsage(/* callback = */ nullptr,
-                             getter_AddRefs(runnable));
-    mMemoryMinimizerRunnable = do_GetWeakReference(runnable);
+      // Cancel the previous task if it's still pending
+      if (runnable) {
+        runnable->Cancel();
+      }
+
+      mgr->MinimizeMemoryUsage(/* callback = */ nullptr,
+                               getter_AddRefs(runnable));
+      mMemoryMinimizerRunnable = do_GetWeakReference(runnable);
+    }
   }
 }
 
 void
 ProcessPriorityManager::ScheduleResetPriority(const char* aTimeoutPref)
 {
   if (mResetPriorityTimer) {
     LOG("ScheduleResetPriority bailing; the timer is already running.");