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

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

Issue 25819002: Revert 210101 "cc: Fix and simplify DelayBasedTimeSource" (Closed) Base URL: svn://svn.chromium.org/chrome/branches/1599_59/src/
Patch Set: Created 7 years, 2 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 | Annotate | Revision Log
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 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/debug/trace_event.h" 11 #include "base/debug/trace_event.h"
12 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/single_thread_task_runner.h" 14 #include "base/single_thread_task_runner.h"
15 15
16 namespace cc { 16 namespace cc {
17 17
18 namespace { 18 namespace {
19 19
20 // kDoubleTickDivisor prevents ticks from running within the specified 20 // kDoubleTickThreshold prevents ticks from running within the specified
21 // fraction of an interval. This helps account for jitter in the timebase as 21 // fraction of an interval. This helps account for jitter in the timebase as
22 // well as quick timer reactivation. 22 // well as quick timer reactivation.
23 static const int kDoubleTickDivisor = 4; 23 static const double kDoubleTickThreshold = 0.25;
24 24
25 // kIntervalChangeThreshold is the fraction of the interval that will trigger an 25 // kIntervalChangeThreshold is the fraction of the interval that will trigger an
26 // immediate interval change. kPhaseChangeThreshold is the fraction of the 26 // immediate interval change. kPhaseChangeThreshold is the fraction of the
27 // interval that will trigger an immediate phase change. If the changes are 27 // interval that will trigger an immediate phase change. If the changes are
28 // within the thresholds, the change will take place on the next tick. If 28 // within the thresholds, the change will take place on the next tick. If
29 // either change is outside the thresholds, the next tick will be canceled and 29 // either change is outside the thresholds, the next tick will be canceled and
30 // reissued immediately. 30 // reissued immediately.
31 static const double kIntervalChangeThreshold = 0.25; 31 static const double kIntervalChangeThreshold = 0.25;
32 static const double kPhaseChangeThreshold = 0.25; 32 static const double kPhaseChangeThreshold = 0.25;
33 33
34 } // namespace 34 } // namespace
35 35
36 scoped_refptr<DelayBasedTimeSource> DelayBasedTimeSource::Create( 36 scoped_refptr<DelayBasedTimeSource> DelayBasedTimeSource::Create(
37 base::TimeDelta interval, 37 base::TimeDelta interval,
38 base::SingleThreadTaskRunner* task_runner) { 38 base::SingleThreadTaskRunner* task_runner) {
39 return make_scoped_refptr(new DelayBasedTimeSource(interval, task_runner)); 39 return make_scoped_refptr(new DelayBasedTimeSource(interval, task_runner));
40 } 40 }
41 41
42 DelayBasedTimeSource::DelayBasedTimeSource( 42 DelayBasedTimeSource::DelayBasedTimeSource(
43 base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner) 43 base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner)
44 : client_(NULL), 44 : client_(NULL),
45 last_tick_time_(base::TimeTicks() - interval), 45 has_tick_target_(false),
46 current_parameters_(interval, base::TimeTicks()), 46 current_parameters_(interval, base::TimeTicks()),
47 next_parameters_(interval, base::TimeTicks()), 47 next_parameters_(interval, base::TimeTicks()),
48 active_(false), 48 state_(STATE_INACTIVE),
49 task_runner_(task_runner), 49 task_runner_(task_runner),
50 weak_factory_(this) {} 50 weak_factory_(this) {}
51 51
52 DelayBasedTimeSource::~DelayBasedTimeSource() {} 52 DelayBasedTimeSource::~DelayBasedTimeSource() {}
53 53
54 void DelayBasedTimeSource::SetActive(bool active) { 54 void DelayBasedTimeSource::SetActive(bool active) {
55 TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active); 55 TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active);
56 if (active == active_) 56 if (!active) {
57 return; 57 state_ = STATE_INACTIVE;
58 active_ = active;
59
60 if (!active_) {
61 weak_factory_.InvalidateWeakPtrs(); 58 weak_factory_.InvalidateWeakPtrs();
62 return; 59 return;
63 } 60 }
64 61
62 if (state_ == STATE_STARTING || state_ == STATE_ACTIVE)
63 return;
64
65 if (!has_tick_target_) {
66 // Becoming active the first time is deferred: we post a 0-delay task.
67 // When it runs, we use that to establish the timebase, become truly
68 // active, and fire the first tick.
69 state_ = STATE_STARTING;
70 task_runner_->PostTask(FROM_HERE,
71 base::Bind(&DelayBasedTimeSource::OnTimerFired,
72 weak_factory_.GetWeakPtr()));
73 return;
74 }
75
76 state_ = STATE_ACTIVE;
77
65 PostNextTickTask(Now()); 78 PostNextTickTask(Now());
66 } 79 }
67 80
68 bool DelayBasedTimeSource::Active() const { return active_; } 81 bool DelayBasedTimeSource::Active() const { return state_ != STATE_INACTIVE; }
69 82
70 base::TimeTicks DelayBasedTimeSource::LastTickTime() { return last_tick_time_; } 83 base::TimeTicks DelayBasedTimeSource::LastTickTime() { return last_tick_time_; }
71 84
72 base::TimeTicks DelayBasedTimeSource::NextTickTime() { 85 base::TimeTicks DelayBasedTimeSource::NextTickTime() {
73 return Active() ? current_parameters_.tick_target : base::TimeTicks(); 86 return Active() ? current_parameters_.tick_target : base::TimeTicks();
74 } 87 }
75 88
76 void DelayBasedTimeSource::OnTimerFired() { 89 void DelayBasedTimeSource::OnTimerFired() {
77 DCHECK(active_); 90 DCHECK(state_ != STATE_INACTIVE);
78 91
79 last_tick_time_ = current_parameters_.tick_target; 92 base::TimeTicks now = this->Now();
93 last_tick_time_ = now;
80 94
81 PostNextTickTask(Now()); 95 if (state_ == STATE_STARTING) {
96 SetTimebaseAndInterval(now, current_parameters_.interval);
97 state_ = STATE_ACTIVE;
98 }
99
100 PostNextTickTask(now);
82 101
83 // Fire the tick. 102 // Fire the tick.
84 if (client_) 103 if (client_)
85 client_->OnTimerTick(); 104 client_->OnTimerTick();
86 } 105 }
87 106
88 void DelayBasedTimeSource::SetClient(TimeSourceClient* client) { 107 void DelayBasedTimeSource::SetClient(TimeSourceClient* client) {
89 client_ = client; 108 client_ = client;
90 } 109 }
91 110
92 void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase, 111 void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase,
93 base::TimeDelta interval) { 112 base::TimeDelta interval) {
94 next_parameters_.interval = interval; 113 next_parameters_.interval = interval;
95 next_parameters_.tick_target = timebase; 114 next_parameters_.tick_target = timebase;
115 has_tick_target_ = true;
96 116
97 if (!active_) { 117 if (state_ != STATE_ACTIVE) {
98 // If we aren't active, there's no need to reset the timer. 118 // If we aren't active, there's no need to reset the timer.
99 return; 119 return;
100 } 120 }
101 121
102 // If the change in interval is larger than the change threshold, 122 // If the change in interval is larger than the change threshold,
103 // request an immediate reset. 123 // request an immediate reset.
104 double interval_delta = 124 double interval_delta =
105 std::abs((interval - current_parameters_.interval).InSecondsF()); 125 std::abs((interval - current_parameters_.interval).InSecondsF());
106 double interval_change = interval_delta / interval.InSecondsF(); 126 double interval_change = interval_delta / interval.InSecondsF();
107 if (interval_change > kIntervalChangeThreshold) { 127 if (interval_change > kIntervalChangeThreshold) {
108 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::IntervalChanged",
109 TRACE_EVENT_SCOPE_THREAD);
110 SetActive(false); 128 SetActive(false);
111 SetActive(true); 129 SetActive(true);
112 return; 130 return;
113 } 131 }
114 132
115 // If the change in phase is greater than the change threshold in either 133 // If the change in phase is greater than the change threshold in either
116 // direction, request an immediate reset. This logic might result in a false 134 // direction, request an immediate reset. This logic might result in a false
117 // negative if there is a simultaneous small change in the interval and the 135 // negative if there is a simultaneous small change in the interval and the
118 // fmod just happens to return something near zero. Assuming the timebase 136 // fmod just happens to return something near zero. Assuming the timebase
119 // is very recent though, which it should be, we'll still be ok because the 137 // is very recent though, which it should be, we'll still be ok because the
120 // old clock and new clock just happen to line up. 138 // old clock and new clock just happen to line up.
121 double target_delta = 139 double target_delta =
122 std::abs((timebase - current_parameters_.tick_target).InSecondsF()); 140 std::abs((timebase - current_parameters_.tick_target).InSecondsF());
123 double phase_change = 141 double phase_change =
124 fmod(target_delta, interval.InSecondsF()) / interval.InSecondsF(); 142 fmod(target_delta, interval.InSecondsF()) / interval.InSecondsF();
125 if (phase_change > kPhaseChangeThreshold && 143 if (phase_change > kPhaseChangeThreshold &&
126 phase_change < (1.0 - kPhaseChangeThreshold)) { 144 phase_change < (1.0 - kPhaseChangeThreshold)) {
127 TRACE_EVENT_INSTANT0("cc", "DelayBasedTimeSource::PhaseChanged",
128 TRACE_EVENT_SCOPE_THREAD);
129 SetActive(false); 145 SetActive(false);
130 SetActive(true); 146 SetActive(true);
131 return; 147 return;
132 } 148 }
133 } 149 }
134 150
135 base::TimeTicks DelayBasedTimeSource::Now() const { 151 base::TimeTicks DelayBasedTimeSource::Now() const {
136 return base::TimeTicks::Now(); 152 return base::TimeTicks::Now();
137 } 153 }
138 154
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 // now=18 tick_target=16.667 new_target=33.333 --> 200 // now=18 tick_target=16.667 new_target=33.333 -->
185 // tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15) 201 // tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15)
186 // This brings us back to 18+15 = 33, which was where we would have been if the 202 // This brings us back to 18+15 = 33, which was where we would have been if the
187 // task hadn't been late. 203 // task hadn't been late.
188 // 204 //
189 // For the really late delay, we we move to the next logical tick. The timebase 205 // For the really late delay, we we move to the next logical tick. The timebase
190 // is not reset. 206 // is not reset.
191 // now=37 tick_target=16.667 new_target=50.000 --> 207 // now=37 tick_target=16.667 new_target=50.000 -->
192 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13) 208 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13)
193 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) { 209 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) {
194 const base::TimeDelta epsilon(base::TimeDelta::FromMicroseconds(1));
195 base::TimeDelta new_interval = next_parameters_.interval; 210 base::TimeDelta new_interval = next_parameters_.interval;
196 int intervals_elapsed = 211 int intervals_elapsed =
197 (now - next_parameters_.tick_target + new_interval - epsilon) / 212 static_cast<int>(floor((now - next_parameters_.tick_target).InSecondsF() /
198 new_interval; 213 new_interval.InSecondsF()));
199 base::TimeTicks new_tick_target = 214 base::TimeTicks last_effective_tick =
200 next_parameters_.tick_target + new_interval * intervals_elapsed; 215 next_parameters_.tick_target + new_interval * intervals_elapsed;
201 DCHECK(now <= new_tick_target) 216 base::TimeTicks new_tick_target = last_effective_tick + new_interval;
217 DCHECK(now < new_tick_target)
202 << "now = " << now.ToInternalValue() 218 << "now = " << now.ToInternalValue()
203 << "; new_tick_target = " << new_tick_target.ToInternalValue() 219 << "; new_tick_target = " << new_tick_target.ToInternalValue()
204 << "; new_interval = " << new_interval.InMicroseconds() 220 << "; new_interval = " << new_interval.InMicroseconds()
205 << "; tick_target = " << next_parameters_.tick_target.ToInternalValue() 221 << "; tick_target = " << next_parameters_.tick_target.ToInternalValue()
206 << "; intervals_elapsed = " << intervals_elapsed; 222 << "; intervals_elapsed = " << intervals_elapsed
223 << "; last_effective_tick = " << last_effective_tick.ToInternalValue();
207 224
208 // Avoid double ticks when: 225 // Avoid double ticks when:
209 // 1) Turning off the timer and turning it right back on. 226 // 1) Turning off the timer and turning it right back on.
210 // 2) Jittery data is passed to SetTimebaseAndInterval(). 227 // 2) Jittery data is passed to SetTimebaseAndInterval().
211 if (new_tick_target - last_tick_time_ <= new_interval / kDoubleTickDivisor) 228 if (new_tick_target - last_tick_time_ <=
229 new_interval / static_cast<int>(1.0 / kDoubleTickThreshold))
212 new_tick_target += new_interval; 230 new_tick_target += new_interval;
213 231
214 return new_tick_target; 232 return new_tick_target;
215 } 233 }
216 234
217 void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) { 235 void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) {
218 base::TimeTicks new_tick_target = NextTickTarget(now); 236 base::TimeTicks new_tick_target = NextTickTarget(now);
219 237
220 // Post another task *before* the tick and update state 238 // Post another task *before* the tick and update state
221 base::TimeDelta delay; 239 base::TimeDelta delay = new_tick_target - now;
222 if (now <= new_tick_target) 240 DCHECK(delay.InMillisecondsF() <=
223 delay = new_tick_target - now; 241 next_parameters_.interval.InMillisecondsF() *
242 (1.0 + kDoubleTickThreshold));
224 task_runner_->PostDelayedTask(FROM_HERE, 243 task_runner_->PostDelayedTask(FROM_HERE,
225 base::Bind(&DelayBasedTimeSource::OnTimerFired, 244 base::Bind(&DelayBasedTimeSource::OnTimerFired,
226 weak_factory_.GetWeakPtr()), 245 weak_factory_.GetWeakPtr()),
227 delay); 246 delay);
228 247
229 next_parameters_.tick_target = new_tick_target; 248 next_parameters_.tick_target = new_tick_target;
230 current_parameters_ = next_parameters_; 249 current_parameters_ = next_parameters_;
231 } 250 }
232 251
233 } // namespace cc 252 } // 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