Home | History | Annotate | Download | only in resources
      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
      3 // found in the LICENSE file.
      4 
      5 #include "cc/resources/task_graph_runner.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/time/time.h"
     11 #include "cc/base/completion_event.h"
     12 #include "cc/debug/lap_timer.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "testing/perf/perf_test.h"
     15 
     16 namespace cc {
     17 namespace {
     18 
     19 static const int kTimeLimitMillis = 2000;
     20 static const int kWarmupRuns = 5;
     21 static const int kTimeCheckInterval = 10;
     22 
     23 class PerfTaskImpl : public Task {
     24  public:
     25   typedef std::vector<scoped_refptr<PerfTaskImpl> > Vector;
     26 
     27   PerfTaskImpl() {}
     28 
     29   // Overridden from Task:
     30   virtual void RunOnWorkerThread() OVERRIDE {}
     31 
     32   void Reset() { did_run_ = false; }
     33 
     34  private:
     35   virtual ~PerfTaskImpl() {}
     36 
     37   DISALLOW_COPY_AND_ASSIGN(PerfTaskImpl);
     38 };
     39 
     40 class TaskGraphRunnerPerfTest : public testing::Test {
     41  public:
     42   TaskGraphRunnerPerfTest()
     43       : timer_(kWarmupRuns,
     44                base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
     45                kTimeCheckInterval) {}
     46 
     47   // Overridden from testing::Test:
     48   virtual void SetUp() OVERRIDE {
     49     task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner);
     50     namespace_token_ = task_graph_runner_->GetNamespaceToken();
     51   }
     52   virtual void TearDown() OVERRIDE { task_graph_runner_.reset(); }
     53 
     54   void AfterTest(const std::string& test_name) {
     55     // Format matches chrome/test/perf/perf_test.h:PrintResult
     56     printf(
     57         "*RESULT %s: %.2f runs/s\n", test_name.c_str(), timer_.LapsPerSecond());
     58   }
     59 
     60   void RunBuildTaskGraphTest(const std::string& test_name,
     61                              int num_top_level_tasks,
     62                              int num_tasks,
     63                              int num_leaf_tasks) {
     64     PerfTaskImpl::Vector top_level_tasks;
     65     PerfTaskImpl::Vector tasks;
     66     PerfTaskImpl::Vector leaf_tasks;
     67     CreateTasks(num_top_level_tasks, &top_level_tasks);
     68     CreateTasks(num_tasks, &tasks);
     69     CreateTasks(num_leaf_tasks, &leaf_tasks);
     70 
     71     // Avoid unnecessary heap allocations by reusing the same graph.
     72     TaskGraph graph;
     73 
     74     timer_.Reset();
     75     do {
     76       graph.Reset();
     77       BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
     78       timer_.NextLap();
     79     } while (!timer_.HasTimeLimitExpired());
     80 
     81     perf_test::PrintResult("build_task_graph",
     82                            TestModifierString(),
     83                            test_name,
     84                            timer_.LapsPerSecond(),
     85                            "runs/s",
     86                            true);
     87   }
     88 
     89   void RunScheduleTasksTest(const std::string& test_name,
     90                             int num_top_level_tasks,
     91                             int num_tasks,
     92                             int num_leaf_tasks) {
     93     PerfTaskImpl::Vector top_level_tasks;
     94     PerfTaskImpl::Vector tasks;
     95     PerfTaskImpl::Vector leaf_tasks;
     96     CreateTasks(num_top_level_tasks, &top_level_tasks);
     97     CreateTasks(num_tasks, &tasks);
     98     CreateTasks(num_leaf_tasks, &leaf_tasks);
     99 
    100     // Avoid unnecessary heap allocations by reusing the same graph and
    101     // completed tasks vector.
    102     TaskGraph graph;
    103     Task::Vector completed_tasks;
    104 
    105     timer_.Reset();
    106     do {
    107       graph.Reset();
    108       BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
    109       task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
    110       // Shouldn't be any tasks to collect as we reschedule the same set
    111       // of tasks.
    112       DCHECK_EQ(0u, CollectCompletedTasks(&completed_tasks));
    113       timer_.NextLap();
    114     } while (!timer_.HasTimeLimitExpired());
    115 
    116     TaskGraph empty;
    117     task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
    118     CollectCompletedTasks(&completed_tasks);
    119 
    120     perf_test::PrintResult("schedule_tasks",
    121                            TestModifierString(),
    122                            test_name,
    123                            timer_.LapsPerSecond(),
    124                            "runs/s",
    125                            true);
    126   }
    127 
    128   void RunScheduleAlternateTasksTest(const std::string& test_name,
    129                                      int num_top_level_tasks,
    130                                      int num_tasks,
    131                                      int num_leaf_tasks) {
    132     const size_t kNumVersions = 2;
    133     PerfTaskImpl::Vector top_level_tasks[kNumVersions];
    134     PerfTaskImpl::Vector tasks[kNumVersions];
    135     PerfTaskImpl::Vector leaf_tasks[kNumVersions];
    136     for (size_t i = 0; i < kNumVersions; ++i) {
    137       CreateTasks(num_top_level_tasks, &top_level_tasks[i]);
    138       CreateTasks(num_tasks, &tasks[i]);
    139       CreateTasks(num_leaf_tasks, &leaf_tasks[i]);
    140     }
    141 
    142     // Avoid unnecessary heap allocations by reusing the same graph and
    143     // completed tasks vector.
    144     TaskGraph graph;
    145     Task::Vector completed_tasks;
    146 
    147     size_t count = 0;
    148     timer_.Reset();
    149     do {
    150       graph.Reset();
    151       BuildTaskGraph(top_level_tasks[count % kNumVersions],
    152                      tasks[count % kNumVersions],
    153                      leaf_tasks[count % kNumVersions],
    154                      &graph);
    155       task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
    156       CollectCompletedTasks(&completed_tasks);
    157       completed_tasks.clear();
    158       ++count;
    159       timer_.NextLap();
    160     } while (!timer_.HasTimeLimitExpired());
    161 
    162     TaskGraph empty;
    163     task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
    164     CollectCompletedTasks(&completed_tasks);
    165 
    166     perf_test::PrintResult("schedule_alternate_tasks",
    167                            TestModifierString(),
    168                            test_name,
    169                            timer_.LapsPerSecond(),
    170                            "runs/s",
    171                            true);
    172   }
    173 
    174   void RunScheduleAndExecuteTasksTest(const std::string& test_name,
    175                                       int num_top_level_tasks,
    176                                       int num_tasks,
    177                                       int num_leaf_tasks) {
    178     PerfTaskImpl::Vector top_level_tasks;
    179     PerfTaskImpl::Vector tasks;
    180     PerfTaskImpl::Vector leaf_tasks;
    181     CreateTasks(num_top_level_tasks, &top_level_tasks);
    182     CreateTasks(num_tasks, &tasks);
    183     CreateTasks(num_leaf_tasks, &leaf_tasks);
    184 
    185     // Avoid unnecessary heap allocations by reusing the same graph and
    186     // completed tasks vector.
    187     TaskGraph graph;
    188     Task::Vector completed_tasks;
    189 
    190     timer_.Reset();
    191     do {
    192       graph.Reset();
    193       BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
    194       task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
    195       task_graph_runner_->RunUntilIdle();
    196       CollectCompletedTasks(&completed_tasks);
    197       completed_tasks.clear();
    198       ResetTasks(&top_level_tasks);
    199       ResetTasks(&tasks);
    200       ResetTasks(&leaf_tasks);
    201       timer_.NextLap();
    202     } while (!timer_.HasTimeLimitExpired());
    203 
    204     perf_test::PrintResult("execute_tasks",
    205                            TestModifierString(),
    206                            test_name,
    207                            timer_.LapsPerSecond(),
    208                            "runs/s",
    209                            true);
    210   }
    211 
    212  private:
    213   static std::string TestModifierString() {
    214     return std::string("_task_graph_runner");
    215   }
    216 
    217   void CreateTasks(int num_tasks, PerfTaskImpl::Vector* tasks) {
    218     for (int i = 0; i < num_tasks; ++i)
    219       tasks->push_back(make_scoped_refptr(new PerfTaskImpl));
    220   }
    221 
    222   void ResetTasks(PerfTaskImpl::Vector* tasks) {
    223     for (PerfTaskImpl::Vector::iterator it = tasks->begin(); it != tasks->end();
    224          ++it) {
    225       PerfTaskImpl* task = it->get();
    226       task->Reset();
    227     }
    228   }
    229 
    230   void BuildTaskGraph(const PerfTaskImpl::Vector& top_level_tasks,
    231                       const PerfTaskImpl::Vector& tasks,
    232                       const PerfTaskImpl::Vector& leaf_tasks,
    233                       TaskGraph* graph) {
    234     DCHECK(graph->nodes.empty());
    235     DCHECK(graph->edges.empty());
    236 
    237     for (PerfTaskImpl::Vector::const_iterator it = leaf_tasks.begin();
    238          it != leaf_tasks.end();
    239          ++it) {
    240       graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, 0u));
    241     }
    242 
    243     for (PerfTaskImpl::Vector::const_iterator it = tasks.begin();
    244          it != tasks.end();
    245          ++it) {
    246       graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, leaf_tasks.size()));
    247 
    248       for (PerfTaskImpl::Vector::const_iterator leaf_it = leaf_tasks.begin();
    249            leaf_it != leaf_tasks.end();
    250            ++leaf_it) {
    251         graph->edges.push_back(TaskGraph::Edge(leaf_it->get(), it->get()));
    252       }
    253 
    254       for (PerfTaskImpl::Vector::const_iterator top_level_it =
    255                top_level_tasks.begin();
    256            top_level_it != top_level_tasks.end();
    257            ++top_level_it) {
    258         graph->edges.push_back(TaskGraph::Edge(it->get(), top_level_it->get()));
    259       }
    260     }
    261 
    262     for (PerfTaskImpl::Vector::const_iterator it = top_level_tasks.begin();
    263          it != top_level_tasks.end();
    264          ++it) {
    265       graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, tasks.size()));
    266     }
    267   }
    268 
    269   size_t CollectCompletedTasks(Task::Vector* completed_tasks) {
    270     DCHECK(completed_tasks->empty());
    271     task_graph_runner_->CollectCompletedTasks(namespace_token_,
    272                                               completed_tasks);
    273     return completed_tasks->size();
    274   }
    275 
    276   scoped_ptr<TaskGraphRunner> task_graph_runner_;
    277   NamespaceToken namespace_token_;
    278   LapTimer timer_;
    279 };
    280 
    281 TEST_F(TaskGraphRunnerPerfTest, BuildTaskGraph) {
    282   RunBuildTaskGraphTest("0_1_0", 0, 1, 0);
    283   RunBuildTaskGraphTest("0_32_0", 0, 32, 0);
    284   RunBuildTaskGraphTest("2_1_0", 2, 1, 0);
    285   RunBuildTaskGraphTest("2_32_0", 2, 32, 0);
    286   RunBuildTaskGraphTest("2_1_1", 2, 1, 1);
    287   RunBuildTaskGraphTest("2_32_1", 2, 32, 1);
    288 }
    289 
    290 TEST_F(TaskGraphRunnerPerfTest, ScheduleTasks) {
    291   RunScheduleTasksTest("0_1_0", 0, 1, 0);
    292   RunScheduleTasksTest("0_32_0", 0, 32, 0);
    293   RunScheduleTasksTest("2_1_0", 2, 1, 0);
    294   RunScheduleTasksTest("2_32_0", 2, 32, 0);
    295   RunScheduleTasksTest("2_1_1", 2, 1, 1);
    296   RunScheduleTasksTest("2_32_1", 2, 32, 1);
    297 }
    298 
    299 TEST_F(TaskGraphRunnerPerfTest, ScheduleAlternateTasks) {
    300   RunScheduleAlternateTasksTest("0_1_0", 0, 1, 0);
    301   RunScheduleAlternateTasksTest("0_32_0", 0, 32, 0);
    302   RunScheduleAlternateTasksTest("2_1_0", 2, 1, 0);
    303   RunScheduleAlternateTasksTest("2_32_0", 2, 32, 0);
    304   RunScheduleAlternateTasksTest("2_1_1", 2, 1, 1);
    305   RunScheduleAlternateTasksTest("2_32_1", 2, 32, 1);
    306 }
    307 
    308 TEST_F(TaskGraphRunnerPerfTest, ScheduleAndExecuteTasks) {
    309   RunScheduleAndExecuteTasksTest("0_1_0", 0, 1, 0);
    310   RunScheduleAndExecuteTasksTest("0_32_0", 0, 32, 0);
    311   RunScheduleAndExecuteTasksTest("2_1_0", 2, 1, 0);
    312   RunScheduleAndExecuteTasksTest("2_32_0", 2, 32, 0);
    313   RunScheduleAndExecuteTasksTest("2_1_1", 2, 1, 1);
    314   RunScheduleAndExecuteTasksTest("2_32_1", 2, 32, 1);
    315 }
    316 
    317 }  // namespace
    318 }  // namespace cc
    319