OLD | NEW |
---|---|
1 // Copyright 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/scheduler/delay_based_time_source.h" | 5 #include "cc/scheduler/delay_based_time_source.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
13 | 13 |
14 namespace cc { | 14 namespace cc { |
15 | 15 |
16 namespace { | 16 namespace { |
17 | 17 |
18 // kDoubleTickThreshold prevents ticks from running within the specified | 18 // kDoubleTickDivisor prevents ticks from running within the specified |
19 // fraction of an interval. This helps account for jitter in the timebase as | 19 // fraction of an interval. This helps account for jitter in the timebase as |
20 // well as quick timer reactivation. | 20 // well as quick timer reactivation. |
21 static const double kDoubleTickThreshold = 0.25; | 21 static const int kDoubleTickDivisor = 4; |
brianderson
2013/07/03 00:01:54
We can divide TimeTicks so I switched this to a di
| |
22 | 22 |
23 // kIntervalChangeThreshold is the fraction of the interval that will trigger an | 23 // kIntervalChangeThreshold is the fraction of the interval that will trigger an |
24 // immediate interval change. kPhaseChangeThreshold is the fraction of the | 24 // immediate interval change. kPhaseChangeThreshold is the fraction of the |
25 // interval that will trigger an immediate phase change. If the changes are | 25 // interval that will trigger an immediate phase change. If the changes are |
26 // within the thresholds, the change will take place on the next tick. If | 26 // within the thresholds, the change will take place on the next tick. If |
27 // either change is outside the thresholds, the next tick will be canceled and | 27 // either change is outside the thresholds, the next tick will be canceled and |
28 // reissued immediately. | 28 // reissued immediately. |
29 static const double kIntervalChangeThreshold = 0.25; | 29 static const double kIntervalChangeThreshold = 0.25; |
30 static const double kPhaseChangeThreshold = 0.25; | 30 static const double kPhaseChangeThreshold = 0.25; |
31 | 31 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 | 80 |
81 base::TimeTicks DelayBasedTimeSource::LastTickTime() { return last_tick_time_; } | 81 base::TimeTicks DelayBasedTimeSource::LastTickTime() { return last_tick_time_; } |
82 | 82 |
83 base::TimeTicks DelayBasedTimeSource::NextTickTime() { | 83 base::TimeTicks DelayBasedTimeSource::NextTickTime() { |
84 return Active() ? current_parameters_.tick_target : base::TimeTicks(); | 84 return Active() ? current_parameters_.tick_target : base::TimeTicks(); |
85 } | 85 } |
86 | 86 |
87 void DelayBasedTimeSource::OnTimerFired() { | 87 void DelayBasedTimeSource::OnTimerFired() { |
88 DCHECK(state_ != STATE_INACTIVE); | 88 DCHECK(state_ != STATE_INACTIVE); |
89 | 89 |
90 last_tick_time_ = current_parameters_.tick_target; | |
brianderson
2013/07/03 00:01:54
Instead of setting the last_tick_time_ to the time
| |
91 | |
90 base::TimeTicks now = this->Now(); | 92 base::TimeTicks now = this->Now(); |
91 last_tick_time_ = now; | 93 if (state_ == STATE_STARTING) |
92 | |
93 if (state_ == STATE_STARTING) { | |
94 SetTimebaseAndInterval(now, current_parameters_.interval); | |
95 state_ = STATE_ACTIVE; | 94 state_ = STATE_ACTIVE; |
96 } | |
97 | 95 |
98 PostNextTickTask(now); | 96 PostNextTickTask(now); |
99 | 97 |
100 // Fire the tick. | 98 // Fire the tick. |
101 if (client_) | 99 if (client_) |
102 client_->OnTimerTick(); | 100 client_->OnTimerTick(); |
103 } | 101 } |
104 | 102 |
105 void DelayBasedTimeSource::SetClient(TimeSourceClient* client) { | 103 void DelayBasedTimeSource::SetClient(TimeSourceClient* client) { |
106 client_ = client; | 104 client_ = client; |
107 } | 105 } |
108 | 106 |
109 void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase, | 107 void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase, |
110 base::TimeDelta interval) { | 108 base::TimeDelta interval) { |
111 next_parameters_.interval = interval; | 109 next_parameters_.interval = interval; |
112 next_parameters_.tick_target = timebase; | 110 next_parameters_.tick_target = timebase; |
113 has_tick_target_ = true; | 111 has_tick_target_ = true; |
114 | 112 |
115 if (state_ != STATE_ACTIVE) { | 113 if (state_ != STATE_ACTIVE) { |
116 // If we aren't active, there's no need to reset the timer. | 114 // If we aren't active, there's no need to reset the timer. |
117 return; | 115 return; |
118 } | 116 } |
119 | 117 |
120 // If the change in interval is larger than the change threshold, | 118 // If the change in interval is larger than the change threshold, |
121 // request an immediate reset. | 119 // request an immediate reset. |
122 double interval_delta = | 120 double interval_delta = |
123 std::abs((interval - current_parameters_.interval).InSecondsF()); | 121 std::abs((interval - current_parameters_.interval).InSecondsF()); |
124 double interval_change = interval_delta / interval.InSecondsF(); | 122 double interval_change = interval_delta / interval.InSecondsF(); |
125 if (interval_change > kIntervalChangeThreshold) { | 123 if (interval_change > kIntervalChangeThreshold) { |
124 TRACE_EVENT0("cc", "DelayBasedTimeSource::IntervalChanged"); | |
126 SetActive(false); | 125 SetActive(false); |
127 SetActive(true); | 126 SetActive(true); |
128 return; | 127 return; |
129 } | 128 } |
130 | 129 |
131 // If the change in phase is greater than the change threshold in either | 130 // If the change in phase is greater than the change threshold in either |
132 // direction, request an immediate reset. This logic might result in a false | 131 // direction, request an immediate reset. This logic might result in a false |
133 // negative if there is a simultaneous small change in the interval and the | 132 // negative if there is a simultaneous small change in the interval and the |
134 // fmod just happens to return something near zero. Assuming the timebase | 133 // fmod just happens to return something near zero. Assuming the timebase |
135 // is very recent though, which it should be, we'll still be ok because the | 134 // is very recent though, which it should be, we'll still be ok because the |
136 // old clock and new clock just happen to line up. | 135 // old clock and new clock just happen to line up. |
137 double target_delta = | 136 double target_delta = |
138 std::abs((timebase - current_parameters_.tick_target).InSecondsF()); | 137 std::abs((timebase - current_parameters_.tick_target).InSecondsF()); |
139 double phase_change = | 138 double phase_change = |
140 fmod(target_delta, interval.InSecondsF()) / interval.InSecondsF(); | 139 fmod(target_delta, interval.InSecondsF()) / interval.InSecondsF(); |
141 if (phase_change > kPhaseChangeThreshold && | 140 if (phase_change > kPhaseChangeThreshold && |
142 phase_change < (1.0 - kPhaseChangeThreshold)) { | 141 phase_change < (1.0 - kPhaseChangeThreshold)) { |
142 TRACE_EVENT0("cc", "DelayBasedTimeSource::PhaseChanged"); | |
brianderson
2013/07/03 00:01:54
IntervalChanged and PhaseChanged show up way too o
| |
143 SetActive(false); | 143 SetActive(false); |
144 SetActive(true); | 144 SetActive(true); |
145 return; | 145 return; |
146 } | 146 } |
147 } | 147 } |
148 | 148 |
149 base::TimeTicks DelayBasedTimeSource::Now() const { | 149 base::TimeTicks DelayBasedTimeSource::Now() const { |
150 return base::TimeTicks::Now(); | 150 return base::TimeTicks::Now(); |
151 } | 151 } |
152 | 152 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
199 // tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15) | 199 // tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15) |
200 // This brings us back to 18+15 = 33, which was where we would have been if the | 200 // This brings us back to 18+15 = 33, which was where we would have been if the |
201 // task hadn't been late. | 201 // task hadn't been late. |
202 // | 202 // |
203 // For the really late delay, we we move to the next logical tick. The timebase | 203 // For the really late delay, we we move to the next logical tick. The timebase |
204 // is not reset. | 204 // is not reset. |
205 // now=37 tick_target=16.667 new_target=50.000 --> | 205 // now=37 tick_target=16.667 new_target=50.000 --> |
206 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13) | 206 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13) |
207 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) { | 207 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) { |
208 base::TimeDelta new_interval = next_parameters_.interval; | 208 base::TimeDelta new_interval = next_parameters_.interval; |
209 int intervals_elapsed = | 209 int intervals_elapsed = (now - next_parameters_.tick_target) / new_interval; |
brianderson
2013/07/03 00:01:54
Goodbye floating point math.
| |
210 static_cast<int>(floor((now - next_parameters_.tick_target).InSecondsF() / | |
211 new_interval.InSecondsF())); | |
212 base::TimeTicks last_effective_tick = | 210 base::TimeTicks last_effective_tick = |
213 next_parameters_.tick_target + new_interval * intervals_elapsed; | 211 next_parameters_.tick_target + new_interval * intervals_elapsed; |
214 base::TimeTicks new_tick_target = last_effective_tick + new_interval; | 212 base::TimeTicks new_tick_target = last_effective_tick + new_interval; |
215 DCHECK(now < new_tick_target) | 213 DCHECK(now < new_tick_target) |
216 << "now = " << now.ToInternalValue() | 214 << "now = " << now.ToInternalValue() |
217 << "; new_tick_target = " << new_tick_target.ToInternalValue() | 215 << "; new_tick_target = " << new_tick_target.ToInternalValue() |
218 << "; new_interval = " << new_interval.InMicroseconds() | 216 << "; new_interval = " << new_interval.InMicroseconds() |
219 << "; tick_target = " << next_parameters_.tick_target.ToInternalValue() | 217 << "; tick_target = " << next_parameters_.tick_target.ToInternalValue() |
220 << "; intervals_elapsed = " << intervals_elapsed | 218 << "; intervals_elapsed = " << intervals_elapsed |
221 << "; last_effective_tick = " << last_effective_tick.ToInternalValue(); | 219 << "; last_effective_tick = " << last_effective_tick.ToInternalValue(); |
222 | 220 |
223 // Avoid double ticks when: | 221 // Avoid double ticks when: |
224 // 1) Turning off the timer and turning it right back on. | 222 // 1) Turning off the timer and turning it right back on. |
225 // 2) Jittery data is passed to SetTimebaseAndInterval(). | 223 // 2) Jittery data is passed to SetTimebaseAndInterval(). |
226 if (new_tick_target - last_tick_time_ <= | 224 if (new_tick_target - last_tick_time_ <= new_interval / kDoubleTickDivisor) |
brianderson
2013/07/03 00:01:54
Goodbye more floating point math.
| |
227 new_interval / static_cast<int>(1.0 / kDoubleTickThreshold)) | |
228 new_tick_target += new_interval; | 225 new_tick_target += new_interval; |
229 | 226 |
230 return new_tick_target; | 227 return new_tick_target; |
231 } | 228 } |
232 | 229 |
233 void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) { | 230 void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) { |
234 base::TimeTicks new_tick_target = NextTickTarget(now); | 231 base::TimeTicks new_tick_target = NextTickTarget(now); |
235 | 232 |
236 // Post another task *before* the tick and update state | 233 // Post another task *before* the tick and update state |
237 base::TimeDelta delay = new_tick_target - now; | 234 base::TimeDelta delay; |
238 DCHECK(delay.InMillisecondsF() <= | 235 if (new_tick_target > now) |
239 next_parameters_.interval.InMillisecondsF() * | 236 delay = new_tick_target - now; |
240 (1.0 + kDoubleTickThreshold)); | |
241 task_runner_->PostDelayedTask(FROM_HERE, | 237 task_runner_->PostDelayedTask(FROM_HERE, |
242 base::Bind(&DelayBasedTimeSource::OnTimerFired, | 238 base::Bind(&DelayBasedTimeSource::OnTimerFired, |
243 weak_factory_.GetWeakPtr()), | 239 weak_factory_.GetWeakPtr()), |
244 delay); | 240 delay); |
245 | 241 |
246 next_parameters_.tick_target = new_tick_target; | 242 next_parameters_.tick_target = new_tick_target; |
247 current_parameters_ = next_parameters_; | 243 current_parameters_ = next_parameters_; |
248 } | 244 } |
249 | 245 |
250 } // namespace cc | 246 } // namespace cc |
OLD | NEW |