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 #include <string> | 9 #include <string> |
| 10 | 10 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 | 35 |
| 36 } // namespace | 36 } // namespace |
| 37 | 37 |
| 38 // The following methods correspond to the DelayBasedTimeSource that uses | 38 // The following methods correspond to the DelayBasedTimeSource that uses |
| 39 // the base::TimeTicks::Now as the timebase. | 39 // the base::TimeTicks::Now as the timebase. |
| 40 DelayBasedTimeSource::DelayBasedTimeSource( | 40 DelayBasedTimeSource::DelayBasedTimeSource( |
| 41 base::TimeDelta interval, | 41 base::TimeDelta interval, |
| 42 base::SingleThreadTaskRunner* task_runner) | 42 base::SingleThreadTaskRunner* task_runner) |
| 43 : client_(NULL), | 43 : client_(NULL), |
| 44 last_tick_time_(base::TimeTicks() - interval), | 44 last_tick_time_(base::TimeTicks() - interval), |
| 45 current_parameters_(interval, base::TimeTicks()), | 45 next_tick_time_(base::TimeTicks()), |
| 46 next_parameters_(interval, base::TimeTicks()), | 46 timebase_(base::TimeTicks()), |
| 47 interval_(interval), | |
| 47 active_(false), | 48 active_(false), |
| 48 task_runner_(task_runner), | 49 task_runner_(task_runner), |
| 49 weak_factory_(this) { | 50 weak_factory_(this) { |
| 50 DCHECK_GT(interval.ToInternalValue(), 0); | 51 DCHECK_GT(interval, base::TimeDelta()); |
| 51 } | 52 } |
| 52 | 53 |
| 53 DelayBasedTimeSource::~DelayBasedTimeSource() {} | 54 DelayBasedTimeSource::~DelayBasedTimeSource() {} |
| 54 | 55 |
| 55 base::TimeTicks DelayBasedTimeSource::SetActive(bool active) { | 56 void DelayBasedTimeSource::SetActive(bool active) { |
| 56 TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active); | 57 TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active); |
| 57 if (active == active_) | 58 if (active == active_) |
| 58 return base::TimeTicks(); | 59 return; |
| 59 active_ = active; | 60 active_ = active; |
| 60 | 61 |
| 61 if (!active_) { | 62 if (!active_) { |
| 63 next_tick_time_ = base::TimeTicks(); | |
| 62 weak_factory_.InvalidateWeakPtrs(); | 64 weak_factory_.InvalidateWeakPtrs(); |
|
mithro-old
2015/06/30 08:11:52
It's really weird that this works by invalidating
| |
| 63 return base::TimeTicks(); | 65 return; |
| 64 } | 66 } |
| 65 | 67 |
| 66 PostNextTickTask(Now()); | 68 base::TimeTicks now = Now(); |
| 69 base::TimeTicks next_tick_target = NextTickTarget(now); | |
| 67 | 70 |
| 68 // Determine if there was a tick that was missed while not active. | 71 // Determine if there was a tick that was missed while not active. |
| 69 base::TimeTicks last_tick_time_if_always_active = | 72 base::TimeTicks last_tick_time_if_always_active = |
| 70 current_parameters_.tick_target - current_parameters_.interval; | 73 next_tick_target - interval_; |
| 71 base::TimeTicks new_tick_time_threshold = | 74 base::TimeTicks last_tick_time_threshold = |
| 72 last_tick_time_ + current_parameters_.interval / kDoubleTickDivisor; | 75 last_tick_time_ + interval_ / kDoubleTickDivisor; |
| 73 if (last_tick_time_if_always_active > new_tick_time_threshold) { | 76 if (last_tick_time_if_always_active > last_tick_time_threshold) { |
| 74 last_tick_time_ = last_tick_time_if_always_active; | 77 missed_tick_time_ = last_tick_time_if_always_active; |
| 75 return last_tick_time_; | 78 task_runner_->PostTask(FROM_HERE, |
| 79 base::Bind(&DelayBasedTimeSource::OnMissedTick, | |
|
brianderson
2015/06/26 19:24:35
Can you bind to a Closure (in the constructor and
| |
| 80 weak_factory_.GetWeakPtr())); | |
| 76 } | 81 } |
| 77 | 82 |
| 78 return base::TimeTicks(); | 83 PostNextTickTask(now); |
| 84 } | |
| 85 | |
| 86 base::TimeDelta DelayBasedTimeSource::Interval() const { | |
| 87 return interval_; | |
| 79 } | 88 } |
| 80 | 89 |
| 81 bool DelayBasedTimeSource::Active() const { return active_; } | 90 bool DelayBasedTimeSource::Active() const { return active_; } |
| 82 | 91 |
| 83 base::TimeTicks DelayBasedTimeSource::LastTickTime() const { | 92 base::TimeTicks DelayBasedTimeSource::LastTickTime() const { |
| 84 return last_tick_time_; | 93 return last_tick_time_; |
| 85 } | 94 } |
| 86 | 95 |
| 87 base::TimeTicks DelayBasedTimeSource::NextTickTime() const { | 96 base::TimeTicks DelayBasedTimeSource::MissedTickTime() const { |
|
brianderson
2015/06/26 19:24:34
Is this needed? Looks like Client::OnMissedTick ca
| |
| 88 return Active() ? current_parameters_.tick_target : base::TimeTicks(); | 97 return missed_tick_time_; |
| 89 } | 98 } |
| 90 | 99 |
| 91 void DelayBasedTimeSource::OnTimerFired() { | 100 base::TimeTicks DelayBasedTimeSource::NextTickTime() const { |
| 101 return next_tick_time_; | |
|
brianderson
2015/06/26 19:24:34
Probably doesn't matter for the current user of th
| |
| 102 } | |
| 103 | |
| 104 void DelayBasedTimeSource::OnMissedTick() { | |
|
brianderson
2015/06/26 19:24:34
Should missed_tick_time_ be reset somewhere in thi
| |
| 92 DCHECK(active_); | 105 DCHECK(active_); |
| 93 | 106 |
| 94 last_tick_time_ = current_parameters_.tick_target; | 107 last_tick_time_ = missed_tick_time_; |
| 108 | |
| 109 if (client_) | |
| 110 client_->OnMissedTick(); | |
| 111 } | |
| 112 | |
| 113 void DelayBasedTimeSource::OnTimerTick() { | |
| 114 DCHECK(active_); | |
| 115 | |
| 116 last_tick_time_ = next_tick_time_; | |
| 95 | 117 |
| 96 PostNextTickTask(Now()); | 118 PostNextTickTask(Now()); |
| 97 | 119 |
| 98 // Fire the tick. | 120 // Fire the tick. |
| 99 if (client_) | 121 if (client_) |
| 100 client_->OnTimerTick(); | 122 client_->OnTimerTick(); |
| 101 } | 123 } |
| 102 | 124 |
| 103 void DelayBasedTimeSource::SetClient(TimeSourceClient* client) { | 125 void DelayBasedTimeSource::SetClient(DelayBasedTimeSourceClient* client) { |
| 104 client_ = client; | 126 client_ = client; |
| 105 } | 127 } |
| 106 | 128 |
| 107 void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase, | 129 void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase, |
| 108 base::TimeDelta interval) { | 130 base::TimeDelta interval) { |
| 109 DCHECK_GT(interval.ToInternalValue(), 0); | 131 DCHECK_GT(interval, base::TimeDelta()); |
| 110 next_parameters_.interval = interval; | |
| 111 next_parameters_.tick_target = timebase; | |
| 112 | |
| 113 if (!active_) { | |
| 114 // If we aren't active, there's no need to reset the timer. | |
| 115 return; | |
| 116 } | |
| 117 | 132 |
| 118 // If the change in interval is larger than the change threshold, | 133 // If the change in interval is larger than the change threshold, |
| 119 // request an immediate reset. | 134 // request an immediate reset. |
| 120 double interval_delta = | 135 double interval_delta = std::abs((interval - interval_).InSecondsF()); |
| 121 std::abs((interval - current_parameters_.interval).InSecondsF()); | 136 double target_delta = std::abs((timebase - timebase_).InSecondsF()); |
| 137 | |
| 138 interval_ = interval; | |
| 139 timebase_ = timebase; | |
| 140 | |
| 141 // If we aren't active, there's no need to reset the timer. | |
| 142 if (!active_) | |
| 143 return; | |
| 144 | |
| 122 double interval_change = interval_delta / interval.InSecondsF(); | 145 double interval_change = interval_delta / interval.InSecondsF(); |
| 123 if (interval_change > kIntervalChangeThreshold) { | 146 if (interval_change > kIntervalChangeThreshold) { |
| 124 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::IntervalChanged", | 147 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::IntervalChanged", |
| 125 TRACE_EVENT_SCOPE_THREAD); | 148 TRACE_EVENT_SCOPE_THREAD); |
| 126 SetActive(false); | 149 ResetTickTask(Now()); |
| 127 SetActive(true); | |
| 128 return; | 150 return; |
| 129 } | 151 } |
| 130 | 152 |
| 131 // If the change in phase is greater than the change threshold in either | 153 // 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 | 154 // 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 | 155 // 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 | 156 // 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 | 157 // 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. | 158 // old clock and new clock just happen to line up. |
| 137 double target_delta = | |
| 138 std::abs((timebase - current_parameters_.tick_target).InSecondsF()); | |
| 139 double phase_change = | 159 double phase_change = |
| 140 fmod(target_delta, interval.InSecondsF()) / interval.InSecondsF(); | 160 fmod(target_delta, interval.InSecondsF()) / interval.InSecondsF(); |
| 141 if (phase_change > kPhaseChangeThreshold && | 161 if (phase_change > kPhaseChangeThreshold && |
| 142 phase_change < (1.0 - kPhaseChangeThreshold)) { | 162 phase_change < (1.0 - kPhaseChangeThreshold)) { |
| 143 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::PhaseChanged", | 163 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::PhaseChanged", |
| 144 TRACE_EVENT_SCOPE_THREAD); | 164 TRACE_EVENT_SCOPE_THREAD); |
| 145 SetActive(false); | 165 ResetTickTask(Now()); |
| 146 SetActive(true); | |
| 147 return; | 166 return; |
| 148 } | 167 } |
| 149 } | 168 } |
| 150 | 169 |
| 151 base::TimeTicks DelayBasedTimeSource::Now() const { | 170 base::TimeTicks DelayBasedTimeSource::Now() const { |
| 152 return base::TimeTicks::Now(); | 171 return base::TimeTicks::Now(); |
| 153 } | 172 } |
| 154 | 173 |
| 155 // This code tries to achieve an average tick rate as close to interval_ as | 174 // This code tries to achieve an average tick rate as close to interval_ as |
| 156 // possible. To do this, it has to deal with a few basic issues: | 175 // possible. To do this, it has to deal with a few basic issues: |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 // Thus, we compute the new_target based on the old timebase: | 218 // Thus, we compute the new_target based on the old timebase: |
| 200 // now=18 tick_target=16.667 new_target=33.333 --> | 219 // now=18 tick_target=16.667 new_target=33.333 --> |
| 201 // tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15) | 220 // tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15) |
| 202 // This brings us back to 18+15 = 33, which was where we would have been if the | 221 // This brings us back to 18+15 = 33, which was where we would have been if the |
| 203 // task hadn't been late. | 222 // task hadn't been late. |
| 204 // | 223 // |
| 205 // For the really late delay, we we move to the next logical tick. The timebase | 224 // For the really late delay, we we move to the next logical tick. The timebase |
| 206 // is not reset. | 225 // is not reset. |
| 207 // now=37 tick_target=16.667 new_target=50.000 --> | 226 // now=37 tick_target=16.667 new_target=50.000 --> |
| 208 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13) | 227 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13) |
| 209 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) { | 228 base::TimeTicks DelayBasedTimeSource::NextTickTarget( |
| 210 base::TimeTicks new_tick_target = now.SnappedToNextTick( | 229 base::TimeTicks now) const { |
| 211 next_parameters_.tick_target, next_parameters_.interval); | 230 base::TimeTicks next_tick_target = |
| 212 DCHECK(now <= new_tick_target) | 231 now.SnappedToNextTick(timebase_, interval_); |
| 232 DCHECK(now <= next_tick_target) | |
| 213 << "now = " << now.ToInternalValue() | 233 << "now = " << now.ToInternalValue() |
| 214 << "; new_tick_target = " << new_tick_target.ToInternalValue() | 234 << "; new_tick_target = " << next_tick_target.ToInternalValue() |
| 215 << "; new_interval = " << next_parameters_.interval.InMicroseconds() | 235 << "; new_interval = " << interval_.InMicroseconds() |
| 216 << "; tick_target = " << next_parameters_.tick_target.ToInternalValue(); | 236 << "; tick_target = " << timebase_.ToInternalValue(); |
| 217 | 237 |
| 218 // Avoid double ticks when: | 238 // Avoid double ticks when: |
| 219 // 1) Turning off the timer and turning it right back on. | 239 // 1) Turning off the timer and turning it right back on. |
| 220 // 2) Jittery data is passed to SetTimebaseAndInterval(). | 240 // 2) Jittery data is passed to SetTimebaseAndInterval(). |
| 221 if (new_tick_target - last_tick_time_ <= | 241 if (next_tick_target - last_tick_time_ <= interval_ / kDoubleTickDivisor) |
| 222 next_parameters_.interval / kDoubleTickDivisor) | 242 next_tick_target += interval_; |
| 223 new_tick_target += next_parameters_.interval; | |
| 224 | 243 |
| 225 return new_tick_target; | 244 return next_tick_target; |
| 226 } | 245 } |
| 227 | 246 |
| 228 void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) { | 247 void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) { |
| 229 base::TimeTicks new_tick_target = NextTickTarget(now); | 248 base::TimeTicks next_tick_target = NextTickTarget(now); |
| 230 | 249 DCHECK(next_tick_target >= now); |
| 231 // Post another task *before* the tick and update state | 250 // Post another task *before* the tick and update state |
| 232 base::TimeDelta delay; | 251 base::TimeDelta delay = next_tick_target - now; |
| 233 if (now <= new_tick_target) | |
| 234 delay = new_tick_target - now; | |
| 235 task_runner_->PostDelayedTask(FROM_HERE, | 252 task_runner_->PostDelayedTask(FROM_HERE, |
| 236 base::Bind(&DelayBasedTimeSource::OnTimerFired, | 253 base::Bind(&DelayBasedTimeSource::OnTimerTick, |
|
brianderson
2015/06/26 19:24:35
Ditto regarding dynamic bind.
| |
| 237 weak_factory_.GetWeakPtr()), | 254 weak_factory_.GetWeakPtr()), |
| 238 delay); | 255 delay); |
| 239 | 256 |
| 240 next_parameters_.tick_target = new_tick_target; | 257 next_tick_time_ = next_tick_target; |
| 241 current_parameters_ = next_parameters_; | 258 } |
| 259 | |
| 260 void DelayBasedTimeSource::ResetTickTask(base::TimeTicks now) { | |
| 261 weak_factory_.InvalidateWeakPtrs(); | |
| 262 PostNextTickTask(now); | |
| 242 } | 263 } |
| 243 | 264 |
| 244 std::string DelayBasedTimeSource::TypeString() const { | 265 std::string DelayBasedTimeSource::TypeString() const { |
| 245 return "DelayBasedTimeSource"; | 266 return "DelayBasedTimeSource"; |
| 246 } | 267 } |
| 247 | 268 |
| 248 void DelayBasedTimeSource::AsValueInto( | 269 void DelayBasedTimeSource::AsValueInto( |
| 249 base::trace_event::TracedValue* state) const { | 270 base::trace_event::TracedValue* state) const { |
| 250 state->SetString("type", TypeString()); | 271 state->SetString("type", TypeString()); |
| 251 state->SetDouble("last_tick_time_us", LastTickTime().ToInternalValue()); | 272 state->SetDouble("last_tick_time_us", LastTickTime().ToInternalValue()); |
| 273 state->SetDouble("missed_tick_time_us", MissedTickTime().ToInternalValue()); | |
| 252 state->SetDouble("next_tick_time_us", NextTickTime().ToInternalValue()); | 274 state->SetDouble("next_tick_time_us", NextTickTime().ToInternalValue()); |
| 253 | 275 state->SetDouble("interval_us", interval_.InMicroseconds()); |
| 254 state->BeginDictionary("current_parameters"); | 276 state->SetDouble("timebase_us", timebase_.ToInternalValue()); |
| 255 state->SetDouble("interval_us", | |
| 256 current_parameters_.interval.InMicroseconds()); | |
| 257 state->SetDouble("tick_target_us", | |
| 258 current_parameters_.tick_target.ToInternalValue()); | |
| 259 state->EndDictionary(); | |
| 260 | |
| 261 state->BeginDictionary("next_parameters"); | |
| 262 state->SetDouble("interval_us", next_parameters_.interval.InMicroseconds()); | |
| 263 state->SetDouble("tick_target_us", | |
| 264 next_parameters_.tick_target.ToInternalValue()); | |
| 265 state->EndDictionary(); | |
| 266 | |
| 267 state->SetBoolean("active", active_); | 277 state->SetBoolean("active", active_); |
| 268 } | 278 } |
| 269 | 279 |
| 270 } // namespace cc | 280 } // namespace cc |
| OLD | NEW |