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.
5 #include "cc/resources/task_graph_runner.h"
10 #include "base/synchronization/lock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
16 const int kNamespaceCount = 3;
18 class TaskGraphRunnerTestBase {
21 Task(int namespace_index,
23 unsigned dependent_id,
24 unsigned dependent_count,
26 : namespace_index(namespace_index),
28 dependent_id(dependent_id),
29 dependent_count(dependent_count),
34 unsigned dependent_id;
35 unsigned dependent_count;
39 void ResetIds(int namespace_index) {
40 run_task_ids_[namespace_index].clear();
41 on_task_completed_ids_[namespace_index].clear();
44 void RunAllTasks(int namespace_index) {
45 task_graph_runner_->WaitForTasksToFinishRunning(
46 namespace_token_[namespace_index]);
48 internal::Task::Vector completed_tasks;
49 task_graph_runner_->CollectCompletedTasks(namespace_token_[namespace_index],
51 for (internal::Task::Vector::const_iterator it = completed_tasks.begin();
52 it != completed_tasks.end();
54 FakeTaskImpl* task = static_cast<FakeTaskImpl*>(it->get());
55 task->CompleteOnOriginThread();
59 void RunTaskOnWorkerThread(int namespace_index, unsigned id) {
60 base::AutoLock lock(run_task_ids_lock_);
61 run_task_ids_[namespace_index].push_back(id);
64 void OnTaskCompleted(int namespace_index, unsigned id) {
65 on_task_completed_ids_[namespace_index].push_back(id);
68 const std::vector<unsigned>& run_task_ids(int namespace_index) {
69 return run_task_ids_[namespace_index];
72 const std::vector<unsigned>& on_task_completed_ids(int namespace_index) {
73 return on_task_completed_ids_[namespace_index];
76 void ScheduleTasks(int namespace_index, const std::vector<Task>& tasks) {
77 internal::Task::Vector new_tasks;
78 internal::Task::Vector new_dependents;
79 internal::TaskGraph new_graph;
81 for (std::vector<Task>::const_iterator it = tasks.begin();
84 scoped_refptr<FakeTaskImpl> new_task(
85 new FakeTaskImpl(this, it->namespace_index, it->id));
86 new_graph.nodes.push_back(
87 internal::TaskGraph::Node(new_task.get(), it->priority, 0u));
88 for (unsigned i = 0; i < it->dependent_count; ++i) {
89 scoped_refptr<FakeDependentTaskImpl> new_dependent_task(
90 new FakeDependentTaskImpl(
91 this, it->namespace_index, it->dependent_id));
92 new_graph.nodes.push_back(internal::TaskGraph::Node(
93 new_dependent_task.get(), it->priority, 1u));
94 new_graph.edges.push_back(internal::TaskGraph::Edge(
95 new_task.get(), new_dependent_task.get()));
97 new_dependents.push_back(new_dependent_task.get());
100 new_tasks.push_back(new_task.get());
103 task_graph_runner_->SetTaskGraph(namespace_token_[namespace_index],
106 dependents_[namespace_index].swap(new_dependents);
107 tasks_[namespace_index].swap(new_tasks);
111 class FakeTaskImpl : public internal::Task {
113 FakeTaskImpl(TaskGraphRunnerTestBase* test, int namespace_index, int id)
114 : test_(test), namespace_index_(namespace_index), id_(id) {}
116 // Overridden from internal::Task:
117 virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
118 test_->RunTaskOnWorkerThread(namespace_index_, id_);
121 virtual void CompleteOnOriginThread() {
122 test_->OnTaskCompleted(namespace_index_, id_);
126 virtual ~FakeTaskImpl() {}
129 TaskGraphRunnerTestBase* test_;
130 int namespace_index_;
133 DISALLOW_COPY_AND_ASSIGN(FakeTaskImpl);
136 class FakeDependentTaskImpl : public FakeTaskImpl {
138 FakeDependentTaskImpl(TaskGraphRunnerTestBase* test,
141 : FakeTaskImpl(test, namespace_index, id) {}
143 // Overridden from FakeTaskImpl:
144 virtual void CompleteOnOriginThread() OVERRIDE {}
147 virtual ~FakeDependentTaskImpl() {}
149 DISALLOW_COPY_AND_ASSIGN(FakeDependentTaskImpl);
152 scoped_ptr<internal::TaskGraphRunner> task_graph_runner_;
153 internal::NamespaceToken namespace_token_[kNamespaceCount];
154 internal::Task::Vector tasks_[kNamespaceCount];
155 internal::Task::Vector dependents_[kNamespaceCount];
156 std::vector<unsigned> run_task_ids_[kNamespaceCount];
157 base::Lock run_task_ids_lock_;
158 std::vector<unsigned> on_task_completed_ids_[kNamespaceCount];
161 class TaskGraphRunnerTest : public TaskGraphRunnerTestBase,
162 public testing::TestWithParam<int> {
164 // Overridden from testing::Test:
165 virtual void SetUp() OVERRIDE {
167 make_scoped_ptr(new internal::TaskGraphRunner(GetParam(), "Test"));
168 for (int i = 0; i < kNamespaceCount; ++i)
169 namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
171 virtual void TearDown() OVERRIDE { task_graph_runner_.reset(); }
174 TEST_P(TaskGraphRunnerTest, Basic) {
175 for (int i = 0; i < kNamespaceCount; ++i) {
176 EXPECT_EQ(0u, run_task_ids(i).size());
177 EXPECT_EQ(0u, on_task_completed_ids(i).size());
179 ScheduleTasks(i, std::vector<Task>(1, Task(i, 0u, 0u, 0u, 0u)));
182 for (int i = 0; i < kNamespaceCount; ++i) {
185 EXPECT_EQ(1u, run_task_ids(i).size());
186 EXPECT_EQ(1u, on_task_completed_ids(i).size());
189 for (int i = 0; i < kNamespaceCount; ++i)
190 ScheduleTasks(i, std::vector<Task>(1, Task(i, 0u, 0u, 1u, 0u)));
192 for (int i = 0; i < kNamespaceCount; ++i) {
195 EXPECT_EQ(3u, run_task_ids(i).size());
196 EXPECT_EQ(2u, on_task_completed_ids(i).size());
199 for (int i = 0; i < kNamespaceCount; ++i)
200 ScheduleTasks(i, std::vector<Task>(1, Task(i, 0u, 0u, 2u, 0u)));
202 for (int i = 0; i < kNamespaceCount; ++i) {
205 EXPECT_EQ(6u, run_task_ids(i).size());
206 EXPECT_EQ(3u, on_task_completed_ids(i).size());
210 TEST_P(TaskGraphRunnerTest, Dependencies) {
211 for (int i = 0; i < kNamespaceCount; ++i) {
221 for (int i = 0; i < kNamespaceCount; ++i) {
224 // Check if task ran before dependent.
225 ASSERT_EQ(2u, run_task_ids(i).size());
226 EXPECT_EQ(0u, run_task_ids(i)[0]);
227 EXPECT_EQ(1u, run_task_ids(i)[1]);
228 ASSERT_EQ(1u, on_task_completed_ids(i).size());
229 EXPECT_EQ(0u, on_task_completed_ids(i)[0]);
232 for (int i = 0; i < kNamespaceCount; ++i) {
242 for (int i = 0; i < kNamespaceCount; ++i) {
245 // Task should only run once.
246 ASSERT_EQ(5u, run_task_ids(i).size());
247 EXPECT_EQ(2u, run_task_ids(i)[2]);
248 EXPECT_EQ(3u, run_task_ids(i)[3]);
249 EXPECT_EQ(3u, run_task_ids(i)[4]);
250 ASSERT_EQ(2u, on_task_completed_ids(i).size());
251 EXPECT_EQ(2u, on_task_completed_ids(i)[1]);
255 INSTANTIATE_TEST_CASE_P(TaskGraphRunnerTests,
257 ::testing::Range(1, 5));
259 class TaskGraphRunnerSingleThreadTest : public TaskGraphRunnerTestBase,
260 public testing::Test {
262 // Overridden from testing::Test:
263 virtual void SetUp() OVERRIDE {
265 make_scoped_ptr(new internal::TaskGraphRunner(1, "Test"));
266 for (int i = 0; i < kNamespaceCount; ++i)
267 namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
269 virtual void TearDown() OVERRIDE { task_graph_runner_.reset(); }
272 TEST_F(TaskGraphRunnerSingleThreadTest, Priority) {
273 for (int i = 0; i < kNamespaceCount; ++i) {
274 Task tasks[] = {Task(i, 0u, 2u, 1u, 1u), // Priority 1
275 Task(i, 1u, 3u, 1u, 0u) // Priority 0
277 ScheduleTasks(i, std::vector<Task>(tasks, tasks + arraysize(tasks)));
280 for (int i = 0; i < kNamespaceCount; ++i) {
283 // Check if tasks ran in order of priority.
284 ASSERT_EQ(4u, run_task_ids(i).size());
285 EXPECT_EQ(1u, run_task_ids(i)[0]);
286 EXPECT_EQ(3u, run_task_ids(i)[1]);
287 EXPECT_EQ(0u, run_task_ids(i)[2]);
288 EXPECT_EQ(2u, run_task_ids(i)[3]);
289 ASSERT_EQ(2u, on_task_completed_ids(i).size());
290 EXPECT_EQ(1u, on_task_completed_ids(i)[0]);
291 EXPECT_EQ(0u, on_task_completed_ids(i)[1]);