Bug 1495032 - Proactively adjust tab priority on switch r=mconley
authorDoug Thayer <dothayer@mozilla.com>
Mon, 01 Oct 2018 17:05:32 +0000
changeset 439007 bcdbc281a48d
parent 439006 6617886468a2
child 439008 c4758f66e313
push id70182
push userdothayer@mozilla.com
push dateMon, 01 Oct 2018 17:06:41 +0000
treeherderautoland@bcdbc281a48d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1495032
milestone64.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 1495032 - Proactively adjust tab priority on switch r=mconley Our current prioritization mechanism doesn't account for tab warming, or for the fact that the current tab should be deprioritized. This corrects that. Differential Revision: https://phabricator.services.mozilla.com/D7205
browser/modules/AsyncTabSwitcher.jsm
dom/interfaces/base/nsITabParent.idl
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
toolkit/content/widgets/browser.xml
--- a/browser/modules/AsyncTabSwitcher.jsm
+++ b/browser/modules/AsyncTabSwitcher.jsm
@@ -990,16 +990,18 @@ class AsyncTabSwitcher {
       Services.telemetry
         .getHistogramById("FX_TAB_SWITCH_REQUEST_TAB_WARMING_STATE")
         .add(warmingState);
     }
 
     this.logState("requestTab " + this.tinfo(tab));
     this.startTabSwitch();
 
+    let oldBrowser = this.requestedTab.linkedBrowser;
+    oldBrowser.deprioritize();
     this.requestedTab = tab;
     if (tabState == this.STATE_LOADED) {
       this.maybeVisibleTabs.clear();
       if (tab.linkedBrowser.isRemoteBrowser) {
         tab.linkedBrowser.forceRepaint();
       }
     }
 
--- a/dom/interfaces/base/nsITabParent.idl
+++ b/dom/interfaces/base/nsITabParent.idl
@@ -38,16 +38,22 @@ interface nsITabParent : nsISupports
   /**
    * Sends a message to the child ensuring that they paint as early as
    * possible. This will send the message to paint even if renderLayers
    * is already true.
    */
   void forceRepaint();
 
   /**
+   * Adjusts the tab's active state in the process priority manager,
+   * allowing its process to be given a lower priority.
+   */
+  void deprioritize();
+
+  /**
    * As an optimisation, setting the docshell's active state to
    * inactive also triggers a layer invalidation to free up some
    * potentially unhelpful memory usage. Calling preserveLayers
    * will cause the layers to be preserved even for inactive
    * docshells.
    */
   void preserveLayers(in boolean aPreserveLayers);
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -165,16 +165,17 @@ TabParent::TabParent(nsIContentParent* a
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
   , mActiveSupressDisplayportCount(0)
 #endif
   , mLayerTreeEpoch{1}
   , mPreserveLayers(false)
   , mRenderLayers(true)
+  , mActiveInPriorityManager(false)
   , mHasLayers(false)
   , mHasPresented(false)
   , mHasBeforeUnload(false)
   , mIsMouseEnterIntoWidgetEventSuppressed(false)
   , mIsActiveRecordReplayTab(false)
 {
   MOZ_ASSERT(aManager);
   // When the input event queue is disabled, we don't need to handle the case
@@ -2853,20 +2854,16 @@ TabParent::SetDocShellIsActive(bool isAc
         } else {
           a11y::nsWinUtils::HideNativeWindow(window);
         }
       }
     }
   }
 #endif
 
-  // Let's inform the priority manager. This operation can end up with the
-  // changing of the process priority.
-  ProcessPriorityManager::TabActivityChanged(this, isActive);
-
   // Keep track of how many active recording/replaying tabs there are.
   if (Manager()->AsContentParent()->IsRecordingOrReplaying()) {
     SetIsActiveRecordReplayTab(isActive);
   }
 
   return NS_OK;
 }
 
@@ -2875,16 +2872,23 @@ TabParent::GetDocShellIsActive(bool* aIs
 {
   *aIsActive = mDocShellIsActive;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabParent::SetRenderLayers(bool aEnabled)
 {
+  if (mActiveInPriorityManager != aEnabled) {
+    mActiveInPriorityManager = aEnabled;
+    // Let's inform the priority manager. This operation can end up with the
+    // changing of the process priority.
+    ProcessPriorityManager::TabActivityChanged(this, aEnabled);
+  }
+
   if (aEnabled == mRenderLayers) {
     if (aEnabled && mHasLayers && mPreserveLayers) {
       // RenderLayers might be called when we've been preserving layers,
       // and already had layers uploaded. In that case, the MozLayerTreeReady
       // event will not naturally arrive, which can confuse the front-end
       // layer. So we fire the event here.
       RefPtr<TabParent> self = this;
       LayersObserverEpoch epoch = mLayerTreeEpoch;
@@ -2921,18 +2925,36 @@ TabParent::GetRenderLayers(bool* aResult
 NS_IMETHODIMP
 TabParent::GetHasLayers(bool* aResult)
 {
   *aResult = mHasLayers;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+TabParent::Deprioritize()
+{
+  if (mActiveInPriorityManager)   {
+    ProcessPriorityManager::TabActivityChanged(this, false);
+    mActiveInPriorityManager = false;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 TabParent::ForceRepaint()
 {
+  if (!mActiveInPriorityManager) {
+    // If a tab is left and then returned to very rapidly, it can be
+    // deprioritized without losing its loaded status. In this case we won't
+    // go through SetRenderLayers.
+    mActiveInPriorityManager = true;
+    ProcessPriorityManager::TabActivityChanged(this, true);
+  }
+
   SetRenderLayersInternal(true /* aEnabled */,
                           true /* aForceRepaint */);
   return NS_OK;
 }
 
 void
 TabParent::SetRenderLayersInternal(bool aEnabled, bool aForceRepaint)
 {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -770,16 +770,19 @@ private:
   // the tab's docshell is inactive.
   bool mPreserveLayers;
 
   // Holds the most recent value passed to the RenderLayers function. This
   // does not necessarily mean that the layers have finished rendering
   // and have uploaded - for that, use mHasLayers.
   bool mRenderLayers;
 
+  // Whether this is active for the ProcessPriorityManager or not.
+  bool mActiveInPriorityManager;
+
   // True if the compositor has reported that the TabChild has uploaded
   // layers.
   bool mHasLayers;
 
   // True if this TabParent has had its layer tree sent to the compositor
   // at least once.
   bool mHasPresented;
 
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -247,16 +247,28 @@
           }
           let {frameLoader} = this;
           if (frameLoader.tabParent) {
             frameLoader.tabParent.preserveLayers(preserve);
           }
         ]]></body>
       </method>
 
+      <method name="deprioritize">
+        <body><![CDATA[
+          if (!this.isRemoteBrowser) {
+            return;
+          }
+          let {frameLoader} = this;
+          if (frameLoader.tabParent) {
+            frameLoader.tabParent.deprioritize();
+          }
+        ]]></body>
+      </method>
+
 
       <property name="renderLayers">
         <getter>
           <![CDATA[
             if (this.isRemoteBrowser) {
               let {frameLoader} = this;
               if (frameLoader && frameLoader.tabParent) {
                 return frameLoader.tabParent.renderLayers;