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

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 for Sami's review. 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/auto_reset.h"
14 bool TestPendingTaskComparator(const base::TestPendingTask& lhs, 14 #include "base/debug/trace_event.h"
15 const base::TestPendingTask& rhs) { 15 #include "base/debug/trace_event_argument.h"
16 return lhs.ShouldRunBefore(rhs); 16 #include "base/strings/string_number_conversions.h"
17 } 17
18 18 #define TRACE_TASK(function, task) \
19 } 19 TRACE_EVENT_INSTANT1( \
20 "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue());
21
22 #define TRACE_TASK_RUN(function, tag, task)
20 23
21 namespace cc { 24 namespace cc {
22 25
23 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() {} 26 // TestOrderablePendingTask implementation
27 TestOrderablePendingTask::TestOrderablePendingTask()
28 : base::TestPendingTask(),
29 task_id_(TestOrderablePendingTask::task_id_counter++) {
30 }
31
32 TestOrderablePendingTask::TestOrderablePendingTask(
33 const tracked_objects::Location& location,
34 const base::Closure& task,
35 base::TimeTicks post_time,
36 base::TimeDelta delay,
37 TestNestability nestability)
38 : base::TestPendingTask(location, task, post_time, delay, nestability),
39 task_id_(TestOrderablePendingTask::task_id_counter++) {
40 }
41
42 size_t TestOrderablePendingTask::task_id_counter = 0;
43
44 TestOrderablePendingTask::~TestOrderablePendingTask() {
45 }
46
47 bool TestOrderablePendingTask::operator==(
48 const TestOrderablePendingTask& other) const {
49 return task_id_ == other.task_id_;
50 }
51
52 bool TestOrderablePendingTask::operator<(
53 const TestOrderablePendingTask& other) const {
54 if (*this == other)
55 return false;
56
57 if (GetTimeToRun() == other.GetTimeToRun()) {
58 return task_id_ < other.task_id_;
59 }
60 return ShouldRunBefore(other);
61 }
62
63 scoped_refptr<base::debug::ConvertableToTraceFormat>
64 TestOrderablePendingTask::AsValue() const {
65 scoped_refptr<base::debug::TracedValue> state =
66 new base::debug::TracedValue();
67 AsValueInto(state);
68 return state;
69 }
70
71 void TestOrderablePendingTask::AsValueInto(
72 base::debug::TracedValue* state) const {
73 state->SetInteger("id", task_id_);
74 state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
75 state->SetString("posted_from", location.ToString());
76 }
77
78 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner()
79 : advance_now_(true),
80 now_src_(TestNowSource::Create(0)),
81 inside_run_tasks_until_(false) {
82 }
83
84 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner(
85 scoped_refptr<TestNowSource> now_src,
86 bool advance_now)
87 : advance_now_(advance_now),
88 now_src_(now_src),
89 max_tasks_(kAbsoluteMaxTasks),
90 inside_run_tasks_until_(false) {
91 }
24 92
25 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} 93 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {}
26 94
27 void OrderedSimpleTaskRunner::RunPendingTasks() { 95 // base::TestSimpleTaskRunner implementation
28 DCHECK(thread_checker_.CalledOnValidThread()); 96 bool OrderedSimpleTaskRunner::PostDelayedTask(
29 // Swap with a local variable to avoid re-entrancy problems. 97 const tracked_objects::Location& from_here,
30 std::deque<base::TestPendingTask> tasks_to_run; 98 const base::Closure& task,
31 tasks_to_run.swap(pending_tasks_); 99 base::TimeDelta delay) {
32 std::stable_sort(tasks_to_run.begin(), 100 DCHECK(thread_checker_.CalledOnValidThread());
33 tasks_to_run.end(), 101 TestOrderablePendingTask pt(
34 TestPendingTaskComparator); 102 from_here, task, now_src_->Now(), delay, base::TestPendingTask::NESTABLE);
35 for (std::deque<base::TestPendingTask>::iterator it = tasks_to_run.begin(); 103
36 it != tasks_to_run.end(); ++it) { 104 TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt);
37 it->task.Run(); 105 pending_tasks_.insert(pt);
38 } 106 return true;
107 }
108
109 bool OrderedSimpleTaskRunner::PostNonNestableDelayedTask(
110 const tracked_objects::Location& from_here,
111 const base::Closure& task,
112 base::TimeDelta delay) {
113 DCHECK(thread_checker_.CalledOnValidThread());
114 TestOrderablePendingTask pt(from_here,
115 task,
116 now_src_->Now(),
117 delay,
118 base::TestPendingTask::NON_NESTABLE);
119
120 TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt);
121 pending_tasks_.insert(pt);
122 return true;
123 }
124
125 bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const {
126 DCHECK(thread_checker_.CalledOnValidThread());
127 return true;
128 }
129
130 base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() {
131 if (pending_tasks_.size() <= 0) {
132 return TestNowSource::kAbsoluteMaxNow;
133 }
134
135 return pending_tasks_.begin()->GetTimeToRun();
136 }
137
138 base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() {
139 DCHECK(thread_checker_.CalledOnValidThread());
140
141 if (pending_tasks_.size() <= 0) {
142 return TestNowSource::kAbsoluteMaxNow - base::TimeTicks();
143 }
144
145 base::TimeDelta delay = NextTaskTime() - now_src_->Now();
146 if (delay > base::TimeDelta())
147 return delay;
148 return base::TimeDelta();
149 }
150
151 const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks =
152 std::numeric_limits<size_t>::max();
153
154 bool OrderedSimpleTaskRunner::RunTasks(base::Callback<bool(void)> condition) {
155 std::vector<base::Callback<bool(void)> > conditions(1);
156 conditions[0] = condition;
157 return RunTasks(conditions);
158 }
159
160 bool OrderedSimpleTaskRunner::RunTasks(
161 const std::vector<base::Callback<bool(void)> >& conditions) {
162 TRACE_EVENT1(
163 "cc", "OrderedSimpleTaskRunner::RunPendingTasks", "this", AsValue());
164 DCHECK(thread_checker_.CalledOnValidThread());
165
166 // Make a copy so we can append some extra run checks.
167 std::vector<base::Callback<bool(void)> > modifiable_conditions(conditions);
168
169 // Provide a timeout base on number of tasks run so this doesn't loop
170 // forever.
171 modifiable_conditions.push_back(WhileTaskRunCountBelow(max_tasks_));
172
173 // If to advance now or not
174 if (!advance_now_) {
175 modifiable_conditions.push_back(WhileNowBefore(now_src_->Now()));
176 } else {
177 modifiable_conditions.push_back(AdvanceNow());
178 }
179
180 if (inside_run_tasks_until_)
brianderson 2014/09/05 02:48:03 Should this early out and the AutoReset move up?
mithro-old 2014/09/08 12:52:19 Done.
181 return true;
182
183 base::AutoReset<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_,
184 true);
185 while (pending_tasks_.size() > 0) {
186 // Check if we should continue to run pending tasks
187 for (std::vector<base::Callback<bool(void)> >::iterator it =
188 modifiable_conditions.begin();
189 it != modifiable_conditions.end();
190 it++) {
191 if (!it->Run()) {
192 return pending_tasks_.size() > 0;
brianderson 2014/09/05 02:48:03 Can you just return true here?
mithro-old 2014/09/08 12:52:19 A condition could possibly modify the queue size a
brianderson 2014/09/08 19:24:08 A comment explaining that a condition might modify
mithro-old 2014/09/09 02:39:44 Done.
193 }
194 }
195
196 std::set<TestOrderablePendingTask>::iterator task_to_run =
197 pending_tasks_.begin();
198 {
199 TRACE_EVENT1("cc",
200 "OrderedSimpleTaskRunner::RunPendingTasks running",
201 "task",
202 task_to_run->AsValue());
203 task_to_run->task.Run();
204 }
205
206 pending_tasks_.erase(task_to_run);
207 }
208
209 return false;
210 }
211
212 bool OrderedSimpleTaskRunner::RunPendingTasks() {
213 return RunTasks(WhileTaskExistedInitially());
214 }
215
216 bool OrderedSimpleTaskRunner::RunUntilIdle() {
217 return RunTasks(std::vector<base::Callback<bool(void)> >());
218 }
219
220 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) {
221 // If we are not auto advancing, force now forward to the time.
222 if (!advance_now_ && now_src_->Now() < time)
223 now_src_->SetNow(time);
224
225 // Run tasks
226 bool result = RunTasks(WhileNowBefore(time));
227
228 // If the next task is after the stopping time and auto-advancing now, then
229 // force time to be the stopping time.
230 if (!result && advance_now_ && now_src_->Now() < time) {
231 now_src_->SetNow(time);
232 }
233
234 return result;
235 }
236
237 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) {
238 return RunUntilTime(now_src_->Now() + period);
239 }
240
241 // base::debug tracing functionality
242 scoped_refptr<base::debug::ConvertableToTraceFormat>
243 OrderedSimpleTaskRunner::AsValue() const {
244 scoped_refptr<base::debug::TracedValue> state =
245 new base::debug::TracedValue();
246 AsValueInto(state);
247 return state;
248 }
249
250 void OrderedSimpleTaskRunner::AsValueInto(
251 base::debug::TracedValue* state) const {
252 state->SetInteger("pending_tasks", pending_tasks_.size());
253 for (std::set<TestOrderablePendingTask>::const_iterator it =
254 pending_tasks_.begin();
255 it != pending_tasks_.end();
256 ++it) {
257 state->BeginDictionary(
258 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str());
259 it->AsValueInto(state);
260 state->EndDictionary();
261 }
262 now_src_->AsValueInto(state);
263 }
264
265 base::Callback<bool(void)> OrderedSimpleTaskRunner::WhileTaskRunCountBelow(
266 size_t max_tasks) {
267 return base::Bind(&OrderedSimpleTaskRunner::WhileTaskRunCountBelowCallback,
268 base::Unretained(this),
269 max_tasks,
270 base::Owned(new size_t(0)));
271 }
272
273 bool OrderedSimpleTaskRunner::WhileTaskRunCountBelowCallback(
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
287 bool OrderedSimpleTaskRunner::WhileTaskExistedInitiallyCallback(
288 const std::set<TestOrderablePendingTask>& existing_tasks) {
289 return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end();
290 }
291
292 base::Callback<bool(void)> OrderedSimpleTaskRunner::WhileNowBefore(
293 base::TimeTicks stop_at) {
294 return base::Bind(&OrderedSimpleTaskRunner::WhileNowBeforeCallback,
295 base::Unretained(this),
296 stop_at);
297 }
298 bool OrderedSimpleTaskRunner::WhileNowBeforeCallback(base::TimeTicks stop_at) {
299 return NextTaskTime() <= stop_at;
300 }
301
302 base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() {
brianderson 2014/09/05 02:48:03 I would want to explictly disallow side-effects li
mithro-old 2014/09/08 12:52:19 We also need side-effects for the "WhileTaskRunCou
brianderson 2014/09/08 19:24:08 Argh, naming is hard. I can't think of any better
mithro-old 2014/09/09 02:39:44 Done.
303 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback,
304 base::Unretained(this));
305 }
306
307 bool OrderedSimpleTaskRunner::AdvanceNowCallback() {
308 base::TimeTicks next_task_time = NextTaskTime();
309 if (now_src_->Now() == TestNowSource::kAbsoluteMaxNow ||
310 next_task_time == TestNowSource::kAbsoluteMaxNow)
311 return false;
brianderson 2014/09/05 02:48:03 This "return false" seems redundant with the exist
mithro-old 2014/09/08 12:52:19 Removed.
312
313 if (now_src_->Now() < next_task_time) {
314 now_src_->SetNow(next_task_time);
315 }
316 return true;
39 } 317 }
40 318
41 } // namespace cc 319 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698