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 |