Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "mozilla/layers/AnimationMetricsTracker.h"
7 :
8 : #include <algorithm>
9 : #include <cmath>
10 : #include <inttypes.h>
11 :
12 : #define AMT_LOG(...)
13 : // #define AMT_LOG(...) printf_stderr("AMT: " __VA_ARGS__)
14 :
15 : namespace mozilla {
16 : namespace layers {
17 :
18 1 : AnimationMetricsTracker::AnimationMetricsTracker()
19 1 : : mMaxLayerAreaAnimated(0)
20 : {
21 1 : }
22 :
23 0 : AnimationMetricsTracker::~AnimationMetricsTracker()
24 : {
25 0 : }
26 :
27 : void
28 29 : AnimationMetricsTracker::UpdateAnimationInProgress(AnimationProcessTypes aActive,
29 : uint64_t aLayerArea,
30 : TimeDuration aVsyncInterval)
31 : {
32 29 : bool inProgress = (aActive != AnimationProcessTypes::eNone);
33 29 : MOZ_ASSERT(inProgress || aLayerArea == 0);
34 29 : if (mCurrentAnimationStart && !inProgress) {
35 0 : AnimationEnded();
36 0 : mCurrentAnimationStart = TimeStamp();
37 0 : mMaxLayerAreaAnimated = 0;
38 29 : } else if (inProgress) {
39 0 : if (!mCurrentAnimationStart) {
40 0 : mCurrentAnimationStart = TimeStamp::Now();
41 0 : mMaxLayerAreaAnimated = aLayerArea;
42 0 : AnimationStarted();
43 : } else {
44 0 : mMaxLayerAreaAnimated = std::max(mMaxLayerAreaAnimated, aLayerArea);
45 : }
46 : }
47 :
48 58 : UpdateAnimationThroughput("chrome",
49 58 : (aActive & AnimationProcessTypes::eChrome) != AnimationProcessTypes::eNone,
50 : mChromeAnimation,
51 : aVsyncInterval,
52 : Telemetry::COMPOSITOR_ANIMATION_THROUGHPUT_CHROME,
53 29 : Telemetry::COMPOSITOR_ANIMATION_MAX_CONTIGUOUS_DROPS_CHROME);
54 58 : UpdateAnimationThroughput("content",
55 58 : (aActive & AnimationProcessTypes::eContent) != AnimationProcessTypes::eNone,
56 : mContentAnimation,
57 : aVsyncInterval,
58 : Telemetry::COMPOSITOR_ANIMATION_THROUGHPUT_CONTENT,
59 29 : Telemetry::COMPOSITOR_ANIMATION_MAX_CONTIGUOUS_DROPS_CONTENT);
60 29 : }
61 :
62 : void
63 29 : AnimationMetricsTracker::UpdateApzAnimationInProgress(bool aInProgress,
64 : TimeDuration aVsyncInterval)
65 : {
66 29 : UpdateAnimationThroughput("apz",
67 : aInProgress,
68 : mApzAnimation,
69 : aVsyncInterval,
70 : Telemetry::COMPOSITOR_ANIMATION_THROUGHPUT_APZ,
71 29 : Telemetry::COMPOSITOR_ANIMATION_MAX_CONTIGUOUS_DROPS_APZ);
72 29 : }
73 :
74 : void
75 0 : AnimationMetricsTracker::AnimationStarted()
76 : {
77 0 : }
78 :
79 : void
80 0 : AnimationMetricsTracker::AnimationEnded()
81 : {
82 0 : MOZ_ASSERT(mCurrentAnimationStart);
83 :
84 0 : Telemetry::AccumulateTimeDelta(Telemetry::COMPOSITOR_ANIMATION_DURATION, mCurrentAnimationStart);
85 0 : Telemetry::Accumulate(Telemetry::COMPOSITOR_ANIMATION_MAX_LAYER_AREA, mMaxLayerAreaAnimated);
86 : AMT_LOG("Ended animation; duration: %f ms, area: %" PRIu64 "\n",
87 : (TimeStamp::Now() - mCurrentAnimationStart).ToMilliseconds(),
88 : mMaxLayerAreaAnimated);
89 0 : }
90 :
91 : void
92 87 : AnimationMetricsTracker::UpdateAnimationThroughput(const char* aLabel,
93 : bool aInProgress,
94 : AnimationData& aAnimation,
95 : TimeDuration aVsyncInterval,
96 : Telemetry::HistogramID aThroughputHistogram,
97 : Telemetry::HistogramID aMaxDropsHistogram)
98 : {
99 87 : if (aInProgress && !aAnimation.mStart) {
100 : // the animation just started
101 0 : aAnimation.mStart = TimeStamp::Now();
102 0 : aAnimation.mLastFrameTime = aAnimation.mStart;
103 0 : aAnimation.mLongestFrame = TimeDuration();
104 0 : aAnimation.mFrameCount = 1;
105 : AMT_LOG("Compositor animation of type %s just started\n", aLabel);
106 87 : } else if (aInProgress && aAnimation.mStart) {
107 : // the animation continues
108 0 : aAnimation.mFrameCount++;
109 0 : TimeStamp now = TimeStamp::Now();
110 0 : aAnimation.mLongestFrame = std::max(aAnimation.mLongestFrame, now - aAnimation.mLastFrameTime);
111 0 : aAnimation.mLastFrameTime = now;
112 87 : } else if (!aInProgress && aAnimation.mStart) {
113 : // the animation just ended
114 :
115 0 : TimeStamp now = TimeStamp::Now();
116 : // Get the length and clear aAnimation.mStart before the early-returns below
117 0 : TimeDuration animationLength = now - aAnimation.mStart;
118 0 : aAnimation.mStart = TimeStamp();
119 :
120 0 : if (aVsyncInterval == TimeDuration::Forever()) {
121 : AMT_LOG("Invalid vsync interval: forever\n");
122 0 : return;
123 : }
124 0 : double vsyncIntervalMs = aVsyncInterval.ToMilliseconds();
125 0 : if (vsyncIntervalMs < 1.0f) {
126 : // Guard to avoid division by zero or other crazy results below
127 : AMT_LOG("Invalid vsync interval: %fms\n", vsyncIntervalMs);
128 0 : return;
129 : }
130 :
131 : // We round the expectedFrameCount because it's a count and should be an
132 : // integer. The animationLength might not be an exact vsync multiple because
133 : // it's taken during the composition process and the amount of work done
134 : // between the vsync signal and the Timestamp::Now() call may vary slightly
135 : // from one composite to another.
136 0 : uint32_t expectedFrameCount = std::lround(animationLength.ToMilliseconds() / vsyncIntervalMs);
137 : AMT_LOG("Type %s ran for %fms (interval: %fms), %u frames (expected: %u)\n",
138 : aLabel, animationLength.ToMilliseconds(), vsyncIntervalMs,
139 : aAnimation.mFrameCount, expectedFrameCount);
140 0 : if (expectedFrameCount <= 0) {
141 : // Graceful handling of probably impossible thing, unless the clock
142 : // changes while running?
143 : // Note that we also skip the frames-dropped probe if this happens,
144 : // because we cannot be sure that the frame length measurements are valid.
145 0 : return;
146 : }
147 :
148 : // Scale up by 1000 because telemetry takes ints, truncate intentionally
149 : // to avoid artificial inflation of the result.
150 0 : uint32_t frameHitRatio = (uint32_t)(1000.0f * aAnimation.mFrameCount / expectedFrameCount);
151 0 : Telemetry::Accumulate(aThroughputHistogram, frameHitRatio);
152 : AMT_LOG("Reported frameHitRatio %u\n", frameHitRatio);
153 :
154 : // Get the longest frame time (make sure to check the final frame as well)
155 0 : TimeDuration longestFrame = std::max(aAnimation.mLongestFrame, now - aAnimation.mLastFrameTime);
156 : // As above, we round to get the frame count. Additionally we subtract one
157 : // from the frame count to get the number of dropped frames.
158 0 : uint32_t framesDropped = std::lround(longestFrame.ToMilliseconds() / vsyncIntervalMs) - 1;
159 : AMT_LOG("Longest frame was %fms (%d drops)\n", longestFrame.ToMilliseconds(), framesDropped);
160 0 : Telemetry::Accumulate(aMaxDropsHistogram, framesDropped);
161 : }
162 : }
163 :
164 : } // namespace layers
165 : } // namespace mozilla
|