Bug 828097: Add telemetry probes for tab animation smoothness. r=felipc,vdjeric
authorAvi Halachmi <avihpit@yahoo.com>
Fri, 08 Feb 2013 01:55:39 +0200
changeset 121360 b39ac5994fd723252edb64311765e64c69ff46a3
parent 121359 7b5e030a276344cbeb2e1ad259b0a580160e1a2c
child 121361 c1ee454506f6b9aca27b59b101c47246b8a3034d
push id24282
push userryanvm@gmail.com
push dateFri, 08 Feb 2013 22:23:58 +0000
treeherdermozilla-central@c1ee454506f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipc, vdjeric
bugs828097
milestone21.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 828097: Add telemetry probes for tab animation smoothness. r=felipc,vdjeric
browser/base/content/tabbrowser.xml
toolkit/components/telemetry/Histograms.json
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1266,22 +1266,18 @@
               setTimeout(function (tabContainer) {
                 tabContainer._handleNewTab(t);
               }, 0, this.tabContainer);
             } else {
               setTimeout(function (tabContainer) {
                 if (t.pinned)
                   tabContainer._handleNewTab(t);
                 else {
-                  if (tabContainer._tabAnimationLoggingEnabled) {
-                    t._recordingHandle = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                                               .getInterface(Ci.nsIDOMWindowUtils)
-                                               .startFrameTimeRecording();
-                  }
-                  t._animStartTime = Date.now();
+                  tabContainer._handleTabTelemetryStart(tabContainer, t, aURI);
+
                   t.setAttribute("fadein", "true");
 
                   // This call to adjustTabstrip is redundant but needed so that
                   // when opening a second tab, the first tab's close buttons
                   // appears immediately rather than when the transition ends.
                   if (tabContainer.childNodes.length == 2)
                     tabContainer.adjustTabstrip();
                 }
@@ -1573,22 +1569,17 @@
                 this._removingTabs.length > 3 /* don't want lots of concurrent animations */ ||
                 aTab.getAttribute("fadein") != "true" /* fade-in transition hasn't been triggered yet */ ||
                 window.getComputedStyle(aTab).maxWidth == "0.1px" /* fade-in transition hasn't moved yet */ ||
                 !Services.prefs.getBoolPref("browser.tabs.animate")) {
               this._endRemoveTab(aTab);
               return;
             }
 
-            if (this.tabContainer._tabAnimationLoggingEnabled) {
-              aTab._recordingHandle = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                                            .getInterface(Ci.nsIDOMWindowUtils)
-                                            .startFrameTimeRecording();
-            }
-            aTab._animStartTime = Date.now();
+            this.tabContainer._handleTabTelemetryStart(this.tabContainer, aTab);
 
             this._blurTab(aTab);
             aTab.removeAttribute("fadein");
 
             setTimeout(function (tab, tabbrowser) {
               if (tab.parentNode &&
                   window.getComputedStyle(tab).maxWidth == "0.1px") {
                 NS_ASSERT(false, "Giving up waiting for the tab closing animation to finish (bug 608589)");
@@ -2900,16 +2891,17 @@
           window.addEventListener("resize", this, false);
           window.addEventListener("load", this, false);
 
           try {
             this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled");
           } catch (ex) {
             this._tabAnimationLoggingEnabled = false;
           }
+          this._browserNewtabpageEnabled = Services.prefs.getBoolPref("browser.newtabpage.enabled");
         ]]>
       </constructor>
 
       <destructor>
         <![CDATA[
           Services.prefs.removeObserver("browser.tabs.", this._prefObserver);
         ]]>
       </destructor>
@@ -3499,51 +3491,125 @@
         <parameter name="aTab"/>
         <body>
         <![CDATA[
           return !aTab.closing;
         ]]>
         </body>
       </method>
 
+      <method name="_handleTabTelemetryStart">
+        <parameter name="aTabContainer"/>
+        <parameter name="aTab"/>
+        <parameter name="aURI"/>
+        <body>
+        <![CDATA[
+          // Animation-smoothness telemetry/logging
+          if (Services.telemetry.canRecord || aTabContainer._tabAnimationLoggingEnabled) {
+            if (aURI == "about:newtab" && (aTab._tPos == 1 || aTab._tPos == 2)) {
+              // Indicate newtab page animation where other tabs are unaffected
+              // (for which case, the 2nd or 3rd tabs are good representatives, even if not absolute)
+              aTab._recordingTabOpenPlain = true;
+            }
+            aTab._recordingHandle = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                                          .getInterface(Ci.nsIDOMWindowUtils)
+                                          .startFrameTimeRecording();
+          }
+
+          // Overall animation duration
+          aTab._animStartTime = Date.now();
+        ]]>
+        </body>
+      </method>
+
+      <method name="_handleTabTelemetryEnd">
+        <parameter name="aTab"/>
+        <body>
+        <![CDATA[
+          if (!aTab._animStartTime) {
+            return;
+          }
+
+          Services.telemetry.getHistogramById(aTab.closing ?
+                                              "FX_TAB_ANIM_CLOSE_MS" :
+                                              "FX_TAB_ANIM_OPEN_MS")
+                            .add(Date.now() - aTab._animStartTime);
+          aTab._animStartTime = 0;
+
+          // Handle tab animation smoothness telemetry/logging of frame intervals and paint times
+          if (!("_recordingHandle" in aTab)) {
+            return;
+          }
+
+          let paints = {};
+          let intervals = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIDOMWindowUtils)
+                                .stopFrameTimeRecording(aTab._recordingHandle, paints);
+          delete aTab._recordingHandle;
+          paints = paints.value; // The result array itself.
+          let frameCount = intervals.length;
+
+          if (this._tabAnimationLoggingEnabled) {
+            let msg = "Tab " + (aTab.closing ? "close" : "open") + " (Frame-interval / paint-processing):\n";
+            for (let i = 0; i < frameCount; i++) {
+              msg += Math.round(intervals[i]) + " / " + Math.round(paints[i]) + "\n";
+            }
+            Services.console.logStringMessage(msg);
+          }
+
+          // For telemetry, the first frame interval is not useful since it may represent an interval
+          // to a relatively old frame (prior to recording start). So we'll ignore it for the average.
+          // But if we recorded only 1 frame (very rare), then the first paint duration is a good
+          // representative of the first frame interval for our cause (indicates very bad animation).
+          // First paint duration is always useful for us.
+          if (frameCount > 0) {
+            let averageInterval = 0;
+            let averagePaint = paints[0];
+            for (let i = 1; i < frameCount; i++) {
+              averageInterval += intervals[i];
+              averagePaint    += paints[i];
+            };
+            averagePaint /= frameCount;
+            averageInterval = (frameCount == 1)
+                              ? averagePaint
+                              : averageInterval / (frameCount - 1);
+
+            Services.telemetry.getHistogramById("FX_TAB_ANIM_ANY_FRAME_INTERVAL_MS").add(averageInterval);
+            Services.telemetry.getHistogramById("FX_TAB_ANIM_ANY_FRAME_PAINT_MS").add(averagePaint);
+
+            if (aTab._recordingTabOpenPlain) {
+              delete aTab._recordingTabOpenPlain;
+              // While we do have a telemetry probe NEWTAB_PAGE_ENABLED to monitor newtab preview, it'll be
+              // easier to overview the data without slicing by it. Hence the additional histograms with _PREVIEW.
+              let preview = this._browserNewtabpageEnabled ? "_PREVIEW" : "";
+              Services.telemetry.getHistogramById("FX_TAB_ANIM_OPEN" + preview + "_FRAME_INTERVAL_MS").add(averageInterval);
+              Services.telemetry.getHistogramById("FX_TAB_ANIM_OPEN" + preview + "_FRAME_PAINT_MS").add(averagePaint);
+            }
+          }
+        ]]>
+        </body>
+      </method>
+
       <!-- Deprecated stuff, implemented for backwards compatibility. -->
       <property name="mTabstripClosebutton" readonly="true"
                 onget="return document.getElementById('tabs-closebutton');"/>
       <property name="mAllTabsPopup" readonly="true"
                 onget="return document.getElementById('alltabs-popup');"/>
     </implementation>
 
     <handlers>
       <handler event="TabSelect" action="this._handleTabSelect();"/>
 
       <handler event="transitionend"><![CDATA[
         if (event.propertyName != "max-width")
           return;
 
         var tab = event.target;
 
-        if (tab._animStartTime) {
-          Services.telemetry.getHistogramById(tab.closing ?
-                                              "FX_TAB_ANIM_CLOSE_MS" :
-                                              "FX_TAB_ANIM_OPEN_MS")
-                            .add(Date.now() - tab._animStartTime);
-          tab._animStartTime = 0;
-
-          if (this._tabAnimationLoggingEnabled && tab.hasOwnProperty("_recordingHandle")) {
-            let paints = {};
-            let intervals = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                                  .getInterface(Ci.nsIDOMWindowUtils)
-                                  .stopFrameTimeRecording(tab._recordingHandle, paints);
-            let msg = "Tab " + (tab.closing ? "close" : "open") + " (Frame-interval / paint-processing):\n";
-            for (let i = 0; i < intervals.length; i++) {
-              msg += Math.round(intervals[i]) + " / " + Math.round(paints.value[i]) + "\n";
-            }
-            Services.console.logStringMessage(msg);
-          }
-        }
+        this._handleTabTelemetryEnd(tab);
 
         if (tab.getAttribute("fadein") == "true") {
           if (tab._fullyOpen)
             this.adjustTabstrip();
           else
             this._handleNewTab(tab);
         } else if (tab.closing) {
           this.tabbrowser._endRemoveTab(tab);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -2055,16 +2055,55 @@
     "description": "Firefox: Time taken by the tab opening animation in milliseconds"
   },
   "FX_TAB_ANIM_CLOSE_MS": {
     "kind": "exponential",
     "high": "3000",
     "n_buckets": 10,
     "description": "Firefox: Time taken by the tab closing animation in milliseconds"
   },
+  "FX_TAB_ANIM_OPEN_PREVIEW_FRAME_INTERVAL_MS": {
+    "kind": "exponential",
+    "low" : 7,
+    "high": "500",
+    "n_buckets": 50,
+    "description": "Average frame interval during tab open animation of about:newtab (preview=on), when other tabs are unaffected"
+  },
+  "FX_TAB_ANIM_OPEN_PREVIEW_FRAME_PAINT_MS": {
+    "kind": "exponential",
+    "high": "500",
+    "n_buckets": 30,
+    "description": "Average paint duration during tab open animation of about:newtab (preview=on), when other tabs are unaffected"
+  },
+  "FX_TAB_ANIM_OPEN_FRAME_INTERVAL_MS": {
+    "kind": "exponential",
+    "low" : 7,
+    "high": "500",
+    "n_buckets": 50,
+    "description": "Average frame interval during tab open animation of about:newtab (preview=off), when other tabs are unaffected"
+  },
+  "FX_TAB_ANIM_OPEN_FRAME_PAINT_MS": {
+    "kind": "exponential",
+    "high": "500",
+    "n_buckets": 30,
+    "description": "Average paint duration during tab open animation of about:newtab (preview=off), when other tabs are unaffected"
+  },
+  "FX_TAB_ANIM_ANY_FRAME_INTERVAL_MS": {
+    "kind": "exponential",
+    "low" : 7,
+    "high": "500",
+    "n_buckets": 50,
+    "description": "Average frame interval during any tab open/close animation (excluding tabstrip scroll)"
+  },
+  "FX_TAB_ANIM_ANY_FRAME_PAINT_MS": {
+    "kind": "exponential",
+    "high": "500",
+    "n_buckets": 30,
+    "description": "Average paint duration during any tab open/close animation (excluding tabstrip scroll)"
+  },
   "FX_TAB_SWITCH_UPDATE_MS": {
     "kind": "exponential",
     "high": "1000",
     "n_buckets": 20,
     "description": "Firefox: Time in ms spent updating UI in response to a tab switch"
   },
   "FX_TAB_SWITCH_TOTAL_MS": {
     "kind": "exponential",