summaryrefslogtreecommitdiffstats
path: root/chromium/cc/resources/task_graph_runner_perftest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/resources/task_graph_runner_perftest.cc')
-rw-r--r--chromium/cc/resources/task_graph_runner_perftest.cc318
1 files changed, 318 insertions, 0 deletions
diff --git a/chromium/cc/resources/task_graph_runner_perftest.cc b/chromium/cc/resources/task_graph_runner_perftest.cc
new file mode 100644
index 00000000000..bfa4ebe8ac3
--- /dev/null
+++ b/chromium/cc/resources/task_graph_runner_perftest.cc
@@ -0,0 +1,318 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/task_graph_runner.h"
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "cc/base/completion_event.h"
+#include "cc/debug/lap_timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+
+class PerfTaskImpl : public Task {
+ public:
+ typedef std::vector<scoped_refptr<PerfTaskImpl> > Vector;
+
+ PerfTaskImpl() {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {}
+
+ void Reset() { did_run_ = false; }
+
+ private:
+ virtual ~PerfTaskImpl() {}
+
+ DISALLOW_COPY_AND_ASSIGN(PerfTaskImpl);
+};
+
+class TaskGraphRunnerPerfTest : public testing::Test {
+ public:
+ TaskGraphRunnerPerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {}
+
+ // Overridden from testing::Test:
+ virtual void SetUp() OVERRIDE {
+ task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner);
+ namespace_token_ = task_graph_runner_->GetNamespaceToken();
+ }
+ virtual void TearDown() OVERRIDE { task_graph_runner_.reset(); }
+
+ void AfterTest(const std::string& test_name) {
+ // Format matches chrome/test/perf/perf_test.h:PrintResult
+ printf(
+ "*RESULT %s: %.2f runs/s\n", test_name.c_str(), timer_.LapsPerSecond());
+ }
+
+ void RunBuildTaskGraphTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph.
+ TaskGraph graph;
+
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("build_task_graph",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunScheduleTasksTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ TaskGraph graph;
+ Task::Vector completed_tasks;
+
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
+ // Shouldn't be any tasks to collect as we reschedule the same set
+ // of tasks.
+ DCHECK_EQ(0u, CollectCompletedTasks(&completed_tasks));
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ CollectCompletedTasks(&completed_tasks);
+
+ perf_test::PrintResult("schedule_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunScheduleAlternateTasksTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ const size_t kNumVersions = 2;
+ PerfTaskImpl::Vector top_level_tasks[kNumVersions];
+ PerfTaskImpl::Vector tasks[kNumVersions];
+ PerfTaskImpl::Vector leaf_tasks[kNumVersions];
+ for (size_t i = 0; i < kNumVersions; ++i) {
+ CreateTasks(num_top_level_tasks, &top_level_tasks[i]);
+ CreateTasks(num_tasks, &tasks[i]);
+ CreateTasks(num_leaf_tasks, &leaf_tasks[i]);
+ }
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ TaskGraph graph;
+ Task::Vector completed_tasks;
+
+ size_t count = 0;
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks[count % kNumVersions],
+ tasks[count % kNumVersions],
+ leaf_tasks[count % kNumVersions],
+ &graph);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
+ CollectCompletedTasks(&completed_tasks);
+ completed_tasks.clear();
+ ++count;
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ CollectCompletedTasks(&completed_tasks);
+
+ perf_test::PrintResult("schedule_alternate_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunScheduleAndExecuteTasksTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ TaskGraph graph;
+ Task::Vector completed_tasks;
+
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
+ task_graph_runner_->RunUntilIdle();
+ CollectCompletedTasks(&completed_tasks);
+ completed_tasks.clear();
+ ResetTasks(&top_level_tasks);
+ ResetTasks(&tasks);
+ ResetTasks(&leaf_tasks);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("execute_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ private:
+ static std::string TestModifierString() {
+ return std::string("_task_graph_runner");
+ }
+
+ void CreateTasks(int num_tasks, PerfTaskImpl::Vector* tasks) {
+ for (int i = 0; i < num_tasks; ++i)
+ tasks->push_back(make_scoped_refptr(new PerfTaskImpl));
+ }
+
+ void ResetTasks(PerfTaskImpl::Vector* tasks) {
+ for (PerfTaskImpl::Vector::iterator it = tasks->begin(); it != tasks->end();
+ ++it) {
+ PerfTaskImpl* task = it->get();
+ task->Reset();
+ }
+ }
+
+ void BuildTaskGraph(const PerfTaskImpl::Vector& top_level_tasks,
+ const PerfTaskImpl::Vector& tasks,
+ const PerfTaskImpl::Vector& leaf_tasks,
+ TaskGraph* graph) {
+ DCHECK(graph->nodes.empty());
+ DCHECK(graph->edges.empty());
+
+ for (PerfTaskImpl::Vector::const_iterator it = leaf_tasks.begin();
+ it != leaf_tasks.end();
+ ++it) {
+ graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, 0u));
+ }
+
+ for (PerfTaskImpl::Vector::const_iterator it = tasks.begin();
+ it != tasks.end();
+ ++it) {
+ graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, leaf_tasks.size()));
+
+ for (PerfTaskImpl::Vector::const_iterator leaf_it = leaf_tasks.begin();
+ leaf_it != leaf_tasks.end();
+ ++leaf_it) {
+ graph->edges.push_back(TaskGraph::Edge(leaf_it->get(), it->get()));
+ }
+
+ for (PerfTaskImpl::Vector::const_iterator top_level_it =
+ top_level_tasks.begin();
+ top_level_it != top_level_tasks.end();
+ ++top_level_it) {
+ graph->edges.push_back(TaskGraph::Edge(it->get(), top_level_it->get()));
+ }
+ }
+
+ for (PerfTaskImpl::Vector::const_iterator it = top_level_tasks.begin();
+ it != top_level_tasks.end();
+ ++it) {
+ graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, tasks.size()));
+ }
+ }
+
+ size_t CollectCompletedTasks(Task::Vector* completed_tasks) {
+ DCHECK(completed_tasks->empty());
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ completed_tasks);
+ return completed_tasks->size();
+ }
+
+ scoped_ptr<TaskGraphRunner> task_graph_runner_;
+ NamespaceToken namespace_token_;
+ LapTimer timer_;
+};
+
+TEST_F(TaskGraphRunnerPerfTest, BuildTaskGraph) {
+ RunBuildTaskGraphTest("0_1_0", 0, 1, 0);
+ RunBuildTaskGraphTest("0_32_0", 0, 32, 0);
+ RunBuildTaskGraphTest("2_1_0", 2, 1, 0);
+ RunBuildTaskGraphTest("2_32_0", 2, 32, 0);
+ RunBuildTaskGraphTest("2_1_1", 2, 1, 1);
+ RunBuildTaskGraphTest("2_32_1", 2, 32, 1);
+}
+
+TEST_F(TaskGraphRunnerPerfTest, ScheduleTasks) {
+ RunScheduleTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleTasksTest("2_32_1", 2, 32, 1);
+}
+
+TEST_F(TaskGraphRunnerPerfTest, ScheduleAlternateTasks) {
+ RunScheduleAlternateTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleAlternateTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleAlternateTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleAlternateTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleAlternateTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleAlternateTasksTest("2_32_1", 2, 32, 1);
+}
+
+TEST_F(TaskGraphRunnerPerfTest, ScheduleAndExecuteTasks) {
+ RunScheduleAndExecuteTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleAndExecuteTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleAndExecuteTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleAndExecuteTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleAndExecuteTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleAndExecuteTasksTest("2_32_1", 2, 32, 1);
+}
+
+} // namespace
+} // namespace cc