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 |