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

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: build fix 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
« no previous file with comments | « cc/resources/task_graph_runner.h ('k') | cc/resources/task_graph_runner_perftest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // 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
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
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
OLDNEW
« no previous file with comments | « cc/resources/task_graph_runner.h ('k') | cc/resources/task_graph_runner_perftest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698