OLD | NEW |
| (Empty) |
1 // Copyright 2013 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/resources/task_graph_runner.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 | |
12 namespace cc { | |
13 namespace { | |
14 | |
15 const int kNamespaceCount = 3; | |
16 | |
17 class TaskGraphRunnerTestBase { | |
18 public: | |
19 struct Task { | |
20 Task(int namespace_index, | |
21 unsigned id, | |
22 unsigned dependent_id, | |
23 unsigned dependent_count, | |
24 unsigned priority) : namespace_index(namespace_index), | |
25 id(id), | |
26 dependent_id(dependent_id), | |
27 dependent_count(dependent_count), | |
28 priority(priority) { | |
29 } | |
30 | |
31 int namespace_index; | |
32 unsigned id; | |
33 unsigned dependent_id; | |
34 unsigned dependent_count; | |
35 unsigned priority; | |
36 }; | |
37 | |
38 void ResetIds(int namespace_index) { | |
39 run_task_ids_[namespace_index].clear(); | |
40 on_task_completed_ids_[namespace_index].clear(); | |
41 } | |
42 | |
43 void RunAllTasks(int namespace_index) { | |
44 task_graph_runner_->WaitForTasksToFinishRunning( | |
45 namespace_token_[namespace_index]); | |
46 | |
47 internal::Task::Vector completed_tasks; | |
48 task_graph_runner_->CollectCompletedTasks( | |
49 namespace_token_[namespace_index], &completed_tasks); | |
50 for (internal::Task::Vector::const_iterator it = completed_tasks.begin(); | |
51 it != completed_tasks.end(); | |
52 ++it) { | |
53 FakeTaskImpl* task = static_cast<FakeTaskImpl*>(it->get()); | |
54 task->CompleteOnOriginThread(); | |
55 } | |
56 } | |
57 | |
58 void RunTask(int namespace_index, unsigned id) { | |
59 run_task_ids_[namespace_index].push_back(id); | |
60 } | |
61 | |
62 void OnTaskCompleted(int namespace_index, unsigned id) { | |
63 on_task_completed_ids_[namespace_index].push_back(id); | |
64 } | |
65 | |
66 const std::vector<unsigned>& run_task_ids(int namespace_index) { | |
67 return run_task_ids_[namespace_index]; | |
68 } | |
69 | |
70 const std::vector<unsigned>& on_task_completed_ids(int namespace_index) { | |
71 return on_task_completed_ids_[namespace_index]; | |
72 } | |
73 | |
74 void ScheduleTasks(int namespace_index, const std::vector<Task>& tasks) { | |
75 internal::Task::Vector new_tasks; | |
76 internal::Task::Vector new_dependents; | |
77 internal::GraphNode::Map new_graph; | |
78 | |
79 for (std::vector<Task>::const_iterator it = tasks.begin(); | |
80 it != tasks.end(); ++it) { | |
81 scoped_refptr<FakeTaskImpl> new_task( | |
82 new FakeTaskImpl(this, it->namespace_index, it->id)); | |
83 scoped_ptr<internal::GraphNode> node( | |
84 new internal::GraphNode(new_task.get(), it->priority)); | |
85 | |
86 for (unsigned i = 0; i < it->dependent_count; ++i) { | |
87 scoped_refptr<FakeDependentTaskImpl> new_dependent_task( | |
88 new FakeDependentTaskImpl( | |
89 this, it->namespace_index, it->dependent_id)); | |
90 scoped_ptr<internal::GraphNode> dependent_node( | |
91 new internal::GraphNode(new_dependent_task.get(), it->priority)); | |
92 node->add_dependent(dependent_node.get()); | |
93 dependent_node->add_dependency(); | |
94 new_graph.set(new_dependent_task.get(), dependent_node.Pass()); | |
95 new_dependents.push_back(new_dependent_task.get()); | |
96 } | |
97 | |
98 new_graph.set(new_task.get(), node.Pass()); | |
99 new_tasks.push_back(new_task.get()); | |
100 } | |
101 | |
102 task_graph_runner_->SetTaskGraph( | |
103 namespace_token_[namespace_index], &new_graph); | |
104 | |
105 dependents_[namespace_index].swap(new_dependents); | |
106 tasks_[namespace_index].swap(new_tasks); | |
107 } | |
108 | |
109 protected: | |
110 class FakeTaskImpl : public internal::Task { | |
111 public: | |
112 FakeTaskImpl(TaskGraphRunnerTestBase* test, | |
113 int namespace_index, | |
114 int id) | |
115 : test_(test), | |
116 namespace_index_(namespace_index), | |
117 id_(id) { | |
118 } | |
119 | |
120 // Overridden from internal::Task: | |
121 virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE { | |
122 test_->RunTask(namespace_index_, id_); | |
123 } | |
124 | |
125 virtual void CompleteOnOriginThread() { | |
126 test_->OnTaskCompleted(namespace_index_, id_); | |
127 } | |
128 | |
129 protected: | |
130 virtual ~FakeTaskImpl() {} | |
131 | |
132 private: | |
133 TaskGraphRunnerTestBase* test_; | |
134 int namespace_index_; | |
135 int id_; | |
136 | |
137 DISALLOW_COPY_AND_ASSIGN(FakeTaskImpl); | |
138 }; | |
139 | |
140 class FakeDependentTaskImpl : public FakeTaskImpl { | |
141 public: | |
142 FakeDependentTaskImpl(TaskGraphRunnerTestBase* test, | |
143 int namespace_index, | |
144 int id) | |
145 : FakeTaskImpl(test, namespace_index, id) { | |
146 } | |
147 | |
148 // Overridden from FakeTaskImpl: | |
149 virtual void CompleteOnOriginThread() OVERRIDE {} | |
150 | |
151 private: | |
152 virtual ~FakeDependentTaskImpl() {} | |
153 | |
154 DISALLOW_COPY_AND_ASSIGN(FakeDependentTaskImpl); | |
155 }; | |
156 | |
157 scoped_ptr<internal::TaskGraphRunner> task_graph_runner_; | |
158 internal::NamespaceToken namespace_token_[kNamespaceCount]; | |
159 internal::Task::Vector tasks_[kNamespaceCount]; | |
160 internal::Task::Vector dependents_[kNamespaceCount]; | |
161 std::vector<unsigned> run_task_ids_[kNamespaceCount]; | |
162 std::vector<unsigned> on_task_completed_ids_[kNamespaceCount]; | |
163 }; | |
164 | |
165 class TaskGraphRunnerTest : public TaskGraphRunnerTestBase, | |
166 public testing::TestWithParam<int> { | |
167 public: | |
168 // Overridden from testing::Test: | |
169 virtual void SetUp() OVERRIDE { | |
170 task_graph_runner_ = make_scoped_ptr( | |
171 new internal::TaskGraphRunner(GetParam(), "Test")); | |
172 for (int i = 0; i < kNamespaceCount; ++i) | |
173 namespace_token_[i] = task_graph_runner_->GetNamespaceToken(); | |
174 } | |
175 virtual void TearDown() OVERRIDE { | |
176 task_graph_runner_.reset(); | |
177 } | |
178 }; | |
179 | |
180 TEST_P(TaskGraphRunnerTest, Basic) { | |
181 for (int i = 0; i < kNamespaceCount; ++i) { | |
182 EXPECT_EQ(0u, run_task_ids(i).size()); | |
183 EXPECT_EQ(0u, on_task_completed_ids(i).size()); | |
184 | |
185 ScheduleTasks(i, std::vector<Task>(1, Task(i, 0u, 0u, 0u, 0u))); | |
186 } | |
187 | |
188 for (int i = 0; i < kNamespaceCount; ++i) { | |
189 RunAllTasks(i); | |
190 | |
191 EXPECT_EQ(1u, run_task_ids(i).size()); | |
192 EXPECT_EQ(1u, on_task_completed_ids(i).size()); | |
193 } | |
194 | |
195 for (int i = 0; i < kNamespaceCount; ++i) | |
196 ScheduleTasks(i, std::vector<Task>(1, Task(i, 0u, 0u, 1u, 0u))); | |
197 | |
198 for (int i = 0; i < kNamespaceCount; ++i) { | |
199 RunAllTasks(i); | |
200 | |
201 EXPECT_EQ(3u, run_task_ids(i).size()); | |
202 EXPECT_EQ(2u, on_task_completed_ids(i).size()); | |
203 } | |
204 | |
205 for (int i = 0; i < kNamespaceCount; ++i) | |
206 ScheduleTasks(i, std::vector<Task>(1, Task(i, 0u, 0u, 2u, 0u))); | |
207 | |
208 for (int i = 0; i < kNamespaceCount; ++i) { | |
209 RunAllTasks(i); | |
210 | |
211 EXPECT_EQ(6u, run_task_ids(i).size()); | |
212 EXPECT_EQ(3u, on_task_completed_ids(i).size()); | |
213 } | |
214 } | |
215 | |
216 TEST_P(TaskGraphRunnerTest, Dependencies) { | |
217 for (int i = 0; i < kNamespaceCount; ++i) { | |
218 ScheduleTasks(i, std::vector<Task>(1, Task(i, | |
219 0u, | |
220 1u, | |
221 1u, // 1 dependent | |
222 0u))); | |
223 } | |
224 | |
225 for (int i = 0; i < kNamespaceCount; ++i) { | |
226 RunAllTasks(i); | |
227 | |
228 // Check if task ran before dependent. | |
229 ASSERT_EQ(2u, run_task_ids(i).size()); | |
230 EXPECT_EQ(0u, run_task_ids(i)[0]); | |
231 EXPECT_EQ(1u, run_task_ids(i)[1]); | |
232 ASSERT_EQ(1u, on_task_completed_ids(i).size()); | |
233 EXPECT_EQ(0u, on_task_completed_ids(i)[0]); | |
234 } | |
235 | |
236 for (int i = 0; i < kNamespaceCount; ++i) { | |
237 ScheduleTasks(i, std::vector<Task>(1, Task(i, | |
238 2u, | |
239 3u, | |
240 2u, // 2 dependents | |
241 0u))); | |
242 } | |
243 | |
244 for (int i = 0; i < kNamespaceCount; ++i) { | |
245 RunAllTasks(i); | |
246 | |
247 // Task should only run once. | |
248 ASSERT_EQ(5u, run_task_ids(i).size()); | |
249 EXPECT_EQ(2u, run_task_ids(i)[2]); | |
250 EXPECT_EQ(3u, run_task_ids(i)[3]); | |
251 EXPECT_EQ(3u, run_task_ids(i)[4]); | |
252 ASSERT_EQ(2u, on_task_completed_ids(i).size()); | |
253 EXPECT_EQ(2u, on_task_completed_ids(i)[1]); | |
254 } | |
255 } | |
256 | |
257 INSTANTIATE_TEST_CASE_P(TaskGraphRunnerTests, | |
258 TaskGraphRunnerTest, | |
259 ::testing::Range(1, 5)); | |
260 | |
261 class TaskGraphRunnerSingleThreadTest : public TaskGraphRunnerTestBase, | |
262 public testing::Test { | |
263 public: | |
264 // Overridden from testing::Test: | |
265 virtual void SetUp() OVERRIDE { | |
266 task_graph_runner_ = make_scoped_ptr( | |
267 new internal::TaskGraphRunner(1, "Test")); | |
268 for (int i = 0; i < kNamespaceCount; ++i) | |
269 namespace_token_[i] = task_graph_runner_->GetNamespaceToken(); | |
270 } | |
271 virtual void TearDown() OVERRIDE { | |
272 task_graph_runner_.reset(); | |
273 } | |
274 }; | |
275 | |
276 TEST_F(TaskGraphRunnerSingleThreadTest, Priority) { | |
277 for (int i = 0; i < kNamespaceCount; ++i) { | |
278 Task tasks[] = { | |
279 Task(i, | |
280 0u, | |
281 2u, | |
282 1u, | |
283 1u), // Priority 1 | |
284 Task(i, | |
285 1u, | |
286 3u, | |
287 1u, | |
288 0u) // Priority 0 | |
289 }; | |
290 ScheduleTasks(i, std::vector<Task>(tasks, tasks + arraysize(tasks))); | |
291 } | |
292 | |
293 for (int i = 0; i < kNamespaceCount; ++i) { | |
294 RunAllTasks(i); | |
295 | |
296 // Check if tasks ran in order of priority. | |
297 ASSERT_EQ(4u, run_task_ids(i).size()); | |
298 EXPECT_EQ(1u, run_task_ids(i)[0]); | |
299 EXPECT_EQ(3u, run_task_ids(i)[1]); | |
300 EXPECT_EQ(0u, run_task_ids(i)[2]); | |
301 EXPECT_EQ(2u, run_task_ids(i)[3]); | |
302 ASSERT_EQ(2u, on_task_completed_ids(i).size()); | |
303 EXPECT_EQ(1u, on_task_completed_ids(i)[0]); | |
304 EXPECT_EQ(0u, on_task_completed_ids(i)[1]); | |
305 } | |
306 | |
307 for (int i = 0; i < kNamespaceCount; ++i) | |
308 ResetIds(i); | |
309 | |
310 for (int i = 0; i < kNamespaceCount; ++i) { | |
311 std::vector<Task> tasks; | |
312 tasks.push_back(Task(i, | |
313 0u, | |
314 3u, | |
315 1u, // 1 dependent | |
316 1u)); // Priority 1 | |
317 tasks.push_back(Task(i, | |
318 1u, | |
319 4u, | |
320 2u, // 2 dependents | |
321 1u)); // Priority 1 | |
322 tasks.push_back(Task(i, | |
323 2u, | |
324 5u, | |
325 1u, // 1 dependent | |
326 0u)); // Priority 0 | |
327 ScheduleTasks(i, tasks); | |
328 } | |
329 | |
330 for (int i = 0; i < kNamespaceCount; ++i) { | |
331 RunAllTasks(i); | |
332 | |
333 // Check if tasks ran in order of priority and that task with more | |
334 // dependents ran first when priority is the same. | |
335 ASSERT_LE(3u, run_task_ids(i).size()); | |
336 EXPECT_EQ(2u, run_task_ids(i)[0]); | |
337 EXPECT_EQ(5u, run_task_ids(i)[1]); | |
338 EXPECT_EQ(1u, run_task_ids(i)[2]); | |
339 ASSERT_EQ(3u, on_task_completed_ids(i).size()); | |
340 EXPECT_EQ(2u, on_task_completed_ids(i)[0]); | |
341 EXPECT_EQ(1u, on_task_completed_ids(i)[1]); | |
342 EXPECT_EQ(0u, on_task_completed_ids(i)[2]); | |
343 } | |
344 } | |
345 | |
346 } // namespace | |
347 } // namespace cc | |
OLD | NEW |