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

Unified Diff: cc/raster/task_graph_runner.cc

Issue 1449133002: TaskGraphRunner refactor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: feedback Created 5 years, 1 month 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/raster/task_graph_runner.h ('k') | cc/raster/task_graph_runner_perftest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/raster/task_graph_runner.cc
diff --git a/cc/raster/task_graph_runner.cc b/cc/raster/task_graph_runner.cc
index 4fbf56e31bde4f5087157d30adc9865257f4a854..4704e524b37ded43d646b8e8e7369ff08d5feb56 100644
--- a/cc/raster/task_graph_runner.cc
+++ b/cc/raster/task_graph_runner.cc
@@ -5,88 +5,16 @@
#include "cc/raster/task_graph_runner.h"
#include <algorithm>
+#include <utility>
+#include "base/atomic_sequence_num.h"
#include "base/containers/hash_tables.h"
-#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
namespace cc {
-namespace {
-// Helper class for iterating over all dependents of a task.
-class DependentIterator {
- public:
- DependentIterator(TaskGraph* graph, const Task* task)
- : graph_(graph),
- task_(task),
- current_index_(static_cast<size_t>(-1)),
- current_node_(NULL) {
- ++(*this);
- }
-
- TaskGraph::Node& operator->() const {
- DCHECK_LT(current_index_, graph_->edges.size());
- DCHECK_EQ(graph_->edges[current_index_].task, task_);
- DCHECK(current_node_);
- return *current_node_;
- }
-
- TaskGraph::Node& operator*() const {
- DCHECK_LT(current_index_, graph_->edges.size());
- DCHECK_EQ(graph_->edges[current_index_].task, task_);
- DCHECK(current_node_);
- return *current_node_;
- }
-
- // Note: Performance can be improved by keeping edges sorted.
- DependentIterator& operator++() {
- // Find next dependency edge for |task_|.
- do {
- ++current_index_;
- if (current_index_ == graph_->edges.size())
- return *this;
- } while (graph_->edges[current_index_].task != task_);
-
- // Now find the node for the dependent of this edge.
- TaskGraph::Node::Vector::iterator it =
- std::find_if(graph_->nodes.begin(),
- graph_->nodes.end(),
- TaskGraph::Node::TaskComparator(
- graph_->edges[current_index_].dependent));
- DCHECK(it != graph_->nodes.end());
- current_node_ = &(*it);
-
- return *this;
- }
-
- operator bool() const { return current_index_ < graph_->edges.size(); }
-
- private:
- TaskGraph* graph_;
- const Task* task_;
- size_t current_index_;
- TaskGraph::Node* current_node_;
-};
-
-bool DependencyMismatch(const TaskGraph* graph) {
- // Value storage will be 0-initialized.
- base::hash_map<const Task*, size_t> dependents;
- for (const TaskGraph::Edge& edge : graph->edges)
- dependents[edge.dependent]++;
-
- for (const TaskGraph::Node& node : graph->nodes) {
- if (dependents[node.task] != node.dependencies)
- return true;
- }
-
- return false;
-}
-
-} // namespace
-
-Task::Task() : will_run_(false), did_run_(false) {
-}
+Task::Task() : will_run_(false), did_run_(false) {}
Task::~Task() {
DCHECK(!will_run_);
@@ -104,7 +32,9 @@ void Task::DidRun() {
did_run_ = true;
}
-bool Task::HasFinishedRunning() const { return did_run_; }
+bool Task::HasFinishedRunning() const {
+ return did_run_;
+}
TaskGraph::TaskGraph() {}
@@ -120,357 +50,4 @@ void TaskGraph::Reset() {
edges.clear();
}
-TaskGraphRunner::TaskNamespace::TaskNamespace() {}
-
-TaskGraphRunner::TaskNamespace::~TaskNamespace() {}
-
-TaskGraphRunner::TaskGraphRunner()
- : lock_(),
- has_ready_to_run_tasks_cv_(&lock_),
- has_namespaces_with_finished_running_tasks_cv_(&lock_),
- next_namespace_id_(1),
- shutdown_(false) {}
-
-TaskGraphRunner::~TaskGraphRunner() {
- {
- base::AutoLock lock(lock_);
-
- DCHECK_EQ(0u, ready_to_run_namespaces_.size());
- DCHECK_EQ(0u, namespaces_.size());
- }
-}
-
-NamespaceToken TaskGraphRunner::GetNamespaceToken() {
- base::AutoLock lock(lock_);
-
- NamespaceToken token(next_namespace_id_++);
- DCHECK(namespaces_.find(token.id_) == namespaces_.end());
- return token;
-}
-
-void TaskGraphRunner::ScheduleTasks(NamespaceToken token, TaskGraph* graph) {
- TRACE_EVENT2("cc",
- "TaskGraphRunner::ScheduleTasks",
- "num_nodes",
- graph->nodes.size(),
- "num_edges",
- graph->edges.size());
-
- DCHECK(token.IsValid());
- DCHECK(!DependencyMismatch(graph));
-
- {
- base::AutoLock lock(lock_);
-
- DCHECK(!shutdown_);
-
- TaskNamespace& task_namespace = namespaces_[token.id_];
-
- // First adjust number of dependencies to reflect completed tasks.
- for (Task::Vector::iterator it = task_namespace.completed_tasks.begin();
- it != task_namespace.completed_tasks.end();
- ++it) {
- for (DependentIterator node_it(graph, it->get()); node_it; ++node_it) {
- TaskGraph::Node& node = *node_it;
- DCHECK_LT(0u, node.dependencies);
- node.dependencies--;
- }
- }
-
- // Build new "ready to run" queue and remove nodes from old graph.
- task_namespace.ready_to_run_tasks.clear();
- for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
- it != graph->nodes.end();
- ++it) {
- TaskGraph::Node& node = *it;
-
- // Remove any old nodes that are associated with this task. The result is
- // that the old graph is left with all nodes not present in this graph,
- // which we use below to determine what tasks need to be canceled.
- TaskGraph::Node::Vector::iterator old_it =
- std::find_if(task_namespace.graph.nodes.begin(),
- task_namespace.graph.nodes.end(),
- TaskGraph::Node::TaskComparator(node.task));
- if (old_it != task_namespace.graph.nodes.end()) {
- std::swap(*old_it, task_namespace.graph.nodes.back());
- task_namespace.graph.nodes.pop_back();
- }
-
- // Task is not ready to run if dependencies are not yet satisfied.
- if (node.dependencies)
- continue;
-
- // Skip if already finished running task.
- if (node.task->HasFinishedRunning())
- continue;
-
- // Skip if already running.
- if (std::find(task_namespace.running_tasks.begin(),
- task_namespace.running_tasks.end(),
- node.task) != task_namespace.running_tasks.end())
- continue;
-
- task_namespace.ready_to_run_tasks.push_back(
- PrioritizedTask(node.task, node.priority));
- }
-
- // Rearrange the elements in |ready_to_run_tasks| in such a way that they
- // form a heap.
- std::make_heap(task_namespace.ready_to_run_tasks.begin(),
- task_namespace.ready_to_run_tasks.end(),
- CompareTaskPriority);
-
- // Swap task graph.
- task_namespace.graph.Swap(graph);
-
- // Determine what tasks in old graph need to be canceled.
- for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
- it != graph->nodes.end();
- ++it) {
- TaskGraph::Node& node = *it;
-
- // Skip if already finished running task.
- if (node.task->HasFinishedRunning())
- continue;
-
- // Skip if already running.
- if (std::find(task_namespace.running_tasks.begin(),
- task_namespace.running_tasks.end(),
- node.task) != task_namespace.running_tasks.end())
- continue;
-
- DCHECK(std::find(task_namespace.completed_tasks.begin(),
- task_namespace.completed_tasks.end(),
- node.task) == task_namespace.completed_tasks.end());
- task_namespace.completed_tasks.push_back(node.task);
- }
-
- // Build new "ready to run" task namespaces queue.
- ready_to_run_namespaces_.clear();
- for (TaskNamespaceMap::iterator it = namespaces_.begin();
- it != namespaces_.end();
- ++it) {
- if (!it->second.ready_to_run_tasks.empty())
- ready_to_run_namespaces_.push_back(&it->second);
- }
-
- // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way
- // that they form a heap.
- std::make_heap(ready_to_run_namespaces_.begin(),
- ready_to_run_namespaces_.end(),
- CompareTaskNamespacePriority);
-
- // If there is more work available, wake up worker thread.
- if (!ready_to_run_namespaces_.empty())
- has_ready_to_run_tasks_cv_.Signal();
- }
-}
-
-void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) {
- TRACE_EVENT0("cc", "TaskGraphRunner::WaitForTasksToFinishRunning");
-
- DCHECK(token.IsValid());
-
- {
- base::AutoLock lock(lock_);
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
-
- TaskNamespaceMap::const_iterator it = namespaces_.find(token.id_);
- if (it == namespaces_.end())
- return;
-
- const TaskNamespace& task_namespace = it->second;
-
- while (!HasFinishedRunningTasksInNamespace(&task_namespace))
- has_namespaces_with_finished_running_tasks_cv_.Wait();
-
- // There may be other namespaces that have finished running tasks, so wake
- // up another origin thread.
- has_namespaces_with_finished_running_tasks_cv_.Signal();
- }
-}
-
-void TaskGraphRunner::CollectCompletedTasks(NamespaceToken token,
- Task::Vector* completed_tasks) {
- TRACE_EVENT0("cc", "TaskGraphRunner::CollectCompletedTasks");
-
- DCHECK(token.IsValid());
-
- {
- base::AutoLock lock(lock_);
-
- TaskNamespaceMap::iterator it = namespaces_.find(token.id_);
- if (it == namespaces_.end())
- return;
-
- TaskNamespace& task_namespace = it->second;
-
- DCHECK_EQ(0u, completed_tasks->size());
- completed_tasks->swap(task_namespace.completed_tasks);
- if (!HasFinishedRunningTasksInNamespace(&task_namespace))
- return;
-
- // Remove namespace if finished running tasks.
- DCHECK_EQ(0u, task_namespace.completed_tasks.size());
- DCHECK_EQ(0u, task_namespace.ready_to_run_tasks.size());
- DCHECK_EQ(0u, task_namespace.running_tasks.size());
- namespaces_.erase(it);
- }
-}
-
-void TaskGraphRunner::Shutdown() {
- base::AutoLock lock(lock_);
-
- DCHECK_EQ(0u, ready_to_run_namespaces_.size());
- DCHECK_EQ(0u, namespaces_.size());
-
- DCHECK(!shutdown_);
- shutdown_ = true;
-
- // Wake up a worker so it knows it should exit. This will cause all workers
- // to exit as each will wake up another worker before exiting.
- has_ready_to_run_tasks_cv_.Signal();
-}
-
-void TaskGraphRunner::FlushForTesting() {
- base::AutoLock lock(lock_);
-
- while (std::find_if(namespaces_.begin(), namespaces_.end(),
- [](const TaskNamespaceMap::value_type& entry) {
- return !HasFinishedRunningTasksInNamespace(
- &entry.second);
- }) != namespaces_.end()) {
- has_namespaces_with_finished_running_tasks_cv_.Wait();
- }
-}
-
-void TaskGraphRunner::Run() {
- base::AutoLock lock(lock_);
-
- while (true) {
- if (ready_to_run_namespaces_.empty()) {
- // Exit when shutdown is set and no more tasks are pending.
- if (shutdown_)
- break;
-
- // Wait for more tasks.
- has_ready_to_run_tasks_cv_.Wait();
- continue;
- }
-
- RunTaskWithLockAcquired();
- }
-
- // We noticed we should exit. Wake up the next worker so it knows it should
- // exit as well (because the Shutdown() code only signals once).
- has_ready_to_run_tasks_cv_.Signal();
-}
-
-void TaskGraphRunner::RunUntilIdle() {
- base::AutoLock lock(lock_);
-
- while (!ready_to_run_namespaces_.empty())
- RunTaskWithLockAcquired();
-}
-
-void TaskGraphRunner::RunTaskWithLockAcquired() {
- TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask");
-
- lock_.AssertAcquired();
- DCHECK(!ready_to_run_namespaces_.empty());
-
- // Take top priority TaskNamespace from |ready_to_run_namespaces_|.
- std::pop_heap(ready_to_run_namespaces_.begin(),
- ready_to_run_namespaces_.end(),
- CompareTaskNamespacePriority);
- TaskNamespace* task_namespace = ready_to_run_namespaces_.back();
- ready_to_run_namespaces_.pop_back();
- DCHECK(!task_namespace->ready_to_run_tasks.empty());
-
- // Take top priority task from |ready_to_run_tasks|.
- std::pop_heap(task_namespace->ready_to_run_tasks.begin(),
- task_namespace->ready_to_run_tasks.end(),
- CompareTaskPriority);
- scoped_refptr<Task> task(task_namespace->ready_to_run_tasks.back().task);
- task_namespace->ready_to_run_tasks.pop_back();
-
- // Add task namespace back to |ready_to_run_namespaces_| if not empty after
- // taking top priority task.
- if (!task_namespace->ready_to_run_tasks.empty()) {
- ready_to_run_namespaces_.push_back(task_namespace);
- std::push_heap(ready_to_run_namespaces_.begin(),
- ready_to_run_namespaces_.end(),
- CompareTaskNamespacePriority);
- }
-
- // Add task to |running_tasks|.
- task_namespace->running_tasks.push_back(task.get());
-
- // There may be more work available, so wake up another worker thread.
- has_ready_to_run_tasks_cv_.Signal();
-
- // Call WillRun() before releasing |lock_| and running task.
- task->WillRun();
-
- {
- base::AutoUnlock unlock(lock_);
-
- task->RunOnWorkerThread();
- }
-
- // This will mark task as finished running.
- task->DidRun();
-
- // Remove task from |running_tasks|.
- TaskVector::iterator it = std::find(task_namespace->running_tasks.begin(),
- task_namespace->running_tasks.end(),
- task.get());
- DCHECK(it != task_namespace->running_tasks.end());
- std::swap(*it, task_namespace->running_tasks.back());
- task_namespace->running_tasks.pop_back();
-
- // Now iterate over all dependents to decrement dependencies and check if they
- // are ready to run.
- bool ready_to_run_namespaces_has_heap_properties = true;
- for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) {
- TaskGraph::Node& dependent_node = *it;
-
- DCHECK_LT(0u, dependent_node.dependencies);
- dependent_node.dependencies--;
- // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|.
- if (!dependent_node.dependencies) {
- bool was_empty = task_namespace->ready_to_run_tasks.empty();
- task_namespace->ready_to_run_tasks.push_back(
- PrioritizedTask(dependent_node.task, dependent_node.priority));
- std::push_heap(task_namespace->ready_to_run_tasks.begin(),
- task_namespace->ready_to_run_tasks.end(),
- CompareTaskPriority);
- // Task namespace is ready if it has at least one ready to run task. Add
- // it to |ready_to_run_namespaces_| if it just become ready.
- if (was_empty) {
- DCHECK(std::find(ready_to_run_namespaces_.begin(),
- ready_to_run_namespaces_.end(),
- task_namespace) == ready_to_run_namespaces_.end());
- ready_to_run_namespaces_.push_back(task_namespace);
- }
- ready_to_run_namespaces_has_heap_properties = false;
- }
- }
-
- // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way
- // that they yet again form a heap.
- if (!ready_to_run_namespaces_has_heap_properties) {
- std::make_heap(ready_to_run_namespaces_.begin(),
- ready_to_run_namespaces_.end(),
- CompareTaskNamespacePriority);
- }
-
- // Finally add task to |completed_tasks_|.
- task_namespace->completed_tasks.push_back(task);
-
- // If namespace has finished running all tasks, wake up origin thread.
- if (HasFinishedRunningTasksInNamespace(task_namespace))
- has_namespaces_with_finished_running_tasks_cv_.Signal();
-}
-
} // namespace cc
« no previous file with comments | « cc/raster/task_graph_runner.h ('k') | cc/raster/task_graph_runner_perftest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698