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/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 } | 158 } |
159 | 159 |
160 void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) { | 160 void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) { |
161 TRACE_EVENT0("cc", "TaskGraphRunner::WaitForTasksToFinishRunning"); | 161 TRACE_EVENT0("cc", "TaskGraphRunner::WaitForTasksToFinishRunning"); |
162 | 162 |
163 DCHECK(token.IsValid()); | 163 DCHECK(token.IsValid()); |
164 | 164 |
165 { | 165 { |
166 base::AutoLock lock(lock_); | 166 base::AutoLock lock(lock_); |
167 | 167 |
168 TaskNamespaceMap::iterator it = namespaces_.find(token.id_); | 168 TaskNamespaceMap::const_iterator it = namespaces_.find(token.id_); |
169 if (it == namespaces_.end()) | 169 if (it == namespaces_.end()) |
170 return; | 170 return; |
171 | 171 |
172 TaskNamespace* task_namespace = it->second; | 172 const TaskNamespace& task_namespace = it->second; |
173 | 173 |
174 while (!HasFinishedRunningTasksInNamespace(task_namespace)) | 174 while (!HasFinishedRunningTasksInNamespace(&task_namespace)) |
175 has_namespaces_with_finished_running_tasks_cv_.Wait(); | 175 has_namespaces_with_finished_running_tasks_cv_.Wait(); |
176 | 176 |
177 // There may be other namespaces that have finished running | 177 // There may be other namespaces that have finished running |
178 // tasks, so wake up another origin thread. | 178 // tasks, so wake up another origin thread. |
179 has_namespaces_with_finished_running_tasks_cv_.Signal(); | 179 has_namespaces_with_finished_running_tasks_cv_.Signal(); |
180 } | 180 } |
181 } | 181 } |
182 | 182 |
183 void TaskGraphRunner::SetTaskGraph(NamespaceToken token, TaskGraph* graph) { | 183 void TaskGraphRunner::SetTaskGraph(NamespaceToken token, TaskGraph* graph) { |
184 TRACE_EVENT2("cc", | 184 TRACE_EVENT2("cc", |
185 "TaskGraphRunner::SetTaskGraph", | 185 "TaskGraphRunner::SetTaskGraph", |
186 "num_nodes", | 186 "num_nodes", |
187 graph->nodes.size(), | 187 graph->nodes.size(), |
188 "num_edges", | 188 "num_edges", |
189 graph->edges.size()); | 189 graph->edges.size()); |
190 | 190 |
191 DCHECK(token.IsValid()); | 191 DCHECK(token.IsValid()); |
192 | 192 |
193 { | 193 { |
194 base::AutoLock lock(lock_); | 194 base::AutoLock lock(lock_); |
195 | 195 |
196 DCHECK(!shutdown_); | 196 DCHECK(!shutdown_); |
197 | 197 |
198 scoped_ptr<TaskNamespace> task_namespace = | 198 TaskNamespace& task_namespace = namespaces_[token.id_]; |
199 namespaces_.take_and_erase(token.id_); | |
200 | |
201 // Create task namespace if it doesn't exist. | |
202 if (!task_namespace) | |
203 task_namespace.reset(new TaskNamespace); | |
204 | 199 |
205 // First adjust number of dependencies to reflect completed tasks. | 200 // First adjust number of dependencies to reflect completed tasks. |
206 for (Task::Vector::iterator it = task_namespace->completed_tasks.begin(); | 201 for (Task::Vector::iterator it = task_namespace.completed_tasks.begin(); |
207 it != task_namespace->completed_tasks.end(); | 202 it != task_namespace.completed_tasks.end(); |
208 ++it) { | 203 ++it) { |
209 for (DependentIterator node_it(graph, it->get()); node_it; ++node_it) { | 204 for (DependentIterator node_it(graph, it->get()); node_it; ++node_it) { |
210 TaskGraph::Node& node = *node_it; | 205 TaskGraph::Node& node = *node_it; |
211 DCHECK_LT(0u, node.dependencies); | 206 DCHECK_LT(0u, node.dependencies); |
212 node.dependencies--; | 207 node.dependencies--; |
213 } | 208 } |
214 } | 209 } |
215 | 210 |
216 // Build new "ready to run" queue and remove nodes from old graph. | 211 // Build new "ready to run" queue and remove nodes from old graph. |
217 task_namespace->ready_to_run_tasks.clear(); | 212 task_namespace.ready_to_run_tasks.clear(); |
218 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); | 213 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); |
219 it != graph->nodes.end(); | 214 it != graph->nodes.end(); |
220 ++it) { | 215 ++it) { |
221 TaskGraph::Node& node = *it; | 216 TaskGraph::Node& node = *it; |
222 | 217 |
223 // Remove any old nodes that are associated with this task. The result is | 218 // Remove any old nodes that are associated with this task. The result is |
224 // that the old graph is left all nodes not present in this graph, which | 219 // that the old graph is left all nodes not present in this graph, which |
225 // we use below to determine what tasks need to be canceled. | 220 // we use below to determine what tasks need to be canceled. |
226 TaskGraph::Node::Vector::iterator old_it = | 221 TaskGraph::Node::Vector::iterator old_it = |
227 std::find_if(task_namespace->graph.nodes.begin(), | 222 std::find_if(task_namespace.graph.nodes.begin(), |
228 task_namespace->graph.nodes.end(), | 223 task_namespace.graph.nodes.end(), |
229 TaskGraph::Node::TaskComparator(node.task)); | 224 TaskGraph::Node::TaskComparator(node.task)); |
230 if (old_it != task_namespace->graph.nodes.end()) { | 225 if (old_it != task_namespace.graph.nodes.end()) { |
231 std::swap(*old_it, task_namespace->graph.nodes.back()); | 226 std::swap(*old_it, task_namespace.graph.nodes.back()); |
232 task_namespace->graph.nodes.pop_back(); | 227 task_namespace.graph.nodes.pop_back(); |
233 } | 228 } |
234 | 229 |
235 // Task is not ready to run if dependencies are not yet satisfied. | 230 // Task is not ready to run if dependencies are not yet satisfied. |
236 if (node.dependencies) | 231 if (node.dependencies) |
237 continue; | 232 continue; |
238 | 233 |
239 // Skip if already finished running task. | 234 // Skip if already finished running task. |
240 if (node.task->HasFinishedRunning()) | 235 if (node.task->HasFinishedRunning()) |
241 continue; | 236 continue; |
242 | 237 |
243 // Skip if already running. | 238 // Skip if already running. |
244 if (std::find(running_tasks_.begin(), running_tasks_.end(), node.task) != | 239 if (std::find(running_tasks_.begin(), running_tasks_.end(), node.task) != |
245 running_tasks_.end()) | 240 running_tasks_.end()) |
246 continue; | 241 continue; |
247 | 242 |
248 task_namespace->ready_to_run_tasks.push_back( | 243 task_namespace.ready_to_run_tasks.push_back( |
249 PrioritizedTask(node.task, node.priority)); | 244 PrioritizedTask(node.task, node.priority)); |
250 } | 245 } |
251 | 246 |
252 // Rearrange the elements in |ready_to_run_tasks| in such a way that | 247 // Rearrange the elements in |ready_to_run_tasks| in such a way that |
253 // they form a heap. | 248 // they form a heap. |
254 std::make_heap(task_namespace->ready_to_run_tasks.begin(), | 249 std::make_heap(task_namespace.ready_to_run_tasks.begin(), |
255 task_namespace->ready_to_run_tasks.end(), | 250 task_namespace.ready_to_run_tasks.end(), |
256 CompareTaskPriority); | 251 CompareTaskPriority); |
257 | 252 |
258 // Swap task graph. | 253 // Swap task graph. |
259 task_namespace->graph.Swap(graph); | 254 task_namespace.graph.Swap(graph); |
260 | 255 |
261 // Determine what tasks in old graph need to be canceled. | 256 // Determine what tasks in old graph need to be canceled. |
262 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); | 257 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); |
263 it != graph->nodes.end(); | 258 it != graph->nodes.end(); |
264 ++it) { | 259 ++it) { |
265 TaskGraph::Node& node = *it; | 260 TaskGraph::Node& node = *it; |
266 | 261 |
267 // Skip if already finished running task. | 262 // Skip if already finished running task. |
268 if (node.task->HasFinishedRunning()) | 263 if (node.task->HasFinishedRunning()) |
269 continue; | 264 continue; |
270 | 265 |
271 // Skip if already running. | 266 // Skip if already running. |
272 if (std::find(running_tasks_.begin(), running_tasks_.end(), node.task) != | 267 if (std::find(running_tasks_.begin(), running_tasks_.end(), node.task) != |
273 running_tasks_.end()) | 268 running_tasks_.end()) |
274 continue; | 269 continue; |
275 | 270 |
276 task_namespace->completed_tasks.push_back(node.task); | 271 task_namespace.completed_tasks.push_back(node.task); |
277 } | 272 } |
278 | 273 |
279 namespaces_.set(token.id_, task_namespace.Pass()); | |
280 | |
281 // Build new "ready to run" task namespaces queue. | 274 // Build new "ready to run" task namespaces queue. |
282 ready_to_run_namespaces_.clear(); | 275 ready_to_run_namespaces_.clear(); |
283 for (TaskNamespaceMap::iterator it = namespaces_.begin(); | 276 for (TaskNamespaceMap::iterator it = namespaces_.begin(); |
284 it != namespaces_.end(); | 277 it != namespaces_.end(); |
285 ++it) { | 278 ++it) { |
286 if (!it->second->ready_to_run_tasks.empty()) | 279 if (!it->second.ready_to_run_tasks.empty()) |
287 ready_to_run_namespaces_.push_back(it->second); | 280 ready_to_run_namespaces_.push_back(&it->second); |
288 } | 281 } |
289 | 282 |
290 // Rearrange the task namespaces in |ready_to_run_namespaces_| | 283 // Rearrange the task namespaces in |ready_to_run_namespaces_| |
291 // in such a way that they form a heap. | 284 // in such a way that they form a heap. |
292 std::make_heap(ready_to_run_namespaces_.begin(), | 285 std::make_heap(ready_to_run_namespaces_.begin(), |
293 ready_to_run_namespaces_.end(), | 286 ready_to_run_namespaces_.end(), |
294 CompareTaskNamespacePriority); | 287 CompareTaskNamespacePriority); |
295 | 288 |
296 // If there is more work available, wake up worker thread. | 289 // If there is more work available, wake up worker thread. |
297 if (!ready_to_run_namespaces_.empty()) | 290 if (!ready_to_run_namespaces_.empty()) |
298 has_ready_to_run_tasks_cv_.Signal(); | 291 has_ready_to_run_tasks_cv_.Signal(); |
299 } | 292 } |
300 } | 293 } |
301 | 294 |
302 void TaskGraphRunner::CollectCompletedTasks(NamespaceToken token, | 295 void TaskGraphRunner::CollectCompletedTasks(NamespaceToken token, |
303 Task::Vector* completed_tasks) { | 296 Task::Vector* completed_tasks) { |
304 TRACE_EVENT0("cc", "TaskGraphRunner::CollectCompletedTasks"); | 297 TRACE_EVENT0("cc", "TaskGraphRunner::CollectCompletedTasks"); |
305 | 298 |
306 DCHECK(token.IsValid()); | 299 DCHECK(token.IsValid()); |
307 | 300 |
308 { | 301 { |
309 base::AutoLock lock(lock_); | 302 base::AutoLock lock(lock_); |
310 | 303 |
311 TaskNamespaceMap::iterator it = namespaces_.find(token.id_); | 304 TaskNamespaceMap::iterator it = namespaces_.find(token.id_); |
312 if (it == namespaces_.end()) | 305 if (it == namespaces_.end()) |
313 return; | 306 return; |
314 | 307 |
315 TaskNamespace* task_namespace = it->second; | 308 TaskNamespace& task_namespace = it->second; |
316 | 309 |
317 DCHECK_EQ(0u, completed_tasks->size()); | 310 DCHECK_EQ(0u, completed_tasks->size()); |
318 completed_tasks->swap(task_namespace->completed_tasks); | 311 completed_tasks->swap(task_namespace.completed_tasks); |
319 if (!HasFinishedRunningTasksInNamespace(task_namespace)) | 312 if (!HasFinishedRunningTasksInNamespace(&task_namespace)) |
320 return; | 313 return; |
321 | 314 |
322 // Remove namespace if finished running tasks. | 315 // Remove namespace if finished running tasks. |
323 DCHECK_EQ(0u, task_namespace->completed_tasks.size()); | 316 DCHECK_EQ(0u, task_namespace.completed_tasks.size()); |
324 DCHECK_EQ(0u, task_namespace->ready_to_run_tasks.size()); | 317 DCHECK_EQ(0u, task_namespace.ready_to_run_tasks.size()); |
325 DCHECK_EQ(0u, task_namespace->num_running_tasks); | 318 DCHECK_EQ(0u, task_namespace.num_running_tasks); |
326 namespaces_.erase(it); | 319 namespaces_.erase(it); |
327 } | 320 } |
328 } | 321 } |
329 | 322 |
330 bool TaskGraphRunner::RunTaskForTesting() { | 323 bool TaskGraphRunner::RunTaskForTesting() { |
331 base::AutoLock lock(lock_); | 324 base::AutoLock lock(lock_); |
332 | 325 |
333 if (ready_to_run_namespaces_.empty()) | 326 if (ready_to_run_namespaces_.empty()) |
334 return false; | 327 return false; |
335 | 328 |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 // Finally add task to |completed_tasks_|. | 454 // Finally add task to |completed_tasks_|. |
462 task_namespace->completed_tasks.push_back(task); | 455 task_namespace->completed_tasks.push_back(task); |
463 | 456 |
464 // If namespace has finished running all tasks, wake up origin thread. | 457 // If namespace has finished running all tasks, wake up origin thread. |
465 if (HasFinishedRunningTasksInNamespace(task_namespace)) | 458 if (HasFinishedRunningTasksInNamespace(task_namespace)) |
466 has_namespaces_with_finished_running_tasks_cv_.Signal(); | 459 has_namespaces_with_finished_running_tasks_cv_.Signal(); |
467 } | 460 } |
468 | 461 |
469 } // namespace internal | 462 } // namespace internal |
470 } // namespace cc | 463 } // namespace cc |
OLD | NEW |