Bug 1361915 - Record telemetry each time we try to run a transform animation on the compositor. r=birtles,bsmedberg
authorBotond Ballo <botond@mozilla.com>
Wed, 03 May 2017 21:39:42 -0400
changeset 357950 39a2a527f529c7bdf162fdc7100f9b062a91046c
parent 357949 0b3de3cdbf997a44fc3c0b55cf5ab60488097779
child 357951 f3e2c93055e2ef0155768ca4ed45d96313dd69b6
push id42546
push userbballo@mozilla.com
push dateFri, 12 May 2017 02:44:57 +0000
treeherderautoland@39a2a527f529 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles, bsmedberg
bugs1361915, 1349808
milestone55.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 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."
   },