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.
--- 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);
}
},