Bug 1366356 - Decrease the process priority of content processes that are not running a foreground tab - part 1 - visibility logic, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 07 Jun 2017 09:59:00 +0200
changeset 413128 a8011068db5a26fc837f8e78fb7e38d38822c2f6
parent 413127 e11291525ae0fd001c72dfa8b5b4d19988e4f2e3
child 413129 d95970dc9b7d41ed028960c7aeacd3584bdef689
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1366356
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 1366356 - Decrease the process priority of content processes that are not running a foreground tab - part 1 - visibility logic, r=smaug
dom/ipc/ProcessPriorityManager.cpp
dom/ipc/ProcessPriorityManager.h
dom/ipc/TabParent.cpp
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -21,16 +21,17 @@
 #include "nsIObserverService.h"
 #include "StaticPtr.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIObserver.h"
 #include "nsITimer.h"
 #include "nsIPropertyBag2.h"
 #include "nsComponentManagerUtils.h"
 #include "nsCRT.h"
+#include "nsTHashtable.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::hal;
 
 #ifdef XP_WIN
 #include <process.h>
 #define getpid _getpid
@@ -144,16 +145,18 @@ public:
     hal::ProcessPriority aOldPriority);
 
   /**
    * Implements WakeLockObserver, used to monitor wake lock changes in the
    * main process.
    */
   virtual void Notify(const WakeLockInformation& aInfo) override;
 
+  void TabActivityChanged(TabParent* aTabParent, bool aIsActive);
+
   /**
    * Call ShutDown before destroying the ProcessPriorityManager because
    * WakeLockObserver hols a strong reference to it.
    */
   void ShutDown();
 
 private:
   static bool sPrefsEnabled;
@@ -262,16 +265,18 @@ public:
     BACKGROUND_GRACE_PERIOD,
   };
 
   void ScheduleResetPriority(TimeoutPref aTimeoutPref);
   void ResetPriority();
   void ResetPriorityNow();
   void SetPriorityNow(ProcessPriority aPriority);
 
+  void TabActivityChanged(TabParent* aTabParent, bool aIsActive);
+
   void ShutDown();
 
 private:
   static uint32_t sBackgroundPerceivableGracePeriodMS;
   static uint32_t sBackgroundGracePeriodMS;
 
   void FireTestOnlyObserverNotification(
     const char* aTopic,
@@ -288,16 +293,19 @@ private:
   bool mHoldsHighPriorityWakeLock;
 
   /**
    * Used to implement NameWithComma().
    */
   nsAutoCString mNameWithComma;
 
   nsCOMPtr<nsITimer> mResetPriorityTimer;
+
+  // This hashtable contains the list of active TabId for this process.
+  nsTHashtable<nsUint64HashKey> mActiveTabParents;
 };
 
 /* static */ bool ProcessPriorityManagerImpl::sInitialized = false;
 /* static */ bool ProcessPriorityManagerImpl::sPrefsEnabled = false;
 /* static */ bool ProcessPriorityManagerImpl::sRemoteTabsDisabled = true;
 /* static */ bool ProcessPriorityManagerImpl::sTestMode = false;
 /* static */ bool ProcessPriorityManagerImpl::sPrefListenersRegistered = false;
 /* static */ StaticRefPtr<ProcessPriorityManagerImpl>
@@ -533,16 +541,30 @@ ProcessPriorityManagerImpl::Notify(const
       mHighPriority = false;
     }
 
     LOG("Got wake lock changed event. "
         "Now mHighPriorityParent = %d\n", mHighPriority);
   }
 }
 
+void
+ProcessPriorityManagerImpl::TabActivityChanged(TabParent* aTabParent,
+                                               bool aIsActive)
+{
+  ContentParent* cp = aTabParent->Manager()->AsContentParent();
+  RefPtr<ParticularProcessPriorityManager> pppm =
+    GetParticularProcessPriorityManager(cp);
+  if (!pppm) {
+    return;
+  }
+
+  pppm->TabActivityChanged(aTabParent, aIsActive);
+}
+
 NS_IMPL_ISUPPORTS(ParticularProcessPriorityManager,
                   nsIObserver,
                   nsITimerCallback,
                   nsISupportsWeakReference);
 
 ParticularProcessPriorityManager::ParticularProcessPriorityManager(
   ContentParent* aContentParent)
   : mContentParent(aContentParent)
@@ -719,16 +741,23 @@ ParticularProcessPriorityManager::OnTabP
   nsCOMPtr<nsITabParent> tp = do_QueryInterface(aSubject);
   NS_ENSURE_TRUE_VOID(tp);
 
   MOZ_ASSERT(XRE_IsParentProcess());
   if (TabParent::GetFrom(tp)->Manager() != mContentParent) {
     return;
   }
 
