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 11namespace cc { 12 13namespace { 14 15static const int kTimeLimitMillis = 2000; 16static const int kWarmupRuns = 5; 17static const int kTimeCheckInterval = 10; 18 19class 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 29class 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 58class 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 145class 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 229TEST_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 239TEST_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