Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(228)

Side by Side Diff: cc/scheduler/delay_based_time_source.cc

Issue 1200113003: cc: Cleanup DelayBasedTimeSource code. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@task_runner_refptr
Patch Set: mithro's review Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 22 matching lines...) Expand all
33 static const double kIntervalChangeThreshold = 0.25; 33 static const double kIntervalChangeThreshold = 0.25;
34 static const double kPhaseChangeThreshold = 0.25; 34 static const double kPhaseChangeThreshold = 0.25;
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_(nullptr),
44 active_(false),
45 timebase_(base::TimeTicks()),
46 interval_(interval),
44 last_tick_time_(base::TimeTicks() - interval), 47 last_tick_time_(base::TimeTicks() - interval),
45 current_parameters_(interval, base::TimeTicks()), 48 next_tick_time_(base::TimeTicks()),
46 next_parameters_(interval, base::TimeTicks()),
47 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 base::TimeTicks DelayBasedTimeSource::SetActive(bool active) {
56 TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active); 57 TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active);
58
57 if (active == active_) 59 if (active == active_)
58 return base::TimeTicks(); 60 return base::TimeTicks();
61
59 active_ = active; 62 active_ = active;
60 63
61 if (!active_) { 64 if (!active_) {
62 weak_factory_.InvalidateWeakPtrs(); 65 next_tick_time_ = base::TimeTicks();
66 tick_closure_.Cancel();
63 return base::TimeTicks(); 67 return base::TimeTicks();
64 } 68 }
65 69
66 PostNextTickTask(Now()); 70 ResetTickTask(Now());
67 71
68 // Determine if there was a tick that was missed while not active. 72 // Determine if there was a tick that was missed while not active.
69 base::TimeTicks last_tick_time_if_always_active = 73 base::TimeTicks last_tick_time_if_always_active = next_tick_time_ - interval_;
70 current_parameters_.tick_target - current_parameters_.interval; 74 base::TimeTicks last_tick_time_threshold =
71 base::TimeTicks new_tick_time_threshold = 75 last_tick_time_ + interval_ / kDoubleTickDivisor;
72 last_tick_time_ + current_parameters_.interval / kDoubleTickDivisor; 76 if (last_tick_time_if_always_active > last_tick_time_threshold) {
73 if (last_tick_time_if_always_active > new_tick_time_threshold) {
74 last_tick_time_ = last_tick_time_if_always_active; 77 last_tick_time_ = last_tick_time_if_always_active;
75 return last_tick_time_; 78 return last_tick_time_;
76 } 79 }
77 80
78 return base::TimeTicks(); 81 return base::TimeTicks();
79 } 82 }
80 83
84 base::TimeDelta DelayBasedTimeSource::Interval() const {
85 return interval_;
86 }
87
81 bool DelayBasedTimeSource::Active() const { return active_; } 88 bool DelayBasedTimeSource::Active() const { return active_; }
82 89
83 base::TimeTicks DelayBasedTimeSource::LastTickTime() const { 90 base::TimeTicks DelayBasedTimeSource::LastTickTime() const {
84 return last_tick_time_; 91 return last_tick_time_;
85 } 92 }
86 93
87 base::TimeTicks DelayBasedTimeSource::NextTickTime() const { 94 base::TimeTicks DelayBasedTimeSource::NextTickTime() const {
88 return Active() ? current_parameters_.tick_target : base::TimeTicks(); 95 return next_tick_time_;
89 } 96 }
90 97
91 void DelayBasedTimeSource::OnTimerFired() { 98 void DelayBasedTimeSource::OnTimerTick() {
92 DCHECK(active_); 99 DCHECK(active_);
93 100
94 last_tick_time_ = current_parameters_.tick_target; 101 last_tick_time_ = next_tick_time_;
95 102
96 PostNextTickTask(Now()); 103 PostNextTickTask(Now());
97 104
98 // Fire the tick. 105 // Fire the tick.
99 if (client_) 106 if (client_)
100 client_->OnTimerTick(); 107 client_->OnTimerTick();
101 } 108 }
102 109
103 void DelayBasedTimeSource::SetClient(TimeSourceClient* client) { 110 void DelayBasedTimeSource::SetClient(DelayBasedTimeSourceClient* client) {
104 client_ = client; 111 client_ = client;
105 } 112 }
106 113
107 void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase, 114 void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase,
108 base::TimeDelta interval) { 115 base::TimeDelta interval) {
109 DCHECK_GT(interval.ToInternalValue(), 0); 116 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 117
118 // If the change in interval is larger than the change threshold, 118 // If the change in interval is larger than the change threshold,
119 // request an immediate reset. 119 // request an immediate reset.
120 double interval_delta = 120 double interval_delta = std::abs((interval - interval_).InSecondsF());
121 std::abs((interval - current_parameters_.interval).InSecondsF()); 121 // Comparing with next_tick_time_ is the right thing to do because we want to
122 // know if we want to cancel the existing tick task and schedule a new one.
123 // Also next_tick_time_ = timebase_ mod interval_.
124 double timebase_delta = std::abs((timebase - next_tick_time_).InSecondsF());
125
126 interval_ = interval;
127 timebase_ = timebase;
128
129 // If we aren't active, there's no need to reset the timer.
130 if (!active_)
131 return;
132
122 double interval_change = interval_delta / interval.InSecondsF(); 133 double interval_change = interval_delta / interval.InSecondsF();
123 if (interval_change > kIntervalChangeThreshold) { 134 if (interval_change > kIntervalChangeThreshold) {
124 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::IntervalChanged", 135 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::IntervalChanged",
125 TRACE_EVENT_SCOPE_THREAD); 136 TRACE_EVENT_SCOPE_THREAD);
126 SetActive(false); 137 ResetTickTask(Now());
127 SetActive(true);
128 return; 138 return;
129 } 139 }
130 140
131 // If the change in phase is greater than the change threshold in either 141 // 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 142 // 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 143 // 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 144 // 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 145 // 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. 146 // 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 = 147 double phase_change =
140 fmod(target_delta, interval.InSecondsF()) / interval.InSecondsF(); 148 fmod(timebase_delta, interval.InSecondsF()) / interval.InSecondsF();
141 if (phase_change > kPhaseChangeThreshold && 149 if (phase_change > kPhaseChangeThreshold &&
142 phase_change < (1.0 - kPhaseChangeThreshold)) { 150 phase_change < (1.0 - kPhaseChangeThreshold)) {
143 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::PhaseChanged", 151 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::PhaseChanged",
144 TRACE_EVENT_SCOPE_THREAD); 152 TRACE_EVENT_SCOPE_THREAD);
145 SetActive(false); 153 ResetTickTask(Now());
146 SetActive(true);
147 return; 154 return;
148 } 155 }
149 } 156 }
150 157
151 base::TimeTicks DelayBasedTimeSource::Now() const { 158 base::TimeTicks DelayBasedTimeSource::Now() const {
152 return base::TimeTicks::Now(); 159 return base::TimeTicks::Now();
153 } 160 }
154 161
155 // This code tries to achieve an average tick rate as close to interval_ as 162 // 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: 163 // 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
199 // Thus, we compute the new_target based on the old timebase: 206 // Thus, we compute the new_target based on the old timebase:
200 // now=18 tick_target=16.667 new_target=33.333 --> 207 // now=18 tick_target=16.667 new_target=33.333 -->
201 // tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15) 208 // 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 209 // This brings us back to 18+15 = 33, which was where we would have been if the
203 // task hadn't been late. 210 // task hadn't been late.
204 // 211 //
205 // For the really late delay, we we move to the next logical tick. The timebase 212 // For the really late delay, we we move to the next logical tick. The timebase
206 // is not reset. 213 // is not reset.
207 // now=37 tick_target=16.667 new_target=50.000 --> 214 // now=37 tick_target=16.667 new_target=50.000 -->
208 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13) 215 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13)
209 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) { 216 base::TimeTicks DelayBasedTimeSource::NextTickTarget(
210 base::TimeTicks new_tick_target = now.SnappedToNextTick( 217 base::TimeTicks now) const {
211 next_parameters_.tick_target, next_parameters_.interval); 218 base::TimeTicks next_tick_target =
212 DCHECK(now <= new_tick_target) 219 now.SnappedToNextTick(timebase_, interval_);
220 DCHECK(now <= next_tick_target)
213 << "now = " << now.ToInternalValue() 221 << "now = " << now.ToInternalValue()
214 << "; new_tick_target = " << new_tick_target.ToInternalValue() 222 << "; new_tick_target = " << next_tick_target.ToInternalValue()
215 << "; new_interval = " << next_parameters_.interval.InMicroseconds() 223 << "; new_interval = " << interval_.InMicroseconds()
216 << "; tick_target = " << next_parameters_.tick_target.ToInternalValue(); 224 << "; new_timbase = " << timebase_.ToInternalValue();
217 225
218 // Avoid double ticks when: 226 // Avoid double ticks when:
219 // 1) Turning off the timer and turning it right back on. 227 // 1) Turning off the timer and turning it right back on.
220 // 2) Jittery data is passed to SetTimebaseAndInterval(). 228 // 2) Jittery data is passed to SetTimebaseAndInterval().
221 if (new_tick_target - last_tick_time_ <= 229 if (next_tick_target - last_tick_time_ <= interval_ / kDoubleTickDivisor)
222 next_parameters_.interval / kDoubleTickDivisor) 230 next_tick_target += interval_;
223 new_tick_target += next_parameters_.interval;
224 231
225 return new_tick_target; 232 return next_tick_target;
226 } 233 }
227 234
228 void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) { 235 void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) {
229 base::TimeTicks new_tick_target = NextTickTarget(now); 236 next_tick_time_ = NextTickTarget(now);
237 DCHECK(next_tick_time_ >= now);
238 // Post another task *before* the tick and update state
239 base::TimeDelta delay = next_tick_time_ - now;
240 task_runner_->PostDelayedTask(FROM_HERE, tick_closure_.callback(), delay);
241 }
230 242
231 // Post another task *before* the tick and update state 243 void DelayBasedTimeSource::ResetTickTask(base::TimeTicks now) {
232 base::TimeDelta delay; 244 tick_closure_.Reset(base::Bind(&DelayBasedTimeSource::OnTimerTick,
233 if (now <= new_tick_target) 245 weak_factory_.GetWeakPtr()));
234 delay = new_tick_target - now; 246 PostNextTickTask(now);
235 task_runner_->PostDelayedTask(FROM_HERE,
236 base::Bind(&DelayBasedTimeSource::OnTimerFired,
237 weak_factory_.GetWeakPtr()),
238 delay);
239
240 next_parameters_.tick_target = new_tick_target;
241 current_parameters_ = next_parameters_;
242 } 247 }
243 248
244 std::string DelayBasedTimeSource::TypeString() const { 249 std::string DelayBasedTimeSource::TypeString() const {
245 return "DelayBasedTimeSource"; 250 return "DelayBasedTimeSource";
246 } 251 }
247 252
248 void DelayBasedTimeSource::AsValueInto( 253 void DelayBasedTimeSource::AsValueInto(
249 base::trace_event::TracedValue* state) const { 254 base::trace_event::TracedValue* state) const {
250 state->SetString("type", TypeString()); 255 state->SetString("type", TypeString());
251 state->SetDouble("last_tick_time_us", LastTickTime().ToInternalValue()); 256 state->SetDouble("last_tick_time_us", LastTickTime().ToInternalValue());
252 state->SetDouble("next_tick_time_us", NextTickTime().ToInternalValue()); 257 state->SetDouble("next_tick_time_us", NextTickTime().ToInternalValue());
253 258 state->SetDouble("interval_us", interval_.InMicroseconds());
254 state->BeginDictionary("current_parameters"); 259 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_); 260 state->SetBoolean("active", active_);
268 } 261 }
269 262
270 } // namespace cc 263 } // namespace cc
OLDNEW
« no previous file with comments | « cc/scheduler/delay_based_time_source.h ('k') | cc/scheduler/delay_based_time_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698