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

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: rebase 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 <utility> 8 #include <utility>
9 9
10 #include "base/trace_event/trace_event.h" 10 #include "base/trace_event/trace_event.h"
11 11
12 namespace cc { 12 namespace cc {
13 namespace {
14
15 template <typename T>
16 void ClearAllVectors(T* array_of_vectors) {
reveman 2015/12/04 02:30:53 nit: remove vector specific references as T can be
ericrk 2015/12/04 19:14:31 no longer needed when using map - but good point.
17 for (auto& vector : *array_of_vectors) {
18 vector.clear();
19 }
20 }
21
22 // Helper which checks if all sub arrays of a group are empty.
23 template <typename T>
24 bool AllVectorsEmpty(const T& array_of_vectors) {
reveman 2015/12/04 02:30:54 ditto. maybe std::for_each and std::find_if with
ericrk 2015/12/04 19:14:31 Acknowledged.
25 for (const auto& vector : array_of_vectors) {
26 if (!vector.empty())
27 return false;
28 }
29 return true;
30 }
31
32 bool CompareTaskPriority(const TaskGraphWorkQueue::PrioritizedTask& a,
33 const TaskGraphWorkQueue::PrioritizedTask& b) {
34 // In this system, numerically lower priority is run first.
35 return a.priority > b.priority;
36 }
37
38 class CompareTaskNamespacePriority {
reveman 2015/12/04 02:30:54 nit: this code predates c++11 support in chromium.
ericrk 2015/12/04 19:14:30 Using a lambda directly is a lot more verbose at t
reveman 2015/12/04 20:55:50 I think this would be OK with auto for arguments b
39 public:
40 explicit CompareTaskNamespacePriority(uint16_t group) : group_(group) {}
41
42 bool operator()(const TaskGraphWorkQueue::TaskNamespace* a,
43 const TaskGraphWorkQueue::TaskNamespace* b) {
44 DCHECK(group_ < TaskGraphWorkQueue::kMaxTaskGroups);
45 DCHECK(!a->ready_to_run_tasks[group_].empty());
46 DCHECK(!b->ready_to_run_tasks[group_].empty());
47
48 // Compare based on task priority of the ready_to_run_tasks heap .front()
49 // will hold the max element of the heap, except after pop_heap, when max
50 // element is moved to .back().
51 return CompareTaskPriority(a->ready_to_run_tasks[group_].front(),
52 b->ready_to_run_tasks[group_].front());
53 }
54
55 private:
56 uint16_t group_;
57 };
58 } // namespace
13 59
14 TaskGraphWorkQueue::TaskNamespace::TaskNamespace() {} 60 TaskGraphWorkQueue::TaskNamespace::TaskNamespace() {}
15 61
16 TaskGraphWorkQueue::TaskNamespace::~TaskNamespace() {} 62 TaskGraphWorkQueue::TaskNamespace::~TaskNamespace() {}
17 63
18 TaskGraphWorkQueue::TaskGraphWorkQueue() : next_namespace_id_(1) {} 64 TaskGraphWorkQueue::TaskGraphWorkQueue() : next_namespace_id_(1) {}
19 TaskGraphWorkQueue::~TaskGraphWorkQueue() {} 65 TaskGraphWorkQueue::~TaskGraphWorkQueue() {}
20 66
21 NamespaceToken TaskGraphWorkQueue::GetNamespaceToken() { 67 NamespaceToken TaskGraphWorkQueue::GetNamespaceToken() {
22 NamespaceToken token(next_namespace_id_++); 68 NamespaceToken token(next_namespace_id_++);
23 DCHECK(namespaces_.find(token) == namespaces_.end()); 69 DCHECK(namespaces_.find(token) == namespaces_.end());
24 return token; 70 return token;
25 } 71 }
26 72
27 void TaskGraphWorkQueue::ScheduleTasks(NamespaceToken token, TaskGraph* graph) { 73 void TaskGraphWorkQueue::ScheduleTasks(NamespaceToken token, TaskGraph* graph) {
74 DCHECK(ValidateGroups(graph));
75
28 TaskNamespace& task_namespace = namespaces_[token]; 76 TaskNamespace& task_namespace = namespaces_[token];
29 77
30 // First adjust number of dependencies to reflect completed tasks. 78 // First adjust number of dependencies to reflect completed tasks.
31 for (const scoped_refptr<Task>& task : task_namespace.completed_tasks) { 79 for (const scoped_refptr<Task>& task : task_namespace.completed_tasks) {
32 for (DependentIterator node_it(graph, task.get()); node_it; ++node_it) { 80 for (DependentIterator node_it(graph, task.get()); node_it; ++node_it) {
33 TaskGraph::Node& node = *node_it; 81 TaskGraph::Node& node = *node_it;
34 DCHECK_LT(0u, node.dependencies); 82 DCHECK_LT(0u, node.dependencies);
35 node.dependencies--; 83 node.dependencies--;
36 } 84 }
37 } 85 }
38 86
39 // Build new "ready to run" queue and remove nodes from old graph. 87 // Build new "ready to run" queue and remove nodes from old graph.
40 task_namespace.ready_to_run_tasks.clear(); 88 ClearAllVectors(&task_namespace.ready_to_run_tasks);
41 for (const TaskGraph::Node& node : graph->nodes) { 89 for (const TaskGraph::Node& node : graph->nodes) {
42 // Remove any old nodes that are associated with this task. The result is 90 // 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, 91 // 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. 92 // which we use below to determine what tasks need to be canceled.
45 TaskGraph::Node::Vector::iterator old_it = std::find_if( 93 TaskGraph::Node::Vector::iterator old_it = std::find_if(
46 task_namespace.graph.nodes.begin(), task_namespace.graph.nodes.end(), 94 task_namespace.graph.nodes.begin(), task_namespace.graph.nodes.end(),
47 [node](const TaskGraph::Node& other) { 95 [node](const TaskGraph::Node& other) {
48 return node.task == other.task; 96 return node.task == other.task;
49 }); 97 });
50 if (old_it != task_namespace.graph.nodes.end()) { 98 if (old_it != task_namespace.graph.nodes.end()) {
51 std::swap(*old_it, task_namespace.graph.nodes.back()); 99 std::swap(*old_it, task_namespace.graph.nodes.back());
52 task_namespace.graph.nodes.pop_back(); 100 task_namespace.graph.nodes.pop_back();
53 } 101 }
54 102
55 // Task is not ready to run if dependencies are not yet satisfied. 103 // Task is not ready to run if dependencies are not yet satisfied.
56 if (node.dependencies) 104 if (node.dependencies)
57 continue; 105 continue;
58 106
59 // Skip if already finished running task. 107 // Skip if already finished running task.
60 if (node.task->HasFinishedRunning()) 108 if (node.task->HasFinishedRunning())
61 continue; 109 continue;
62 110
63 // Skip if already running. 111 // Skip if already running.
64 if (std::find(task_namespace.running_tasks.begin(), 112 if (std::find(task_namespace.running_tasks.begin(),
65 task_namespace.running_tasks.end(), 113 task_namespace.running_tasks.end(),
66 node.task) != task_namespace.running_tasks.end()) 114 node.task) != task_namespace.running_tasks.end())
67 continue; 115 continue;
68 116
69 task_namespace.ready_to_run_tasks.push_back( 117 task_namespace.ready_to_run_tasks[node.group].push_back(
70 PrioritizedTask(node.task, &task_namespace, node.priority)); 118 PrioritizedTask(node.task, &task_namespace, node.group, node.priority));
71 } 119 }
72 120
73 // Rearrange the elements in |ready_to_run_tasks| in such a way that they 121 // Rearrange the elements in each vector within |ready_to_run_tasks| in such a
74 // form a heap. 122 // way that they form a heap.
75 std::make_heap(task_namespace.ready_to_run_tasks.begin(), 123 for (auto& vector : task_namespace.ready_to_run_tasks) {
reveman 2015/12/04 02:30:54 nit: s/vector/ready_to_run_tasks/ not a fan of nam
ericrk 2015/12/04 19:14:30 Done.
76 task_namespace.ready_to_run_tasks.end(), CompareTaskPriority); 124 std::make_heap(vector.begin(), vector.end(), CompareTaskPriority);
125 }
77 126
78 // Swap task graph. 127 // Swap task graph.
79 task_namespace.graph.Swap(graph); 128 task_namespace.graph.Swap(graph);
80 129
81 // Determine what tasks in old graph need to be canceled. 130 // Determine what tasks in old graph need to be canceled.
82 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin(); 131 for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
83 it != graph->nodes.end(); ++it) { 132 it != graph->nodes.end(); ++it) {
84 TaskGraph::Node& node = *it; 133 TaskGraph::Node& node = *it;
85 134
86 // Skip if already finished running task. 135 // Skip if already finished running task.
87 if (node.task->HasFinishedRunning()) 136 if (node.task->HasFinishedRunning())
88 continue; 137 continue;
89 138
90 // Skip if already running. 139 // Skip if already running.
91 if (std::find(task_namespace.running_tasks.begin(), 140 if (std::find(task_namespace.running_tasks.begin(),
92 task_namespace.running_tasks.end(), 141 task_namespace.running_tasks.end(),
93 node.task) != task_namespace.running_tasks.end()) 142 node.task) != task_namespace.running_tasks.end())
94 continue; 143 continue;
95 144
96 DCHECK(std::find(task_namespace.completed_tasks.begin(), 145 DCHECK(std::find(task_namespace.completed_tasks.begin(),
97 task_namespace.completed_tasks.end(), 146 task_namespace.completed_tasks.end(),
98 node.task) == task_namespace.completed_tasks.end()); 147 node.task) == task_namespace.completed_tasks.end());
99 task_namespace.completed_tasks.push_back(node.task); 148 task_namespace.completed_tasks.push_back(node.task);
100 } 149 }
101 150
102 // Build new "ready to run" task namespaces queue. 151 // Build new "ready to run" task namespaces queue.
103 ready_to_run_namespaces_.clear(); 152 ClearAllVectors(&ready_to_run_namespaces_);
104 for (auto& it : namespaces_) { 153 for (auto& it : namespaces_) {
reveman 2015/12/04 02:30:53 would be nice if this could be something like: fo
ericrk 2015/12/04 19:14:31 Couldn't do that before (when using an array), as
105 if (!it.second.ready_to_run_tasks.empty()) 154 for (uint16_t group = 0; group < kMaxTaskGroups; ++group) {
106 ready_to_run_namespaces_.push_back(&it.second); 155 if (!it.second.ready_to_run_tasks[group].empty())
156 ready_to_run_namespaces_[group].push_back(&it.second);
157 }
107 } 158 }
108 159
109 // Rearrange the task namespaces in |ready_to_run_namespaces| in such a 160 // Rearrange the task namespaces in |ready_to_run_namespaces| in such a
110 // way that they form a heap. 161 // way that they form a heap.
111 std::make_heap(ready_to_run_namespaces_.begin(), 162 for (uint16_t group = 0; group < kMaxTaskGroups; ++group) {
112 ready_to_run_namespaces_.end(), CompareTaskNamespacePriority); 163 std::make_heap(ready_to_run_namespaces_[group].begin(),
164 ready_to_run_namespaces_[group].end(),
165 CompareTaskNamespacePriority(group));
166 }
113 } 167 }
114 168
115 TaskGraphWorkQueue::PrioritizedTask TaskGraphWorkQueue::GetNextTaskToRun() { 169 TaskGraphWorkQueue::PrioritizedTask
116 DCHECK(!ready_to_run_namespaces_.empty()); 170 TaskGraphWorkQueue::GetNextTaskToRunForGroup(uint16_t group) {
171 DCHECK(group < kMaxTaskGroups);
117 172
118 // Take top priority TaskNamespace from |ready_to_run_namespaces_|. 173 TaskNamespace::Vector& namespaces_for_group = ready_to_run_namespaces_[group];
reveman 2015/12/04 02:30:54 nit: s/namespaces_for_group/ready_to_run_namespace
ericrk 2015/12/04 19:14:31 Done.
119 std::pop_heap(ready_to_run_namespaces_.begin(), 174 DCHECK(!namespaces_for_group.empty());
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 175
125 // Take top priority task from |ready_to_run_tasks|. 176 // Take top priority TaskNamespace from |namespaces_for_group|.
126 std::pop_heap(task_namespace->ready_to_run_tasks.begin(), 177 std::pop_heap(namespaces_for_group.begin(), namespaces_for_group.end(),
127 task_namespace->ready_to_run_tasks.end(), CompareTaskPriority); 178 CompareTaskNamespacePriority(group));
128 PrioritizedTask task = task_namespace->ready_to_run_tasks.back(); 179 TaskNamespace* task_namespace = namespaces_for_group.back();
129 task_namespace->ready_to_run_tasks.pop_back(); 180 namespaces_for_group.pop_back();
130 181
131 // Add task namespace back to |ready_to_run_namespaces_| if not empty after 182 PrioritizedTask::Vector& tasks_for_group =
reveman 2015/12/04 02:30:54 nit: s/tasks_for_group/ready_to_run_tasks_for_grou
ericrk 2015/12/04 19:14:30 Done.
183 task_namespace->ready_to_run_tasks[group];
184 DCHECK(!tasks_for_group.empty());
185
186 // Take top priority task from |tasks_for_group|.
187 std::pop_heap(tasks_for_group.begin(), tasks_for_group.end(),
188 CompareTaskPriority);
189 PrioritizedTask task = tasks_for_group.back();
190 tasks_for_group.pop_back();
191
192 // Add task namespace back to |namespaces_for_group| if not empty after
132 // taking top priority task. 193 // taking top priority task.
133 if (!task_namespace->ready_to_run_tasks.empty()) { 194 if (!tasks_for_group.empty()) {
134 ready_to_run_namespaces_.push_back(task_namespace); 195 namespaces_for_group.push_back(task_namespace);
135 std::push_heap(ready_to_run_namespaces_.begin(), 196 std::push_heap(namespaces_for_group.begin(), namespaces_for_group.end(),
136 ready_to_run_namespaces_.end(), 197 CompareTaskNamespacePriority(group));
137 CompareTaskNamespacePriority);
138 } 198 }
139 199
140 // Add task to |running_tasks|. 200 // Add task to |running_tasks|.
141 task_namespace->running_tasks.push_back(task.task); 201 task_namespace->running_tasks.push_back(task.task);
142 202
143 return task; 203 return task;
144 } 204 }
145 205
206 TaskGraphWorkQueue::PrioritizedTask TaskGraphWorkQueue::GetNextTaskToRun() {
207 for (uint16_t group = 0; group < kMaxTaskGroups; ++group) {
208 if (!ready_to_run_namespaces_[group].empty()) {
209 return GetNextTaskToRunForGroup(group);
210 }
211 }
212
213 // This function must only be called when there is at least one task to run.
214 NOTREACHED();
215 return GetNextTaskToRunForGroup(0);
216 }
217
146 void TaskGraphWorkQueue::CompleteTask(const PrioritizedTask& completed_task) { 218 void TaskGraphWorkQueue::CompleteTask(const PrioritizedTask& completed_task) {
147 TaskNamespace* task_namespace = completed_task.task_namespace; 219 TaskNamespace* task_namespace = completed_task.task_namespace;
148 scoped_refptr<Task> task(completed_task.task); 220 scoped_refptr<Task> task(completed_task.task);
149 221
150 // Remove task from |running_tasks|. 222 // Remove task from |running_tasks|.
151 auto it = std::find(task_namespace->running_tasks.begin(), 223 auto it = std::find(task_namespace->running_tasks.begin(),
152 task_namespace->running_tasks.end(), task); 224 task_namespace->running_tasks.end(), task);
153 DCHECK(it != task_namespace->running_tasks.end()); 225 DCHECK(it != task_namespace->running_tasks.end());
154 std::swap(*it, task_namespace->running_tasks.back()); 226 std::swap(*it, task_namespace->running_tasks.back());
155 task_namespace->running_tasks.pop_back(); 227 task_namespace->running_tasks.pop_back();
156 228
157 // Now iterate over all dependents to decrement dependencies and check if they 229 // Now iterate over all dependents to decrement dependencies and check if they
158 // are ready to run. 230 // are ready to run.
159 bool ready_to_run_namespaces_has_heap_properties = true; 231 bool ready_to_run_namespaces_has_heap_properties = true;
160 for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) { 232 for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) {
161 TaskGraph::Node& dependent_node = *it; 233 TaskGraph::Node& dependent_node = *it;
162 234
163 DCHECK_LT(0u, dependent_node.dependencies); 235 DCHECK_LT(0u, dependent_node.dependencies);
164 dependent_node.dependencies--; 236 dependent_node.dependencies--;
165 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|. 237 // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|.
166 if (!dependent_node.dependencies) { 238 if (!dependent_node.dependencies) {
167 bool was_empty = task_namespace->ready_to_run_tasks.empty(); 239 PrioritizedTask::Vector& tasks_for_group =
reveman 2015/12/04 02:30:53 nit: same as above, ready_to_run_tasks_for_group o
ericrk 2015/12/04 19:14:31 Done.
168 task_namespace->ready_to_run_tasks.push_back(PrioritizedTask( 240 task_namespace->ready_to_run_tasks[dependent_node.group];
169 dependent_node.task, task_namespace, dependent_node.priority)); 241
170 std::push_heap(task_namespace->ready_to_run_tasks.begin(), 242 bool was_empty = tasks_for_group.empty();
171 task_namespace->ready_to_run_tasks.end(), 243 tasks_for_group.push_back(
244 PrioritizedTask(dependent_node.task, task_namespace,
245 dependent_node.group, dependent_node.priority));
246 std::push_heap(tasks_for_group.begin(), tasks_for_group.end(),
172 CompareTaskPriority); 247 CompareTaskPriority);
248
173 // Task namespace is ready if it has at least one ready to run task. Add 249 // 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. 250 // it to |ready_to_run_namespaces_| if it just become ready.
175 if (was_empty) { 251 if (was_empty) {
176 DCHECK(std::find(ready_to_run_namespaces_.begin(), 252 TaskNamespace::Vector& namespaces_for_group =
reveman 2015/12/04 02:30:53 ditto
ericrk 2015/12/04 19:14:31 Done.
177 ready_to_run_namespaces_.end(), 253 ready_to_run_namespaces_[dependent_node.group];
178 task_namespace) == ready_to_run_namespaces_.end()); 254
179 ready_to_run_namespaces_.push_back(task_namespace); 255 DCHECK(std::find(namespaces_for_group.begin(),
256 namespaces_for_group.end(),
257 task_namespace) == namespaces_for_group.end());
258 namespaces_for_group.push_back(task_namespace);
180 } 259 }
181 ready_to_run_namespaces_has_heap_properties = false; 260 ready_to_run_namespaces_has_heap_properties = false;
182 } 261 }
183 } 262 }
184 263
185 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way 264 // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way
186 // that they yet again form a heap. 265 // that they yet again form a heap.
187 if (!ready_to_run_namespaces_has_heap_properties) { 266 if (!ready_to_run_namespaces_has_heap_properties) {
188 std::make_heap(ready_to_run_namespaces_.begin(), 267 for (uint16_t group = 0; group < kMaxTaskGroups; ++group) {
189 ready_to_run_namespaces_.end(), 268 std::make_heap(ready_to_run_namespaces_[group].begin(),
190 CompareTaskNamespacePriority); 269 ready_to_run_namespaces_[group].end(),
270 CompareTaskNamespacePriority(group));
271 }
191 } 272 }
192 273
193 // Finally add task to |completed_tasks_|. 274 // Finally add task to |completed_tasks_|.
194 task_namespace->completed_tasks.push_back(task); 275 task_namespace->completed_tasks.push_back(task);
195 } 276 }
196 277
197 void TaskGraphWorkQueue::CollectCompletedTasks(NamespaceToken token, 278 void TaskGraphWorkQueue::CollectCompletedTasks(NamespaceToken token,
198 Task::Vector* completed_tasks) { 279 Task::Vector* completed_tasks) {
199 TaskNamespaceMap::iterator it = namespaces_.find(token); 280 TaskNamespaceMap::iterator it = namespaces_.find(token);
200 if (it == namespaces_.end()) 281 if (it == namespaces_.end())
201 return; 282 return;
202 283
203 TaskNamespace& task_namespace = it->second; 284 TaskNamespace& task_namespace = it->second;
204 285
205 DCHECK_EQ(0u, completed_tasks->size()); 286 DCHECK_EQ(0u, completed_tasks->size());
206 completed_tasks->swap(task_namespace.completed_tasks); 287 completed_tasks->swap(task_namespace.completed_tasks);
207 if (!HasFinishedRunningTasksInNamespace(&task_namespace)) 288 if (!HasFinishedRunningTasksInNamespace(&task_namespace))
208 return; 289 return;
209 290
210 // Remove namespace if finished running tasks. 291 // Remove namespace if finished running tasks.
211 DCHECK_EQ(0u, task_namespace.completed_tasks.size()); 292 DCHECK_EQ(0u, task_namespace.completed_tasks.size());
212 DCHECK_EQ(0u, task_namespace.ready_to_run_tasks.size()); 293 DCHECK(AllVectorsEmpty(task_namespace.ready_to_run_tasks));
213 DCHECK_EQ(0u, task_namespace.running_tasks.size()); 294 DCHECK_EQ(0u, task_namespace.running_tasks.size());
214 namespaces_.erase(it); 295 namespaces_.erase(it);
215 } 296 }
216 297
298 bool TaskGraphWorkQueue::HasReadyToRunTasks() const {
299 return !AllVectorsEmpty(ready_to_run_namespaces_);
300 }
301
302 bool TaskGraphWorkQueue::HasFinishedRunningTasksInNamespace(
303 const TaskNamespace* task_namespace) {
304 return task_namespace->running_tasks.empty() &&
305 AllVectorsEmpty(task_namespace->ready_to_run_tasks);
306 }
307
217 bool TaskGraphWorkQueue::DependencyMismatch(const TaskGraph* graph) { 308 bool TaskGraphWorkQueue::DependencyMismatch(const TaskGraph* graph) {
218 // Value storage will be 0-initialized. 309 // Value storage will be 0-initialized.
219 base::hash_map<const Task*, size_t> dependents; 310 base::hash_map<const Task*, size_t> dependents;
220 for (const TaskGraph::Edge& edge : graph->edges) 311 for (const TaskGraph::Edge& edge : graph->edges)
221 dependents[edge.dependent]++; 312 dependents[edge.dependent]++;
222 313
223 for (const TaskGraph::Node& node : graph->nodes) { 314 for (const TaskGraph::Node& node : graph->nodes) {
224 if (dependents[node.task] != node.dependencies) 315 if (dependents[node.task] != node.dependencies)
225 return true; 316 return true;
226 } 317 }
227 318
228 return false; 319 return false;
229 } 320 }
230 321
322 bool TaskGraphWorkQueue::ValidateGroups(const TaskGraph* graph) {
323 for (const TaskGraph::Node& node : graph->nodes) {
324 if (node.group >= kMaxTaskGroups)
325 return false;
326 }
327 return true;
328 }
329
231 } // namespace cc 330 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698