Chromium Code Reviews| 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 |