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

Side by Side Diff: cc/test/ordered_simple_task_runner.cc

Issue 387493002: Fixing and enhancing OrderedSimpleTaskRunner to allow 100% deterministic tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase onto master. Created 6 years, 3 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/test/ordered_simple_task_runner.h" 5 #include "cc/test/ordered_simple_task_runner.h"
6 6
7 #include <algorithm> 7 #include <limits>
8 #include <deque> 8 #include <set>
9 9 #include <sstream>
10 #include "base/logging.h" 10 #include <string>
11 11 #include <vector>
12 namespace { 12
13 13 #include "base/debug/trace_event.h"
14 bool TestPendingTaskComparator(const base::TestPendingTask& lhs, 14 #include "base/debug/trace_event_argument.h"
15 const base::TestPendingTask& rhs) { 15 #include "base/strings/string_number_conversions.h"
16 return lhs.ShouldRunBefore(rhs); 16
17 } 17 #define TRACE_TASK(function, task) \
18 18 TRACE_EVENT_INSTANT1( \
19 } 19 "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue());
20
21 #define TRACE_TASK_RUN(function, tag, task)
20 22
21 namespace cc { 23 namespace cc {
22 24
23 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() {} 25 // TestOrderablePendingTask implementation
26 TestOrderablePendingTask::TestOrderablePendingTask()
27 : base::TestPendingTask(),
28 task_id_(TestOrderablePendingTask::task_id_counter++) {
29 }
30
31 TestOrderablePendingTask::TestOrderablePendingTask(
32 const tracked_objects::Location& location,
33 const base::Closure& task,
34 base::TimeTicks post_time,
35 base::TimeDelta delay,
36 TestNestability nestability)
37 : base::TestPendingTask(location, task, post_time, delay, nestability),
38 task_id_(TestOrderablePendingTask::task_id_counter++) {
39 }
40
41 size_t TestOrderablePendingTask::TestOrderablePendingTask::task_id_counter = 0;
42
43 TestOrderablePendingTask::~TestOrderablePendingTask() {
44 }
45
46 bool TestOrderablePendingTask::operator==(
47 const TestOrderablePendingTask& other) const {
48 return task_id_ == other.task_id_;
49 }
50
51 bool TestOrderablePendingTask::operator<(
52 const TestOrderablePendingTask& other) const {
53 if (*this == other)
54 return false;
55
56 if (GetTimeToRun() == other.GetTimeToRun()) {
57 return task_id_ < other.task_id_;
58 }
59 return ShouldRunBefore(other);
60 }
61
62 scoped_refptr<base::debug::ConvertableToTraceFormat>
63 TestOrderablePendingTask::AsValue() const {
64 scoped_refptr<base::debug::TracedValue> state =
65 new base::debug::TracedValue();
66 AsValueInto(state);
67 return state;
68 }
69
70 void TestOrderablePendingTask::AsValueInto(
71 base::debug::TracedValue* state) const {
72 state->SetInteger("id", task_id_);
73 state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
74 state->SetString("posted_from", location.ToString());
75 }
76
77 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner()
78 : advance_now_(true),
79 now_src_(TestNowSource::Create(0)),
80 inside_run_tasks_until_(false) {
81 }
82
83 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner(
84 scoped_refptr<TestNowSource> now_src,
85 bool advance_now)
86 : advance_now_(advance_now),
87 now_src_(now_src),
88 max_tasks_(absolute_max_tasks),
89 inside_run_tasks_until_(false) {
90 }
24 91
25 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} 92 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {}
26 93
27 void OrderedSimpleTaskRunner::RunPendingTasks() { 94 // base::TestSimpleTaskRunner implementation
28 DCHECK(thread_checker_.CalledOnValidThread()); 95 bool OrderedSimpleTaskRunner::PostDelayedTask(
29 // Swap with a local variable to avoid re-entrancy problems. 96 const tracked_objects::Location& from_here,
30 std::deque<base::TestPendingTask> tasks_to_run; 97 const base::Closure& task,
31 tasks_to_run.swap(pending_tasks_); 98 base::TimeDelta delay) {
32 std::stable_sort(tasks_to_run.begin(), 99 DCHECK(thread_checker_.CalledOnValidThread());
33 tasks_to_run.end(), 100 TestOrderablePendingTask pt(
34 TestPendingTaskComparator); 101 from_here, task, now_src_->Now(), delay, base::TestPendingTask::NESTABLE);
35 for (std::deque<base::TestPendingTask>::iterator it = tasks_to_run.begin(); 102
36 it != tasks_to_run.end(); ++it) { 103 TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt);
37 it->task.Run(); 104 pending_tasks_.insert(pt);
38 } 105 return true;
106 }
107
108 bool OrderedSimpleTaskRunner::PostNonNestableDelayedTask(
109 const tracked_objects::Location& from_here,
110 const base::Closure& task,
111 base::TimeDelta delay) {
112 DCHECK(thread_checker_.CalledOnValidThread());
113 TestOrderablePendingTask pt(from_here,
114 task,
115 now_src_->Now(),
116 delay,
117 base::TestPendingTask::NON_NESTABLE);
118
119 TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt);
120 pending_tasks_.insert(pt);
121 return true;
122 }
123
124 bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const {
125 DCHECK(thread_checker_.CalledOnValidThread());
126 return true;
127 }
128
129 //
130 bool OrderedSimpleTaskRunner::RunPendingTasks() {
131 return RunTasksUntil(RunOnlyExisting(this));
132 }
133
134 bool OrderedSimpleTaskRunner::RunUntilIdle() {
135 std::vector<base::Callback<bool(void)> > check_callbacks;
136 return RunTasksUntil(check_callbacks);
137 }
138
139 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) {
140 return RunUntilTime(now_src_->Now() + period);
141 }
142
143 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) {
144 // If we are not auto advancing, force now forward to the time.
145 if (!advance_now_ && now_src_->Now() < time)
146 now_src_->SetNow(time);
147
148 // Run tasks
149 bool result = RunTasksUntil(RunOnlyBefore(this, now_src_, time));
150
151 // If we didn't end up at exactly the time given, force now forward to the
152 // time.
153 if (!result || pending_tasks_.begin()->GetTimeToRun() > time)
154 now_src_->SetNow(time);
155
156 return result;
157 }
158
159 bool OrderedSimpleTaskRunner::RunTasksUntil(const RunCheck& check_callback) {
160 return RunTasksUntil(check_callback.AsCallback());
161 }
162
163 bool OrderedSimpleTaskRunner::RunTasksUntil(RunCheck* check_callback) {
164 return RunTasksUntil(check_callback->AsCallback());
165 }
166
167 bool OrderedSimpleTaskRunner::RunTasksUntil(
168 const std::vector<RunCheck*> check_callbacks) {
169 std::vector<base::Callback<bool(void)> > check_callbacks_converted(
170 check_callbacks.size());
171 for (size_t i = 0; i < check_callbacks.size(); i++) {
172 check_callbacks_converted[i] = check_callbacks[i]->AsCallback();
173 }
174
175 return RunTasksUntil(check_callbacks_converted);
176 }
177
178 bool OrderedSimpleTaskRunner::RunTasksUntil(
179 base::Callback<bool(void)> check_callback) {
180 std::vector<base::Callback<bool(void)> > check_callbacks = {check_callback};
181 return RunTasksUntil(check_callbacks);
182 }
183
184 bool OrderedSimpleTaskRunner::RunTasksUntil(
185 const std::vector<base::Callback<bool(void)> > check_callbacks) {
186 TRACE_EVENT1(
187 "cc", "OrderedSimpleTaskRunner::RunPendingTasks", "this", AsValue());
188 DCHECK(thread_checker_.CalledOnValidThread());
189
190 // Make a copy so we can append some extra run checks.
191 std::vector<base::Callback<bool(void)> > usable_check_callbacks(
192 check_callbacks);
193
194 // Provide a timeout so this doesn't loop forever.
195 RunNTasks timeout(max_tasks_);
196 usable_check_callbacks.push_back(timeout.AsCallback());
197
198 // If to advance now or not
199 RunOnlyBefore only_before(this, now_src_, now_src_->Now());
200 RunAdvanceNow advance_now(this, now_src_);
201 if (!advance_now_) {
202 usable_check_callbacks.push_back(only_before.AsCallback());
203 } else {
204 usable_check_callbacks.push_back(advance_now.AsCallback());
205 }
206
207 if (inside_run_tasks_until_)
208 return true;
209 inside_run_tasks_until_ = true;
210
211 while (pending_tasks_.size() > 0) {
212 std::set<TestOrderablePendingTask>::iterator task_to_run =
213 pending_tasks_.begin();
214
215 // Check if we should continue to run the tasks
216 for (std::vector<base::Callback<bool(void)> >::iterator it =
217 usable_check_callbacks.begin();
218 it != usable_check_callbacks.end();
219 it++) {
220 if (!it->Run()) {
221 goto run_tasks_until_exit;
222 }
223 }
224
225 {
226 TRACE_EVENT1("cc",
227 "OrderedSimpleTaskRunner::RunPendingTasks running",
228 "task",
229 task_to_run->AsValue());
230 task_to_run->task.Run();
231 }
232
233 pending_tasks_.erase(task_to_run);
234 }
235
236 run_tasks_until_exit:
237 inside_run_tasks_until_ = false;
238
239 return pending_tasks_.size() > 0;
240 }
241
242 base::TimeDelta OrderedSimpleTaskRunner::DelayToNextPendingTask() {
243 DCHECK(thread_checker_.CalledOnValidThread());
244
245 if (pending_tasks_.size() <= 0)
246 return base::TimeDelta::FromInternalValue(
247 std::numeric_limits<int64_t>::max());
248
249 base::TimeDelta delay =
250 pending_tasks_.begin()->GetTimeToRun() - now_src_->Now();
251 if (delay > base::TimeDelta())
252 return delay;
253 return base::TimeDelta();
254 }
255
256 // base::debug tracing functionality
257 scoped_refptr<base::debug::ConvertableToTraceFormat>
258 OrderedSimpleTaskRunner::AsValue() const {
259 scoped_refptr<base::debug::TracedValue> state =
260 new base::debug::TracedValue();
261 AsValueInto(state);
262 return state;
263 }
264
265 void OrderedSimpleTaskRunner::AsValueInto(
266 base::debug::TracedValue* state) const {
267 state->SetInteger("pending_tasks", pending_tasks_.size());
268 for (std::set<TestOrderablePendingTask>::const_iterator it =
269 pending_tasks_.begin();
270 it != pending_tasks_.end();
271 ++it) {
272 state->BeginDictionary(
273 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str());
274 it->AsValueInto(state);
275 state->EndDictionary();
276 }
277 now_src_->AsValueInto(state);
278 }
279
280 base::Callback<bool(void)> OrderedSimpleTaskRunner::RunCheck::AsCallback()
281 const {
282 return base::Bind(
283 &RunCheck::Check,
284 base::Unretained(const_cast<OrderedSimpleTaskRunner::RunCheck*>(this)));
285 }
286
287 OrderedSimpleTaskRunner::RunCheckNeedsNextTask::RunCheckNeedsNextTask(
288 OrderedSimpleTaskRunner* task_runner)
289 : task_runner_(task_runner) {
290 }
291 bool OrderedSimpleTaskRunner::RunCheckNeedsNextTask::Check() {
292 DCHECK(task_runner_);
293 DCHECK_GT(task_runner_->pending_tasks_.size(), 0U);
294 return CheckWithTask(*task_runner_->pending_tasks_.begin());
295 }
296
297 OrderedSimpleTaskRunner::RunNTasks::RunNTasks(size_t number)
298 : tasks_run_(0), tasks_to_run_(number) {
299 }
300 OrderedSimpleTaskRunner::RunNTasks::~RunNTasks() {
301 }
302 bool OrderedSimpleTaskRunner::RunNTasks::Check() {
303 return tasks_run_++ < tasks_to_run_;
304 }
305
306 OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime::RunCheckNeedsNextTaskTime(
307 OrderedSimpleTaskRunner* task_runner,
308 scoped_refptr<TestNowSource> now_src)
309 : RunCheckNeedsNextTask(task_runner), now_src_(now_src) {
310 }
311 OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime::
312 ~RunCheckNeedsNextTaskTime() {
313 }
314 bool OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime::CheckWithTask(
315 const TestOrderablePendingTask& next_task) {
316 return CheckWithTaskTime(now_src_->Now(), next_task.GetTimeToRun());
317 }
318
319 OrderedSimpleTaskRunner::RunOnlyBefore::RunOnlyBefore(
320 OrderedSimpleTaskRunner* task_runner,
321 scoped_refptr<TestNowSource> now_src,
322 base::TimeTicks stop_at)
323 : RunCheckNeedsNextTaskTime(task_runner, now_src), stop_at_(stop_at) {
324 }
325 OrderedSimpleTaskRunner::RunOnlyBefore::~RunOnlyBefore() {
326 }
327 bool OrderedSimpleTaskRunner::RunOnlyBefore::CheckWithTaskTime(
328 base::TimeTicks now,
329 base::TimeTicks next_task) {
330 return next_task <= stop_at_;
331 }
332
333 OrderedSimpleTaskRunner::RunOnlyExisting::RunOnlyExisting(
334 OrderedSimpleTaskRunner* task_runner)
335 : RunCheckNeedsNextTask(task_runner),
336 pending_tasks_(task_runner->pending_tasks_) {
337 }
338 OrderedSimpleTaskRunner::RunOnlyExisting::~RunOnlyExisting() {
339 }
340 bool OrderedSimpleTaskRunner::RunOnlyExisting::CheckWithTask(
341 const TestOrderablePendingTask& next_task) {
342 return pending_tasks_.find(next_task) != pending_tasks_.end();
343 }
344
345 OrderedSimpleTaskRunner::RunAdvanceNow::RunAdvanceNow(
346 OrderedSimpleTaskRunner* task_runner,
347 scoped_refptr<TestNowSource> now_src)
348 : RunCheckNeedsNextTaskTime(task_runner, now_src) {
349 }
350 OrderedSimpleTaskRunner::RunAdvanceNow::~RunAdvanceNow() {
351 }
352 bool OrderedSimpleTaskRunner::RunAdvanceNow::CheckWithTaskTime(
353 base::TimeTicks now,
354 base::TimeTicks next_task) {
355 if (now < next_task) {
356 now_src_->SetNow(next_task);
357 }
358 return true;
39 } 359 }
40 360
41 } // namespace cc 361 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698