1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/frame_rate_counter.h"
9 #include "base/metrics/histogram.h"
14 const double FrameRateCounter::kFrameTooFast
= 1.0 / 70.0; // measured in seconds
15 const double FrameRateCounter::kFrameTooSlow
= 1.0 / 4.0;
16 const double FrameRateCounter::kDroppedFrameTime
= 1.0 / 50.0;
18 // safeMod works on -1, returning m-1 in that case.
19 static inline int safeMod(int number
, int modulus
)
21 return (number
+ modulus
) % modulus
;
25 scoped_ptr
<FrameRateCounter
> FrameRateCounter::create(bool hasImplThread
) {
26 return make_scoped_ptr(new FrameRateCounter(hasImplThread
));
29 inline base::TimeDelta
FrameRateCounter::frameInterval(int frameNumber
) const
31 return m_timeStampHistory
[frameIndex(frameNumber
)] -
32 m_timeStampHistory
[frameIndex(frameNumber
- 1)];
35 inline int FrameRateCounter::frameIndex(int frameNumber
) const
37 return safeMod(frameNumber
, kTimeStampHistorySize
);
40 FrameRateCounter::FrameRateCounter(bool hasImplThread
)
41 : m_hasImplThread(hasImplThread
)
42 , m_currentFrameNumber(1)
43 , m_droppedFrameCount(0)
45 m_timeStampHistory
[0] = base::TimeTicks::Now();
46 m_timeStampHistory
[1] = m_timeStampHistory
[0];
47 for (int i
= 2; i
< kTimeStampHistorySize
; i
++)
48 m_timeStampHistory
[i
] = base::TimeTicks();
51 void FrameRateCounter::markBeginningOfFrame(base::TimeTicks timestamp
)
53 m_timeStampHistory
[frameIndex(m_currentFrameNumber
)] = timestamp
;
54 base::TimeDelta frameIntervalSeconds
= frameInterval(m_currentFrameNumber
);
56 if (m_hasImplThread
&& m_currentFrameNumber
> 0) {
57 HISTOGRAM_CUSTOM_COUNTS("Renderer4.CompositorThreadImplDrawDelay", frameIntervalSeconds
.InMilliseconds(), 1, 120, 60);
60 if (!isBadFrameInterval(frameIntervalSeconds
) &&
61 frameIntervalSeconds
.InSecondsF() > kDroppedFrameTime
)
62 ++m_droppedFrameCount
;
65 void FrameRateCounter::markEndOfFrame()
67 m_currentFrameNumber
+= 1;
70 bool FrameRateCounter::isBadFrameInterval(base::TimeDelta intervalBetweenConsecutiveFrames
) const
72 double delta
= intervalBetweenConsecutiveFrames
.InSecondsF();
73 bool schedulerAllowsDoubleFrames
= !m_hasImplThread
;
74 bool intervalTooFast
= schedulerAllowsDoubleFrames
? delta
< kFrameTooFast
: delta
<= 0.0;
75 bool intervalTooSlow
= delta
> kFrameTooSlow
;
76 return intervalTooFast
|| intervalTooSlow
;
79 bool FrameRateCounter::isBadFrame(int frameNumber
) const
81 return isBadFrameInterval(frameInterval(frameNumber
));
84 double FrameRateCounter::getAverageFPS() const
86 int frameNumber
= m_currentFrameNumber
- 1;
88 double frameTimesTotal
= 0;
89 double averageFPS
= 0;
91 // Walk backwards through the samples looking for a run of good frame
92 // timings from which to compute the mean.
94 // Slow frames occur just because the user is inactive, and should be
95 // ignored. Fast frames are ignored if the scheduler is in single-thread
96 // mode in order to represent the true frame rate in spite of the fact that
97 // the first few swapbuffers happen instantly which skews the statistics
98 // too much for short lived animations.
100 // isBadFrameInterval encapsulates the frame too slow/frame too fast logic.
102 while (frameIndex(frameNumber
) != frameIndex(m_currentFrameNumber
) && frameNumber
>= 0 && frameTimesTotal
< 1.0) {
103 base::TimeDelta delta
= frameInterval(frameNumber
);
105 if (!isBadFrameInterval(delta
)) {
107 frameTimesTotal
+= delta
.InSecondsF();
108 } else if (frameCount
)
115 averageFPS
= frameCount
/ frameTimesTotal
;
120 base::TimeTicks
FrameRateCounter::timeStampOfRecentFrame(int n
) const
123 DCHECK(n
< kTimeStampHistorySize
);
124 int desiredIndex
= (frameIndex(m_currentFrameNumber
) + n
) % kTimeStampHistorySize
;
125 return m_timeStampHistory
[desiredIndex
];