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