OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/resources/worker_pool.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "cc/base/completion_event.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 | |
12 namespace cc { | |
13 | |
14 namespace { | |
15 | |
16 const int kWorkerPoolCount = 3; | |
17 | |
18 class FakeWorkerPoolTaskImpl : public internal::WorkerPoolTask { | |
19 public: | |
20 FakeWorkerPoolTaskImpl(const base::Closure& callback, | |
21 const base::Closure& reply) | |
22 : callback_(callback), | |
23 reply_(reply) { | |
24 } | |
25 | |
26 // Overridden from internal::WorkerPoolTask: | |
27 virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE { | |
28 if (!callback_.is_null()) | |
29 callback_.Run(); | |
30 } | |
31 virtual void CompleteOnOriginThread() OVERRIDE { | |
32 if (!reply_.is_null()) | |
33 reply_.Run(); | |
34 } | |
35 | |
36 private: | |
37 virtual ~FakeWorkerPoolTaskImpl() {} | |
38 | |
39 const base::Closure callback_; | |
40 const base::Closure reply_; | |
41 | |
42 DISALLOW_COPY_AND_ASSIGN(FakeWorkerPoolTaskImpl); | |
43 }; | |
44 | |
45 class FakeWorkerPool : public WorkerPool { | |
46 public: | |
47 struct Task { | |
48 Task(const base::Closure& callback, | |
49 const base::Closure& reply, | |
50 const base::Closure& dependent, | |
51 unsigned dependent_count, | |
52 unsigned priority) : callback(callback), | |
53 reply(reply), | |
54 dependent(dependent), | |
55 dependent_count(dependent_count), | |
56 priority(priority) { | |
57 } | |
58 | |
59 base::Closure callback; | |
60 base::Closure reply; | |
61 base::Closure dependent; | |
62 unsigned dependent_count; | |
63 unsigned priority; | |
64 }; | |
65 FakeWorkerPool() : WorkerPool() {} | |
66 virtual ~FakeWorkerPool() {} | |
67 | |
68 static scoped_ptr<FakeWorkerPool> Create() { | |
69 return make_scoped_ptr(new FakeWorkerPool); | |
70 } | |
71 | |
72 void ScheduleTasks(const std::vector<Task>& tasks) { | |
73 TaskVector new_tasks; | |
74 TaskVector new_dependents; | |
75 TaskGraph new_graph; | |
76 | |
77 scoped_refptr<FakeWorkerPoolTaskImpl> new_completion_task( | |
78 new FakeWorkerPoolTaskImpl( | |
79 base::Bind(&FakeWorkerPool::OnTasksCompleted, | |
80 base::Unretained(this)), | |
81 base::Closure())); | |
82 scoped_ptr<internal::GraphNode> completion_node( | |
83 new internal::GraphNode(new_completion_task.get(), 0u)); | |
84 | |
85 for (std::vector<Task>::const_iterator it = tasks.begin(); | |
86 it != tasks.end(); ++it) { | |
87 scoped_refptr<FakeWorkerPoolTaskImpl> new_task( | |
88 new FakeWorkerPoolTaskImpl(it->callback, it->reply)); | |
89 scoped_ptr<internal::GraphNode> node( | |
90 new internal::GraphNode(new_task.get(), it->priority)); | |
91 | |
92 DCHECK(it->dependent_count); | |
93 for (unsigned i = 0; i < it->dependent_count; ++i) { | |
94 scoped_refptr<FakeWorkerPoolTaskImpl> new_dependent_task( | |
95 new FakeWorkerPoolTaskImpl(it->dependent, base::Closure())); | |
96 scoped_ptr<internal::GraphNode> dependent_node( | |
97 new internal::GraphNode(new_dependent_task.get(), it->priority)); | |
98 dependent_node->add_dependent(completion_node.get()); | |
99 completion_node->add_dependency(); | |
100 node->add_dependent(dependent_node.get()); | |
101 dependent_node->add_dependency(); | |
102 new_graph.set(new_dependent_task.get(), dependent_node.Pass()); | |
103 new_dependents.push_back(new_dependent_task.get()); | |
104 } | |
105 | |
106 new_graph.set(new_task.get(), node.Pass()); | |
107 new_tasks.push_back(new_task.get()); | |
108 } | |
109 | |
110 new_graph.set(new_completion_task.get(), completion_node.Pass()); | |
111 | |
112 scheduled_tasks_completion_.reset(new CompletionEvent); | |
113 | |
114 SetTaskGraph(&new_graph); | |
115 | |
116 dependents_.swap(new_dependents); | |
117 completion_task_.swap(new_completion_task); | |
118 tasks_.swap(new_tasks); | |
119 } | |
120 | |
121 void CheckForCompletedTasks() { | |
122 CheckForCompletedWorkerTasks(); | |
123 } | |
124 | |
125 void WaitForTasksToComplete() { | |
126 DCHECK(scheduled_tasks_completion_); | |
127 scheduled_tasks_completion_->Wait(); | |
128 } | |
129 | |
130 private: | |
131 typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector; | |
132 | |
133 void OnTasksCompleted() { | |
134 DCHECK(scheduled_tasks_completion_); | |
135 scheduled_tasks_completion_->Signal(); | |
136 } | |
137 | |
138 TaskVector tasks_; | |
139 TaskVector dependents_; | |
140 scoped_refptr<FakeWorkerPoolTaskImpl> completion_task_; | |
141 scoped_ptr<CompletionEvent> scheduled_tasks_completion_; | |
142 | |
143 DISALLOW_COPY_AND_ASSIGN(FakeWorkerPool); | |
144 }; | |
145 | |
146 class WorkerPoolTest : public testing::Test { | |
147 public: | |
148 WorkerPoolTest() {} | |
149 virtual ~WorkerPoolTest() {} | |
150 | |
151 // Overridden from testing::Test: | |
152 virtual void SetUp() OVERRIDE { | |
153 for (int i = 0; i < kWorkerPoolCount; ++i) | |
154 worker_pools_[i] = FakeWorkerPool::Create(); | |
155 } | |
156 virtual void TearDown() OVERRIDE { | |
157 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
158 worker_pools_[i]->Shutdown(); | |
159 worker_pools_[i]->CheckForCompletedTasks(); | |
160 } | |
161 } | |
162 | |
163 void ResetAllIdsforWorkerPool(int worker_pool_index) { | |
164 run_task_ids_[worker_pool_index].clear(); | |
165 on_task_completed_ids_[worker_pool_index].clear(); | |
166 } | |
167 | |
168 void RunAllTasksforWorkerPool(int worker_pool_index) { | |
169 worker_pools_[worker_pool_index]->WaitForTasksToComplete(); | |
170 worker_pools_[worker_pool_index]->CheckForCompletedTasks(); | |
171 } | |
172 | |
173 FakeWorkerPool* worker_pool(int worker_pool_index) { | |
174 return worker_pools_[worker_pool_index].get(); | |
175 } | |
176 | |
177 void RunTask(int worker_pool_index, unsigned id) { | |
178 run_task_ids_[worker_pool_index].push_back(id); | |
179 } | |
180 | |
181 void OnTaskCompleted(int worker_pool_index, unsigned id) { | |
182 on_task_completed_ids_[worker_pool_index].push_back(id); | |
183 } | |
184 | |
185 const std::vector<unsigned>& run_task_ids(int worker_pool_index) { | |
186 return run_task_ids_[worker_pool_index]; | |
187 } | |
188 | |
189 const std::vector<unsigned>& on_task_completed_ids(int worker_pool_index) { | |
190 return on_task_completed_ids_[worker_pool_index]; | |
191 } | |
192 | |
193 private: | |
194 scoped_ptr<FakeWorkerPool> worker_pools_[kWorkerPoolCount]; | |
195 std::vector<unsigned> run_task_ids_[kWorkerPoolCount]; | |
196 std::vector<unsigned> on_task_completed_ids_[kWorkerPoolCount]; | |
197 }; | |
198 | |
199 TEST_F(WorkerPoolTest, Basic) { | |
200 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
201 EXPECT_EQ(0u, run_task_ids(i).size()); | |
202 EXPECT_EQ(0u, on_task_completed_ids(i).size()); | |
203 | |
204 worker_pool(i)->ScheduleTasks( | |
205 std::vector<FakeWorkerPool::Task>( | |
206 1, | |
207 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
208 base::Unretained(this), | |
209 i, | |
210 0u), | |
211 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
212 base::Unretained(this), | |
213 i, | |
214 0u), | |
215 base::Closure(), | |
216 1u, | |
217 0u))); | |
218 } | |
219 | |
220 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
221 RunAllTasksforWorkerPool(i); | |
222 | |
223 EXPECT_EQ(1u, run_task_ids(i).size()); | |
224 EXPECT_EQ(1u, on_task_completed_ids(i).size()); | |
225 } | |
226 | |
227 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
228 worker_pool(i)->ScheduleTasks( | |
229 std::vector<FakeWorkerPool::Task>( | |
230 1, | |
231 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
232 base::Unretained(this), | |
233 i, | |
234 0u), | |
235 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
236 base::Unretained(this), | |
237 i, | |
238 0u), | |
239 base::Bind(&WorkerPoolTest::RunTask, | |
240 base::Unretained(this), | |
241 i, | |
242 0u), | |
243 1u, | |
244 0u))); | |
245 } | |
246 | |
247 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
248 RunAllTasksforWorkerPool(i); | |
249 | |
250 EXPECT_EQ(3u, run_task_ids(i).size()); | |
251 EXPECT_EQ(2u, on_task_completed_ids(i).size()); | |
252 } | |
253 | |
254 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
255 worker_pool(i)->ScheduleTasks( | |
256 std::vector<FakeWorkerPool::Task>( | |
257 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
258 base::Unretained(this), | |
259 i, | |
260 0u), | |
261 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
262 base::Unretained(this), | |
263 i, | |
264 0u), | |
265 base::Bind(&WorkerPoolTest::RunTask, | |
266 base::Unretained(this), | |
267 i, | |
268 0u), | |
269 2u, | |
270 0u))); | |
271 } | |
272 | |
273 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
274 RunAllTasksforWorkerPool(i); | |
275 | |
276 EXPECT_EQ(6u, run_task_ids(i).size()); | |
277 EXPECT_EQ(3u, on_task_completed_ids(i).size()); | |
278 } | |
279 } | |
280 | |
281 TEST_F(WorkerPoolTest, Dependencies) { | |
282 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
283 worker_pool(i)->ScheduleTasks( | |
284 std::vector<FakeWorkerPool::Task>( | |
285 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
286 base::Unretained(this), | |
287 i, | |
288 0u), | |
289 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
290 base::Unretained(this), | |
291 i, | |
292 0u), | |
293 base::Bind(&WorkerPoolTest::RunTask, | |
294 base::Unretained(this), | |
295 i, | |
296 1u), | |
297 1u, | |
298 0u))); | |
299 } | |
300 | |
301 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
302 RunAllTasksforWorkerPool(i); | |
303 | |
304 // Check if task ran before dependent. | |
305 ASSERT_EQ(2u, run_task_ids(i).size()); | |
306 EXPECT_EQ(0u, run_task_ids(i)[0]); | |
307 EXPECT_EQ(1u, run_task_ids(i)[1]); | |
308 ASSERT_EQ(1u, on_task_completed_ids(i).size()); | |
309 EXPECT_EQ(0u, on_task_completed_ids(i)[0]); | |
310 } | |
311 | |
312 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
313 worker_pool(i)->ScheduleTasks( | |
314 std::vector<FakeWorkerPool::Task>( | |
315 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
316 base::Unretained(this), | |
317 i, | |
318 2u), | |
319 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
320 base::Unretained(this), | |
321 i, | |
322 2u), | |
323 base::Bind(&WorkerPoolTest::RunTask, | |
324 base::Unretained(this), | |
325 i, | |
326 3u), | |
327 2u, | |
328 0u))); | |
329 } | |
330 | |
331 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
332 RunAllTasksforWorkerPool(i); | |
333 | |
334 // Task should only run once. | |
335 ASSERT_EQ(5u, run_task_ids(i).size()); | |
336 EXPECT_EQ(2u, run_task_ids(i)[2]); | |
337 EXPECT_EQ(3u, run_task_ids(i)[3]); | |
338 EXPECT_EQ(3u, run_task_ids(i)[4]); | |
339 ASSERT_EQ(2u, on_task_completed_ids(i).size()); | |
340 EXPECT_EQ(2u, on_task_completed_ids(i)[1]); | |
341 } | |
342 } | |
343 | |
344 TEST_F(WorkerPoolTest, Priority) { | |
345 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
346 FakeWorkerPool::Task tasks[] = { | |
347 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
348 base::Unretained(this), | |
349 i, | |
350 0u), | |
351 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
352 base::Unretained(this), | |
353 i, | |
354 0u), | |
355 base::Bind(&WorkerPoolTest::RunTask, | |
356 base::Unretained(this), | |
357 i, | |
358 2u), | |
359 1u, | |
360 1u), // Priority 1 | |
361 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
362 base::Unretained(this), | |
363 i, | |
364 1u), | |
365 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
366 base::Unretained(this), | |
367 i, | |
368 1u), | |
369 base::Bind(&WorkerPoolTest::RunTask, | |
370 base::Unretained(this), | |
371 i, | |
372 3u), | |
373 1u, | |
374 0u) // Priority 0 | |
375 }; | |
376 worker_pool(i)->ScheduleTasks( | |
377 std::vector<FakeWorkerPool::Task>(tasks, tasks + arraysize(tasks))); | |
378 } | |
379 | |
380 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
381 RunAllTasksforWorkerPool(i); | |
382 | |
383 // Check if tasks ran in order of priority. | |
384 ASSERT_EQ(4u, run_task_ids(i).size()); | |
385 EXPECT_EQ(1u, run_task_ids(i)[0]); | |
386 EXPECT_EQ(3u, run_task_ids(i)[1]); | |
387 EXPECT_EQ(0u, run_task_ids(i)[2]); | |
388 EXPECT_EQ(2u, run_task_ids(i)[3]); | |
389 ASSERT_EQ(2u, on_task_completed_ids(i).size()); | |
390 EXPECT_EQ(1u, on_task_completed_ids(i)[0]); | |
391 EXPECT_EQ(0u, on_task_completed_ids(i)[1]); | |
392 } | |
393 | |
394 for (int i = 0; i < kWorkerPoolCount; ++i) | |
395 ResetAllIdsforWorkerPool(i); | |
396 | |
397 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
398 std::vector<FakeWorkerPool::Task> tasks; | |
399 tasks.push_back( | |
400 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
401 base::Unretained(this), | |
402 i, | |
403 0u), | |
404 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
405 base::Unretained(this), | |
406 i, | |
407 0u), | |
408 base::Bind(&WorkerPoolTest::RunTask, | |
409 base::Unretained(this), | |
410 i, | |
411 3u), | |
412 1u, // 1 dependent | |
413 1u)); // Priority 1 | |
414 tasks.push_back( | |
415 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
416 base::Unretained(this), | |
417 i, | |
418 1u), | |
419 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
420 base::Unretained(this), | |
421 i, | |
422 1u), | |
423 base::Bind(&WorkerPoolTest::RunTask, | |
424 base::Unretained(this), | |
425 i, | |
426 4u), | |
427 2u, // 2 dependents | |
428 1u)); // Priority 1 | |
429 tasks.push_back( | |
430 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, | |
431 base::Unretained(this), | |
432 i, | |
433 2u), | |
434 base::Bind(&WorkerPoolTest::OnTaskCompleted, | |
435 base::Unretained(this), | |
436 i, | |
437 2u), | |
438 base::Bind(&WorkerPoolTest::RunTask, | |
439 base::Unretained(this), | |
440 i, | |
441 5u), | |
442 1u, // 1 dependent | |
443 0u)); // Priority 0 | |
444 worker_pool(i)->ScheduleTasks(tasks); | |
445 } | |
446 | |
447 for (int i = 0; i < kWorkerPoolCount; ++i) { | |
448 RunAllTasksforWorkerPool(i); | |
449 | |
450 // Check if tasks ran in order of priority and that task with more | |
451 // dependents ran first when priority is the same. | |
452 ASSERT_LE(3u, run_task_ids(i).size()); | |
453 EXPECT_EQ(2u, run_task_ids(i)[0]); | |
454 EXPECT_EQ(5u, run_task_ids(i)[1]); | |
455 EXPECT_EQ(1u, run_task_ids(i)[2]); | |
456 ASSERT_EQ(3u, on_task_completed_ids(i).size()); | |
457 EXPECT_EQ(2u, on_task_completed_ids(i)[0]); | |
458 EXPECT_EQ(1u, on_task_completed_ids(i)[1]); | |
459 EXPECT_EQ(0u, on_task_completed_ids(i)[2]); | |
460 } | |
461 } | |
462 | |
463 } // namespace | |
464 | |
465 } // namespace cc | |
OLD | NEW |