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 "base/time/time.h"
      8 #include "cc/base/completion_event.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace cc {
     12 
     13 namespace {
     14 
     15 static const int kTimeLimitMillis = 2000;
     16 static const int kWarmupRuns = 5;
     17 static const int kTimeCheckInterval = 10;
     18 
     19 class PerfWorkerPoolTaskImpl : public internal::WorkerPoolTask {
     20  public:
     21   // Overridden from internal::WorkerPoolTask:
     22   virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {}
     23   virtual void CompleteOnOriginThread() OVERRIDE {}
     24 
     25  private:
     26   virtual ~PerfWorkerPoolTaskImpl() {}
     27 };
     28 
     29 class PerfControlWorkerPoolTaskImpl : public internal::WorkerPoolTask {
     30  public:
     31   PerfControlWorkerPoolTaskImpl() : did_start_(new CompletionEvent),
     32                                     can_finish_(new CompletionEvent) {}
     33 
     34   // Overridden from internal::WorkerPoolTask:
     35   virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
     36     did_start_->Signal();
     37     can_finish_->Wait();
     38   }
     39   virtual void CompleteOnOriginThread() OVERRIDE {}
     40 
     41   void WaitForTaskToStartRunning() {
     42     did_start_->Wait();
     43   }
     44 
     45   void AllowTaskToFinish() {
     46     can_finish_->Signal();
     47   }
     48 
     49  private:
     50   virtual ~PerfControlWorkerPoolTaskImpl() {}
     51 
     52   scoped_ptr<CompletionEvent> did_start_;
     53   scoped_ptr<CompletionEvent> can_finish_;
     54 
     55   DISALLOW_COPY_AND_ASSIGN(PerfControlWorkerPoolTaskImpl);
     56 };
     57 
     58 class PerfWorkerPool : public WorkerPool {
     59  public:
     60   PerfWorkerPool() : WorkerPool(1, "test") {}
     61   virtual ~PerfWorkerPool() {}
     62 
     63   static scoped_ptr<PerfWorkerPool> Create() {
     64     return make_scoped_ptr(new PerfWorkerPool);
     65   }
     66 
     67   void ScheduleTasks(internal::WorkerPoolTask* root_task,
     68                      internal::WorkerPoolTask* leaf_task,
     69                      unsigned max_depth,
     70                      unsigned num_children_per_node) {
     71     TaskVector tasks;
     72     TaskGraph graph;
     73 
     74     scoped_ptr<internal::GraphNode> root_node;
     75     if (root_task)
     76       root_node = make_scoped_ptr(new internal::GraphNode(root_task, 0u));
     77 
     78     scoped_ptr<internal::GraphNode> leaf_node;
     79     if (leaf_task)
     80       leaf_node = make_scoped_ptr(new internal::GraphNode(leaf_task, 0u));
     81 
     82     if (max_depth) {
     83       BuildTaskGraph(&tasks,
     84                      &graph,
     85                      root_node.get(),
     86                      leaf_node.get(),
     87                      0,
     88                      max_depth,
     89                      num_children_per_node);
     90     }
     91 
     92     if (leaf_node)
     93       graph.set(leaf_task, leaf_node.Pass());
     94 
     95     if (root_node)
     96       graph.set(root_task, root_node.Pass());
     97 
     98     SetTaskGraph(&graph);
     99 
    100     tasks_.swap(tasks);
    101   }
    102 
    103  private:
    104   typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector;
    105 
    106   void BuildTaskGraph(TaskVector* tasks,
    107                       TaskGraph* graph,
    108                       internal::GraphNode* dependent_node,
    109                       internal::GraphNode* leaf_node,
    110                       unsigned current_depth,
    111                       unsigned max_depth,
    112                       unsigned num_children_per_node) {
    113     scoped_refptr<PerfWorkerPoolTaskImpl> task(new PerfWorkerPoolTaskImpl);
    114     scoped_ptr<internal::GraphNode> node(
    115         new internal::GraphNode(task.get(), 0u));
    116 
    117     if (current_depth < max_depth) {
    118       for (unsigned i = 0; i < num_children_per_node; ++i) {
    119         BuildTaskGraph(tasks,
    120                        graph,
    121                        node.get(),
    122                        leaf_node,
    123                        current_depth + 1,
    124                        max_depth,
    125                        num_children_per_node);
    126       }
    127     } else if (leaf_node) {
    128       leaf_node->add_dependent(node.get());
    129       node->add_dependency();
    130     }
    131 
    132     if (dependent_node) {
    133       node->add_dependent(dependent_node);
    134       dependent_node->add_dependency();
    135     }
    136     graph->set(task.get(), node.Pass());
    137     tasks->push_back(task.get());
    138   }
    139 
    140   TaskVector tasks_;
    141 
    142   DISALLOW_COPY_AND_ASSIGN(PerfWorkerPool);
    143 };
    144 
    145 class WorkerPoolPerfTest : public testing::Test {
    146  public:
    147   WorkerPoolPerfTest() : num_runs_(0) {}
    148 
    149   // Overridden from testing::Test:
    150   virtual void SetUp() OVERRIDE {
    151     worker_pool_ = PerfWorkerPool::Create();
    152   }
    153   virtual void TearDown() OVERRIDE {
    154     worker_pool_->Shutdown();
    155     worker_pool_->CheckForCompletedTasks();
    156   }
    157 
    158   void EndTest() {
    159     elapsed_ = base::TimeTicks::HighResNow() - start_time_;
    160   }
    161 
    162   void AfterTest(const std::string test_name) {
    163     // Format matches chrome/test/perf/perf_test.h:PrintResult
    164     printf("*RESULT %s: %.2f runs/s\n",
    165            test_name.c_str(),
    166            num_runs_ / elapsed_.InSecondsF());
    167   }
    168 
    169   bool DidRun() {
    170     ++num_runs_;
    171     if (num_runs_ == kWarmupRuns)
    172       start_time_ = base::TimeTicks::HighResNow();
    173 
    174     if (!start_time_.is_null() && (num_runs_ % kTimeCheckInterval) == 0) {
    175       base::TimeDelta elapsed = base::TimeTicks::HighResNow() - start_time_;
    176       if (elapsed >= base::TimeDelta::FromMilliseconds(kTimeLimitMillis)) {
    177         elapsed_ = elapsed;
    178         return false;
    179       }
    180     }
    181 
    182     return true;
    183   }
    184 
    185   void RunScheduleTasksTest(const std::string test_name,
    186                             unsigned max_depth,
    187                             unsigned num_children_per_node) {
    188     start_time_ = base::TimeTicks();
    189     num_runs_ = 0;
    190     do {
    191       scoped_refptr<PerfControlWorkerPoolTaskImpl> leaf_task(
    192           new PerfControlWorkerPoolTaskImpl);
    193       worker_pool_->ScheduleTasks(
    194           NULL, leaf_task.get(), max_depth, num_children_per_node);
    195       leaf_task->WaitForTaskToStartRunning();
    196       worker_pool_->ScheduleTasks(NULL, NULL, 0, 0);
    197       worker_pool_->CheckForCompletedTasks();
    198       leaf_task->AllowTaskToFinish();
    199     } while (DidRun());
    200 
    201     AfterTest(test_name);
    202   }
    203 
    204   void RunExecuteTasksTest(const std::string test_name,
    205                            unsigned max_depth,
    206                            unsigned num_children_per_node) {
    207     start_time_ = base::TimeTicks();
    208     num_runs_ = 0;
    209     do {
    210       scoped_refptr<PerfControlWorkerPoolTaskImpl> root_task(
    211           new PerfControlWorkerPoolTaskImpl);
    212       worker_pool_->ScheduleTasks(
    213           root_task.get(), NULL, max_depth, num_children_per_node);
    214       root_task->WaitForTaskToStartRunning();
    215       root_task->AllowTaskToFinish();
    216       worker_pool_->CheckForCompletedTasks();
    217     } while (DidRun());
    218 
    219     AfterTest(test_name);
    220   }
    221 
    222  protected:
    223   scoped_ptr<PerfWorkerPool> worker_pool_;
    224   base::TimeTicks start_time_;
    225   base::TimeDelta elapsed_;
    226   int num_runs_;
    227 };
    228 
    229 TEST_F(WorkerPoolPerfTest, ScheduleTasks) {
    230   RunScheduleTasksTest("schedule_tasks_1_10", 1, 10);
    231   RunScheduleTasksTest("schedule_tasks_1_1000", 1, 1000);
    232   RunScheduleTasksTest("schedule_tasks_2_10", 2, 10);
    233   RunScheduleTasksTest("schedule_tasks_5_5", 5, 5);
    234   RunScheduleTasksTest("schedule_tasks_10_2", 10, 2);
    235   RunScheduleTasksTest("schedule_tasks_1000_1", 1000, 1);
    236   RunScheduleTasksTest("schedule_tasks_10_1", 10, 1);
    237 }
    238 
    239 TEST_F(WorkerPoolPerfTest, ExecuteTasks) {
    240   RunExecuteTasksTest("execute_tasks_1_10", 1, 10);
    241   RunExecuteTasksTest("execute_tasks_1_1000", 1, 1000);
    242   RunExecuteTasksTest("execute_tasks_2_10", 2, 10);
    243   RunExecuteTasksTest("execute_tasks_5_5", 5, 5);
    244   RunExecuteTasksTest("execute_tasks_10_2", 10, 2);
    245   RunExecuteTasksTest("execute_tasks_1000_1", 1000, 1);
    246   RunExecuteTasksTest("execute_tasks_10_1", 10, 1);
    247 }
    248 
    249 }  // namespace
    250 
    251 }  // namespace cc
    252