| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/resources/worker_pool.h" | 5 #include "cc/resources/worker_pool.h" |
| 6 | 6 |
| 7 #if defined(OS_ANDROID) | 7 #if defined(OS_ANDROID) |
| 8 // TODO(epenner): Move thread priorities to base. (crbug.com/170549) | 8 // TODO(epenner): Move thread priorities to base. (crbug.com/170549) |
| 9 #include <sys/resource.h> | 9 #include <sys/resource.h> |
| 10 #endif | 10 #endif |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 } | 62 } |
| 63 | 63 |
| 64 bool WorkerPoolTask::HasFinishedRunning() const { | 64 bool WorkerPoolTask::HasFinishedRunning() const { |
| 65 return did_run_; | 65 return did_run_; |
| 66 } | 66 } |
| 67 | 67 |
| 68 bool WorkerPoolTask::HasCompleted() const { | 68 bool WorkerPoolTask::HasCompleted() const { |
| 69 return did_complete_; | 69 return did_complete_; |
| 70 } | 70 } |
| 71 | 71 |
| 72 GraphNode::GraphNode(internal::WorkerPoolTask* task, unsigned priority) |
| 73 : task_(task), |
| 74 priority_(priority), |
| 75 num_dependencies_(0) { |
| 76 } |
| 77 |
| 78 GraphNode::~GraphNode() { |
| 79 } |
| 80 |
| 72 } // namespace internal | 81 } // namespace internal |
| 73 | 82 |
| 74 // Internal to the worker pool. Any data or logic that needs to be | 83 // Internal to the worker pool. Any data or logic that needs to be |
| 75 // shared between threads lives in this class. All members are guarded | 84 // shared between threads lives in this class. All members are guarded |
| 76 // by |lock_|. | 85 // by |lock_|. |
| 77 class WorkerPool::Inner : public base::DelegateSimpleThread::Delegate { | 86 class WorkerPool::Inner : public base::DelegateSimpleThread::Delegate { |
| 78 public: | 87 public: |
| 79 Inner(size_t num_threads, const std::string& thread_name_prefix); | 88 Inner(size_t num_threads, const std::string& thread_name_prefix); |
| 80 virtual ~Inner(); | 89 virtual ~Inner(); |
| 81 | 90 |
| 82 void Shutdown(); | 91 void Shutdown(); |
| 83 | 92 |
| 84 // Schedule running of tasks in |graph|. Tasks previously scheduled but | 93 // Schedule running of tasks in |graph|. Tasks previously scheduled but |
| 85 // no longer needed will be canceled unless already running. Canceled | 94 // no longer needed will be canceled unless already running. Canceled |
| 86 // tasks are moved to |completed_tasks_| without being run. The result | 95 // tasks are moved to |completed_tasks_| without being run. The result |
| 87 // is that once scheduled, a task is guaranteed to end up in the | 96 // is that once scheduled, a task is guaranteed to end up in the |
| 88 // |completed_tasks_| queue even if they later get canceled by another | 97 // |completed_tasks_| queue even if they later get canceled by another |
| 89 // call to SetTaskGraph(). | 98 // call to SetTaskGraph(). |
| 90 void SetTaskGraph(TaskGraph* graph); | 99 void SetTaskGraph(TaskGraph* graph); |
| 91 | 100 |
| 92 // Collect all completed tasks in |completed_tasks|. | 101 // Collect all completed tasks in |completed_tasks|. |
| 93 void CollectCompletedTasks(TaskVector* completed_tasks); | 102 void CollectCompletedTasks(TaskVector* completed_tasks); |
| 94 | 103 |
| 95 private: | 104 private: |
| 96 class PriorityComparator { | 105 class PriorityComparator { |
| 97 public: | 106 public: |
| 98 bool operator()(const GraphNode* a, | 107 bool operator()(const internal::GraphNode* a, |
| 99 const GraphNode* b) { | 108 const internal::GraphNode* b) { |
| 100 // In this system, numerically lower priority is run first. | 109 // In this system, numerically lower priority is run first. |
| 101 return a->priority() > b->priority(); | 110 return a->priority() > b->priority(); |
| 102 } | 111 } |
| 103 }; | 112 }; |
| 104 | 113 |
| 105 // Overridden from base::DelegateSimpleThread: | 114 // Overridden from base::DelegateSimpleThread: |
| 106 virtual void Run() OVERRIDE; | 115 virtual void Run() OVERRIDE; |
| 107 | 116 |
| 108 // This lock protects all members of this class except | 117 // This lock protects all members of this class except |
| 109 // |worker_pool_on_origin_thread_|. Do not read or modify anything | 118 // |worker_pool_on_origin_thread_|. Do not read or modify anything |
| 110 // without holding this lock. Do not block while holding this lock. | 119 // without holding this lock. Do not block while holding this lock. |
| 111 mutable base::Lock lock_; | 120 mutable base::Lock lock_; |
| 112 | 121 |
| 113 // Condition variable that is waited on by worker threads until new | 122 // Condition variable that is waited on by worker threads until new |
| 114 // tasks are ready to run or shutdown starts. | 123 // tasks are ready to run or shutdown starts. |
| 115 base::ConditionVariable has_ready_to_run_tasks_cv_; | 124 base::ConditionVariable has_ready_to_run_tasks_cv_; |
| 116 | 125 |
| 117 // Provides each running thread loop with a unique index. First thread | 126 // Provides each running thread loop with a unique index. First thread |
| 118 // loop index is 0. | 127 // loop index is 0. |
| 119 unsigned next_thread_index_; | 128 unsigned next_thread_index_; |
| 120 | 129 |
| 121 // Set during shutdown. Tells workers to exit when no more tasks | 130 // Set during shutdown. Tells workers to exit when no more tasks |
| 122 // are pending. | 131 // are pending. |
| 123 bool shutdown_; | 132 bool shutdown_; |
| 124 | 133 |
| 125 // This set contains all pending tasks. | 134 // This set contains all pending tasks. |
| 126 GraphNodeMap pending_tasks_; | 135 GraphNodeMap pending_tasks_; |
| 127 | 136 |
| 128 // Ordered set of tasks that are ready to run. | 137 // Ordered set of tasks that are ready to run. |
| 129 typedef std::priority_queue<GraphNode*, | 138 typedef std::priority_queue<internal::GraphNode*, |
| 130 std::vector<GraphNode*>, | 139 std::vector<internal::GraphNode*>, |
| 131 PriorityComparator> TaskQueue; | 140 PriorityComparator> TaskQueue; |
| 132 TaskQueue ready_to_run_tasks_; | 141 TaskQueue ready_to_run_tasks_; |
| 133 | 142 |
| 134 // This set contains all currently running tasks. | 143 // This set contains all currently running tasks. |
| 135 GraphNodeMap running_tasks_; | 144 GraphNodeMap running_tasks_; |
| 136 | 145 |
| 137 // Completed tasks not yet collected by origin thread. | 146 // Completed tasks not yet collected by origin thread. |
| 138 TaskVector completed_tasks_; | 147 TaskVector completed_tasks_; |
| 139 | 148 |
| 140 ScopedPtrDeque<base::DelegateSimpleThread> workers_; | 149 ScopedPtrDeque<base::DelegateSimpleThread> workers_; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 | 216 |
| 208 { | 217 { |
| 209 base::AutoLock lock(lock_); | 218 base::AutoLock lock(lock_); |
| 210 | 219 |
| 211 // First remove all completed tasks from |new_pending_tasks| and | 220 // First remove all completed tasks from |new_pending_tasks| and |
| 212 // adjust number of dependencies. | 221 // adjust number of dependencies. |
| 213 for (TaskVector::iterator it = completed_tasks_.begin(); | 222 for (TaskVector::iterator it = completed_tasks_.begin(); |
| 214 it != completed_tasks_.end(); ++it) { | 223 it != completed_tasks_.end(); ++it) { |
| 215 internal::WorkerPoolTask* task = it->get(); | 224 internal::WorkerPoolTask* task = it->get(); |
| 216 | 225 |
| 217 scoped_ptr<GraphNode> node = new_pending_tasks.take_and_erase(task); | 226 scoped_ptr<internal::GraphNode> node = new_pending_tasks.take_and_erase( |
| 227 task); |
| 218 if (node) { | 228 if (node) { |
| 219 for (GraphNode::Vector::const_iterator it = node->dependents().begin(); | 229 for (internal::GraphNode::Vector::const_iterator it = |
| 230 node->dependents().begin(); |
| 220 it != node->dependents().end(); ++it) { | 231 it != node->dependents().end(); ++it) { |
| 221 GraphNode* dependent_node = *it; | 232 internal::GraphNode* dependent_node = *it; |
| 222 dependent_node->remove_dependency(); | 233 dependent_node->remove_dependency(); |
| 223 } | 234 } |
| 224 } | 235 } |
| 225 } | 236 } |
| 226 | 237 |
| 227 // Move tasks not present in |new_pending_tasks| to |completed_tasks_|. | 238 // Move tasks not present in |new_pending_tasks| to |completed_tasks_|. |
| 228 for (GraphNodeMap::iterator it = pending_tasks_.begin(); | 239 for (GraphNodeMap::iterator it = pending_tasks_.begin(); |
| 229 it != pending_tasks_.end(); ++it) { | 240 it != pending_tasks_.end(); ++it) { |
| 230 internal::WorkerPoolTask* task = it->first; | 241 internal::WorkerPoolTask* task = it->first; |
| 231 | 242 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 244 // the right in both cases. | 255 // the right in both cases. |
| 245 new_running_tasks.set(task, new_pending_tasks.take_and_erase(task)); | 256 new_running_tasks.set(task, new_pending_tasks.take_and_erase(task)); |
| 246 } | 257 } |
| 247 | 258 |
| 248 // Build new "ready to run" tasks queue. | 259 // Build new "ready to run" tasks queue. |
| 249 // TODO(reveman): Create this queue when building the task graph instead. | 260 // TODO(reveman): Create this queue when building the task graph instead. |
| 250 for (GraphNodeMap::iterator it = new_pending_tasks.begin(); | 261 for (GraphNodeMap::iterator it = new_pending_tasks.begin(); |
| 251 it != new_pending_tasks.end(); ++it) { | 262 it != new_pending_tasks.end(); ++it) { |
| 252 internal::WorkerPoolTask* task = it->first; | 263 internal::WorkerPoolTask* task = it->first; |
| 253 DCHECK(task); | 264 DCHECK(task); |
| 254 GraphNode* node = it->second; | 265 internal::GraphNode* node = it->second; |
| 255 | 266 |
| 256 // Completed tasks should not exist in |new_pending_tasks|. | 267 // Completed tasks should not exist in |new_pending_tasks|. |
| 257 DCHECK(!task->HasFinishedRunning()); | 268 DCHECK(!task->HasFinishedRunning()); |
| 258 | 269 |
| 259 // Call DidSchedule() to indicate that this task has been scheduled. | 270 // Call DidSchedule() to indicate that this task has been scheduled. |
| 260 // Note: This is only for debugging purposes. | 271 // Note: This is only for debugging purposes. |
| 261 task->DidSchedule(); | 272 task->DidSchedule(); |
| 262 | 273 |
| 263 if (!node->num_dependencies()) | 274 if (!node->num_dependencies()) |
| 264 new_ready_to_run_tasks.push(node); | 275 new_ready_to_run_tasks.push(node); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 base::AutoUnlock unlock(lock_); | 342 base::AutoUnlock unlock(lock_); |
| 332 | 343 |
| 333 task->RunOnWorkerThread(thread_index); | 344 task->RunOnWorkerThread(thread_index); |
| 334 } | 345 } |
| 335 | 346 |
| 336 // This will mark task as finished running. | 347 // This will mark task as finished running. |
| 337 task->DidRun(); | 348 task->DidRun(); |
| 338 | 349 |
| 339 // Now iterate over all dependents to remove dependency and check | 350 // Now iterate over all dependents to remove dependency and check |
| 340 // if they are ready to run. | 351 // if they are ready to run. |
| 341 scoped_ptr<GraphNode> node = running_tasks_.take_and_erase(task.get()); | 352 scoped_ptr<internal::GraphNode> node = running_tasks_.take_and_erase( |
| 353 task.get()); |
| 342 if (node) { | 354 if (node) { |
| 343 for (GraphNode::Vector::const_iterator it = node->dependents().begin(); | 355 for (internal::GraphNode::Vector::const_iterator it = |
| 356 node->dependents().begin(); |
| 344 it != node->dependents().end(); ++it) { | 357 it != node->dependents().end(); ++it) { |
| 345 GraphNode* dependent_node = *it; | 358 internal::GraphNode* dependent_node = *it; |
| 346 | 359 |
| 347 dependent_node->remove_dependency(); | 360 dependent_node->remove_dependency(); |
| 348 // Dependent is not ready unless number of dependencies are 0. | 361 // Dependent is not ready unless number of dependencies are 0. |
| 349 if (dependent_node->num_dependencies()) | 362 if (dependent_node->num_dependencies()) |
| 350 continue; | 363 continue; |
| 351 | 364 |
| 352 // Task is ready. Add it to |ready_to_run_tasks_|. | 365 // Task is ready. Add it to |ready_to_run_tasks_|. |
| 353 ready_to_run_tasks_.push(dependent_node); | 366 ready_to_run_tasks_.push(dependent_node); |
| 354 } | 367 } |
| 355 } | 368 } |
| 356 | 369 |
| 357 // Finally add task to |completed_tasks_|. | 370 // Finally add task to |completed_tasks_|. |
| 358 completed_tasks_.push_back(task); | 371 completed_tasks_.push_back(task); |
| 359 } | 372 } |
| 360 | 373 |
| 361 // We noticed we should exit. Wake up the next worker so it knows it should | 374 // We noticed we should exit. Wake up the next worker so it knows it should |
| 362 // exit as well (because the Shutdown() code only signals once). | 375 // exit as well (because the Shutdown() code only signals once). |
| 363 has_ready_to_run_tasks_cv_.Signal(); | 376 has_ready_to_run_tasks_cv_.Signal(); |
| 364 } | 377 } |
| 365 | 378 |
| 366 WorkerPool::GraphNode::GraphNode() | |
| 367 : task_(NULL), | |
| 368 priority_(0), | |
| 369 num_dependencies_(0) { | |
| 370 } | |
| 371 | |
| 372 WorkerPool::GraphNode::~GraphNode() { | |
| 373 } | |
| 374 | |
| 375 WorkerPool::WorkerPool(size_t num_threads, | 379 WorkerPool::WorkerPool(size_t num_threads, |
| 376 const std::string& thread_name_prefix) | 380 const std::string& thread_name_prefix) |
| 377 : in_dispatch_completion_callbacks_(false), | 381 : in_dispatch_completion_callbacks_(false), |
| 378 inner_(make_scoped_ptr(new Inner(num_threads, thread_name_prefix))) { | 382 inner_(make_scoped_ptr(new Inner(num_threads, thread_name_prefix))) { |
| 379 } | 383 } |
| 380 | 384 |
| 381 WorkerPool::~WorkerPool() { | 385 WorkerPool::~WorkerPool() { |
| 382 } | 386 } |
| 383 | 387 |
| 384 void WorkerPool::Shutdown() { | 388 void WorkerPool::Shutdown() { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 void WorkerPool::SetTaskGraph(TaskGraph* graph) { | 426 void WorkerPool::SetTaskGraph(TaskGraph* graph) { |
| 423 TRACE_EVENT1("cc", "WorkerPool::SetTaskGraph", | 427 TRACE_EVENT1("cc", "WorkerPool::SetTaskGraph", |
| 424 "num_tasks", graph->size()); | 428 "num_tasks", graph->size()); |
| 425 | 429 |
| 426 DCHECK(!in_dispatch_completion_callbacks_); | 430 DCHECK(!in_dispatch_completion_callbacks_); |
| 427 | 431 |
| 428 inner_->SetTaskGraph(graph); | 432 inner_->SetTaskGraph(graph); |
| 429 } | 433 } |
| 430 | 434 |
| 431 } // namespace cc | 435 } // namespace cc |
| OLD | NEW |