blob: ac78a6d0fd2776f0f7afabc0ec97e913412da5c0 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/raster/task_graph_work_queue.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
class FakeTaskImpl : public Task {
public:
FakeTaskImpl() = default;
FakeTaskImpl(const FakeTaskImpl&) = delete;
FakeTaskImpl& operator=(const FakeTaskImpl&) = delete;
// Overridden from Task:
void RunOnWorkerThread() override {}
private:
~FakeTaskImpl() override = default;
};
TEST(TaskGraphWorkQueueTest, TestChangingDependency) {
TaskGraphWorkQueue work_queue;
NamespaceToken token = work_queue.GenerateNamespaceToken();
// Create a graph with one task
TaskGraph graph1;
scoped_refptr<FakeTaskImpl> task(new FakeTaskImpl());
graph1.nodes.push_back(TaskGraph::Node(task.get(), 0u, 0u, 0u));
// Schedule the graph
work_queue.ScheduleTasks(token, &graph1);
// Run the task.
TaskGraphWorkQueue::PrioritizedTask prioritized_task =
work_queue.GetNextTaskToRun(0u);
work_queue.CompleteTask(std::move(prioritized_task));
// Create a graph where task1 has a dependency
TaskGraph graph2;
scoped_refptr<FakeTaskImpl> dependency_task(new FakeTaskImpl());
graph2.nodes.push_back(TaskGraph::Node(task.get(), 0u, 0u, 1u));
graph2.nodes.push_back(TaskGraph::Node(dependency_task.get(), 0u, 0u, 0u));
graph2.edges.push_back(TaskGraph::Edge(dependency_task.get(), task.get()));
// Schedule the second graph.
work_queue.ScheduleTasks(token, &graph2);
// Run the |dependency_task|
TaskGraphWorkQueue::PrioritizedTask prioritized_dependency_task =
work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
// We should have no tasks to run, as the dependent task already completed.
EXPECT_FALSE(work_queue.HasReadyToRunTasks());
}
// Tasks with same priority but in different category.
TEST(TaskGraphWorkQueueTest, TestTaskWithDifferentCategory) {
TaskGraphWorkQueue work_queue;
NamespaceToken token = work_queue.GenerateNamespaceToken();
// Create a graph where | task| has dependencies.
TaskGraph graph;
scoped_refptr<FakeTaskImpl> task(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task1(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task2(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task3(new FakeTaskImpl());
graph.nodes.push_back(TaskGraph::Node(task.get(), 0u, 0u, 3u));
graph.nodes.push_back(TaskGraph::Node(dependency_task1.get(), 0u, 0u, 0u));
graph.nodes.push_back(TaskGraph::Node(dependency_task2.get(), 1u, 0u, 0u));
graph.nodes.push_back(TaskGraph::Node(dependency_task3.get(), 2u, 0u, 0u));
graph.edges.push_back(TaskGraph::Edge(dependency_task1.get(), task.get()));
graph.edges.push_back(TaskGraph::Edge(dependency_task2.get(), task.get()));
graph.edges.push_back(TaskGraph::Edge(dependency_task3.get(), task.get()));
// Schedule the graph.
work_queue.ScheduleTasks(token, &graph);
// Run the |dependency_task1|from category 0.
TaskGraphWorkQueue::PrioritizedTask prioritized_dependency_task =
work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task1.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
EXPECT_FALSE(work_queue.HasReadyToRunTasksForCategory(0u));
EXPECT_TRUE(work_queue.HasReadyToRunTasksForCategory(1u));
EXPECT_TRUE(work_queue.HasReadyToRunTasksForCategory(2u));
// Run the |dependency_task2|from category 1.
prioritized_dependency_task = work_queue.GetNextTaskToRun(1u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task2.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
EXPECT_FALSE(work_queue.HasReadyToRunTasksForCategory(0u));
EXPECT_FALSE(work_queue.HasReadyToRunTasksForCategory(1u));
EXPECT_TRUE(work_queue.HasReadyToRunTasksForCategory(2u));
// Run the |dependency_task3|from category 2.
prioritized_dependency_task = work_queue.GetNextTaskToRun(2u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task3.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
// Once all dependencies from different category completed, | task| turns
// ready to run.
EXPECT_TRUE(work_queue.HasReadyToRunTasksForCategory(0u));
EXPECT_FALSE(work_queue.HasReadyToRunTasksForCategory(1u));
EXPECT_FALSE(work_queue.HasReadyToRunTasksForCategory(2u));
prioritized_dependency_task = work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), task.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_FALSE(work_queue.HasReadyToRunTasks());
}
// Tasks with different priority run in a priority order. But need to guarantee
// its dependences are completed.
TEST(TaskGraphWorkQueueTest, TestTaskWithDifferentPriority) {
TaskGraphWorkQueue work_queue;
NamespaceToken token = work_queue.GenerateNamespaceToken();
{
// Create a graph where task has a dependency
TaskGraph graph;
scoped_refptr<FakeTaskImpl> task(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task1(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task2(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task3(new FakeTaskImpl());
// | task| has the lowest priority and 3 dependences, will run last.
graph.nodes.push_back(TaskGraph::Node(task.get(), 0u, 2u, 3u));
graph.nodes.push_back(TaskGraph::Node(dependency_task1.get(), 0u, 3u, 0u));
graph.nodes.push_back(TaskGraph::Node(dependency_task2.get(), 0u, 2u, 0u));
graph.nodes.push_back(TaskGraph::Node(dependency_task3.get(), 0u, 1u, 0u));
graph.edges.push_back(TaskGraph::Edge(dependency_task1.get(), task.get()));
graph.edges.push_back(TaskGraph::Edge(dependency_task2.get(), task.get()));
graph.edges.push_back(TaskGraph::Edge(dependency_task3.get(), task.get()));
// Schedule the graph.
work_queue.ScheduleTasks(token, &graph);
// Run the |dependency_task|
TaskGraphWorkQueue::PrioritizedTask prioritized_dependency_task =
work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task3.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
prioritized_dependency_task = work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task2.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
prioritized_dependency_task = work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task1.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
// | task| runs last.
prioritized_dependency_task = work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), task.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_FALSE(work_queue.HasReadyToRunTasks());
}
{
// Create a graph where task has dependencies
TaskGraph graph;
scoped_refptr<FakeTaskImpl> task(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task1(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task2(new FakeTaskImpl());
scoped_refptr<FakeTaskImpl> dependency_task3(new FakeTaskImpl());
// | task| has the highest priority and 3 dependences, also will run last.
graph.nodes.push_back(TaskGraph::Node(task.get(), 0u, 0u, 3u));
graph.nodes.push_back(TaskGraph::Node(dependency_task1.get(), 0u, 3u, 0u));
graph.nodes.push_back(TaskGraph::Node(dependency_task2.get(), 0u, 2u, 0u));
graph.nodes.push_back(TaskGraph::Node(dependency_task3.get(), 0u, 1u, 0u));
graph.edges.push_back(TaskGraph::Edge(dependency_task1.get(), task.get()));
graph.edges.push_back(TaskGraph::Edge(dependency_task2.get(), task.get()));
graph.edges.push_back(TaskGraph::Edge(dependency_task3.get(), task.get()));
// Schedule the graph.
work_queue.ScheduleTasks(token, &graph);
// Run the |dependency_task|
TaskGraphWorkQueue::PrioritizedTask prioritized_dependency_task =
work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task3.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
prioritized_dependency_task = work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task2.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
prioritized_dependency_task = work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), dependency_task1.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_TRUE(work_queue.HasReadyToRunTasks());
// | task| runs last.
prioritized_dependency_task = work_queue.GetNextTaskToRun(0u);
EXPECT_EQ(prioritized_dependency_task.task.get(), task.get());
work_queue.CompleteTask(std::move(prioritized_dependency_task));
EXPECT_FALSE(work_queue.HasReadyToRunTasks());
}
}
} // namespace
} // namespace cc