Bug 1361915 - Record telemetry each time we try to run a transform animation on the compositor. r=birtles,bsmedberg draft
authorBotond Ballo <botond@mozilla.com>
Wed, 03 May 2017 21:39:42 -0400
changeset 576581 a5adf4ea9c0836d9ad0ecde5e5869d00eccc2205
parent 576334 3b96f277325747fe668ca8cd896d2f581238e4ee
child 628251 50d40f8a955ef9882c259476238a06f0344e561b
push id58420
push userbballo@mozilla.com
push dateThu, 11 May 2017 22:28:25 +0000
reviewersbirtles, bsmedberg
bugs1361915, 1349808
milestone55.0a1
Bug 1361915 - Record telemetry each time we try to run a transform animation on the compositor. r=birtles,bsmedberg The telemetry is recorded once per effect:target pair, and is intended for comparison with the telemetry added in bug 1349808. MozReview-Commit-ID: 8JYbAifjmki
dom/animation/KeyframeEffect.cpp
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/KeyframeEffectReadOnly.h
layout/painting/nsDisplayList.cpp
toolkit/components/telemetry/Histograms.json
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -129,16 +129,17 @@ KeyframeEffect::SetTarget(const Nullable
     // 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;
+  mRecordedFrameSize = 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
@@ -1657,16 +1657,24 @@ KeyframeEffectReadOnly::SetPerformanceWa
         nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
         AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement);
       }
       return;
     }
   }
 }
 
+void
+KeyframeEffectReadOnly::RecordFrameSizeTelemetry(uint32_t aPixelArea) {
+  if (!mRecordedFrameSize) {
+    Telemetry::Accumulate(Telemetry::ASYNC_ANIMATION_FRAME_SIZE, aPixelArea);
+    mRecordedFrameSize = true;
+  }
+}
+
 static already_AddRefed<nsStyleContext>
 CreateStyleContextForAnimationValue(nsCSSPropertyID aProperty,
                                     const StyleAnimationValue& aValue,
                                     nsStyleContext* aBaseStyleContext)
 {
   MOZ_ASSERT(aBaseStyleContext,
              "CreateStyleContextForAnimationValue needs to be called "
              "with a valid nsStyleContext");
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -252,16 +252,19 @@ public:
   // Associates a warning with the animated property on the specified frame
   // indicating why, for example, the property could not be animated on the
   // compositor. |aParams| and |aParamsLength| are optional parameters which
   // will be used to generate a localized message for devtools.
   void SetPerformanceWarning(
     nsCSSPropertyID aProperty,
     const AnimationPerformanceWarning& aWarning);
 
+  // Record telemetry about the size of the content being animated.
+  void RecordFrameSizeTelemetry(uint32_t aPixelArea);
+
   // Cumulative change hint on each segment for each property.
   // This is used for deciding the animation is paint-only.
   void CalculateCumulativeChangeHint(nsStyleContext* aStyleContext);
   void CalculateCumulativeChangeHint(
     const ServoComputedValuesWithParent& aServoValues)
   {
   }
 
@@ -411,16 +414,20 @@ protected:
   nsDataHashtable<nsUint32HashKey, StyleAnimationValue> mBaseStyleValues;
   nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>
     mBaseStyleValuesForServo;
 
   // 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;
+  // Similarly, as a point of comparison we record telemetry whether or not
+  // we get a "ContentTooLarge" warning, but again only once per effect:target
+  // pair.
+  bool mRecordedFrameSize = false;
 
 private:
   nsChangeHint mCumulativeChangeHint;
 
   template<typename StyleType>
   void DoSetKeyframes(nsTArray<Keyframe>&& aKeyframes, StyleType&& aStyle);
 
   template<typename StyleType>
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -7331,16 +7331,31 @@ static nsRect ComputePartialPrerenderAre
   // redistributing from one axis to another, or from one side to another.
   nscoord xExcess = aPrerenderSize.width - aDirtyRect.width;
   nscoord yExcess = aPrerenderSize.height - aDirtyRect.height;
   nsRect result = aDirtyRect;
   result.Inflate(xExcess / 2, yExcess / 2);
   return result.MoveInsideAndClamp(aOverflow);
 }
 
+static void
+RecordAnimationFrameSizeTelemetry(nsIFrame* aFrame, const nsSize& overflow)
+{
+  gfxSize scale = nsLayoutUtils::GetTransformToAncestorScale(aFrame);
+  nsSize frameSize = nsSize(overflow.width * scale.width,
+                            overflow.height * scale.height);
+  uint32_t pixelArea = uint32_t(nsPresContext::AppUnitsToIntCSSPixels(frameSize.width))
+                     * nsPresContext::AppUnitsToIntCSSPixels(frameSize.height);
+  if (EffectSet* effects = EffectSet::GetEffectSet(aFrame)) {
+    for (KeyframeEffectReadOnly* effect : *effects) {
+      effect->RecordFrameSizeTelemetry(pixelArea);
+    }
+  }
+}
+
 /* static */ auto
 nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
                                                       nsIFrame* aFrame,
                                                       nsRect* aDirtyRect) -> PrerenderDecision
 {
   // Elements whose transform has been modified recently, or which
   // have a compositor-animated transform, can be prerendered. An element
   // might have only just had its transform animated in which case
@@ -7351,19 +7366,27 @@ nsDisplayTransform::ShouldPrerenderTrans
     EffectCompositor::SetPerformanceWarning(
       aFrame, eCSSProperty_transform,
       AnimationPerformanceWarning(
         AnimationPerformanceWarning::Type::TransformFrameInactive));
 
     return NoPrerender;
   }
 
+  nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
+
+  // Record telemetry about the size of the animated content.
+  // Check CanRecordExtended() so we don't do any processing if the
+  // telemetry won't be recorded anyways.
+  if (Telemetry::CanRecordExtended()) {
+    RecordAnimationFrameSizeTelemetry(aFrame, overflow.Size());
+  }
+
   // If the incoming dirty rect already contains the entire overflow area,
   // we are already rendering the entire content.
-  nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
   if (aDirtyRect->Contains(overflow)) {
     return FullPrerender;
   }
 
   float viewportRatioX = gfxPrefs::AnimationPrerenderViewportRatioLimitX();
   float viewportRatioY = gfxPrefs::AnimationPrerenderViewportRatioLimitY();
   uint32_t absoluteLimitX = gfxPrefs::AnimationPrerenderAbsoluteLimitX();
   uint32_t absoluteLimitY = gfxPrefs::AnimationPrerenderAbsoluteLimitY();
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -171,16 +171,26 @@
     "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)"
   },
+  "ASYNC_ANIMATION_FRAME_SIZE": {
+    "record_in_processes": ["main", "content"],
+    "alert_emails": ["bbirtles@mozilla.com"],
+    "expires_in_version": "59",
+    "kind": "exponential",
+    "high": 80000000,
+    "n_buckets": 100,
+    "bug_numbers": [1100357, 1361915],
+    "description": "The number of pixels of the frame each time we potentially run a transform animation on the compositor. Intended for comparison with ASYNC_ANIMATION_CONTENT_TOO_LARGE_FRAME_SIZE. "
+  },
   "AUDIOSTREAM_FIRST_OPEN_MS": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "50",
     "kind": "exponential",
     "high": 10000,
     "n_buckets": 50,
     "description": "The length of time (in milliseconds) for the first open of AudioStream."
   },