OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/task_graph_runner.h" | 5 #include "cc/resources/task_graph_runner.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/containers/hash_tables.h" | |
10 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
11 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
12 #include "base/threading/thread_restrictions.h" | 11 #include "base/threading/thread_restrictions.h" |
13 | 12 |
14 namespace cc { | 13 namespace cc { |
15 namespace internal { | 14 namespace internal { |
| 15 namespace { |
| 16 |
| 17 // Helper class for iterating over all dependents of a task. |
| 18 class DependentIterator { |
| 19 public: |
| 20 DependentIterator(TaskGraph* graph, const Task* task) |
| 21 : graph_(graph), task_(task), current_index_(-1), current_node_(NULL) { |
| 22 ++(*this); |
| 23 } |
| 24 |
| 25 TaskGraph::Node& operator->() const { |
| 26 DCHECK_LT(current_index_, graph_->edges.size()); |
| 27 DCHECK_EQ(graph_->edges[current_index_].task, task_); |
| 28 DCHECK(current_node_); |
| 29 return *current_node_; |
| 30 } |
| 31 |
| 32 TaskGraph::Node& operator*() const { |
| 33 DCHECK_LT(current_index_, graph_->edges.size()); |
| 34 DCHECK_EQ(graph_->edges[current_index_].task, task_); |
| 35 DCHECK(current_node_); |
| 36 return *current_node_; |
| 37 } |
| 38 |
| 39 // Note: Performance can be improved by keeping edges sorted. |
| 40 DependentIterator& operator++() { |
| 41 // Find next dependency edge for |task_|. |
| 42 do { |
| 43 ++current_index_; |
| 44 if (current_index_ == graph_->edges.size()) |
| 45 return *this; |
| 46 } while (graph_->edges[current_index_].task != task_); |
| 47 |
| 48 // Now find the node for the dependent of this edge. |
| 49 TaskGraph::Node::Vector::iterator it = |
| 50 std::find_if(graph_->nodes.begin(), |
| 51 graph_->nodes.end(), |
| 52 TaskGraph::Node::TaskComparator( |
| 53 graph_->edges[current_index_].dependent)); |
| 54 DCHECK(it != graph_->nodes.end()); |
| 55 current_node_ = &(*it); |
| 56 |
| 57 return *this; |
| 58 } |
| 59 |
| 60 operator bool() const { return current_index_ < graph_->edges.size(); } |
| 61 |
| 62 private: |
| 63 TaskGraph* graph_; |
| 64 const Task* task_; |
| 65 size_t current_index_; |
| 66 TaskGraph::Node* current_node_; |
| 67 }; |
| 68 |
| 69 } // namespace |
16 | 70 |
17 Task::Task() : did_run_(false) {} | 71 Task::Task() : did_run_(false) {} |
18 | 72 |
19 Task::~Task() {} | 73 Task::~Task() {} |
20 | 74 |
21 void Task::WillRun() { | 75 void Task::WillRun() { |
22 DCHECK(!did_run_); | 76 DCHECK(!did_run_); |
23 } | 77 } |
24 | 78 |
25 void Task::DidRun() { did_run_ = true; } | 79 void Task::DidRun() { did_run_ = true; } |
26 | 80 |
27 bool Task::HasFinishedRunning() const { return did_run_; } | 81 bool Task::HasFinishedRunning() const { return did_run_; } |
28 | 82 |
29 GraphNode::GraphNode(Task* task, unsigned priority) | 83 TaskGraph::TaskGraph() {} |
30 : task_(task), priority_(priority), num_dependencies_(0) {} | |
31 | 84 |
32 GraphNode::~GraphNode() {} | 85 TaskGraph::~TaskGraph() {} |
33 | 86 |
34 TaskGraphRunner::TaskNamespace::TaskNamespace() {} | 87 void TaskGraph::Swap(TaskGraph* other) { |
| 88 nodes.swap(other->nodes); |
| 89 edges.swap(other->edges); |
| 90 } |
| 91 |
| 92 void TaskGraph::Reset() { |
| 93 nodes.clear(); |
| 94 edges.clear(); |
| 95 } |
| 96 |
| 97 TaskGraphRunner::TaskNamespace::TaskNamespace() : num_running_tasks(0u) {} |
35 | 98 |
36 TaskGraphRunner::TaskNamespace::~TaskNamespace() {} | 99 TaskGraphRunner::TaskNamespace::~TaskNamespace() {} |
37 | 100 |
38 TaskGraphRunner::TaskGraphRunner(size_t num_threads, | 101 TaskGraphRunner::TaskGraphRunner(size_t num_threads, |
39 const std::string& thread_name_prefix) | 102 const std::string& thread_name_prefix) |
40 : lock_(), | 103 : lock_(), |
41 has_ready_to_run_tasks_cv_(&lock_), | 104 has_ready_to_run_tasks_cv_(&lock_), |
42 has_namespaces_with_finished_running_tasks_cv_(&lock_), | 105 has_namespaces_with_finished_running_tasks_cv_(&lock_), |
43 next_namespace_id_(1), | 106 next_namespace_id_(1), |
44 next_thread_index_(0u), | 107 next_thread_index_(0u), |
| 108 // |num_threads| can be 0 for test. |
| 109 running_tasks_(std::max(num_threads, static_cast<size_t>(1)), NULL), |
45 shutdown_(false) { | 110 shutdown_(false) { |
46 base::AutoLock lock(lock_); | 111 base::AutoLock lock(lock_); |
47 | 112 |
48 while (workers_.size() < num_threads) { | 113 while (workers_.size() < num_threads) { |
49 scoped_ptr<base::DelegateSimpleThread> worker = | 114 scoped_ptr<base::DelegateSimpleThread> worker = |
50 make_scoped_ptr(new base::DelegateSimpleThread( | 115 make_scoped_ptr(new base::DelegateSimpleThread( |
51 this, | 116 this, |
52 thread_name_prefix + | 117 thread_name_prefix + |
53 base::StringPrintf("Worker%u", | 118 base::StringPrintf("Worker%u", |
54 static_cast<unsigned>(workers_.size() + 1)) | 119 static_cast<unsigned>(workers_.size() + 1)) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 | 151 |
87 NamespaceToken TaskGraphRunner::GetNamespaceToken() { | 152 NamespaceToken TaskGraphRunner::GetNamespaceToken() { |
88 base::AutoLock lock(lock_); | 153 base::AutoLock lock(lock_); |
89 | 154 |
90 NamespaceToken token(next_namespace_id_++); | 155 NamespaceToken token(next_namespace_id_++); |
91 DCHECK(namespaces_.find(token.id_) == namespaces_.end()); | 156 DCHECK(namespaces_.find(token.id_) == namespaces_.end()); |
92 return token; | 157 return token; |
93 } | 158 } |
94 | 159 |
95 void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) { | 160 void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) { |
96 base::AutoLock lock(lock_); | 161 TRACE_EVENT0("cc", "TaskGraphRunner::WaitForTasksToFinishRunning"); |
97 | 162 |
98 DCHECK(token.IsValid()); | 163 DCHECK(token.IsValid()); |
99 TaskNamespaceMap::iterator it = namespaces_.find(token.id_); | |
100 if (it == namespaces_.end()) | |
101 return; | |
102 | 164 |
103 TaskNamespace* task_namespace = it->second; | 165 { |
104 while (!HasFinishedRunningTasksInNamespace(task_namespace)) | 166 base::AutoLock lock(lock_); |
105 has_namespaces_with_finished_running_tasks_cv_.Wait(); | |
106 | 167 |
107 // There may be other namespaces that have finished running | 168 TaskNamespaceMap::iterator it = namespaces_.find(token.id_); |
108 // tasks, so wake up another origin thread. | 169 if (it == namespaces_.end()) |
109 has_namespaces_with_finished_running_tasks_cv_.Signal(); | 170 return; |
| 171 |
| 172 TaskNamespace* task_namespace = it->second; |
| 173 |
| 174 while (!HasFinishedRunningTasksInNamespace(task_namespace)) |
| 175 has_namespaces_with_finished_running_tasks_cv_.Wait(); |
| 176 |
| 177 // There may be other namespaces that have finished running |
| 178 // tasks, so wake up another origin thread. |
| 179 has_namespaces_with_finished_running_tasks_cv_.Signal(); |
| 180 } |
110 } | 181 } |
111 | 182 |
112 void TaskGraphRunner::SetTaskGraph(NamespaceToken token, TaskGraph* graph) { | 183 void TaskGraphRunner::SetTaskGraph(NamespaceToken token, TaskGraph* graph) { |
| 184 TRACE_EVENT2("cc", |
| 185 "TaskGraphRunner::SetTaskGraph", |
| 186 "num_nodes", |
| 187 graph->nodes.size(), |
| 188 "num_edges", |
| 189 graph->edges.size()); |
| 190 |
113 DCHECK(token.IsValid()); | 191 DCHECK(token.IsValid()); |
114 | 192 |
115 TaskGraph new_pending_tasks; | |
116 TaskGraph new_running_tasks; | |
117 | |
118 new_pending_tasks.swap(*graph); | |
119 | |
120 { | 193 { |
121 base::AutoLock lock(lock_); | 194 base::AutoLock lock(lock_); |
122 | 195 |
123 DCHECK(!shutdown_); | 196 DCHECK(!shutdown_); |
124 | 197 |
125 scoped_ptr<TaskNamespace> task_namespace = | 198 scoped_ptr<TaskNamespace> task_namespace = |
126 namespaces_.take_and_erase(token.id_); | 199 namespaces_.take_and_erase(token.id_); |
127 | 200 |
128 // Create task namespace if it doesn't exist. | 201 // Create task namespace if it doesn't exist. |
129 if (!task_namespace) | 202 if (!task_namespace) |
130 task_namespace.reset(new TaskNamespace); | 203 task_namespace.reset(new TaskNamespace); |
131 | 204 |
132 // First remove all completed tasks from |new_pending_tasks| and | 205 // First adjust number of dependencies to reflect completed tasks. |
133 // adjust number of dependencies. | |
134 for (Task::Vector::iterator it = task_namespace->completed_tasks.begin(); | 206 for (Task::Vector::iterator it = task_namespace->completed_tasks.begin(); |
135 it != task_namespace->completed_tasks.end(); | 207 it != task_namespace->completed_tasks.end(); |
136 ++it) { | 208 ++it) { |
137 Task* task = it->get(); | 209 for (DependentIterator node_it(graph, it->get()); node_it; ++node_it) { |
138 | 210 TaskGraph::Node& node = *node_it; |
139 scoped_ptr<GraphNode> node = new_pending_tasks.take_and_erase(task); | 211 DCHECK_LT(0u, node.dependencies); |
140 if (node) { | 212 node.dependencies--; |
141 for (GraphNode::Vector::const_iterator it = node->dependents().begin(); | |
142 it != node->dependents().end(); | |
143 ++it) { | |
144 GraphNode* dependent_node = *it; | |
145 dependent_node->remove_dependency(); | |
146 } | |
147 } | 213 } |
148 } | 214 } |
149 | 215 |
150 // Build new running task set. | 216 // Build new "ready to run" queue and remove nodes from old graph. |
151 for (TaskGraph::iterator it = task_namespace->running_tasks.begin(); | 217 task_namespace->ready_to_run_tasks.clear(); |
152 it != task_namespace->running_tasks.end(); | 218 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); |
| 219 it != graph->nodes.end(); |
153 ++it) { | 220 ++it) { |
154 Task* task = it->first; | 221 TaskGraph::Node& node = *it; |
155 // Transfer scheduled task value from |new_pending_tasks| to | |
156 // |new_running_tasks| if currently running. Value must be set to | |
157 // NULL if |new_pending_tasks| doesn't contain task. This does | |
158 // the right in both cases. | |
159 new_running_tasks.set(task, new_pending_tasks.take_and_erase(task)); | |
160 } | |
161 | 222 |
162 // Build new "ready to run" tasks queue. | 223 // Remove any old nodes that are associated with this task. The result is |
163 task_namespace->ready_to_run_tasks.clear(); | 224 // that the old graph is left all nodes not present in this graph, which |
164 for (TaskGraph::iterator it = new_pending_tasks.begin(); | 225 // we use below to determine what tasks need to be canceled. |
165 it != new_pending_tasks.end(); | 226 TaskGraph::Node::Vector::iterator old_it = |
166 ++it) { | 227 std::find_if(task_namespace->graph.nodes.begin(), |
167 Task* task = it->first; | 228 task_namespace->graph.nodes.end(), |
168 DCHECK(task); | 229 TaskGraph::Node::TaskComparator(node.task)); |
169 GraphNode* node = it->second; | 230 if (old_it != task_namespace->graph.nodes.end()) { |
| 231 std::swap(*old_it, task_namespace->graph.nodes.back()); |
| 232 task_namespace->graph.nodes.pop_back(); |
| 233 } |
170 | 234 |
171 // Completed tasks should not exist in |new_pending_tasks|. | 235 // Task is not ready to run if dependencies are not yet satisfied. |
172 DCHECK(!task->HasFinishedRunning()); | 236 if (node.dependencies) |
| 237 continue; |
173 | 238 |
174 if (!node->num_dependencies()) | 239 // Skip if already finished running task. |
175 task_namespace->ready_to_run_tasks.push_back(node); | 240 if (node.task->HasFinishedRunning()) |
| 241 continue; |
176 | 242 |
177 // Erase the task from old pending tasks. | 243 // Skip if already running. |
178 task_namespace->pending_tasks.erase(task); | 244 if (std::find(running_tasks_.begin(), running_tasks_.end(), node.task) != |
| 245 running_tasks_.end()) |
| 246 continue; |
| 247 |
| 248 task_namespace->ready_to_run_tasks.push_back( |
| 249 PrioritizedTask(node.task, node.priority)); |
179 } | 250 } |
180 | 251 |
181 // Rearrange the elements in |ready_to_run_tasks| in such a way that | 252 // Rearrange the elements in |ready_to_run_tasks| in such a way that |
182 // they form a heap. | 253 // they form a heap. |
183 std::make_heap(task_namespace->ready_to_run_tasks.begin(), | 254 std::make_heap(task_namespace->ready_to_run_tasks.begin(), |
184 task_namespace->ready_to_run_tasks.end(), | 255 task_namespace->ready_to_run_tasks.end(), |
185 CompareTaskPriority); | 256 CompareTaskPriority); |
186 | 257 |
187 task_namespace->completed_tasks.reserve( | 258 // Swap task graph. |
188 task_namespace->completed_tasks.size() + | 259 task_namespace->graph.Swap(graph); |
189 task_namespace->pending_tasks.size()); | |
190 | 260 |
191 // The items left in |pending_tasks| need to be canceled. | 261 // Determine what tasks in old graph need to be canceled. |
192 for (TaskGraph::const_iterator it = task_namespace->pending_tasks.begin(); | 262 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); |
193 it != task_namespace->pending_tasks.end(); | 263 it != graph->nodes.end(); |
194 ++it) { | 264 ++it) { |
195 task_namespace->completed_tasks.push_back(it->first); | 265 TaskGraph::Node& node = *it; |
| 266 |
| 267 // Skip if already finished running task. |
| 268 if (node.task->HasFinishedRunning()) |
| 269 continue; |
| 270 |
| 271 // Skip if already running. |
| 272 if (std::find(running_tasks_.begin(), running_tasks_.end(), node.task) != |
| 273 running_tasks_.end()) |
| 274 continue; |
| 275 |
| 276 task_namespace->completed_tasks.push_back(node.task); |
196 } | 277 } |
197 | 278 |
198 // Swap task sets. | 279 namespaces_.set(token.id_, task_namespace.Pass()); |
199 // Note: old tasks are intentionally destroyed after releasing |lock_|. | |
200 task_namespace->pending_tasks.swap(new_pending_tasks); | |
201 task_namespace->running_tasks.swap(new_running_tasks); | |
202 | |
203 // If |ready_to_run_tasks| is empty, it means we either have | |
204 // running tasks, or we have no pending tasks. | |
205 DCHECK(!task_namespace->ready_to_run_tasks.empty() || | |
206 (task_namespace->pending_tasks.empty() || | |
207 !task_namespace->running_tasks.empty())); | |
208 | |
209 // Add task namespace if not empty. | |
210 if (!task_namespace->pending_tasks.empty() || | |
211 !task_namespace->running_tasks.empty() || | |
212 !task_namespace->completed_tasks.empty()) { | |
213 namespaces_.set(token.id_, task_namespace.Pass()); | |
214 } | |
215 | 280 |
216 // Build new "ready to run" task namespaces queue. | 281 // Build new "ready to run" task namespaces queue. |
217 ready_to_run_namespaces_.clear(); | 282 ready_to_run_namespaces_.clear(); |
218 for (TaskNamespaceMap::iterator it = namespaces_.begin(); | 283 for (TaskNamespaceMap::iterator it = namespaces_.begin(); |
219 it != namespaces_.end(); | 284 it != namespaces_.end(); |
220 ++it) { | 285 ++it) { |
221 if (!it->second->ready_to_run_tasks.empty()) | 286 if (!it->second->ready_to_run_tasks.empty()) |
222 ready_to_run_namespaces_.push_back(it->second); | 287 ready_to_run_namespaces_.push_back(it->second); |
223 } | 288 } |
224 | 289 |
225 // Rearrange the task namespaces in |ready_to_run_namespaces_| | 290 // Rearrange the task namespaces in |ready_to_run_namespaces_| |
226 // in such a way that they form a heap. | 291 // in such a way that they form a heap. |
227 std::make_heap(ready_to_run_namespaces_.begin(), | 292 std::make_heap(ready_to_run_namespaces_.begin(), |
228 ready_to_run_namespaces_.end(), | 293 ready_to_run_namespaces_.end(), |
229 CompareTaskNamespacePriority); | 294 CompareTaskNamespacePriority); |
230 | 295 |
231 // If there is more work available, wake up worker thread. | 296 // If there is more work available, wake up worker thread. |
232 if (!ready_to_run_namespaces_.empty()) | 297 if (!ready_to_run_namespaces_.empty()) |
233 has_ready_to_run_tasks_cv_.Signal(); | 298 has_ready_to_run_tasks_cv_.Signal(); |
234 } | 299 } |
235 } | 300 } |
236 | 301 |
237 void TaskGraphRunner::CollectCompletedTasks(NamespaceToken token, | 302 void TaskGraphRunner::CollectCompletedTasks(NamespaceToken token, |
238 Task::Vector* completed_tasks) { | 303 Task::Vector* completed_tasks) { |
239 base::AutoLock lock(lock_); | 304 TRACE_EVENT0("cc", "TaskGraphRunner::CollectCompletedTasks"); |
240 | 305 |
241 DCHECK(token.IsValid()); | 306 DCHECK(token.IsValid()); |
242 TaskNamespaceMap::iterator it = namespaces_.find(token.id_); | |
243 if (it == namespaces_.end()) | |
244 return; | |
245 | 307 |
246 TaskNamespace* task_namespace = it->second; | 308 { |
| 309 base::AutoLock lock(lock_); |
247 | 310 |
248 DCHECK_EQ(0u, completed_tasks->size()); | 311 TaskNamespaceMap::iterator it = namespaces_.find(token.id_); |
249 completed_tasks->swap(task_namespace->completed_tasks); | 312 if (it == namespaces_.end()) |
250 if (!HasFinishedRunningTasksInNamespace(task_namespace)) | 313 return; |
251 return; | |
252 | 314 |
253 // Remove namespace if finished running tasks. | 315 TaskNamespace* task_namespace = it->second; |
254 DCHECK_EQ(0u, task_namespace->pending_tasks.size()); | 316 |
255 DCHECK_EQ(0u, task_namespace->running_tasks.size()); | 317 DCHECK_EQ(0u, completed_tasks->size()); |
256 DCHECK_EQ(0u, task_namespace->completed_tasks.size()); | 318 completed_tasks->swap(task_namespace->completed_tasks); |
257 DCHECK_EQ(0u, task_namespace->ready_to_run_tasks.size()); | 319 if (!HasFinishedRunningTasksInNamespace(task_namespace)) |
258 namespaces_.erase(it); | 320 return; |
| 321 |
| 322 // Remove namespace if finished running tasks. |
| 323 DCHECK_EQ(0u, task_namespace->completed_tasks.size()); |
| 324 DCHECK_EQ(0u, task_namespace->ready_to_run_tasks.size()); |
| 325 DCHECK_EQ(0u, task_namespace->num_running_tasks); |
| 326 namespaces_.erase(it); |
| 327 } |
259 } | 328 } |
260 | 329 |
261 bool TaskGraphRunner::RunTaskForTesting() { | 330 bool TaskGraphRunner::RunTaskForTesting() { |
262 base::AutoLock lock(lock_); | 331 base::AutoLock lock(lock_); |
263 | 332 |
264 if (ready_to_run_namespaces_.empty()) | 333 if (ready_to_run_namespaces_.empty()) |
265 return false; | 334 return false; |
266 | 335 |
267 RunTaskWithLockAcquired(0); | 336 RunTaskWithLockAcquired(0); |
268 return true; | 337 return true; |
(...skipping 18 matching lines...) Expand all Loading... |
287 | 356 |
288 RunTaskWithLockAcquired(thread_index); | 357 RunTaskWithLockAcquired(thread_index); |
289 } | 358 } |
290 | 359 |
291 // We noticed we should exit. Wake up the next worker so it knows it should | 360 // We noticed we should exit. Wake up the next worker so it knows it should |
292 // exit as well (because the Shutdown() code only signals once). | 361 // exit as well (because the Shutdown() code only signals once). |
293 has_ready_to_run_tasks_cv_.Signal(); | 362 has_ready_to_run_tasks_cv_.Signal(); |
294 } | 363 } |
295 | 364 |
296 void TaskGraphRunner::RunTaskWithLockAcquired(int thread_index) { | 365 void TaskGraphRunner::RunTaskWithLockAcquired(int thread_index) { |
| 366 TRACE_EVENT1("cc", "TaskGraphRunner::RunTask", "thread_index", thread_index); |
| 367 |
297 lock_.AssertAcquired(); | 368 lock_.AssertAcquired(); |
298 DCHECK(!ready_to_run_namespaces_.empty()); | 369 DCHECK(!ready_to_run_namespaces_.empty()); |
299 | 370 |
300 // Take top priority TaskNamespace from |ready_to_run_namespaces_|. | 371 // Take top priority TaskNamespace from |ready_to_run_namespaces_|. |
301 std::pop_heap(ready_to_run_namespaces_.begin(), | 372 std::pop_heap(ready_to_run_namespaces_.begin(), |
302 ready_to_run_namespaces_.end(), | 373 ready_to_run_namespaces_.end(), |
303 CompareTaskNamespacePriority); | 374 CompareTaskNamespacePriority); |
304 TaskNamespace* task_namespace = ready_to_run_namespaces_.back(); | 375 TaskNamespace* task_namespace = ready_to_run_namespaces_.back(); |
305 ready_to_run_namespaces_.pop_back(); | 376 ready_to_run_namespaces_.pop_back(); |
306 DCHECK(!task_namespace->ready_to_run_tasks.empty()); | 377 DCHECK(!task_namespace->ready_to_run_tasks.empty()); |
307 | 378 |
308 // Take top priority task from |ready_to_run_tasks|. | 379 // Take top priority task from |ready_to_run_tasks|. |
309 std::pop_heap(task_namespace->ready_to_run_tasks.begin(), | 380 std::pop_heap(task_namespace->ready_to_run_tasks.begin(), |
310 task_namespace->ready_to_run_tasks.end(), | 381 task_namespace->ready_to_run_tasks.end(), |
311 CompareTaskPriority); | 382 CompareTaskPriority); |
312 scoped_refptr<Task> task(task_namespace->ready_to_run_tasks.back()->task()); | 383 scoped_refptr<Task> task(task_namespace->ready_to_run_tasks.back().task); |
313 task_namespace->ready_to_run_tasks.pop_back(); | 384 task_namespace->ready_to_run_tasks.pop_back(); |
314 | 385 |
315 // Add task namespace back to |ready_to_run_namespaces_| if not | 386 // Add task namespace back to |ready_to_run_namespaces_| if not |
316 // empty after taking top priority task. | 387 // empty after taking top priority task. |
317 if (!task_namespace->ready_to_run_tasks.empty()) { | 388 if (!task_namespace->ready_to_run_tasks.empty()) { |
318 ready_to_run_namespaces_.push_back(task_namespace); | 389 ready_to_run_namespaces_.push_back(task_namespace); |
319 std::push_heap(ready_to_run_namespaces_.begin(), | 390 std::push_heap(ready_to_run_namespaces_.begin(), |
320 ready_to_run_namespaces_.end(), | 391 ready_to_run_namespaces_.end(), |
321 CompareTaskNamespacePriority); | 392 CompareTaskNamespacePriority); |
322 } | 393 } |
323 | 394 |
324 // Move task from |pending_tasks| to |running_tasks|. | 395 // Add task to |running_tasks_|. |
325 DCHECK(task_namespace->pending_tasks.contains(task.get())); | 396 DCHECK_LT(static_cast<size_t>(thread_index), running_tasks_.size()); |
326 DCHECK(!task_namespace->running_tasks.contains(task.get())); | 397 DCHECK(!running_tasks_[thread_index]); |
327 task_namespace->running_tasks.set( | 398 running_tasks_[thread_index] = task.get(); |
328 task.get(), task_namespace->pending_tasks.take_and_erase(task.get())); | 399 |
| 400 // Increment running task count for task namespace. |
| 401 task_namespace->num_running_tasks++; |
329 | 402 |
330 // There may be more work available, so wake up another worker thread. | 403 // There may be more work available, so wake up another worker thread. |
331 has_ready_to_run_tasks_cv_.Signal(); | 404 has_ready_to_run_tasks_cv_.Signal(); |
332 | 405 |
333 // Call WillRun() before releasing |lock_| and running task. | 406 // Call WillRun() before releasing |lock_| and running task. |
334 task->WillRun(); | 407 task->WillRun(); |
335 | 408 |
336 { | 409 { |
337 base::AutoUnlock unlock(lock_); | 410 base::AutoUnlock unlock(lock_); |
338 | 411 |
339 task->RunOnWorkerThread(thread_index); | 412 task->RunOnWorkerThread(thread_index); |
340 } | 413 } |
341 | 414 |
342 // This will mark task as finished running. | 415 // This will mark task as finished running. |
343 task->DidRun(); | 416 task->DidRun(); |
344 | 417 |
345 // Now iterate over all dependents to remove dependency and check | 418 // Decrement running task count for task namespace. |
346 // if they are ready to run. | 419 DCHECK_LT(0u, task_namespace->num_running_tasks); |
347 scoped_ptr<GraphNode> node = | 420 task_namespace->num_running_tasks--; |
348 task_namespace->running_tasks.take_and_erase(task.get()); | |
349 if (node) { | |
350 bool ready_to_run_namespaces_has_heap_properties = true; | |
351 | 421 |
352 for (GraphNode::Vector::const_iterator it = node->dependents().begin(); | 422 // Remove task from |running_tasks_|. |
353 it != node->dependents().end(); | 423 running_tasks_[thread_index] = NULL; |
354 ++it) { | |
355 GraphNode* dependent_node = *it; | |
356 | 424 |
357 dependent_node->remove_dependency(); | 425 // Now iterate over all dependents to decrement dependencies and check if they |
358 // Task is ready if it has no dependencies. Add it to | 426 // are ready to run. |
359 // |ready_to_run_tasks_|. | 427 bool ready_to_run_namespaces_has_heap_properties = true; |
360 if (!dependent_node->num_dependencies()) { | 428 for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) { |
361 bool was_empty = task_namespace->ready_to_run_tasks.empty(); | 429 TaskGraph::Node& dependent_node = *it; |
362 task_namespace->ready_to_run_tasks.push_back(dependent_node); | 430 |
363 std::push_heap(task_namespace->ready_to_run_tasks.begin(), | 431 DCHECK_LT(0u, dependent_node.dependencies); |
364 task_namespace->ready_to_run_tasks.end(), | 432 dependent_node.dependencies--; |
365 CompareTaskPriority); | 433 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|. |
366 // Task namespace is ready if it has at least one ready | 434 if (!dependent_node.dependencies) { |
367 // to run task. Add it to |ready_to_run_namespaces_| if | 435 bool was_empty = task_namespace->ready_to_run_tasks.empty(); |
368 // it just become ready. | 436 task_namespace->ready_to_run_tasks.push_back( |
369 if (was_empty) { | 437 PrioritizedTask(dependent_node.task, dependent_node.priority)); |
370 DCHECK(std::find(ready_to_run_namespaces_.begin(), | 438 std::push_heap(task_namespace->ready_to_run_tasks.begin(), |
371 ready_to_run_namespaces_.end(), | 439 task_namespace->ready_to_run_tasks.end(), |
372 task_namespace) == ready_to_run_namespaces_.end()); | 440 CompareTaskPriority); |
373 ready_to_run_namespaces_.push_back(task_namespace); | 441 // Task namespace is ready if it has at least one ready to run task. Add |
374 } | 442 // it to |ready_to_run_namespaces_| if it just become ready. |
375 ready_to_run_namespaces_has_heap_properties = false; | 443 if (was_empty) { |
| 444 DCHECK(std::find(ready_to_run_namespaces_.begin(), |
| 445 ready_to_run_namespaces_.end(), |
| 446 task_namespace) == ready_to_run_namespaces_.end()); |
| 447 ready_to_run_namespaces_.push_back(task_namespace); |
376 } | 448 } |
377 } | 449 ready_to_run_namespaces_has_heap_properties = false; |
378 | |
379 // Rearrange the task namespaces in |ready_to_run_namespaces_| | |
380 // in such a way that they yet again form a heap. | |
381 if (!ready_to_run_namespaces_has_heap_properties) { | |
382 std::make_heap(ready_to_run_namespaces_.begin(), | |
383 ready_to_run_namespaces_.end(), | |
384 CompareTaskNamespacePriority); | |
385 } | 450 } |
386 } | 451 } |
387 | 452 |
| 453 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way |
| 454 // that they yet again form a heap. |
| 455 if (!ready_to_run_namespaces_has_heap_properties) { |
| 456 std::make_heap(ready_to_run_namespaces_.begin(), |
| 457 ready_to_run_namespaces_.end(), |
| 458 CompareTaskNamespacePriority); |
| 459 } |
| 460 |
388 // Finally add task to |completed_tasks_|. | 461 // Finally add task to |completed_tasks_|. |
389 task_namespace->completed_tasks.push_back(task); | 462 task_namespace->completed_tasks.push_back(task); |
390 | 463 |
391 // If namespace has finished running all tasks, wake up origin thread. | 464 // If namespace has finished running all tasks, wake up origin thread. |
392 if (HasFinishedRunningTasksInNamespace(task_namespace)) | 465 if (HasFinishedRunningTasksInNamespace(task_namespace)) |
393 has_namespaces_with_finished_running_tasks_cv_.Signal(); | 466 has_namespaces_with_finished_running_tasks_cv_.Signal(); |
394 } | 467 } |
395 | 468 |
396 } // namespace internal | 469 } // namespace internal |
397 } // namespace cc | 470 } // namespace cc |
OLD | NEW |