Bug 1349808 - Add telemetry for cases when we can't run async animations due to layer size being too large. data-review=bsmedberg, r=birtles,botond draft
authorBoris Chiou <boris.chiou@gmail.com>
Fri, 24 Mar 2017 15:53:54 +0800
changeset 554880 f439164709eebdb70d6a280192697eca3d670a0d
parent 554803 38894655c89e68bcd8f45d31a0d3005f2c2b53db
child 622463 08a8977aa01115507e37416cad83a5084ce66e55
push id52080
push userbmo:boris.chiou@gmail.com
push dateMon, 03 Apr 2017 06:32:42 +0000
reviewersbirtles, botond
bugs1349808
milestone55.0a1
Bug 1349808 - Add telemetry for cases when we can't run async animations due to layer size being too large. data-review=bsmedberg, r=birtles,botond MozReview-Commit-ID: 61DBw1DHbQA
dom/animation/KeyframeEffect.cpp
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/KeyframeEffectReadOnly.h
toolkit/components/telemetry/Histograms.json
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -124,16 +124,21 @@ KeyframeEffect::SetTarget(const Nullable
     nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
     if (mAnimation) {
       nsNodeUtils::AnimationAdded(mAnimation);
     }
   } else if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
     // New target is null, so fall back to distribute spacing.
     KeyframeUtils::ApplyDistributeSpacing(mKeyframes);
   }
