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
--- 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."
},