Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: cc/resources/task_graph_runner.cc

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

Powered by Google App Engine
This is Rietveld 408576698