Bug 1342464 - Collect Telemetry on when a tab switch spinner is shown. r?billm, data-review=liuche
MozReview-Commit-ID: 1Ss2f9A2JtK
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3697,16 +3697,17 @@
return this._switcher;
}
let switcher = {
// How long to wait for a tab's layers to load. After this
// time elapses, we're free to put up the spinner and start
// trying to load a different tab.
TAB_SWITCH_TIMEOUT: 400 /* ms */,
+ NEWNESS_THRESHOLD: 1000 /* ms */,
// When the user hasn't switched tabs for this long, we unload
// layers for all tabs that aren't in use.
UNLOAD_DELAY: 300 /* ms */,
// The next three tabs form the principal state variables.
// See the assertions in postActions for their invariants.
@@ -4429,21 +4430,43 @@
this.addMarker("AsyncTabSwitch:Finish");
}
this.switchInProgress = false;
}
},
spinnerDisplayed() {
this.assert(!this.spinnerTab);
+ let browser = this.requestedTab.linkedBrowser;
+ this.assert(browser.isRemoteBrowser);
TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
// We have a second, similar probe for capturing recordings of
// when the spinner is displayed for very long periods.
TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS", window);
this.addMarker("AsyncTabSwitch:SpinnerShown");
+
+ // What kind of tab is about to display this spinner? We have three basic
+ // kinds:
+ //
+ // 1) A tab that we've presented before
+ // 2) A tab that we've never presented before, and it's quite new
+ // 3) A tab that we've never presented before, but it's not so new
+ //
+ // Being "new" in this sense means being a tab that was created less than
+ // NEWNESS_THRESHOLD ms ago.
+
+ let histogram = Services.telemetry.getHistogramById("FX_TAB_SWITCH_SPINNER_TYPE");
+ if (browser.frameLoader.tabParent.hasPresented) {
+ // We've presented this tab before.
+ histogram.add("seen");
+ } else if (Date.now() - this.requestedTab.creationTime < this.NEWNESS_THRESHOLD) {
+ histogram.add("unseenNew");
+ } else {
+ histogram.add("unseenOld");
+ }
},
spinnerHidden() {
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);
TelemetryStopwatch.finish("FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS", window);
@@ -7073,16 +7096,20 @@
</xul:stack>
</content>
<implementation>
<constructor><![CDATA[
if (!("_lastAccessed" in this)) {
this.updateLastAccessed();
}
+
+ if (!("_creationTime" in this)) {
+ this._creationTime = Date.now();
+ }
]]></constructor>
<property name="_visuallySelected">
<setter>
<![CDATA[
if (val)
this.setAttribute("visuallyselected", "true");
else
@@ -7179,16 +7206,22 @@
<parameter name="aDate"/>
<body><![CDATA[
this._lastAccessed = this.selected ? Infinity : (aDate || Date.now());
]]></body>
</method>
<field name="cachePosition">Infinity</field>
+ <property name="creationTime">
+ <getter>
+ return this._creationTime;
+ </getter>
+ </property>
+
<field name="mOverCloseButton">false</field>
<property name="_overPlayingIcon" readonly="true">
<getter><![CDATA[
let iconVisible = this.hasAttribute("soundplaying") ||
this.hasAttribute("muted") ||
this.hasAttribute("blocked");
let soundPlayingIcon =
document.getAnonymousElementByAttribute(this, "anonid", "soundplaying-icon");
--- a/dom/interfaces/base/nsITabParent.idl
+++ b/dom/interfaces/base/nsITabParent.idl
@@ -51,9 +51,14 @@ interface nsITabParent : nsISupports
* If aForDocumentNavigation is false, navigate by element.
*
* If aForward is true, navigate to the first focusable element or document.
* If aForward is false, navigate to the last focusable element or document.
*/
void navigateByKey(in bool aForward, in bool aForDocumentNavigation);
readonly attribute boolean hasContentOpener;
+ /**
+ * True if we've previously received layers for this tab when switching to
+ * it.
+ */
+ readonly attribute boolean hasPresented;
};
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2801,16 +2801,23 @@ TabParent::GetHasContentOpener(bool* aRe
void
TabParent::SetHasContentOpener(bool aHasContentOpener)
{
mHasContentOpener = aHasContentOpener;
}
NS_IMETHODIMP
+TabParent::GetHasPresented(bool* aResult)
+{
+ *aResult = mHasPresented;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
TabParent::NavigateByKey(bool aForward, bool aForDocumentNavigation)
{
Unused << SendNavigateByKey(aForward, aForDocumentNavigation);
return NS_OK;
}
class LayerTreeUpdateRunnable final
: public mozilla::Runnable
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -5087,16 +5087,25 @@
"low": 1000,
"high": 64000,
"n_buckets": 7,
"bug_numbers": [1301104],
"alert_emails": ["mconley@mozilla.com"],
"releaseChannelCollection": "opt-out",
"description": "Firefox: If the spinner interstitial displays during tab switching, records the time in ms the graphic is visible. This probe is similar to FX_TAB_SWITCH_SPINNER_VISIBLE_MS, but is for truly degenerate cases."
},
+ "FX_TAB_SWITCH_SPINNER_TYPE": {
+ "expires_in_version": "60",
+ "kind": "categorical",
+ "bug_numbers": [1301104],
+ "alert_emails": ["mconley@mozilla.com"],
+ "releaseChannelCollection": "opt-out",
+ "description": "Firefox: If the spinner interstitial displays during tab switching, record if the tab being switched to has been seen (content was visible) before. If not, record if the tab is 'old' (> 1000ms since creation) or 'new'.",
+ "labels": ["seen", "unseenOld", "unseenNew"]
+ },
"FX_TAB_CLICK_MS": {
"expires_in_version": "default",
"kind": "exponential",
"high": 1000,
"n_buckets": 20,
"description": "Firefox: Time in ms spent on switching tabs in response to a tab click"
},
"FX_BOOKMARKS_TOOLBAR_INIT_MS": {