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

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: Fixing Windows compile (no idea why this worked on non-windows!) 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::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 base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() {
130 if (pending_tasks_.size() <= 0)
Sami 2014/09/01 11:35:33 nit: Add braces
mithro-old 2014/09/01 12:00:19 Done.
Sami 2014/09/01 12:50:29 No need for them now but oh well :)
131 return base::TimeTicks::FromInternalValue(
132 std::numeric_limits<int64_t>::max());
133
134 return pending_tasks_.begin()->GetTimeToRun();
135 }
136
137 base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() {
138 DCHECK(thread_checker_.CalledOnValidThread());
139
140 if (pending_tasks_.size() <= 0)
Sami 2014/09/01 11:35:33 nit: Add braces
mithro-old 2014/09/01 12:00:19 Done.
141 return base::TimeDelta::FromInternalValue(
142 std::numeric_limits<int64_t>::max());
143
144 base::TimeDelta delay = NextTaskTime() - now_src_->Now();
145 if (delay > base::TimeDelta())
146 return delay;
147 return base::TimeDelta();
148 }
149
150 const size_t OrderedSimpleTaskRunner::absolute_max_tasks =
151 std::numeric_limits<size_t>::max();
152
153 bool OrderedSimpleTaskRunner::RunTasks(base::Callback<bool(void)> condition) {
154 std::vector<base::Callback<bool(void)> > conditions(1);
155 conditions[0] = condition;
156 return RunTasks(conditions);
157 }
158
159 bool OrderedSimpleTaskRunner::RunTasks(
160 const std::vector<base::Callback<bool(void)> > conditions) {
161 TRACE_EVENT1(
162 "cc", "OrderedSimpleTaskRunner::RunPendingTasks", "this", AsValue());
163 DCHECK(thread_checker_.CalledOnValidThread());
164
165 // Make a copy so we can append some extra run checks.
166 std::vector<base::Callback<bool(void)> > modifiable_conditions(conditions);
167
168 // Provide a timeout base on number of tasks run so this doesn't loop
169 // forever.
170 modifiable_conditions.push_back(WhileTaskRunCountBelow(max_tasks_));
171
172 // If to advance now or not
173 if (!advance_now_) {
174 modifiable_conditions.push_back(WhileNowBefore(now_src_->Now()));
175 } else {
176 modifiable_conditions.push_back(AdvanceNow());
Sami 2014/09/01 11:35:33 It's clever but having AdvanceNow() as a condition
mithro-old 2014/09/01 12:00:19 Actually, come to think of it - there is actually
Sami 2014/09/01 12:50:29 I'm fine with conditions having side effects, but
177 }
178
179 if (inside_run_tasks_until_)
180 return true;
181 inside_run_tasks_until_ = true;
182
183 while (pending_tasks_.size() > 0) {
184 // Check if we should continue to run pending tasks
185 for (std::vector<base::Callback<bool(void)> >::iterator it =
186 modifiable_conditions.begin();
187 it != modifiable_conditions.end();
188 it++) {
189 if (!it->Run()) {
190 goto run_tasks_exit;
Sami 2014/09/01 11:35:32 I feel like I almost have to offer an alternative
mithro-old 2014/09/01 12:00:19 Done. Never seen base::AutoReset before! LGTM.
191 }
192 }
193
194 std::set<TestOrderablePendingTask>::iterator task_to_run =
195 pending_tasks_.begin();
196 {
197 TRACE_EVENT1("cc",
198 "OrderedSimpleTaskRunner::RunPendingTasks running",
199 "task",
200 task_to_run->AsValue());
201 task_to_run->task.Run();
202 }
203
204 pending_tasks_.erase(task_to_run);
205 }
206
207 run_tasks_exit:
208
209 inside_run_tasks_until_ = false;
210 return pending_tasks_.size() > 0;
211 }
212
213 bool OrderedSimpleTaskRunner::RunPendingTasks() {
214 return RunTasks(WhileTaskExistedInitially());
215 }
216
217 bool OrderedSimpleTaskRunner::RunUntilIdle() {
218 return RunTasks(std::vector<base::Callback<bool(void)> >());
219 }
220
221 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) {
222 // If we are not auto advancing, force now forward to the time.
223 if (!advance_now_ && now_src_->Now() < time)
224 now_src_->SetNow(time);
225
226 // Run tasks
227 bool result = RunTasks(WhileNowBefore(time));
228
229 // If the next task is after the stopping time and auto-advancing now, then
230 // force time to be the stopping time.
231 if (!result && advance_now_ && now_src_->Now() < time) {
232 now_src_->SetNow(time);
233 }
234
235 return result;
236 }
237
238 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) {
239 return RunUntilTime(now_src_->Now() + period);
240 }
241
242 // base::debug tracing functionality
243 scoped_refptr<base::debug::ConvertableToTraceFormat>
244 OrderedSimpleTaskRunner::AsValue() const {
245 scoped_refptr<base::debug::TracedValue> state =
246 new base::debug::TracedValue();
247 AsValueInto(state);
248 return state;
249 }
250
251 void OrderedSimpleTaskRunner::AsValueInto(
252 base::debug::TracedValue* state) const {
253 state->SetInteger("pending_tasks", pending_tasks_.size());
254 for (std::set<TestOrderablePendingTask>::const_iterator it =
255 pending_tasks_.begin();
256 it != pending_tasks_.end();
257 ++it) {
258 state->BeginDictionary(
259 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str());
260 it->AsValueInto(state);
261 state->EndDictionary();
262 }
263 now_src_->AsValueInto(state);
264 }
265
266 base::Callback<bool(void)> OrderedSimpleTaskRunner::WhileTaskRunCountBelow(
267 size_t max_tasks) {
268 return base::Bind(&OrderedSimpleTaskRunner::WhileTaskRunCountBelowCallback,
269 base::Unretained(this),
270 max_tasks,
271 base::Owned(new size_t(0)));
272 }
273 bool OrderedSimpleTaskRunner::WhileTaskRunCountBelowCallback(
Sami 2014/09/01 11:35:33 nit: Add blank line.
mithro-old 2014/09/01 12:00:19 Done.
274 size_t max_tasks,
275 size_t* tasks_run) {
276 return (*tasks_run)++ < max_tasks;
277 }
278
279 base::Callback<bool(void)>
280 OrderedSimpleTaskRunner::WhileTaskExistedInitially() {
281 // base::Bind takes a copy of pending_tasks_
282 return base::Bind(&OrderedSimpleTaskRunner::WhileTaskExistedInitiallyCallback,
283 base::Unretained(this),
284 pending_tasks_);
285 }
286 bool OrderedSimpleTaskRunner::WhileTaskExistedInitiallyCallback(
Sami 2014/09/01 11:35:33 nit: Add blank line.
mithro-old 2014/09/01 12:00:19 Done.
287 const std::set<TestOrderablePendingTask>& existing_tasks) {
288 return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end();
289 }
290
291 base::Callback<bool(void)> OrderedSimpleTaskRunner::WhileNowBefore(
292 base::TimeTicks stop_at) {
293 return base::Bind(&OrderedSimpleTaskRunner::WhileNowBeforeCallback,
294 base::Unretained(this),
295 stop_at);
296 }
297 bool OrderedSimpleTaskRunner::WhileNowBeforeCallback(base::TimeTicks stop_at) {
Sami 2014/09/01 11:35:33 nit: add Blank line.
mithro-old 2014/09/01 12:00:19 Done.
298 return NextTaskTime() <= stop_at;
299 }
300
301 base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() {
302 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback,
303 base::Unretained(this));
304 }
305
306 bool OrderedSimpleTaskRunner::AdvanceNowCallback() {
307 base::TimeTicks next_task_time = NextTaskTime();
308 if (now_src_->Now() < next_task_time) {
309 now_src_->SetNow(next_task_time);
310 }
311 return true;
39 } 312 }
40 313
41 } // namespace cc 314 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698