OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "cc/debug/frame_rate_counter.h" | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
9 | |
10 #include "base/metrics/histogram.h" | |
11 #include "cc/trees/proxy.h" | |
12 | |
13 namespace cc { | |
14 | |
15 // The following constants are measured in seconds. | |
16 | |
17 // Two thresholds (measured in seconds) that describe what is considered to be a | |
18 // "no-op frame" that should not be counted. | |
19 // - if the frame is too fast, then given our compositor implementation, the | |
20 // frame probably was a no-op and did not draw. | |
21 // - if the frame is too slow, then there is probably not animating content, so | |
22 // we should not pollute the average. | |
23 static const double kFrameTooFast = 1.0 / 70.0; | |
24 static const double kFrameTooSlow = 1.0 / 4.0; | |
25 | |
26 // If a frame takes longer than this threshold (measured in seconds) then we | |
27 // (naively) assume that it missed a screen refresh; that is, we dropped a | |
28 // frame. | |
29 // TODO(brianderson): Determine this threshold based on monitor refresh rate, | |
30 // crbug.com/138642. | |
31 static const double kDroppedFrameTime = 1.0 / 50.0; | |
32 | |
33 // static | |
34 scoped_ptr<FrameRateCounter> FrameRateCounter::Create(bool has_impl_thread) { | |
35 return make_scoped_ptr(new FrameRateCounter(has_impl_thread)); | |
36 } | |
37 | |
38 base::TimeDelta FrameRateCounter::RecentFrameInterval(size_t n) const { | |
39 DCHECK_GT(n, 0u); | |
40 DCHECK_LT(n, ring_buffer_.BufferSize()); | |
41 return ring_buffer_.ReadBuffer(n) - ring_buffer_.ReadBuffer(n - 1); | |
42 } | |
43 | |
44 FrameRateCounter::FrameRateCounter(bool has_impl_thread) | |
45 : has_impl_thread_(has_impl_thread), dropped_frame_count_(0) {} | |
46 | |
47 void FrameRateCounter::SaveTimeStamp(base::TimeTicks timestamp, bool software) { | |
48 ring_buffer_.SaveToBuffer(timestamp); | |
49 | |
50 // Check if frame interval can be computed. | |
51 if (ring_buffer_.CurrentIndex() < 2) | |
52 return; | |
53 | |
54 base::TimeDelta frame_interval_seconds = | |
55 RecentFrameInterval(ring_buffer_.BufferSize() - 1); | |
56 | |
57 if (has_impl_thread_ && ring_buffer_.CurrentIndex() > 0) { | |
58 if (software) { | |
59 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
60 "Renderer4.SoftwareCompositorThreadImplDrawDelay", | |
61 frame_interval_seconds.InMilliseconds(), | |
62 1, | |
63 120, | |
64 60); | |
65 } else { | |
66 UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CompositorThreadImplDrawDelay", | |
67 frame_interval_seconds.InMilliseconds(), | |
68 1, | |
69 120, | |
70 60); | |
71 } | |
72 } | |
73 | |
74 if (!IsBadFrameInterval(frame_interval_seconds) && | |
75 frame_interval_seconds.InSecondsF() > kDroppedFrameTime) | |
76 dropped_frame_count_ += | |
77 frame_interval_seconds.InSecondsF() / kDroppedFrameTime; | |
78 } | |
79 | |
80 bool FrameRateCounter::IsBadFrameInterval( | |
81 base::TimeDelta interval_between_consecutive_frames) const { | |
82 double delta = interval_between_consecutive_frames.InSecondsF(); | |
83 bool scheduler_allows_double_frames = !has_impl_thread_; | |
84 bool interval_too_fast = | |
85 scheduler_allows_double_frames ? delta < kFrameTooFast : delta <= 0.0; | |
86 bool interval_too_slow = delta > kFrameTooSlow; | |
87 return interval_too_fast || interval_too_slow; | |
88 } | |
89 | |
90 void FrameRateCounter::GetMinAndMaxFPS(double* min_fps, double* max_fps) const { | |
91 *min_fps = std::numeric_limits<double>::max(); | |
92 *max_fps = 0.0; | |
93 | |
94 for (RingBufferType::Iterator it = --ring_buffer_.End(); it; --it) { | |
95 base::TimeDelta delta = RecentFrameInterval(it.index() + 1); | |
96 | |
97 if (IsBadFrameInterval(delta)) | |
98 continue; | |
99 | |
100 DCHECK_GT(delta.InSecondsF(), 0.f); | |
101 double fps = 1.0 / delta.InSecondsF(); | |
102 | |
103 *min_fps = std::min(fps, *min_fps); | |
104 *max_fps = std::max(fps, *max_fps); | |
105 } | |
106 | |
107 if (*min_fps > *max_fps) | |
108 *min_fps = *max_fps; | |
109 } | |
110 | |
111 double FrameRateCounter::GetAverageFPS() const { | |
112 int frame_count = 0; | |
113 double frame_times_total = 0.0; | |
114 double average_fps = 0.0; | |
115 | |
116 // Walk backwards through the samples looking for a run of good frame | |
117 // timings from which to compute the mean. | |
118 // | |
119 // Slow frames occur just because the user is inactive, and should be | |
120 // ignored. Fast frames are ignored if the scheduler is in single-thread | |
121 // mode in order to represent the true frame rate in spite of the fact that | |
122 // the first few swapbuffers happen instantly which skews the statistics | |
123 // too much for short lived animations. | |
124 // | |
125 // IsBadFrameInterval encapsulates the frame too slow/frame too fast logic. | |
126 | |
127 for (RingBufferType::Iterator it = --ring_buffer_.End(); | |
128 it && frame_times_total < 1.0; | |
129 --it) { | |
130 base::TimeDelta delta = RecentFrameInterval(it.index() + 1); | |
131 | |
132 if (!IsBadFrameInterval(delta)) { | |
133 frame_count++; | |
134 frame_times_total += delta.InSecondsF(); | |
135 } else if (frame_count) { | |
136 break; | |
137 } | |
138 } | |
139 | |
140 if (frame_count) { | |
141 DCHECK_GT(frame_times_total, 0.0); | |
142 average_fps = frame_count / frame_times_total; | |
143 } | |
144 | |
145 return average_fps; | |
146 } | |
147 | |
148 } // namespace cc | |
OLD | NEW |