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

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

Issue 1489233003: TaskGraphRunner Group support (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@refactor
Patch Set: array > map + 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
OLDNEW
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698