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/raster/task_graph_work_queue.h" | 5 #include "cc/raster/task_graph_work_queue.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | |
8 #include <utility> | 9 #include <utility> |
9 | 10 |
10 #include "base/trace_event/trace_event.h" | 11 #include "base/trace_event/trace_event.h" |
11 | 12 |
12 namespace cc { | 13 namespace cc { |
14 namespace { | |
15 | |
16 bool CompareTaskPriority(const TaskGraphWorkQueue::PrioritizedTask& a, | |
17 const TaskGraphWorkQueue::PrioritizedTask& b) { | |
18 // In this system, numerically lower priority is run first. | |
19 return a.priority > b.priority; | |
20 } | |
21 | |
22 class CompareTaskNamespacePriority { | |
23 public: | |
24 explicit CompareTaskNamespacePriority(uint16_t category) | |
25 : category_(category) {} | |
26 | |
27 bool operator()(const TaskGraphWorkQueue::TaskNamespace* a, | |
28 const TaskGraphWorkQueue::TaskNamespace* b) { | |
29 DCHECK_GT(a->ready_to_run_tasks.count(category_), 0u); | |
30 DCHECK_GT(b->ready_to_run_tasks.count(category_), 0u); | |
31 | |
32 // Compare based on task priority of the ready_to_run_tasks heap .front() | |
33 // will hold the max element of the heap, except after pop_heap, when max | |
34 // element is moved to .back(). | |
35 return CompareTaskPriority(a->ready_to_run_tasks.at(category_).front(), | |
36 b->ready_to_run_tasks.at(category_).front()); | |
reveman
2015/12/04 20:55:51
ready_to_run_tasks[category_] instead?
ericrk
2015/12/09 22:56:43
Can't call operator[] on const maps (as it may nee
| |
37 } | |
38 | |
39 private: | |
40 uint16_t category_; | |
41 }; | |
42 } // namespace | |
13 | 43 |
14 TaskGraphWorkQueue::TaskNamespace::TaskNamespace() {} | 44 TaskGraphWorkQueue::TaskNamespace::TaskNamespace() {} |
15 | 45 |
16 TaskGraphWorkQueue::TaskNamespace::~TaskNamespace() {} | 46 TaskGraphWorkQueue::TaskNamespace::~TaskNamespace() {} |
17 | 47 |
18 TaskGraphWorkQueue::TaskGraphWorkQueue() : next_namespace_id_(1) {} | 48 TaskGraphWorkQueue::TaskGraphWorkQueue() : next_namespace_id_(1) {} |
19 TaskGraphWorkQueue::~TaskGraphWorkQueue() {} | 49 TaskGraphWorkQueue::~TaskGraphWorkQueue() {} |
20 | 50 |
21 NamespaceToken TaskGraphWorkQueue::GetNamespaceToken() { | 51 NamespaceToken TaskGraphWorkQueue::GetNamespaceToken() { |
22 NamespaceToken token(next_namespace_id_++); | 52 NamespaceToken token(next_namespace_id_++); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
59 // Skip if already finished running task. | 89 // Skip if already finished running task. |
60 if (node.task->HasFinishedRunning()) | 90 if (node.task->HasFinishedRunning()) |
61 continue; | 91 continue; |
62 | 92 |
63 // Skip if already running. | 93 // Skip if already running. |
64 if (std::find(task_namespace.running_tasks.begin(), | 94 if (std::find(task_namespace.running_tasks.begin(), |
65 task_namespace.running_tasks.end(), | 95 task_namespace.running_tasks.end(), |
66 node.task) != task_namespace.running_tasks.end()) | 96 node.task) != task_namespace.running_tasks.end()) |
67 continue; | 97 continue; |
68 | 98 |
69 task_namespace.ready_to_run_tasks.push_back( | 99 task_namespace.ready_to_run_tasks[node.category].push_back(PrioritizedTask( |
70 PrioritizedTask(node.task, &task_namespace, node.priority)); | 100 node.task, &task_namespace, node.category, node.priority)); |
71 } | 101 } |
72 | 102 |
73 // Rearrange the elements in |ready_to_run_tasks| in such a way that they | 103 // Rearrange the elements in each vector within |ready_to_run_tasks| in such a |
74 // form a heap. | 104 // way that they form a heap. |
75 std::make_heap(task_namespace.ready_to_run_tasks.begin(), | 105 for (auto& it : task_namespace.ready_to_run_tasks) { |
76 task_namespace.ready_to_run_tasks.end(), CompareTaskPriority); | 106 auto& ready_to_run_tasks = it.second; |
107 std::make_heap(ready_to_run_tasks.begin(), ready_to_run_tasks.end(), | |
108 CompareTaskPriority); | |
109 } | |
77 | 110 |
78 // Swap task graph. | 111 // Swap task graph. |
79 task_namespace.graph.Swap(graph); | 112 task_namespace.graph.Swap(graph); |
80 | 113 |
81 // Determine what tasks in old graph need to be canceled. | 114 // Determine what tasks in old graph need to be canceled. |
82 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); | 115 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); |
83 it != graph->nodes.end(); ++it) { | 116 it != graph->nodes.end(); ++it) { |
84 TaskGraph::Node& node = *it; | 117 TaskGraph::Node& node = *it; |
85 | 118 |
86 // Skip if already finished running task. | 119 // Skip if already finished running task. |
87 if (node.task->HasFinishedRunning()) | 120 if (node.task->HasFinishedRunning()) |
88 continue; | 121 continue; |
89 | 122 |
90 // Skip if already running. | 123 // Skip if already running. |
91 if (std::find(task_namespace.running_tasks.begin(), | 124 if (std::find(task_namespace.running_tasks.begin(), |
92 task_namespace.running_tasks.end(), | 125 task_namespace.running_tasks.end(), |
93 node.task) != task_namespace.running_tasks.end()) | 126 node.task) != task_namespace.running_tasks.end()) |
94 continue; | 127 continue; |
95 | 128 |
96 DCHECK(std::find(task_namespace.completed_tasks.begin(), | 129 DCHECK(std::find(task_namespace.completed_tasks.begin(), |
97 task_namespace.completed_tasks.end(), | 130 task_namespace.completed_tasks.end(), |
98 node.task) == task_namespace.completed_tasks.end()); | 131 node.task) == task_namespace.completed_tasks.end()); |
99 task_namespace.completed_tasks.push_back(node.task); | 132 task_namespace.completed_tasks.push_back(node.task); |
100 } | 133 } |
101 | 134 |
102 // Build new "ready to run" task namespaces queue. | 135 // Build new "ready to run" task namespaces queue. |
103 ready_to_run_namespaces_.clear(); | 136 ready_to_run_namespaces_.clear(); |
104 for (auto& it : namespaces_) { | 137 for (auto& namespace_it : namespaces_) { |
105 if (!it.second.ready_to_run_tasks.empty()) | 138 auto& task_namespace = namespace_it.second; |
106 ready_to_run_namespaces_.push_back(&it.second); | 139 for (auto& tasks_it : task_namespace.ready_to_run_tasks) { |
reveman
2015/12/04 20:55:51
nit: ready_to_run_tasks_it to be perfectly consist
ericrk
2015/12/09 22:56:43
Done.
| |
140 uint16_t category = tasks_it.first; | |
141 ready_to_run_namespaces_[category].push_back(&task_namespace); | |
142 } | |
107 } | 143 } |
108 | 144 |
109 // Rearrange the task namespaces in |ready_to_run_namespaces| in such a | 145 // Rearrange the task namespaces in |ready_to_run_namespaces| in such a |
110 // way that they form a heap. | 146 // way that they form a heap. |
111 std::make_heap(ready_to_run_namespaces_.begin(), | 147 for (auto& it : ready_to_run_namespaces_) { |
112 ready_to_run_namespaces_.end(), CompareTaskNamespacePriority); | 148 uint16_t category = it.first; |
149 auto& task_namespace = it.second; | |
150 std::make_heap(task_namespace.begin(), task_namespace.end(), | |
151 CompareTaskNamespacePriority(category)); | |
152 } | |
113 } | 153 } |
114 | 154 |
115 TaskGraphWorkQueue::PrioritizedTask TaskGraphWorkQueue::GetNextTaskToRun() { | 155 TaskGraphWorkQueue::PrioritizedTask TaskGraphWorkQueue::GetNextTaskToRun( |
116 DCHECK(!ready_to_run_namespaces_.empty()); | 156 uint16_t category) { |
157 DCHECK_GT(ready_to_run_namespaces_.count(category), 0u); | |
reveman
2015/12/04 20:55:51
nit: this failing isn't really a problem but ready
ericrk
2015/12/09 22:56:43
yup = this made more sense when I was erasing thin
| |
158 TaskNamespace::Vector& ready_to_run_namespaces = | |
159 ready_to_run_namespaces_[category]; | |
117 | 160 |
118 // Take top priority TaskNamespace from |ready_to_run_namespaces_|. | 161 // Take top priority TaskNamespace from |ready_to_run_namespaces|. |
119 std::pop_heap(ready_to_run_namespaces_.begin(), | 162 std::pop_heap(ready_to_run_namespaces.begin(), ready_to_run_namespaces.end(), |
120 ready_to_run_namespaces_.end(), CompareTaskNamespacePriority); | 163 CompareTaskNamespacePriority(category)); |
121 TaskNamespace* task_namespace = ready_to_run_namespaces_.back(); | 164 TaskNamespace* task_namespace = ready_to_run_namespaces.back(); |
122 ready_to_run_namespaces_.pop_back(); | 165 ready_to_run_namespaces.pop_back(); |
123 DCHECK(!task_namespace->ready_to_run_tasks.empty()); | 166 |
167 DCHECK_GT(task_namespace->ready_to_run_tasks.count(category), 0u); | |
reveman
2015/12/04 20:55:51
same here, DCHECK(!empty()) instead?
ericrk
2015/12/09 22:56:43
done.
| |
168 PrioritizedTask::Vector& ready_to_run_tasks = | |
169 task_namespace->ready_to_run_tasks[category]; | |
124 | 170 |
125 // Take top priority task from |ready_to_run_tasks|. | 171 // Take top priority task from |ready_to_run_tasks|. |
126 std::pop_heap(task_namespace->ready_to_run_tasks.begin(), | 172 std::pop_heap(ready_to_run_tasks.begin(), ready_to_run_tasks.end(), |
127 task_namespace->ready_to_run_tasks.end(), CompareTaskPriority); | 173 CompareTaskPriority); |
128 PrioritizedTask task = task_namespace->ready_to_run_tasks.back(); | 174 PrioritizedTask task = ready_to_run_tasks.back(); |
129 task_namespace->ready_to_run_tasks.pop_back(); | 175 ready_to_run_tasks.pop_back(); |
130 | 176 |
131 // Add task namespace back to |ready_to_run_namespaces_| if not empty after | 177 // Add task namespace back to |ready_to_run_namespaces| if not empty after |
132 // taking top priority task. | 178 // taking top priority task. |
133 if (!task_namespace->ready_to_run_tasks.empty()) { | 179 if (!ready_to_run_tasks.empty()) { |
134 ready_to_run_namespaces_.push_back(task_namespace); | 180 ready_to_run_namespaces.push_back(task_namespace); |
135 std::push_heap(ready_to_run_namespaces_.begin(), | 181 std::push_heap(ready_to_run_namespaces.begin(), |
136 ready_to_run_namespaces_.end(), | 182 ready_to_run_namespaces.end(), |
137 CompareTaskNamespacePriority); | 183 CompareTaskNamespacePriority(category)); |
184 } else { | |
185 // Task namespace is empty for this category, remove the entry from the map. | |
186 task_namespace->ready_to_run_tasks.erase(category); | |
187 } | |
188 | |
189 // If |ready_to_run_namespaces| is now empty, remove it from the map. | |
190 if (ready_to_run_namespaces.empty()) { | |
191 ready_to_run_namespaces_.erase(category); | |
reveman
2015/12/04 20:55:51
Will this and the above erase not cause a large am
ericrk
2015/12/09 22:56:43
Got rid of the erasing - took some benchmarks and
| |
138 } | 192 } |
139 | 193 |
140 // Add task to |running_tasks|. | 194 // Add task to |running_tasks|. |
141 task_namespace->running_tasks.push_back(task.task); | 195 task_namespace->running_tasks.push_back(task.task); |
142 | 196 |
143 return task; | 197 return task; |
144 } | 198 } |
145 | 199 |
146 void TaskGraphWorkQueue::CompleteTask(const PrioritizedTask& completed_task) { | 200 void TaskGraphWorkQueue::CompleteTask(const PrioritizedTask& completed_task) { |
147 TaskNamespace* task_namespace = completed_task.task_namespace; | 201 TaskNamespace* task_namespace = completed_task.task_namespace; |
148 scoped_refptr<Task> task(completed_task.task); | 202 scoped_refptr<Task> task(completed_task.task); |
149 | 203 |
150 // Remove task from |running_tasks|. | 204 // Remove task from |running_tasks|. |
151 auto it = std::find(task_namespace->running_tasks.begin(), | 205 auto it = std::find(task_namespace->running_tasks.begin(), |
152 task_namespace->running_tasks.end(), task); | 206 task_namespace->running_tasks.end(), task); |
153 DCHECK(it != task_namespace->running_tasks.end()); | 207 DCHECK(it != task_namespace->running_tasks.end()); |
154 std::swap(*it, task_namespace->running_tasks.back()); | 208 std::swap(*it, task_namespace->running_tasks.back()); |
155 task_namespace->running_tasks.pop_back(); | 209 task_namespace->running_tasks.pop_back(); |
156 | 210 |
157 // Now iterate over all dependents to decrement dependencies and check if they | 211 // Now iterate over all dependents to decrement dependencies and check if they |
158 // are ready to run. | 212 // are ready to run. |
159 bool ready_to_run_namespaces_has_heap_properties = true; | 213 bool ready_to_run_namespaces_has_heap_properties = true; |
160 for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) { | 214 for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) { |
161 TaskGraph::Node& dependent_node = *it; | 215 TaskGraph::Node& dependent_node = *it; |
162 | 216 |
163 DCHECK_LT(0u, dependent_node.dependencies); | 217 DCHECK_LT(0u, dependent_node.dependencies); |
164 dependent_node.dependencies--; | 218 dependent_node.dependencies--; |
165 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|. | 219 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|. |
166 if (!dependent_node.dependencies) { | 220 if (!dependent_node.dependencies) { |
167 bool was_empty = task_namespace->ready_to_run_tasks.empty(); | 221 PrioritizedTask::Vector& ready_to_run_tasks = |
168 task_namespace->ready_to_run_tasks.push_back(PrioritizedTask( | 222 task_namespace->ready_to_run_tasks[dependent_node.category]; |
169 dependent_node.task, task_namespace, dependent_node.priority)); | 223 |
170 std::push_heap(task_namespace->ready_to_run_tasks.begin(), | 224 bool was_empty = ready_to_run_tasks.empty(); |
171 task_namespace->ready_to_run_tasks.end(), | 225 ready_to_run_tasks.push_back( |
226 PrioritizedTask(dependent_node.task, task_namespace, | |
227 dependent_node.category, dependent_node.priority)); | |
228 std::push_heap(ready_to_run_tasks.begin(), ready_to_run_tasks.end(), | |
172 CompareTaskPriority); | 229 CompareTaskPriority); |
230 | |
173 // Task namespace is ready if it has at least one ready to run task. Add | 231 // Task namespace is ready if it has at least one ready to run task. Add |
174 // it to |ready_to_run_namespaces_| if it just become ready. | 232 // it to |ready_to_run_namespaces_| if it just become ready. |
175 if (was_empty) { | 233 if (was_empty) { |
176 DCHECK(std::find(ready_to_run_namespaces_.begin(), | 234 TaskNamespace::Vector& ready_to_run_namespaces = |
177 ready_to_run_namespaces_.end(), | 235 ready_to_run_namespaces_[dependent_node.category]; |
178 task_namespace) == ready_to_run_namespaces_.end()); | 236 |
179 ready_to_run_namespaces_.push_back(task_namespace); | 237 DCHECK(std::find(ready_to_run_namespaces.begin(), |
238 ready_to_run_namespaces.end(), | |
239 task_namespace) == ready_to_run_namespaces.end()); | |
240 ready_to_run_namespaces.push_back(task_namespace); | |
180 } | 241 } |
181 ready_to_run_namespaces_has_heap_properties = false; | 242 ready_to_run_namespaces_has_heap_properties = false; |
182 } | 243 } |
183 } | 244 } |
184 | 245 |
185 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way | 246 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way |
186 // that they yet again form a heap. | 247 // that they yet again form a heap. |
187 if (!ready_to_run_namespaces_has_heap_properties) { | 248 if (!ready_to_run_namespaces_has_heap_properties) { |
188 std::make_heap(ready_to_run_namespaces_.begin(), | 249 for (auto& it : ready_to_run_namespaces_) { |
189 ready_to_run_namespaces_.end(), | 250 uint16_t category = it.first; |
190 CompareTaskNamespacePriority); | 251 auto& ready_to_run_namespaces = it.second; |
252 std::make_heap(ready_to_run_namespaces.begin(), | |
253 ready_to_run_namespaces.end(), | |
254 CompareTaskNamespacePriority(category)); | |
255 } | |
191 } | 256 } |
192 | 257 |
193 // Finally add task to |completed_tasks_|. | 258 // Finally add task to |completed_tasks_|. |
194 task_namespace->completed_tasks.push_back(task); | 259 task_namespace->completed_tasks.push_back(task); |
195 } | 260 } |
196 | 261 |
197 void TaskGraphWorkQueue::CollectCompletedTasks(NamespaceToken token, | 262 void TaskGraphWorkQueue::CollectCompletedTasks(NamespaceToken token, |
198 Task::Vector* completed_tasks) { | 263 Task::Vector* completed_tasks) { |
199 TaskNamespaceMap::iterator it = namespaces_.find(token); | 264 TaskNamespaceMap::iterator it = namespaces_.find(token); |
200 if (it == namespaces_.end()) | 265 if (it == namespaces_.end()) |
201 return; | 266 return; |
202 | 267 |
203 TaskNamespace& task_namespace = it->second; | 268 TaskNamespace& task_namespace = it->second; |
204 | 269 |
205 DCHECK_EQ(0u, completed_tasks->size()); | 270 DCHECK_EQ(0u, completed_tasks->size()); |
206 completed_tasks->swap(task_namespace.completed_tasks); | 271 completed_tasks->swap(task_namespace.completed_tasks); |
207 if (!HasFinishedRunningTasksInNamespace(&task_namespace)) | 272 if (!HasFinishedRunningTasksInNamespace(&task_namespace)) |
208 return; | 273 return; |
209 | 274 |
210 // Remove namespace if finished running tasks. | 275 // Remove namespace if finished running tasks. |
211 DCHECK_EQ(0u, task_namespace.completed_tasks.size()); | 276 DCHECK_EQ(0u, task_namespace.completed_tasks.size()); |
212 DCHECK_EQ(0u, task_namespace.ready_to_run_tasks.size()); | 277 DCHECK(task_namespace.ready_to_run_tasks.empty()); |
213 DCHECK_EQ(0u, task_namespace.running_tasks.size()); | 278 DCHECK_EQ(0u, task_namespace.running_tasks.size()); |
214 namespaces_.erase(it); | 279 namespaces_.erase(it); |
215 } | 280 } |
216 | 281 |
217 bool TaskGraphWorkQueue::DependencyMismatch(const TaskGraph* graph) { | 282 bool TaskGraphWorkQueue::DependencyMismatch(const TaskGraph* graph) { |
218 // Value storage will be 0-initialized. | 283 // Value storage will be 0-initialized. |
219 base::hash_map<const Task*, size_t> dependents; | 284 base::hash_map<const Task*, size_t> dependents; |
220 for (const TaskGraph::Edge& edge : graph->edges) | 285 for (const TaskGraph::Edge& edge : graph->edges) |
221 dependents[edge.dependent]++; | 286 dependents[edge.dependent]++; |
222 | 287 |
223 for (const TaskGraph::Node& node : graph->nodes) { | 288 for (const TaskGraph::Node& node : graph->nodes) { |
224 if (dependents[node.task] != node.dependencies) | 289 if (dependents[node.task] != node.dependencies) |
225 return true; | 290 return true; |
226 } | 291 } |
227 | 292 |
228 return false; | 293 return false; |
229 } | 294 } |
230 | 295 |
296 void TaskGraphWorkQueue::UncategorizeTaskGraph(TaskGraph* graph) { | |
297 for (auto& node : graph->nodes) { | |
298 node.category = 0u; | |
299 } | |
300 } | |
301 | |
231 } // namespace cc | 302 } // namespace cc |
OLD | NEW |