Home | History | Annotate | Download | only in resources
      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:
     18   FakeWorkerPoolTaskImpl(const base::Closure& callback,
     19                          const base::Closure& reply)
     20       : callback_(callback),
     21         reply_(reply) {
     22   }
     23 
     24   // Overridden from internal::WorkerPoolTask:
     25   virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
     26     if (!callback_.is_null())
     27       callback_.Run();
     28   }
     29   virtual void CompleteOnOriginThread() OVERRIDE {
     30     if (!reply_.is_null())
     31       reply_.Run();
     32   }
     33 
     34  private:
     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 {
     46     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   };
     63   FakeWorkerPool() : WorkerPool(1, "test") {}
     64   virtual ~FakeWorkerPool() {}
     65 
     66   static scoped_ptr<FakeWorkerPool> Create() {
     67     return make_scoped_ptr(new FakeWorkerPool);
     68   }
     69 
     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 
    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 
    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:
    142   WorkerPoolTest() {}
    143   virtual ~WorkerPoolTest() {}
    144 
    145   // Overridden from testing::Test:
    146   virtual void SetUp() OVERRIDE {
    147     worker_pool_ = FakeWorkerPool::Create();
    148   }
    149   virtual void TearDown() OVERRIDE {
    150     worker_pool_->Shutdown();
    151     worker_pool_->CheckForCompletedTasks();
    152   }
    153 
    154   void ResetIds() {
    155     run_task_ids_.clear();
    156     on_task_completed_ids_.clear();
    157   }
    158 
    159   void RunAllTasks() {
    160     worker_pool_->WaitForTasksToComplete();
    161     worker_pool_->CheckForCompletedTasks();
    162   }
    163 
    164   FakeWorkerPool* worker_pool() {
    165     return worker_pool_.get();
    166   }
    167 
    168   void RunTask(unsigned id) {
    169     run_task_ids_.push_back(id);
    170   }
    171 
    172   void OnTaskCompleted(unsigned id) {
    173     on_task_completed_ids_.push_back(id);
    174   }
    175 
    176   const std::vector<unsigned>& run_task_ids() {
    177     return run_task_ids_;
    178   }
    179 
    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 
    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 
    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 
    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