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

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

Powered by Google App Engine
This is Rietveld 408576698