+  uint64_t tabId;
+  if (NS_WARN_IF(NS_FAILED(tp->GetTabId(&tabId)))) {
+    return;
+  }
+
+  mActiveTabParents.RemoveEntry(tabId);
+
   ResetPriority();
 }
 
 void
 ParticularProcessPriorityManager::ResetPriority()
 {
   ProcessPriority processPriority = ComputePriority();
   if (mPriority == PROCESS_PRIORITY_UNKNOWN ||
@@ -794,18 +823,19 @@ ProcessPriority
 ParticularProcessPriorityManager::CurrentPriority()
 {
   return mPriority;
 }
 
 ProcessPriority
 ParticularProcessPriorityManager::ComputePriority()
 {
-  // TODO...
-  return PROCESS_PRIORITY_FOREGROUND;
+  if (!mActiveTabParents.IsEmpty()) {
+    return PROCESS_PRIORITY_FOREGROUND;
+  }
 
   if (mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) {
     return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
   }
 
   return PROCESS_PRIORITY_BACKGROUND;
 }
 
@@ -844,16 +874,31 @@ ParticularProcessPriorityManager::SetPri
     Unused << mContentParent->SendNotifyProcessPriorityChanged(mPriority);
   }
 
   FireTestOnlyObserverNotification("process-priority-set",
     ProcessPriorityToString(mPriority));
 }
 
 void
+ParticularProcessPriorityManager::TabActivityChanged(TabParent* aTabParent,
+                                                     bool aIsActive)
+{
+  MOZ_ASSERT(aTabParent);
+
+  if (!aIsActive) {
+    mActiveTabParents.RemoveEntry(aTabParent->GetTabId());
+  } else {
+    mActiveTabParents.PutEntry(aTabParent->GetTabId());
+  }
+
+  ResetPriority();
+}
+
+void
 ParticularProcessPriorityManager::ShutDown()
 {
   MOZ_ASSERT(mContentParent);
 
   UnregisterWakeLockObserver(this);
 
   if (mResetPriorityTimer) {
     mResetPriorityTimer->Cancel();
@@ -1018,9 +1063,24 @@ ProcessPriorityManager::SetProcessPriori
 
 /* static */ bool
 ProcessPriorityManager::CurrentProcessIsForeground()
 {
   return ProcessPriorityManagerChild::Singleton()->
     CurrentProcessIsForeground();
 }
 
+/* static */ void
+ProcessPriorityManager::TabActivityChanged(TabParent* aTabParent,
+                                           bool aIsActive)
+{
+  MOZ_ASSERT(aTabParent);
+
+  ProcessPriorityManagerImpl* singleton =
+    ProcessPriorityManagerImpl::GetSingleton();
+  if (!singleton) {
+    return;
+  }
+
+  singleton->TabActivityChanged(aTabParent, aIsActive);
+}
+
 } // namespace mozilla
--- a/dom/ipc/ProcessPriorityManager.h
+++ b/dom/ipc/ProcessPriorityManager.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_ProcessPriorityManager_h_
 #define mozilla_ProcessPriorityManager_h_
 
 #include "mozilla/HalTypes.h"
 
 namespace mozilla {
 namespace dom {
 class ContentParent;
+class TabParent;
 } // namespace dom
 
 /**
  * This class sets the priority of subprocesses in response to explicit
  * requests and events in the system.
  *
  * A process's priority changes e.g. when it goes into the background via
  * mozbrowser's setVisible(false).  Process priority affects CPU scheduling and
@@ -63,16 +64,18 @@ public:
    * Returns true iff this process's priority is FOREGROUND*.
    *
    * Note that because process priorities are set in the main process, it's
    * possible for this method to return a stale value.  So be careful about
    * what you use this for.
    */
   static bool CurrentProcessIsForeground();
 
+  static void TabActivityChanged(dom::TabParent* aTabParent, bool aIsActive);
+
 private:
   ProcessPriorityManager();
   DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManager);
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -93,16 +93,17 @@
 #include "nsIAuthPrompt2.h"
 #include "gfxDrawable.h"
 #include "ImageOps.h"
 #include "UnitTransforms.h"
 #include <algorithm>
 #include "mozilla/WebBrowserPersistDocumentParent.h"
 #include "nsIGroupedSHistory.h"
 #include "PartialSHistory.h"
+#include "ProcessPriorityManager.h"
 #include "nsString.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PluginWidgetParent.h"
 #endif
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
 #include "mozilla/a11y/AccessibleWrap.h"
@@ -2643,16 +2644,20 @@ TabParent::SetDocShellIsActive(bool isAc
   // SetDocShellIsActive requests are ignored.
   mLayerTreeEpoch++;
 
   // docshell is consider prerendered only if not active yet
   mIsPrerendered &= !isActive;
   mDocShellIsActive = isActive;
   Unused << SendSetDocShellIsActive(isActive, mPreserveLayers, mLayerTreeEpoch);
 
+  // Let's inform the priority manager. This operation can end up with the
+  // changing of the process priority.
+  ProcessPriorityManager::TabActivityChanged(this, isActive);
+
   // Ask the child to repaint using the PHangMonitor channel/thread (which may
   // be less congested).
   if (isActive) {
     ContentParent* cp = Manager()->AsContentParent();
     cp->ForceTabPaint(this, mLayerTreeEpoch);
   }
 
   return NS_OK;