Chromium Code Reviews| 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/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/threading/thread_restrictions.h" | 10 #include "base/threading/thread_restrictions.h" |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 void TaskGraph::Swap(TaskGraph* other) { | 127 void TaskGraph::Swap(TaskGraph* other) { |
| 128 nodes.swap(other->nodes); | 128 nodes.swap(other->nodes); |
| 129 edges.swap(other->edges); | 129 edges.swap(other->edges); |
| 130 } | 130 } |
| 131 | 131 |
| 132 void TaskGraph::Reset() { | 132 void TaskGraph::Reset() { |
| 133 nodes.clear(); | 133 nodes.clear(); |
| 134 edges.clear(); | 134 edges.clear(); |
| 135 } | 135 } |
| 136 | 136 |
| 137 TaskGraphRunner::TaskNamespace::TaskNamespace() {} | 137 TaskGraphRunner::TaskSubNamespace::TaskSubNamespace() |
| 138 : task_namespace(nullptr), | |
| 139 is_in_ready_sub_namespaces(false), | |
| 140 running_task_count(0) { | |
| 141 } | |
| 142 | |
| 143 TaskGraphRunner::TaskSubNamespace::~TaskSubNamespace() { | |
| 144 } | |
| 145 | |
| 146 bool TaskGraphRunner::TaskSubNamespace::IsReadyToRun() const { | |
| 147 // A sub namespace is ready to run if it has ready to run tasks, | |
| 148 // and the number of running tasks in the sub namespace is not | |
| 149 // greater than the next prioritized task's |max_concurrent_tasks|. | |
| 150 return !ready_to_run_tasks.empty() && | |
| 151 running_task_count < ready_to_run_tasks.front().max_concurrent_tasks; | |
| 152 } | |
| 153 | |
| 154 TaskGraphRunner::TaskNamespace::TaskNamespace() { | |
| 155 for (TaskSubNamespace& sub_namespace : sub_namespaces) | |
| 156 sub_namespace.task_namespace = this; | |
| 157 } | |
| 138 | 158 |
| 139 TaskGraphRunner::TaskNamespace::~TaskNamespace() {} | 159 TaskGraphRunner::TaskNamespace::~TaskNamespace() {} |
| 140 | 160 |
| 141 TaskGraphRunner::TaskGraphRunner() | 161 TaskGraphRunner::TaskGraphRunner() |
| 142 : lock_(), | 162 : lock_(), |
| 143 has_ready_to_run_tasks_cv_(&lock_), | 163 has_ready_to_run_tasks_cv_(&lock_), |
| 144 has_namespaces_with_finished_running_tasks_cv_(&lock_), | 164 has_namespaces_with_finished_running_tasks_cv_(&lock_), |
| 145 next_namespace_id_(1), | 165 next_namespace_id_(1), |
| 146 shutdown_(false) {} | 166 shutdown_(false) {} |
| 147 | 167 |
| 148 TaskGraphRunner::~TaskGraphRunner() { | 168 TaskGraphRunner::~TaskGraphRunner() { |
| 149 { | 169 { |
| 150 base::AutoLock lock(lock_); | 170 base::AutoLock lock(lock_); |
| 151 | 171 |
| 152 DCHECK_EQ(0u, ready_to_run_namespaces_.size()); | 172 DCHECK_EQ(0u, ready_to_run_sub_namespaces_.size()); |
| 153 DCHECK_EQ(0u, namespaces_.size()); | 173 DCHECK_EQ(0u, namespaces_.size()); |
| 154 } | 174 } |
| 155 } | 175 } |
| 156 | 176 |
| 157 NamespaceToken TaskGraphRunner::GetNamespaceToken() { | 177 NamespaceToken TaskGraphRunner::GetNamespaceToken() { |
| 158 base::AutoLock lock(lock_); | 178 base::AutoLock lock(lock_); |
| 159 | 179 |
| 160 NamespaceToken token(next_namespace_id_++); | 180 NamespaceToken token(next_namespace_id_++); |
| 161 DCHECK(namespaces_.find(token.id_) == namespaces_.end()); | 181 DCHECK(namespaces_.find(token.id_) == namespaces_.end()); |
| 162 return token; | 182 return token; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 188 it != task_namespace.completed_tasks.end(); | 208 it != task_namespace.completed_tasks.end(); |
| 189 ++it) { | 209 ++it) { |
| 190 for (DependentIterator node_it(graph, it->get()); node_it; ++node_it) { | 210 for (DependentIterator node_it(graph, it->get()); node_it; ++node_it) { |
| 191 TaskGraph::Node& node = *node_it; | 211 TaskGraph::Node& node = *node_it; |
| 192 DCHECK_LT(0u, node.dependencies); | 212 DCHECK_LT(0u, node.dependencies); |
| 193 node.dependencies--; | 213 node.dependencies--; |
| 194 } | 214 } |
| 195 } | 215 } |
| 196 | 216 |
| 197 // Build new "ready to run" queue and remove nodes from old graph. | 217 // Build new "ready to run" queue and remove nodes from old graph. |
| 198 task_namespace.ready_to_run_tasks.clear(); | 218 for (TaskSubNamespace& sub_namespace : task_namespace.sub_namespaces) |
| 219 sub_namespace.ready_to_run_tasks.clear(); | |
| 220 | |
| 199 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); | 221 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); |
| 200 it != graph->nodes.end(); | 222 it != graph->nodes.end(); |
| 201 ++it) { | 223 ++it) { |
| 202 TaskGraph::Node& node = *it; | 224 TaskGraph::Node& node = *it; |
| 203 | 225 |
| 204 // Remove any old nodes that are associated with this task. The result is | 226 // Remove any old nodes that are associated with this task. The result is |
| 205 // that the old graph is left with all nodes not present in this graph, | 227 // that the old graph is left with all nodes not present in this graph, |
| 206 // which we use below to determine what tasks need to be canceled. | 228 // which we use below to determine what tasks need to be canceled. |
| 207 TaskGraph::Node::Vector::iterator old_it = | 229 TaskGraph::Node::Vector::iterator old_it = |
| 208 std::find_if(task_namespace.graph.nodes.begin(), | 230 std::find_if(task_namespace.graph.nodes.begin(), |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 220 // Skip if already finished running task. | 242 // Skip if already finished running task. |
| 221 if (node.task->HasFinishedRunning()) | 243 if (node.task->HasFinishedRunning()) |
| 222 continue; | 244 continue; |
| 223 | 245 |
| 224 // Skip if already running. | 246 // Skip if already running. |
| 225 if (std::find(task_namespace.running_tasks.begin(), | 247 if (std::find(task_namespace.running_tasks.begin(), |
| 226 task_namespace.running_tasks.end(), | 248 task_namespace.running_tasks.end(), |
| 227 node.task) != task_namespace.running_tasks.end()) | 249 node.task) != task_namespace.running_tasks.end()) |
| 228 continue; | 250 continue; |
| 229 | 251 |
| 230 task_namespace.ready_to_run_tasks.push_back( | 252 task_namespace.sub_namespaces[node.sub_namespace] |
| 231 PrioritizedTask(node.task, node.priority)); | 253 .ready_to_run_tasks.push_back(PrioritizedTask( |
| 254 node.task, node.priority, node.max_concurrent_tasks)); | |
| 232 } | 255 } |
| 233 | 256 |
| 234 // Rearrange the elements in |ready_to_run_tasks| in such a way that they | 257 // Prioritize tasks in each sub namespace. |
| 235 // form a heap. | 258 for (TaskSubNamespace& sub_namespace : task_namespace.sub_namespaces) { |
| 236 std::make_heap(task_namespace.ready_to_run_tasks.begin(), | 259 if (!sub_namespace.ready_to_run_tasks.empty()) { |
| 237 task_namespace.ready_to_run_tasks.end(), | 260 // Rearrange the elements in |ready_to_run_tasks| in |
| 238 CompareTaskPriority); | 261 // such a way that they form a heap. |
| 262 std::make_heap(sub_namespace.ready_to_run_tasks.begin(), | |
| 263 sub_namespace.ready_to_run_tasks.end(), | |
| 264 CompareTaskPriority); | |
| 265 } | |
| 266 } | |
| 239 | 267 |
| 240 // Swap task graph. | 268 // Swap task graph. |
| 241 task_namespace.graph.Swap(graph); | 269 task_namespace.graph.Swap(graph); |
| 242 | 270 |
| 243 // Determine what tasks in old graph need to be canceled. | 271 // Determine what tasks in old graph need to be canceled. |
| 244 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); | 272 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); |
| 245 it != graph->nodes.end(); | 273 it != graph->nodes.end(); |
| 246 ++it) { | 274 ++it) { |
| 247 TaskGraph::Node& node = *it; | 275 TaskGraph::Node& node = *it; |
| 248 | 276 |
| 249 // Skip if already finished running task. | 277 // Skip if already finished running task. |
| 250 if (node.task->HasFinishedRunning()) | 278 if (node.task->HasFinishedRunning()) |
| 251 continue; | 279 continue; |
| 252 | 280 |
| 253 // Skip if already running. | 281 // Skip if already running. |
| 254 if (std::find(task_namespace.running_tasks.begin(), | 282 if (std::find(task_namespace.running_tasks.begin(), |
| 255 task_namespace.running_tasks.end(), | 283 task_namespace.running_tasks.end(), |
| 256 node.task) != task_namespace.running_tasks.end()) | 284 node.task) != task_namespace.running_tasks.end()) |
| 257 continue; | 285 continue; |
| 258 | 286 |
| 259 DCHECK(std::find(task_namespace.completed_tasks.begin(), | 287 DCHECK(std::find(task_namespace.completed_tasks.begin(), |
| 260 task_namespace.completed_tasks.end(), | 288 task_namespace.completed_tasks.end(), |
| 261 node.task) == task_namespace.completed_tasks.end()); | 289 node.task) == task_namespace.completed_tasks.end()); |
| 262 task_namespace.completed_tasks.push_back(node.task); | 290 task_namespace.completed_tasks.push_back(node.task); |
| 263 } | 291 } |
| 264 | 292 |
| 265 // Build new "ready to run" task namespaces queue. | 293 // Build new "ready to run" task namespaces queue. |
| 266 ready_to_run_namespaces_.clear(); | 294 ready_to_run_sub_namespaces_.clear(); |
| 267 for (TaskNamespaceMap::iterator it = namespaces_.begin(); | 295 for (TaskNamespaceMap::iterator it = namespaces_.begin(); |
| 268 it != namespaces_.end(); | 296 it != namespaces_.end(); |
| 269 ++it) { | 297 ++it) { |
| 270 if (!it->second.ready_to_run_tasks.empty()) | 298 for (TaskSubNamespace& sub_namespace : it->second.sub_namespaces) { |
| 271 ready_to_run_namespaces_.push_back(&it->second); | 299 if (sub_namespace.IsReadyToRun()) { |
| 300 ready_to_run_sub_namespaces_.push_back(&sub_namespace); | |
| 301 sub_namespace.is_in_ready_sub_namespaces = true; | |
| 302 } else { | |
| 303 sub_namespace.is_in_ready_sub_namespaces = false; | |
| 304 } | |
| 305 } | |
| 272 } | 306 } |
| 273 | 307 |
| 274 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way | 308 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way |
| 275 // that they form a heap. | 309 // that they form a heap. |
| 276 std::make_heap(ready_to_run_namespaces_.begin(), | 310 std::make_heap(ready_to_run_sub_namespaces_.begin(), |
| 277 ready_to_run_namespaces_.end(), | 311 ready_to_run_sub_namespaces_.end(), |
| 278 CompareTaskNamespacePriority); | 312 CompareTaskSubNamespacePriority); |
| 279 | 313 |
| 280 // If there is more work available, wake up worker thread. | 314 // If there is more work available, wake up worker thread. |
| 281 if (!ready_to_run_namespaces_.empty()) | 315 if (!ready_to_run_sub_namespaces_.empty()) |
| 282 has_ready_to_run_tasks_cv_.Signal(); | 316 has_ready_to_run_tasks_cv_.Signal(); |
| 283 } | 317 } |
| 284 } | 318 } |
| 285 | 319 |
| 286 void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) { | 320 void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) { |
| 287 TRACE_EVENT0("cc", "TaskGraphRunner::WaitForTasksToFinishRunning"); | 321 TRACE_EVENT0("cc", "TaskGraphRunner::WaitForTasksToFinishRunning"); |
| 288 | 322 |
| 289 DCHECK(token.IsValid()); | 323 DCHECK(token.IsValid()); |
| 290 | 324 |
| 291 { | 325 { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 319 if (it == namespaces_.end()) | 353 if (it == namespaces_.end()) |
| 320 return; | 354 return; |
| 321 | 355 |
| 322 TaskNamespace& task_namespace = it->second; | 356 TaskNamespace& task_namespace = it->second; |
| 323 | 357 |
| 324 DCHECK_EQ(0u, completed_tasks->size()); | 358 DCHECK_EQ(0u, completed_tasks->size()); |
| 325 completed_tasks->swap(task_namespace.completed_tasks); | 359 completed_tasks->swap(task_namespace.completed_tasks); |
| 326 if (!HasFinishedRunningTasksInNamespace(&task_namespace)) | 360 if (!HasFinishedRunningTasksInNamespace(&task_namespace)) |
| 327 return; | 361 return; |
| 328 | 362 |
| 329 // Remove namespace if finished running tasks. | 363 // Remove empty namespace. |
| 330 DCHECK_EQ(0u, task_namespace.completed_tasks.size()); | |
| 331 DCHECK_EQ(0u, task_namespace.ready_to_run_tasks.size()); | |
| 332 DCHECK_EQ(0u, task_namespace.running_tasks.size()); | |
| 333 namespaces_.erase(it); | 364 namespaces_.erase(it); |
| 334 } | 365 } |
| 335 } | 366 } |
| 336 | 367 |
| 337 void TaskGraphRunner::Shutdown() { | 368 void TaskGraphRunner::Shutdown() { |
| 338 base::AutoLock lock(lock_); | 369 base::AutoLock lock(lock_); |
| 339 | 370 |
| 340 DCHECK_EQ(0u, ready_to_run_namespaces_.size()); | 371 DCHECK_EQ(0u, ready_to_run_sub_namespaces_.size()); |
| 341 DCHECK_EQ(0u, namespaces_.size()); | 372 DCHECK_EQ(0u, namespaces_.size()); |
| 342 | 373 |
| 343 DCHECK(!shutdown_); | 374 DCHECK(!shutdown_); |
| 344 shutdown_ = true; | 375 shutdown_ = true; |
| 345 | 376 |
| 346 // Wake up a worker so it knows it should exit. This will cause all workers | 377 // Wake up a worker so it knows it should exit. This will cause all workers |
| 347 // to exit as each will wake up another worker before exiting. | 378 // to exit as each will wake up another worker before exiting. |
| 348 has_ready_to_run_tasks_cv_.Signal(); | 379 has_ready_to_run_tasks_cv_.Signal(); |
| 349 } | 380 } |
| 350 | 381 |
| 351 void TaskGraphRunner::Run() { | 382 void TaskGraphRunner::Run() { |
| 352 base::AutoLock lock(lock_); | 383 base::AutoLock lock(lock_); |
| 353 | 384 |
| 354 while (true) { | 385 while (true) { |
| 355 if (ready_to_run_namespaces_.empty()) { | 386 if (ready_to_run_sub_namespaces_.empty()) { |
| 356 // Exit when shutdown is set and no more tasks are pending. | 387 // Exit when shutdown is set and no more tasks are pending. |
| 357 if (shutdown_) | 388 if (shutdown_) |
| 358 break; | 389 break; |
| 359 | 390 |
| 360 // Wait for more tasks. | 391 // Wait for more tasks. |
| 361 has_ready_to_run_tasks_cv_.Wait(); | 392 has_ready_to_run_tasks_cv_.Wait(); |
| 362 continue; | 393 continue; |
| 363 } | 394 } |
| 364 | 395 |
| 365 RunTaskWithLockAcquired(); | 396 RunTaskWithLockAcquired(); |
| 366 } | 397 } |
| 367 | 398 |
| 368 // We noticed we should exit. Wake up the next worker so it knows it should | 399 // We noticed we should exit. Wake up the next worker so it knows it should |
| 369 // exit as well (because the Shutdown() code only signals once). | 400 // exit as well (because the Shutdown() code only signals once). |
| 370 has_ready_to_run_tasks_cv_.Signal(); | 401 has_ready_to_run_tasks_cv_.Signal(); |
| 371 } | 402 } |
| 372 | 403 |
| 373 void TaskGraphRunner::RunUntilIdle() { | 404 void TaskGraphRunner::RunUntilIdle() { |
| 374 base::AutoLock lock(lock_); | 405 base::AutoLock lock(lock_); |
| 375 | 406 |
| 376 while (!ready_to_run_namespaces_.empty()) | 407 while (!ready_to_run_sub_namespaces_.empty()) |
| 377 RunTaskWithLockAcquired(); | 408 RunTaskWithLockAcquired(); |
| 378 } | 409 } |
| 379 | 410 |
| 380 void TaskGraphRunner::RunTaskWithLockAcquired() { | 411 void TaskGraphRunner::RunTaskWithLockAcquired() { |
| 381 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); | 412 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); |
| 382 | 413 |
| 383 lock_.AssertAcquired(); | 414 lock_.AssertAcquired(); |
| 384 DCHECK(!ready_to_run_namespaces_.empty()); | 415 DCHECK(!ready_to_run_sub_namespaces_.empty()); |
| 385 | 416 |
| 386 // Take top priority TaskNamespace from |ready_to_run_namespaces_|. | 417 // Take top priority TaskSubNamespace from |ready_to_run_sub_namespaces_|. |
| 387 std::pop_heap(ready_to_run_namespaces_.begin(), | 418 std::pop_heap(ready_to_run_sub_namespaces_.begin(), |
| 388 ready_to_run_namespaces_.end(), | 419 ready_to_run_sub_namespaces_.end(), |
| 389 CompareTaskNamespacePriority); | 420 CompareTaskSubNamespacePriority); |
| 390 TaskNamespace* task_namespace = ready_to_run_namespaces_.back(); | 421 TaskSubNamespace* sub_namespace = ready_to_run_sub_namespaces_.back(); |
| 391 ready_to_run_namespaces_.pop_back(); | 422 ready_to_run_sub_namespaces_.pop_back(); |
| 392 DCHECK(!task_namespace->ready_to_run_tasks.empty()); | 423 sub_namespace->is_in_ready_sub_namespaces = false; |
| 424 | |
| 425 TaskNamespace* task_namespace = sub_namespace->task_namespace; | |
| 393 | 426 |
| 394 // Take top priority task from |ready_to_run_tasks|. | 427 // Take top priority task from |ready_to_run_tasks|. |
| 395 std::pop_heap(task_namespace->ready_to_run_tasks.begin(), | 428 DCHECK(sub_namespace->IsReadyToRun()); |
| 396 task_namespace->ready_to_run_tasks.end(), | 429 std::pop_heap(sub_namespace->ready_to_run_tasks.begin(), |
| 397 CompareTaskPriority); | 430 sub_namespace->ready_to_run_tasks.end(), CompareTaskPriority); |
| 398 scoped_refptr<Task> task(task_namespace->ready_to_run_tasks.back().task); | |
| 399 task_namespace->ready_to_run_tasks.pop_back(); | |
| 400 | 431 |
| 401 // Add task namespace back to |ready_to_run_namespaces_| if not empty after | 432 PrioritizedTask& prioritized_task = sub_namespace->ready_to_run_tasks.back(); |
| 402 // taking top priority task. | 433 scoped_refptr<Task> task(prioritized_task.task); |
| 403 if (!task_namespace->ready_to_run_tasks.empty()) { | 434 sub_namespace->ready_to_run_tasks.pop_back(); |
| 404 ready_to_run_namespaces_.push_back(task_namespace); | 435 |
| 405 std::push_heap(ready_to_run_namespaces_.begin(), | 436 // Update number of concurrently running tasks in sub namespace. |
| 406 ready_to_run_namespaces_.end(), | 437 sub_namespace->running_task_count++; |
| 407 CompareTaskNamespacePriority); | 438 DCHECK_LE(sub_namespace->running_task_count, |
| 439 prioritized_task.max_concurrent_tasks); | |
| 440 | |
| 441 // Add |sub_namespace| back to |ready_to_run_sub_namespaces_| if it's | |
| 442 // still ready to run. | |
| 443 if (sub_namespace->IsReadyToRun()) { | |
| 444 ready_to_run_sub_namespaces_.push_back(sub_namespace); | |
| 445 std::push_heap(ready_to_run_sub_namespaces_.begin(), | |
| 446 ready_to_run_sub_namespaces_.end(), | |
| 447 CompareTaskSubNamespacePriority); | |
| 448 sub_namespace->is_in_ready_sub_namespaces = true; | |
| 408 } | 449 } |
| 409 | 450 |
| 410 // Add task to |running_tasks|. | 451 // Add task to |running_tasks|. |
| 411 task_namespace->running_tasks.push_back(task.get()); | 452 task_namespace->running_tasks.push_back(task.get()); |
| 412 | 453 |
| 413 // There may be more work available, so wake up another worker thread. | 454 // There may be more work available, so wake up another worker thread. |
| 414 has_ready_to_run_tasks_cv_.Signal(); | 455 has_ready_to_run_tasks_cv_.Signal(); |
| 415 | 456 |
| 416 // Call WillRun() before releasing |lock_| and running task. | 457 // Call WillRun() before releasing |lock_| and running task. |
| 417 task->WillRun(); | 458 task->WillRun(); |
| 418 | 459 |
| 419 { | 460 { |
| 420 base::AutoUnlock unlock(lock_); | 461 base::AutoUnlock unlock(lock_); |
| 421 | 462 |
| 422 task->RunOnWorkerThread(); | 463 task->RunOnWorkerThread(); |
| 423 } | 464 } |
| 424 | 465 |
| 425 // This will mark task as finished running. | 466 // This will mark task as finished running. |
| 426 task->DidRun(); | 467 task->DidRun(); |
| 427 | 468 |
| 469 // Update number of concurrently running tasks in sub namespace. | |
| 470 sub_namespace->running_task_count--; | |
| 471 | |
| 472 // If sub namespace became ready to run, add it to | |
| 473 // |ready_to_run_sub_namespaces_|. | |
| 474 if (!sub_namespace->is_in_ready_sub_namespaces && | |
| 475 sub_namespace->IsReadyToRun()) { | |
| 476 ready_to_run_sub_namespaces_.push_back(sub_namespace); | |
| 477 std::push_heap(ready_to_run_sub_namespaces_.begin(), | |
| 478 ready_to_run_sub_namespaces_.end(), | |
| 479 CompareTaskSubNamespacePriority); | |
| 480 sub_namespace->is_in_ready_sub_namespaces = true; | |
| 481 } | |
| 482 | |
| 428 // Remove task from |running_tasks|. | 483 // Remove task from |running_tasks|. |
| 429 TaskVector::iterator it = std::find(task_namespace->running_tasks.begin(), | 484 TaskVector::iterator it = std::find(task_namespace->running_tasks.begin(), |
| 430 task_namespace->running_tasks.end(), | 485 task_namespace->running_tasks.end(), |
| 431 task.get()); | 486 task.get()); |
| 432 DCHECK(it != task_namespace->running_tasks.end()); | 487 DCHECK(it != task_namespace->running_tasks.end()); |
| 433 std::swap(*it, task_namespace->running_tasks.back()); | 488 std::swap(*it, task_namespace->running_tasks.back()); |
| 434 task_namespace->running_tasks.pop_back(); | 489 task_namespace->running_tasks.pop_back(); |
| 435 | 490 |
| 436 // Now iterate over all dependents to decrement dependencies and check if they | 491 // Now iterate over all dependents to decrement dependencies and check if they |
| 437 // are ready to run. | 492 // are ready to run. |
| 438 bool ready_to_run_namespaces_has_heap_properties = true; | 493 bool ready_to_run_sub_namespaces_has_heap_properties = true; |
| 439 for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) { | 494 for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) { |
| 440 TaskGraph::Node& dependent_node = *it; | 495 TaskGraph::Node& dependent_node = *it; |
| 441 | 496 |
| 442 DCHECK_LT(0u, dependent_node.dependencies); | 497 DCHECK_LT(0u, dependent_node.dependencies); |
| 443 dependent_node.dependencies--; | 498 dependent_node.dependencies--; |
| 444 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|. | 499 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks|. |
| 445 if (!dependent_node.dependencies) { | 500 if (!dependent_node.dependencies) { |
| 446 bool was_empty = task_namespace->ready_to_run_tasks.empty(); | 501 TaskSubNamespace& dependent_sub_namespace = |
| 447 task_namespace->ready_to_run_tasks.push_back( | 502 task_namespace->sub_namespaces[dependent_node.sub_namespace]; |
| 448 PrioritizedTask(dependent_node.task, dependent_node.priority)); | 503 |
| 449 std::push_heap(task_namespace->ready_to_run_tasks.begin(), | 504 dependent_sub_namespace.ready_to_run_tasks.push_back( |
| 450 task_namespace->ready_to_run_tasks.end(), | 505 PrioritizedTask(dependent_node.task, dependent_node.priority, |
| 506 dependent_node.max_concurrent_tasks)); | |
| 507 std::push_heap(dependent_sub_namespace.ready_to_run_tasks.begin(), | |
| 508 dependent_sub_namespace.ready_to_run_tasks.end(), | |
| 451 CompareTaskPriority); | 509 CompareTaskPriority); |
| 452 // Task namespace is ready if it has at least one ready to run task. Add | 510 |
| 453 // it to |ready_to_run_namespaces_| if it just become ready. | 511 // If sub namespace became ready to run, add it to |
| 454 if (was_empty) { | 512 // |ready_to_run_sub_namespaces_|. |
| 455 DCHECK(std::find(ready_to_run_namespaces_.begin(), | 513 if (!dependent_sub_namespace.is_in_ready_sub_namespaces && |
| 456 ready_to_run_namespaces_.end(), | 514 dependent_sub_namespace.IsReadyToRun()) { |
| 457 task_namespace) == ready_to_run_namespaces_.end()); | 515 ready_to_run_sub_namespaces_.push_back(&dependent_sub_namespace); |
| 458 ready_to_run_namespaces_.push_back(task_namespace); | 516 dependent_sub_namespace.is_in_ready_sub_namespaces = true; |
| 459 } | 517 } |
| 460 ready_to_run_namespaces_has_heap_properties = false; | 518 |
| 519 ready_to_run_sub_namespaces_has_heap_properties = false; | |
| 461 } | 520 } |
| 462 } | 521 } |
| 463 | 522 |
| 464 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way | 523 // Rearrange the sub namespaces in |ready_to_run_sub_namespaces_| in such a |
| 524 // way | |
|
danakj
2015/02/23 18:45:01
wrapping
| |
| 465 // that they yet again form a heap. | 525 // that they yet again form a heap. |
| 466 if (!ready_to_run_namespaces_has_heap_properties) { | 526 if (!ready_to_run_sub_namespaces_has_heap_properties) { |
| 467 std::make_heap(ready_to_run_namespaces_.begin(), | 527 std::make_heap(ready_to_run_sub_namespaces_.begin(), |
| 468 ready_to_run_namespaces_.end(), | 528 ready_to_run_sub_namespaces_.end(), |
| 469 CompareTaskNamespacePriority); | 529 CompareTaskSubNamespacePriority); |
| 470 } | 530 } |
| 471 | 531 |
| 472 // Finally add task to |completed_tasks_|. | 532 // Finally add task to |completed_tasks_|. |
| 473 task_namespace->completed_tasks.push_back(task); | 533 task_namespace->completed_tasks.push_back(task); |
| 474 | 534 |
| 475 // If namespace has finished running all tasks, wake up origin thread. | 535 // If namespace has finished running all tasks, wake up origin thread. |
| 476 if (HasFinishedRunningTasksInNamespace(task_namespace)) | 536 if (HasFinishedRunningTasksInNamespace(task_namespace)) |
| 477 has_namespaces_with_finished_running_tasks_cv_.Signal(); | 537 has_namespaces_with_finished_running_tasks_cv_.Signal(); |
| 478 } | 538 } |
| 479 | 539 |
| 480 } // namespace cc | 540 } // namespace cc |
| OLD | NEW |