| 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 |