Bug 1342464 - Collect Telemetry on when a tab switch spinner is shown. r?billm, data-review=liuche draft
authorMike Conley <mconley@mozilla.com>
Sat, 04 Mar 2017 14:19:22 -0500
changeset 495477 0a095cccd2b35d336f3d33119d7db2ed238e1117
parent 494684 3d341b9ba5353b6b8ab45b6ca03dcb1b2d789faa
child 495478 9bca018b7cc6192ed1e107863b32e6ff3e5894fd
push id48345
push usermconley@mozilla.com
push dateWed, 08 Mar 2017 21:41:20 +0000
reviewersbillm
bugs1342464
milestone55.0a1
Bug 1342464 - Collect Telemetry on when a tab switch spinner is shown. r?billm, data-review=liuche MozReview-Commit-ID: 1Ss2f9A2JtK
browser/base/content/tabbrowser.xml
dom/interfaces/base/nsITabParent.idl
dom/ipc/TabParent.cpp
toolkit/components/telemetry/Histograms.json
--- 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": {