Index: cc/resources/worker_pool_perftest.cc |
diff --git a/cc/resources/worker_pool_perftest.cc b/cc/resources/worker_pool_perftest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..108586964b9d5bd75a0c6b72b4eefbc5000983af |
--- /dev/null |
+++ b/cc/resources/worker_pool_perftest.cc |
@@ -0,0 +1,239 @@ |
+// Copyright 2013 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/worker_pool.h" |
+ |
+#include "base/time/time.h" |
+#include "cc/base/completion_event.h" |
+#include "cc/test/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 PerfWorkerPoolTaskImpl : public internal::WorkerPoolTask { |
+ public: |
+ // Overridden from internal::WorkerPoolTask: |
+ virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {} |
+ virtual void CompleteOnOriginThread() OVERRIDE {} |
+ |
+ private: |
+ virtual ~PerfWorkerPoolTaskImpl() {} |
+}; |
+ |
+class PerfControlWorkerPoolTaskImpl : public internal::WorkerPoolTask { |
+ public: |
+ PerfControlWorkerPoolTaskImpl() : did_start_(new CompletionEvent), |
+ can_finish_(new CompletionEvent) {} |
+ |
+ // Overridden from internal::WorkerPoolTask: |
+ virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE { |
+ did_start_->Signal(); |
+ can_finish_->Wait(); |
+ } |
+ virtual void CompleteOnOriginThread() OVERRIDE {} |
+ |
+ void WaitForTaskToStartRunning() { |
+ did_start_->Wait(); |
+ } |
+ |
+ void AllowTaskToFinish() { |
+ can_finish_->Signal(); |
+ } |
+ |
+ private: |
+ virtual ~PerfControlWorkerPoolTaskImpl() {} |
+ |
+ scoped_ptr<CompletionEvent> did_start_; |
+ scoped_ptr<CompletionEvent> can_finish_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(PerfControlWorkerPoolTaskImpl); |
+}; |
+ |
+class PerfWorkerPool : public WorkerPool { |
+ public: |
+ PerfWorkerPool() : WorkerPool() {} |
+ virtual ~PerfWorkerPool() {} |
+ |
+ static scoped_ptr<PerfWorkerPool> Create() { |
+ return make_scoped_ptr(new PerfWorkerPool); |
+ } |
+ |
+ void ScheduleTasks(internal::WorkerPoolTask* root_task, |
+ internal::WorkerPoolTask* leaf_task, |
+ unsigned max_depth, |
+ unsigned num_children_per_node) { |
+ TaskVector tasks; |
+ TaskGraph graph; |
+ |
+ scoped_ptr<internal::GraphNode> root_node; |
+ if (root_task) |
+ root_node = make_scoped_ptr(new internal::GraphNode(root_task, 0u)); |
+ |
+ scoped_ptr<internal::GraphNode> leaf_node; |
+ if (leaf_task) |
+ leaf_node = make_scoped_ptr(new internal::GraphNode(leaf_task, 0u)); |
+ |
+ if (max_depth) { |
+ BuildTaskGraph(&tasks, |
+ &graph, |
+ root_node.get(), |
+ leaf_node.get(), |
+ 0, |
+ max_depth, |
+ num_children_per_node); |
+ } |
+ |
+ if (leaf_node) |
+ graph.set(leaf_task, leaf_node.Pass()); |
+ |
+ if (root_node) |
+ graph.set(root_task, root_node.Pass()); |
+ |
+ SetTaskGraph(&graph); |
+ |
+ tasks_.swap(tasks); |
+ } |
+ |
+ void CheckForCompletedTasks() { |
+ CheckForCompletedWorkerTasks(); |
+ } |
+ |
+ private: |
+ typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector; |
+ |
+ void BuildTaskGraph(TaskVector* tasks, |
+ TaskGraph* graph, |
+ internal::GraphNode* dependent_node, |
+ internal::GraphNode* leaf_node, |
+ unsigned current_depth, |
+ unsigned max_depth, |
+ unsigned num_children_per_node) { |
+ scoped_refptr<PerfWorkerPoolTaskImpl> task(new PerfWorkerPoolTaskImpl); |
+ scoped_ptr<internal::GraphNode> node( |
+ new internal::GraphNode(task.get(), 0u)); |
+ |
+ if (current_depth < max_depth) { |
+ for (unsigned i = 0; i < num_children_per_node; ++i) { |
+ BuildTaskGraph(tasks, |
+ graph, |
+ node.get(), |
+ leaf_node, |
+ current_depth + 1, |
+ max_depth, |
+ num_children_per_node); |
+ } |
+ } else if (leaf_node) { |
+ leaf_node->add_dependent(node.get()); |
+ node->add_dependency(); |
+ } |
+ |
+ if (dependent_node) { |
+ node->add_dependent(dependent_node); |
+ dependent_node->add_dependency(); |
+ } |
+ graph->set(task.get(), node.Pass()); |
+ tasks->push_back(task.get()); |
+ } |
+ |
+ TaskVector tasks_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(PerfWorkerPool); |
+}; |
+ |
+class WorkerPoolPerfTest : public testing::Test { |
+ public: |
+ WorkerPoolPerfTest() |
+ : timer_(kWarmupRuns, |
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis), |
+ kTimeCheckInterval) {} |
+ |
+ // Overridden from testing::Test: |
+ virtual void SetUp() OVERRIDE { |
+ worker_pool_ = PerfWorkerPool::Create(); |
+ } |
+ virtual void TearDown() OVERRIDE { |
+ worker_pool_->Shutdown(); |
+ worker_pool_->CheckForCompletedTasks(); |
+ } |
+ |
+ 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 RunScheduleTasksTest(const std::string& test_name, |
+ unsigned max_depth, |
+ unsigned num_children_per_node) { |
+ timer_.Reset(); |
+ do { |
+ scoped_refptr<PerfControlWorkerPoolTaskImpl> leaf_task( |
+ new PerfControlWorkerPoolTaskImpl); |
+ worker_pool_->ScheduleTasks( |
+ NULL, leaf_task.get(), max_depth, num_children_per_node); |
+ leaf_task->WaitForTaskToStartRunning(); |
+ worker_pool_->ScheduleTasks(NULL, NULL, 0, 0); |
+ worker_pool_->CheckForCompletedTasks(); |
+ leaf_task->AllowTaskToFinish(); |
+ timer_.NextLap(); |
+ } while (!timer_.HasTimeLimitExpired()); |
+ |
+ perf_test::PrintResult("schedule_tasks", "", test_name, |
+ timer_.LapsPerSecond(), "runs/s", true); |
+ } |
+ |
+ void RunExecuteTasksTest(const std::string& test_name, |
+ unsigned max_depth, |
+ unsigned num_children_per_node) { |
+ timer_.Reset(); |
+ do { |
+ scoped_refptr<PerfControlWorkerPoolTaskImpl> root_task( |
+ new PerfControlWorkerPoolTaskImpl); |
+ worker_pool_->ScheduleTasks( |
+ root_task.get(), NULL, max_depth, num_children_per_node); |
+ root_task->WaitForTaskToStartRunning(); |
+ root_task->AllowTaskToFinish(); |
+ worker_pool_->CheckForCompletedTasks(); |
+ timer_.NextLap(); |
+ } while (!timer_.HasTimeLimitExpired()); |
+ |
+ perf_test::PrintResult("execute_tasks", "", test_name, |
+ timer_.LapsPerSecond(), "runs/s", true); |
+ } |
+ |
+ protected: |
+ scoped_ptr<PerfWorkerPool> worker_pool_; |
+ LapTimer timer_; |
+}; |
+ |
+TEST_F(WorkerPoolPerfTest, ScheduleTasks) { |
+ RunScheduleTasksTest("1_10", 1, 10); |
+ RunScheduleTasksTest("1_1000", 1, 1000); |
+ RunScheduleTasksTest("2_10", 2, 10); |
+ RunScheduleTasksTest("5_5", 5, 5); |
+ RunScheduleTasksTest("10_2", 10, 2); |
+ RunScheduleTasksTest("1000_1", 1000, 1); |
+ RunScheduleTasksTest("10_1", 10, 1); |
+} |
+ |
+TEST_F(WorkerPoolPerfTest, ExecuteTasks) { |
+ RunExecuteTasksTest("1_10", 1, 10); |
+ RunExecuteTasksTest("1_1000", 1, 1000); |
+ RunExecuteTasksTest("2_10", 2, 10); |
+ RunExecuteTasksTest("5_5", 5, 5); |
+ RunExecuteTasksTest("10_2", 10, 2); |
+ RunExecuteTasksTest("1000_1", 1000, 1); |
+ RunExecuteTasksTest("10_1", 10, 1); |
+} |
+ |
+} // namespace |
+ |
+} // namespace cc |