OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "cc/raster/task_graph_work_queue.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <utility> |
| 9 |
| 10 #include "base/trace_event/trace_event.h" |
| 11 |
| 12 namespace cc { |
| 13 |
| 14 TaskGraphWorkQueue::TaskNamespace::TaskNamespace() {} |
| 15 |
| 16 TaskGraphWorkQueue::TaskNamespace::~TaskNamespace() {} |
| 17 |
| 18 TaskGraphWorkQueue::TaskGraphWorkQueue() {} |
| 19 TaskGraphWorkQueue::~TaskGraphWorkQueue() {} |
| 20 |
| 21 void TaskGraphWorkQueue::ScheduleTasks(NamespaceToken token, TaskGraph* graph) { |
| 22 TaskNamespace& task_namespace = namespaces_[token]; |
| 23 |
| 24 // First adjust number of dependencies to reflect completed tasks. |
| 25 for (const scoped_refptr<Task>& task : task_namespace.completed_tasks) { |
| 26 for (DependentIterator node_it(graph, task.get()); node_it; ++node_it) { |
| 27 TaskGraph::Node& node = *node_it; |
| 28 DCHECK_LT(0u, node.dependencies); |
| 29 node.dependencies--; |
| 30 } |
| 31 } |
| 32 |
| 33 // Build new "ready to run" queue and remove nodes from old graph. |
| 34 task_namespace.ready_to_run_tasks.clear(); |
| 35 for (const TaskGraph::Node& node : graph->nodes) { |
| 36 // Remove any old nodes that are associated with this task. The result is |
| 37 // that the old graph is left with all nodes not present in this graph, |
| 38 // which we use below to determine what tasks need to be canceled. |
| 39 TaskGraph::Node::Vector::iterator old_it = std::find_if( |
| 40 task_namespace.graph.nodes.begin(), task_namespace.graph.nodes.end(), |
| 41 [node](const TaskGraph::Node& other) { |
| 42 return node.task == other.task; |
| 43 }); |
| 44 if (old_it != task_namespace.graph.nodes.end()) { |
| 45 std::swap(*old_it, task_namespace.graph.nodes.back()); |
| 46 task_namespace.graph.nodes.pop_back(); |
| 47 } |
| 48 |
| 49 // Task is not ready to run if dependencies are not yet satisfied. |
| 50 if (node.dependencies) |
| 51 continue; |
| 52 |
| 53 // Skip if already finished running task. |
| 54 if (node.task->HasFinishedRunning()) |
| 55 continue; |
| 56 |
| 57 // Skip if already running. |
| 58 if (std::find(task_namespace.running_tasks.begin(), |
| 59 task_namespace.running_tasks.end(), |
| 60 node.task) != task_namespace.running_tasks.end()) |
| 61 continue; |
| 62 |
| 63 task_namespace.ready_to_run_tasks.push_back( |
| 64 PrioritizedTask(node.task, &task_namespace, node.priority)); |
| 65 } |
| 66 |
| 67 // Rearrange the elements in |ready_to_run_tasks| in such a way that they |
| 68 // form a heap. |
| 69 std::make_heap(task_namespace.ready_to_run_tasks.begin(), |
| 70 task_namespace.ready_to_run_tasks.end(), CompareTaskPriority); |
| 71 |
| 72 // Swap task graph. |
| 73 task_namespace.graph.Swap(graph); |
| 74 |
| 75 // Determine what tasks in old graph need to be canceled. |
| 76 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); |
| 77 it != graph->nodes.end(); ++it) { |
| 78 TaskGraph::Node& node = *it; |
| 79 |
| 80 // Skip if already finished running task. |
| 81 if (node.task->HasFinishedRunning()) |
| 82 continue; |
| 83 |
| 84 // Skip if already running. |
| 85 if (std::find(task_namespace.running_tasks.begin(), |
| 86 task_namespace.running_tasks.end(), |
| 87 node.task) != task_namespace.running_tasks.end()) |
| 88 continue; |
| 89 |
| 90 DCHECK(std::find(task_namespace.completed_tasks.begin(), |
| 91 task_namespace.completed_tasks.end(), |
| 92 node.task) == task_namespace.completed_tasks.end()); |
| 93 task_namespace.completed_tasks.push_back(node.task); |
| 94 } |
| 95 |
| 96 // Build new "ready to run" task namespaces queue. |
| 97 ready_to_run_namespaces_.clear(); |
| 98 for (auto& it : namespaces_) { |
| 99 if (!it.second.ready_to_run_tasks.empty()) |
| 100 ready_to_run_namespaces_.push_back(&it.second); |
| 101 } |
| 102 |
| 103 // Rearrange the task namespaces in |ready_to_run_namespaces| in such a |
| 104 // way that they form a heap. |
| 105 std::make_heap(ready_to_run_namespaces_.begin(), |
| 106 ready_to_run_namespaces_.end(), CompareTaskNamespacePriority); |
| 107 } |
| 108 |
| 109 TaskGraphWorkQueue::PrioritizedTask TaskGraphWorkQueue::GetNextTaskToRun() { |
| 110 DCHECK(!ready_to_run_namespaces_.empty()); |
| 111 |
| 112 // Take top priority TaskNamespace from |ready_to_run_namespaces_|. |
| 113 std::pop_heap(ready_to_run_namespaces_.begin(), |
| 114 ready_to_run_namespaces_.end(), CompareTaskNamespacePriority); |
| 115 TaskNamespace* task_namespace = ready_to_run_namespaces_.back(); |
| 116 ready_to_run_namespaces_.pop_back(); |
| 117 DCHECK(!task_namespace->ready_to_run_tasks.empty()); |
| 118 |
| 119 // Take top priority task from |ready_to_run_tasks|. |
| 120 std::pop_heap(task_namespace->ready_to_run_tasks.begin(), |
| 121 task_namespace->ready_to_run_tasks.end(), CompareTaskPriority); |
| 122 PrioritizedTask task = task_namespace->ready_to_run_tasks.back(); |
| 123 task_namespace->ready_to_run_tasks.pop_back(); |
| 124 |
| 125 // Add task namespace back to |ready_to_run_namespaces_| if not empty after |
| 126 // taking top priority task. |
| 127 if (!task_namespace->ready_to_run_tasks.empty()) { |
| 128 ready_to_run_namespaces_.push_back(task_namespace); |
| 129 std::push_heap(ready_to_run_namespaces_.begin(), |
| 130 ready_to_run_namespaces_.end(), |
| 131 CompareTaskNamespacePriority); |
| 132 } |
| 133 |
| 134 // Add task to |running_tasks|. |
| 135 task_namespace->running_tasks.push_back(task.task); |
| 136 |
| 137 return task; |
| 138 } |
| 139 |
| 140 void TaskGraphWorkQueue::CompleteTask(const PrioritizedTask& completed_task) { |
| 141 TaskNamespace* task_namespace = completed_task.task_namespace; |
| 142 Task* task = completed_task.task; |
| 143 |
| 144 // Remove task from |running_tasks|. |
| 145 auto it = std::find(task_namespace->running_tasks.begin(), |
| 146 task_namespace->running_tasks.end(), task); |
| 147 DCHECK(it != task_namespace->running_tasks.end()); |
| 148 std::swap(*it, task_namespace->running_tasks.back()); |
| 149 task_namespace->running_tasks.pop_back(); |
| 150 |
| 151 // Now iterate over all dependents to decrement dependencies and check if they |
| 152 // are ready to run. |
| 153 bool ready_to_run_namespaces_has_heap_properties = true; |
| 154 for (DependentIterator it(&task_namespace->graph, task); it; ++it) { |
| 155 TaskGraph::Node& dependent_node = *it; |
| 156 |
| 157 DCHECK_LT(0u, dependent_node.dependencies); |
| 158 dependent_node.dependencies--; |
| 159 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|. |
| 160 if (!dependent_node.dependencies) { |
| 161 bool was_empty = task_namespace->ready_to_run_tasks.empty(); |
| 162 task_namespace->ready_to_run_tasks.push_back(PrioritizedTask( |
| 163 dependent_node.task, task_namespace, dependent_node.priority)); |
| 164 std::push_heap(task_namespace->ready_to_run_tasks.begin(), |
| 165 task_namespace->ready_to_run_tasks.end(), |
| 166 CompareTaskPriority); |
| 167 // Task namespace is ready if it has at least one ready to run task. Add |
| 168 // it to |ready_to_run_namespaces_| if it just become ready. |
| 169 if (was_empty) { |
| 170 DCHECK(std::find(ready_to_run_namespaces_.begin(), |
| 171 ready_to_run_namespaces_.end(), |
| 172 task_namespace) == ready_to_run_namespaces_.end()); |
| 173 ready_to_run_namespaces_.push_back(task_namespace); |
| 174 } |
| 175 ready_to_run_namespaces_has_heap_properties = false; |
| 176 } |
| 177 } |
| 178 |
| 179 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way |
| 180 // that they yet again form a heap. |
| 181 if (!ready_to_run_namespaces_has_heap_properties) { |
| 182 std::make_heap(ready_to_run_namespaces_.begin(), |
| 183 ready_to_run_namespaces_.end(), |
| 184 CompareTaskNamespacePriority); |
| 185 } |
| 186 |
| 187 // Finally add task to |completed_tasks_|. |
| 188 task_namespace->completed_tasks.push_back(task); |
| 189 } |
| 190 |
| 191 void TaskGraphWorkQueue::CollectCompletedTasks(NamespaceToken token, |
| 192 Task::Vector* completed_tasks) { |
| 193 TaskNamespaceMap::iterator it = namespaces_.find(token); |
| 194 if (it == namespaces_.end()) |
| 195 return; |
| 196 |
| 197 TaskNamespace& task_namespace = it->second; |
| 198 |
| 199 DCHECK_EQ(0u, completed_tasks->size()); |
| 200 completed_tasks->swap(task_namespace.completed_tasks); |
| 201 if (!HasFinishedRunningTasksInNamespace(&task_namespace)) |
| 202 return; |
| 203 |
| 204 // Remove namespace if finished running tasks. |
| 205 DCHECK_EQ(0u, task_namespace.completed_tasks.size()); |
| 206 DCHECK_EQ(0u, task_namespace.ready_to_run_tasks.size()); |
| 207 DCHECK_EQ(0u, task_namespace.running_tasks.size()); |
| 208 // namespaces_.erase(it); |
| 209 } |
| 210 |
| 211 } // namespace cc |
OLD | NEW |