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 <vector> 8 9#include "cc/base/completion_event.h" 10#include "testing/gtest/include/gtest/gtest.h" 11 12namespace cc { 13 14namespace { 15 16class FakeWorkerPoolTaskImpl : public internal::WorkerPoolTask { 17 public: 18 FakeWorkerPoolTaskImpl(const base::Closure& callback, 19 const base::Closure& reply) 20 : callback_(callback), 21 reply_(reply) { 22 } 23 24 // Overridden from internal::WorkerPoolTask: 25 virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE { 26 if (!callback_.is_null()) 27 callback_.Run(); 28 } 29 virtual void CompleteOnOriginThread() OVERRIDE { 30 if (!reply_.is_null()) 31 reply_.Run(); 32 } 33 34 private: 35 virtual ~FakeWorkerPoolTaskImpl() {} 36 37 const base::Closure callback_; 38 const base::Closure reply_; 39 40 DISALLOW_COPY_AND_ASSIGN(FakeWorkerPoolTaskImpl); 41}; 42 43class FakeWorkerPool : public WorkerPool { 44 public: 45 struct Task { 46 Task(const base::Closure& callback, 47 const base::Closure& reply, 48 const base::Closure& dependent, 49 unsigned dependent_count, 50 unsigned priority) : callback(callback), 51 reply(reply), 52 dependent(dependent), 53 dependent_count(dependent_count), 54 priority(priority) { 55 } 56 57 base::Closure callback; 58 base::Closure reply; 59 base::Closure dependent; 60 unsigned dependent_count; 61 unsigned priority; 62 }; 63 FakeWorkerPool() : WorkerPool(1, "test") {} 64 virtual ~FakeWorkerPool() {} 65 66 static scoped_ptr<FakeWorkerPool> Create() { 67 return make_scoped_ptr(new FakeWorkerPool); 68 } 69 70 void ScheduleTasks(const std::vector<Task>& tasks) { 71 TaskVector new_tasks; 72 TaskVector new_dependents; 73 TaskGraph new_graph; 74 75 scoped_refptr<FakeWorkerPoolTaskImpl> new_completion_task( 76 new FakeWorkerPoolTaskImpl( 77 base::Bind(&FakeWorkerPool::OnTasksCompleted, 78 base::Unretained(this)), 79 base::Closure())); 80 scoped_ptr<internal::GraphNode> completion_node( 81 new internal::GraphNode(new_completion_task.get(), 0u)); 82 83 for (std::vector<Task>::const_iterator it = tasks.begin(); 84 it != tasks.end(); ++it) { 85 scoped_refptr<FakeWorkerPoolTaskImpl> new_task( 86 new FakeWorkerPoolTaskImpl(it->callback, it->reply)); 87 scoped_ptr<internal::GraphNode> node( 88 new internal::GraphNode(new_task.get(), it->priority)); 89 90 DCHECK(it->dependent_count); 91 for (unsigned i = 0; i < it->dependent_count; ++i) { 92 scoped_refptr<FakeWorkerPoolTaskImpl> new_dependent_task( 93 new FakeWorkerPoolTaskImpl(it->dependent, base::Closure())); 94 scoped_ptr<internal::GraphNode> dependent_node( 95 new internal::GraphNode(new_dependent_task.get(), it->priority)); 96 dependent_node->add_dependent(completion_node.get()); 97 completion_node->add_dependency(); 98 node->add_dependent(dependent_node.get()); 99 dependent_node->add_dependency(); 100 new_graph.set(new_dependent_task.get(), dependent_node.Pass()); 101 new_dependents.push_back(new_dependent_task.get()); 102 } 103 104 new_graph.set(new_task.get(), node.Pass()); 105 new_tasks.push_back(new_task.get()); 106 } 107 108 new_graph.set(new_completion_task.get(), completion_node.Pass()); 109 110 scheduled_tasks_completion_.reset(new CompletionEvent); 111 112 SetTaskGraph(&new_graph); 113 114 dependents_.swap(new_dependents); 115 completion_task_.swap(new_completion_task); 116 tasks_.swap(new_tasks); 117 } 118 119 void WaitForTasksToComplete() { 120 DCHECK(scheduled_tasks_completion_); 121 scheduled_tasks_completion_->Wait(); 122 } 123 124 private: 125 typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector; 126 127 void OnTasksCompleted() { 128 DCHECK(scheduled_tasks_completion_); 129 scheduled_tasks_completion_->Signal(); 130 } 131 132 TaskVector tasks_; 133 TaskVector dependents_; 134 scoped_refptr<FakeWorkerPoolTaskImpl> completion_task_; 135 scoped_ptr<CompletionEvent> scheduled_tasks_completion_; 136 137 DISALLOW_COPY_AND_ASSIGN(FakeWorkerPool); 138}; 139 140class WorkerPoolTest : public testing::Test { 141 public: 142 WorkerPoolTest() {} 143 virtual ~WorkerPoolTest() {} 144 145 // Overridden from testing::Test: 146 virtual void SetUp() OVERRIDE { 147 worker_pool_ = FakeWorkerPool::Create(); 148 } 149 virtual void TearDown() OVERRIDE { 150 worker_pool_->Shutdown(); 151 worker_pool_->CheckForCompletedTasks(); 152 } 153 154 void ResetIds() { 155 run_task_ids_.clear(); 156 on_task_completed_ids_.clear(); 157 } 158 159 void RunAllTasks() { 160 worker_pool_->WaitForTasksToComplete(); 161 worker_pool_->CheckForCompletedTasks(); 162 } 163 164 FakeWorkerPool* worker_pool() { 165 return worker_pool_.get(); 166 } 167 168 void RunTask(unsigned id) { 169 run_task_ids_.push_back(id); 170 } 171 172 void OnTaskCompleted(unsigned id) { 173 on_task_completed_ids_.push_back(id); 174 } 175 176 const std::vector<unsigned>& run_task_ids() { 177 return run_task_ids_; 178 } 179 180 const std::vector<unsigned>& on_task_completed_ids() { 181 return on_task_completed_ids_; 182 } 183 184 private: 185 scoped_ptr<FakeWorkerPool> worker_pool_; 186 std::vector<unsigned> run_task_ids_; 187 std::vector<unsigned> on_task_completed_ids_; 188}; 189 190TEST_F(WorkerPoolTest, Basic) { 191 EXPECT_EQ(0u, run_task_ids().size()); 192 EXPECT_EQ(0u, on_task_completed_ids().size()); 193 194 worker_pool()->ScheduleTasks( 195 std::vector<FakeWorkerPool::Task>( 196 1, 197 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 198 base::Unretained(this), 199 0u), 200 base::Bind(&WorkerPoolTest::OnTaskCompleted, 201 base::Unretained(this), 202 0u), 203 base::Closure(), 204 1u, 205 0u))); 206 RunAllTasks(); 207 208 EXPECT_EQ(1u, run_task_ids().size()); 209 EXPECT_EQ(1u, on_task_completed_ids().size()); 210 211 worker_pool()->ScheduleTasks( 212 std::vector<FakeWorkerPool::Task>( 213 1, 214 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 215 base::Unretained(this), 216 0u), 217 base::Bind(&WorkerPoolTest::OnTaskCompleted, 218 base::Unretained(this), 219 0u), 220 base::Bind(&WorkerPoolTest::RunTask, 221 base::Unretained(this), 222 0u), 223 1u, 224 0u))); 225 RunAllTasks(); 226 227 EXPECT_EQ(3u, run_task_ids().size()); 228 EXPECT_EQ(2u, on_task_completed_ids().size()); 229 230 worker_pool()->ScheduleTasks( 231 std::vector<FakeWorkerPool::Task>( 232 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 233 base::Unretained(this), 234 0u), 235 base::Bind(&WorkerPoolTest::OnTaskCompleted, 236 base::Unretained(this), 237 0u), 238 base::Bind(&WorkerPoolTest::RunTask, 239 base::Unretained(this), 240 0u), 241 2u, 242 0u))); 243 RunAllTasks(); 244 245 EXPECT_EQ(6u, run_task_ids().size()); 246 EXPECT_EQ(3u, on_task_completed_ids().size()); 247} 248 249TEST_F(WorkerPoolTest, Dependencies) { 250 worker_pool()->ScheduleTasks( 251 std::vector<FakeWorkerPool::Task>( 252 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 253 base::Unretained(this), 254 0u), 255 base::Bind(&WorkerPoolTest::OnTaskCompleted, 256 base::Unretained(this), 257 0u), 258 base::Bind(&WorkerPoolTest::RunTask, 259 base::Unretained(this), 260 1u), 261 1u, 262 0u))); 263 RunAllTasks(); 264 265 // Check if task ran before dependent. 266 ASSERT_EQ(2u, run_task_ids().size()); 267 EXPECT_EQ(0u, run_task_ids()[0]); 268 EXPECT_EQ(1u, run_task_ids()[1]); 269 ASSERT_EQ(1u, on_task_completed_ids().size()); 270 EXPECT_EQ(0u, on_task_completed_ids()[0]); 271 272 worker_pool()->ScheduleTasks( 273 std::vector<FakeWorkerPool::Task>( 274 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 275 base::Unretained(this), 276 2u), 277 base::Bind(&WorkerPoolTest::OnTaskCompleted, 278 base::Unretained(this), 279 2u), 280 base::Bind(&WorkerPoolTest::RunTask, 281 base::Unretained(this), 282 3u), 283 2u, 284 0u))); 285 RunAllTasks(); 286 287 // Task should only run once. 288 ASSERT_EQ(5u, run_task_ids().size()); 289 EXPECT_EQ(2u, run_task_ids()[2]); 290 EXPECT_EQ(3u, run_task_ids()[3]); 291 EXPECT_EQ(3u, run_task_ids()[4]); 292 ASSERT_EQ(2u, on_task_completed_ids().size()); 293 EXPECT_EQ(2u, on_task_completed_ids()[1]); 294} 295 296TEST_F(WorkerPoolTest, Priority) { 297 { 298 FakeWorkerPool::Task tasks[] = { 299 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 300 base::Unretained(this), 301 0u), 302 base::Bind(&WorkerPoolTest::OnTaskCompleted, 303 base::Unretained(this), 304 0u), 305 base::Bind(&WorkerPoolTest::RunTask, 306 base::Unretained(this), 307 2u), 308 1u, 309 1u), // Priority 1 310 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 311 base::Unretained(this), 312 1u), 313 base::Bind(&WorkerPoolTest::OnTaskCompleted, 314 base::Unretained(this), 315 1u), 316 base::Bind(&WorkerPoolTest::RunTask, 317 base::Unretained(this), 318 3u), 319 1u, 320 0u) // Priority 0 321 }; 322 worker_pool()->ScheduleTasks( 323 std::vector<FakeWorkerPool::Task>(tasks, tasks + arraysize(tasks))); 324 } 325 RunAllTasks(); 326 327 // Check if tasks ran in order of priority. 328 ASSERT_EQ(4u, run_task_ids().size()); 329 EXPECT_EQ(1u, run_task_ids()[0]); 330 EXPECT_EQ(3u, run_task_ids()[1]); 331 EXPECT_EQ(0u, run_task_ids()[2]); 332 EXPECT_EQ(2u, run_task_ids()[3]); 333 ASSERT_EQ(2u, on_task_completed_ids().size()); 334 EXPECT_EQ(1u, on_task_completed_ids()[0]); 335 EXPECT_EQ(0u, on_task_completed_ids()[1]); 336 337 ResetIds(); 338 { 339 std::vector<FakeWorkerPool::Task> tasks; 340 tasks.push_back( 341 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 342 base::Unretained(this), 343 0u), 344 base::Bind(&WorkerPoolTest::OnTaskCompleted, 345 base::Unretained(this), 346 0u), 347 base::Bind(&WorkerPoolTest::RunTask, 348 base::Unretained(this), 349 3u), 350 1u, // 1 dependent 351 1u)); // Priority 1 352 tasks.push_back( 353 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 354 base::Unretained(this), 355 1u), 356 base::Bind(&WorkerPoolTest::OnTaskCompleted, 357 base::Unretained(this), 358 1u), 359 base::Bind(&WorkerPoolTest::RunTask, 360 base::Unretained(this), 361 4u), 362 2u, // 2 dependents 363 1u)); // Priority 1 364 tasks.push_back( 365 FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask, 366 base::Unretained(this), 367 2u), 368 base::Bind(&WorkerPoolTest::OnTaskCompleted, 369 base::Unretained(this), 370 2u), 371 base::Bind(&WorkerPoolTest::RunTask, 372 base::Unretained(this), 373 5u), 374 1u, // 1 dependent 375 0u)); // Priority 0 376 worker_pool()->ScheduleTasks(tasks); 377 } 378 RunAllTasks(); 379 380 // Check if tasks ran in order of priority and that task with more 381 // dependents ran first when priority is the same. 382 ASSERT_LE(3u, run_task_ids().size()); 383 EXPECT_EQ(2u, run_task_ids()[0]); 384 EXPECT_EQ(5u, run_task_ids()[1]); 385 EXPECT_EQ(1u, run_task_ids()[2]); 386 ASSERT_EQ(3u, on_task_completed_ids().size()); 387 EXPECT_EQ(2u, on_task_completed_ids()[0]); 388 EXPECT_EQ(1u, on_task_completed_ids()[1]); 389 EXPECT_EQ(0u, on_task_completed_ids()[2]); 390} 391 392} // namespace 393 394} // namespace cc 395