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

Side by Side Diff: cc/raster/task_graph_work_queue.cc

Issue 1449133002: TaskGraphRunner refactor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: feedback Created 5 years 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 unified diff | Download patch
« no previous file with comments | « cc/raster/task_graph_work_queue.h ('k') | cc/raster/tile_task_worker_pool.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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() : next_namespace_id_(1) {}
19 TaskGraphWorkQueue::~TaskGraphWorkQueue() {}
20
21 NamespaceToken TaskGraphWorkQueue::GetNamespaceToken() {
22 NamespaceToken token(next_namespace_id_++);
23 DCHECK(namespaces_.find(token) == namespaces_.end());
24 return token;
25 }
26
27 void TaskGraphWorkQueue::ScheduleTasks(NamespaceToken token, TaskGraph* graph) {
28 TaskNamespace& task_namespace = namespaces_[token];
29
30 // First adjust number of dependencies to reflect completed tasks.
31 for (const scoped_refptr<Task>& task : task_namespace.completed_tasks) {
32 for (DependentIterator node_it(graph, task.get()); node_it; ++node_it) {
33 TaskGraph::Node& node = *node_it;
34 DCHECK_LT(0u, node.dependencies);
35 node.dependencies--;
36 }
37 }
38
39 // Build new "ready to run" queue and remove nodes from old graph.
40 task_namespace.ready_to_run_tasks.clear();
41 for (const TaskGraph::Node& node : graph->nodes) {
42 // Remove any old nodes that are associated with this task. The result is
43 // that the old graph is left with all nodes not present in this graph,
44 // which we use below to determine what tasks need to be canceled.
45 TaskGraph::Node::Vector::iterator old_it = std::find_if(
46 task_namespace.graph.nodes.begin(), task_namespace.graph.nodes.end(),
47 [node](const TaskGraph::Node& other) {
48 return node.task == other.task;
49 });
50 if (old_it != task_namespace.graph.nodes.end()) {
51 std::swap(*old_it, task_namespace.graph.nodes.back());
52 task_namespace.graph.nodes.pop_back();
53 }
54
55 // Task is not ready to run if dependencies are not yet satisfied.
56 if (node.dependencies)
57 continue;
58
59 // Skip if already finished running task.
60 if (node.task->HasFinishedRunning())
61 continue;
62
63 // Skip if already running.
64 if (std::find(task_namespace.running_tasks.begin(),
65 task_namespace.running_tasks.end(),
66 node.task) != task_namespace.running_tasks.end())
67 continue;
68
69 task_namespace.ready_to_run_tasks.push_back(
70 PrioritizedTask(node.task, &task_namespace, node.priority));
71 }
72
73 // Rearrange the elements in |ready_to_run_tasks| in such a way that they
74 // form a heap.
75 std::make_heap(task_namespace.ready_to_run_tasks.begin(),
76 task_namespace.ready_to_run_tasks.end(), CompareTaskPriority);
77
78 // Swap task graph.
79 task_namespace.graph.Swap(graph);
80
81 // Determine what tasks in old graph need to be canceled.
82 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
83 it != graph->nodes.end(); ++it) {
84 TaskGraph::Node& node = *it;
85
86 // Skip if already finished running task.
87 if (node.task->HasFinishedRunning())
88 continue;
89
90 // Skip if already running.
91 if (std::find(task_namespace.running_tasks.begin(),
92 task_namespace.running_tasks.end(),
93 node.task) != task_namespace.running_tasks.end())
94 continue;
95
96 DCHECK(std::find(task_namespace.completed_tasks.begin(),
97 task_namespace.completed_tasks.end(),
98 node.task) == task_namespace.completed_tasks.end());
99 task_namespace.completed_tasks.push_back(node.task);
100 }
101
102 // Build new "ready to run" task namespaces queue.
103 ready_to_run_namespaces_.clear();
104 for (auto& it : namespaces_) {
105 if (!it.second.ready_to_run_tasks.empty())
106 ready_to_run_namespaces_.push_back(&it.second);
107 }
108
109 // Rearrange the task namespaces in |ready_to_run_namespaces| in such a
110 // way that they form a heap.
111 std::make_heap(ready_to_run_namespaces_.begin(),
112 ready_to_run_namespaces_.end(), CompareTaskNamespacePriority);
113 }
114
115 TaskGraphWorkQueue::PrioritizedTask TaskGraphWorkQueue::GetNextTaskToRun() {
116 DCHECK(!ready_to_run_namespaces_.empty());
117
118 // Take top priority TaskNamespace from |ready_to_run_namespaces_|.
119 std::pop_heap(ready_to_run_namespaces_.begin(),
120 ready_to_run_namespaces_.end(), CompareTaskNamespacePriority);
121 TaskNamespace* task_namespace = ready_to_run_namespaces_.back();
122 ready_to_run_namespaces_.pop_back();
123 DCHECK(!task_namespace->ready_to_run_tasks.empty());
124
125 // Take top priority task from |ready_to_run_tasks|.
126 std::pop_heap(task_namespace->ready_to_run_tasks.begin(),
127 task_namespace->ready_to_run_tasks.end(), CompareTaskPriority);
128 PrioritizedTask task = task_namespace->ready_to_run_tasks.back();
129 task_namespace->ready_to_run_tasks.pop_back();
130
131 // Add task namespace back to |ready_to_run_namespaces_| if not empty after
132 // taking top priority task.
133 if (!task_namespace->ready_to_run_tasks.empty()) {
134 ready_to_run_namespaces_.push_back(task_namespace);
135 std::push_heap(ready_to_run_namespaces_.begin(),
136 ready_to_run_namespaces_.end(),
137 CompareTaskNamespacePriority);
138 }
139
140 // Add task to |running_tasks|.
141 task_namespace->running_tasks.push_back(task.task);
142
143 return task;
144 }
145
146 void TaskGraphWorkQueue::CompleteTask(const PrioritizedTask& completed_task) {
147 TaskNamespace* task_namespace = completed_task.task_namespace;
148 scoped_refptr<Task> task(completed_task.task);
149
150 // Remove task from |running_tasks|.
151 auto it = std::find(task_namespace->running_tasks.begin(),
152 task_namespace->running_tasks.end(), task);
153 DCHECK(it != task_namespace->running_tasks.end());
154 std::swap(*it, task_namespace->running_tasks.back());
155 task_namespace->running_tasks.pop_back();
156
157 // Now iterate over all dependents to decrement dependencies and check if they
158 // are ready to run.
159 bool ready_to_run_namespaces_has_heap_properties = true;
160 for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) {
161 TaskGraph::Node& dependent_node = *it;
162
163 DCHECK_LT(0u, dependent_node.dependencies);
164 dependent_node.dependencies--;
165 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|.
166 if (!dependent_node.dependencies) {
167 bool was_empty = task_namespace->ready_to_run_tasks.empty();
168 task_namespace->ready_to_run_tasks.push_back(PrioritizedTask(
169 dependent_node.task, task_namespace, dependent_node.priority));
170 std::push_heap(task_namespace->ready_to_run_tasks.begin(),
171 task_namespace->ready_to_run_tasks.end(),
172 CompareTaskPriority);
173 // 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.
175 if (was_empty) {
176 DCHECK(std::find(ready_to_run_namespaces_.begin(),
177 ready_to_run_namespaces_.end(),
178 task_namespace) == ready_to_run_namespaces_.end());
179 ready_to_run_namespaces_.push_back(task_namespace);
180 }
181 ready_to_run_namespaces_has_heap_properties = false;
182 }
183 }
184
185 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way
186 // that they yet again form a heap.
187 if (!ready_to_run_namespaces_has_heap_properties) {
188 std::make_heap(ready_to_run_namespaces_.begin(),
189 ready_to_run_namespaces_.end(),
190 CompareTaskNamespacePriority);
191 }
192
193 // Finally add task to |completed_tasks_|.
194 task_namespace->completed_tasks.push_back(task);
195 }
196
197 void TaskGraphWorkQueue::CollectCompletedTasks(NamespaceToken token,
198 Task::Vector* completed_tasks) {
199 TaskNamespaceMap::iterator it = namespaces_.find(token);
200 if (it == namespaces_.end())
201 return;
202
203 TaskNamespace& task_namespace = it->second;
204
205 DCHECK_EQ(0u, completed_tasks->size());
206 completed_tasks->swap(task_namespace.completed_tasks);
207 if (!HasFinishedRunningTasksInNamespace(&task_namespace))
208 return;
209
210 // Remove namespace if finished running tasks.
211 DCHECK_EQ(0u, task_namespace.completed_tasks.size());
212 DCHECK_EQ(0u, task_namespace.ready_to_run_tasks.size());
213 DCHECK_EQ(0u, task_namespace.running_tasks.size());
214 namespaces_.erase(it);
215 }
216
217 bool TaskGraphWorkQueue::DependencyMismatch(const TaskGraph* graph) {
218 // Value storage will be 0-initialized.
219 base::hash_map<const Task*, size_t> dependents;
220 for (const TaskGraph::Edge& edge : graph->edges)
221 dependents[edge.dependent]++;
222
223 for (const TaskGraph::Node& node : graph->nodes) {
224 if (dependents[node.task] != node.dependencies)
225 return true;
226 }
227
228 return false;
229 }
230
231 } // namespace cc
OLDNEW
« no previous file with comments | « cc/raster/task_graph_work_queue.h ('k') | cc/raster/tile_task_worker_pool.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698