+
+  // If the new target frame is also oversized we should probably record that
+  // too so we have a more complete picture of the type of frame sizes we
+  // encounter, hence we reset the telemetry flag here.
+  mRecordedContentTooLarge = false;
 }
 
 void
 KeyframeEffect::SetIterationComposite(
   const IterationCompositeOperation& aIterationComposite,
   CallerType aCallerType)
 {
   // Ignore iterationComposite if the Web Animations API is not enabled,
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -1,28 +1,30 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/KeyframeEffectReadOnly.h"
 
+#include "gfxPrefs.h"
 #include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
   // For UnrestrictedDoubleOrKeyframeAnimationOptions;
 #include "mozilla/dom/CSSPseudoElement.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "mozilla/AnimValuesStyleRule.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/FloatingPoint.h" // For IsFinite
 #include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
 #include "mozilla/KeyframeUtils.h"
 #include "mozilla/ServoBindings.h"
+#include "mozilla/Telemetry.h"
 #include "mozilla/TypeTraits.h"
 #include "Layers.h" // For Layer
 #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
 #include "nsContentUtils.h"  // nsContentUtils::ReportToConsole
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
 #include "nsCSSPseudoElements.h" // For CSSPseudoElementType
 #include "nsIPresShell.h"
@@ -1592,16 +1594,41 @@ KeyframeEffectReadOnly::HasGeometricProp
   return false;
 }
 
 void
 KeyframeEffectReadOnly::SetPerformanceWarning(
   nsCSSPropertyID aProperty,
   const AnimationPerformanceWarning& aWarning)
 {
+  if (aWarning.mType == AnimationPerformanceWarning::Type::ContentTooLarge &&
+      !mRecordedContentTooLarge) {
+    // ContentTooLarge stores: frameSize (w x h),
+    //                         relativeLimit (w x h), i.e. =~ viewport size *
+    //                                                          ratioLimit
+    //                         absoluteLimit (w x h)
+    MOZ_ASSERT(aWarning.mParams && aWarning.mParams->Length() >= 4,
+               "ContentTooLarge warning should have at least 4 parameters");
+    const nsTArray<int32_t>& params = aWarning.mParams.ref();
+    uint32_t frameSize = uint32_t(params[0]) * params[1];
+    float viewportRatioX = gfxPrefs::AnimationPrerenderViewportRatioLimitX();
+    float viewportRatioY = gfxPrefs::AnimationPrerenderViewportRatioLimitY();
+    double viewportWidth = viewportRatioX ? params[2] / viewportRatioX
+                                          : params[2];
+    double viewportHeight = viewportRatioY ? params[3] / viewportRatioY
+                                           : params[3];
+    double viewportSize = viewportWidth * viewportHeight;
+    uint32_t frameToViewport = frameSize / viewportSize * 100.0;
+    Telemetry::Accumulate(
+      Telemetry::ASYNC_ANIMATION_CONTENT_TOO_LARGE_FRAME_SIZE, frameSize);
+    Telemetry::Accumulate(
+      Telemetry::ASYNC_ANIMATION_CONTENT_TOO_LARGE_PERCENTAGE, frameToViewport);
+    mRecordedContentTooLarge = true;
+  }
+
   for (AnimationProperty& property : mProperties) {
     if (property.mProperty == aProperty &&
         (!property.mPerformanceWarning ||
          *property.mPerformanceWarning != aWarning)) {
       property.mPerformanceWarning = Some(aWarning);
 
       nsXPIDLString localizedString;
       if (nsLayoutUtils::IsAnimationLoggingEnabled() &&
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -450,16 +450,21 @@ protected:
   // we need to re-evaluate the cascade of animations when that changes.
   bool mInEffectOnLastAnimationTimingUpdate;
 
   // The non-animated values for properties in this effect that contain at
   // least one animation value that is composited with the underlying value
   // (i.e. it uses the additive or accumulate composite mode).
   nsDataHashtable<nsUint32HashKey, StyleAnimationValue> mBaseStyleValues;
 
+  // We only want to record telemetry data for "ContentTooLarge" warnings once
+  // per effect:target pair so we use this member to record if we have already
+  // reported a "ContentTooLarge" warning for the current target.
+  bool mRecordedContentTooLarge = false;
+
 private:
   nsChangeHint mCumulativeChangeHint;
 
   template<typename StyleType>
   void DoSetKeyframes(nsTArray<Keyframe>&& aKeyframes, StyleType&& aStyle);
 
   template<typename StyleType>
   void DoUpdateProperties(StyleType&& aStyle);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -132,16 +132,35 @@
   "APPLICATION_REPUTATION_ALLOWLIST_MATCH": {
     "alert_emails": ["safebrowsing-telemetry@mozilla.org"],
     "expires_in_version": "60",
     "kind": "enumerated",
     "n_values": 4,
     "bug_numbers": [1331139],
     "description": "For each Application Reputation lookup against both the V2 and V4 Google lists, note which version of the allow list returned a match (0 = no match, 1 = match only V2, 2 = match only V4, 3 = match both V2 and V4)"
   },
+  "ASYNC_ANIMATION_CONTENT_TOO_LARGE_FRAME_SIZE": {
+    "alert_emails": ["bbirtles@mozilla.com"],
+    "expires_in_version": "59",
+    "kind": "exponential",
+    "high": 80000000,
+    "n_buckets": 100,
+    "bug_numbers": [1100357, 1349808],
+    "description": "The number of pixels of the frame for each time we encountered a layer that was so large we decided not to run its animations on the compositor."
+  },
+  "ASYNC_ANIMATION_CONTENT_TOO_LARGE_PERCENTAGE": {
+    "alert_emails": ["bbirtles@mozilla.com"],
+    "expires_in_version": "59",
+    "kind": "exponential",
+    "low": 100,
+    "high": 1000,
+    "n_buckets": 50,
+    "bug_numbers": [1100357, 1349808],
+    "description": "The ratio of the frame size (in total number of pixels) to the relative limit (~viewport size plus some tolerance factor, typically 12.5% in each dimension, i.e. ~27% tolerance in total area) for each time we encountered a layer that was so large we decided not to run its animations on the compositor expressed as a percentage (e.g. 130 = frame area was 30% larger than the relative limit)"
+  },
   "AUDIOSTREAM_FIRST_OPEN_MS": {
     "expires_in_version": "50",
     "kind": "exponential",
     "high": 10000,
     "n_buckets": 50,
     "description": "The length of time (in milliseconds) for the first open of AudioStream."
   },
   "AUDIOSTREAM_LATER_OPEN_MS": {