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