Bug 1233368 - Be more careful about how we measure when an async tab switch has finished. r?billm draft
authorMike Conley <mconley@mozilla.com>
Tue, 05 Jan 2016 19:03:45 -0500
changeset 319153 25878aef3f6a2a4da242eb86590b13d1aeb98c69
parent 319152 dd6d447fc6e06da33a6b4a0ff44e6ce31ebc47dd
child 512556 4210e095b6332fd4f9ca3e1de9767e90f9945624
push id8987
push usermconley@mozilla.com
push dateWed, 06 Jan 2016 00:09:55 +0000
reviewersbillm
bugs1233368
milestone46.0a1
Bug 1233368 - Be more careful about how we measure when an async tab switch has finished. r?billm Now we only attempt to stop any measurements if we're sure a switch was in progress.
browser/base/content/tabbrowser.xml
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3096,16 +3096,19 @@
 
             tabbrowser: this,  // Reference to gBrowser.
             loadTimer: null,   // TAB_SWITCH_TIMEOUT timer.
             unloadTimer: null, // UNLOAD_DELAY timer.
 
             // Map from tabs to STATE_* (below).
             tabState: new Map(),
 
+            // True if we're in the midst of switching tabs.
+            switchInProgress: false,
+
             // Keep an exact list of content processes (tabParent) in which
             // we're actively suppressing the display port. This gives a robust
             // way to make sure we don't forget to un-suppress.
             activeSuppressDisplayport: new Set(),
 
             // Set of tabs that might be visible right now. We maintain
             // this set because we can't be sure when a tab is actually
             // drawn. A tab is added to this set when we ask to make it
@@ -3405,31 +3408,31 @@
 
             // Fires when the layers become available for a tab.
             onLayersReady: function(browser) {
               this.logState("onLayersReady");
 
               let tab = this.tabbrowser.getTabForBrowser(browser);
               this.setTabState(tab, this.STATE_LOADED);
 
-              this.finishTabSwitch();
+              this.maybeFinishTabSwitch();
 
               if (this.loadingTab === tab) {
                 clearTimeout(this.loadTimer);
                 this.loadTimer = null;
                 this.loadingTab = null;
               }
             },
 
             // Fires when we paint the screen. Any tab switches we initiated
             // previously are done, so there's no need to keep the old layers
             // around.
             onPaint: function() {
               this.maybeVisibleTabs.clear();
-              this.finishTabSwitch();
+              this.maybeFinishTabSwitch();
             },
 
             // Called when we're done clearing the layers for a tab.
             onLayersCleared: function(browser) {
               this.logState("onLayersCleared");
 
               let tab = this.tabbrowser.getTabForBrowser(browser);
               if (tab) {
@@ -3518,50 +3521,59 @@
              * Telemetry and Profiler related helpers for recording tab switch
              * timing.
              */
 
             startTabSwitch: function () {
               TelemetryStopwatch.cancel("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
               TelemetryStopwatch.start("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
               this.addMarker("AsyncTabSwitch:Start");
+              this.switchInProgress = true;
             },
 
-            finishTabSwitch: function () {
-              if (this.requestedTab && this.getTabState(this.requestedTab) == this.STATE_LOADED) {
+            /**
+             * Something has occurred that might mean that we've completed
+             * the tab switch (layers are ready, paints are done, spinners
+             * are hidden). This checks to make sure all conditions are
+             * satisfies, and then records the tab switch as finished.
+             */
+            maybeFinishTabSwitch: function () {
+              if (this.switchInProgress && this.requestedTab &&
+                  this.getTabState(this.requestedTab) == this.STATE_LOADED) {
                 // After this point the tab has switched from the content thread's point of view.
                 // The changes will be visible after the next refresh driver tick + composite.
                 let event = new CustomEvent("TabSwitched", {
                   bubbles: true,
                   cancelable: true
                 });
                 this.tabbrowser.dispatchEvent(event);
                 let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                 if (time != -1) {
                   TelemetryStopwatch.finish("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                   this.log("DEBUG: tab switch time = " + time);
                   this.addMarker("AsyncTabSwitch:Finish");
                 }
+                this.switchInProgress = false;
               }
             },
 
             spinnerDisplayed: function () {
               this.assert(!this.spinnerTab);
               TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
               this.addMarker("AsyncTabSwitch:SpinnerShown");
             },
 
             spinnerHidden: function () {
               this.assert(this.spinnerTab);
               this.log("DEBUG: spinner time = " +
                        TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window));
               TelemetryStopwatch.finish("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
               this.addMarker("AsyncTabSwitch:SpinnerHidden");
               // we do not get a onPaint after displaying the spinner
-              this.finishTabSwitch();
+              this.maybeFinishTabSwitch();
             },
 
             addMarker: function(marker) {
               if (Services.profiler) {
                 Services.profiler.AddMarker(marker);
               }
             },