#include "cc/resources/task_graph_runner.h"
+#include <vector>
+
#include "base/time/time.h"
#include "cc/base/completion_event.h"
#include "cc/test/lap_timer.h"
class PerfTaskImpl : public internal::Task {
public:
+ typedef std::vector<scoped_refptr<PerfTaskImpl> > Vector;
+
PerfTaskImpl() {}
// Overridden from internal::Task:
virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {}
+ void Reset() { did_run_ = false; }
+
private:
virtual ~PerfTaskImpl() {}
DISALLOW_COPY_AND_ASSIGN(PerfTaskImpl);
};
-class PerfControlTaskImpl : public internal::Task {
- public:
- PerfControlTaskImpl() {}
-
- // Overridden from internal::Task:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
- did_start_.Signal();
- can_finish_.Wait();
- }
-
- void WaitForTaskToStartRunning() { did_start_.Wait(); }
-
- void AllowTaskToFinish() { can_finish_.Signal(); }
-
- private:
- virtual ~PerfControlTaskImpl() {}
-
- CompletionEvent did_start_;
- CompletionEvent can_finish_;
-
- DISALLOW_COPY_AND_ASSIGN(PerfControlTaskImpl);
-};
-
class TaskGraphRunnerPerfTest : public testing::Test {
public:
TaskGraphRunnerPerfTest()
// Overridden from testing::Test:
virtual void SetUp() OVERRIDE {
task_graph_runner_ =
- make_scoped_ptr(new internal::TaskGraphRunner(1, "PerfTest"));
+ make_scoped_ptr(new internal::TaskGraphRunner(0, // 0 worker threads
+ "PerfTest"));
namespace_token_ = task_graph_runner_->GetNamespaceToken();
}
virtual void TearDown() OVERRIDE { task_graph_runner_.reset(); }
"*RESULT %s: %.2f runs/s\n", test_name.c_str(), timer_.LapsPerSecond());
}
+ void RunBuildTaskGraphTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph.
+ internal::TaskGraph graph;
+
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("build_task_graph",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
void RunScheduleTasksTest(const std::string& test_name,
- unsigned max_depth,
- unsigned num_children_per_node) {
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ internal::TaskGraph graph;
+ internal::Task::Vector completed_tasks;
+
timer_.Reset();
do {
- scoped_refptr<PerfControlTaskImpl> leaf_task(new PerfControlTaskImpl);
- ScheduleTasks(NULL, leaf_task.get(), max_depth, num_children_per_node);
- leaf_task->WaitForTaskToStartRunning();
- ScheduleTasks(NULL, NULL, 0, 0);
- leaf_task->AllowTaskToFinish();
- task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
- internal::Task::Vector completed_tasks;
- task_graph_runner_->CollectCompletedTasks(namespace_token_,
- &completed_tasks);
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ task_graph_runner_->SetTaskGraph(namespace_token_, &graph);
+ // Shouldn't be any tasks to collect as we reschedule the same set
+ // of tasks.
+ DCHECK_EQ(0u, CollectCompletedTasks(&completed_tasks));
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
+ internal::TaskGraph empty;
+ task_graph_runner_->SetTaskGraph(namespace_token_, &empty);
+ CollectCompletedTasks(&completed_tasks);
+
perf_test::PrintResult("schedule_tasks",
"",
test_name,
true);
}
- void RunExecuteTasksTest(const std::string& test_name,
- unsigned max_depth,
- unsigned num_children_per_node) {
+ void RunScheduleAlternateTasksTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ const size_t kNumVersions = 2;
+ PerfTaskImpl::Vector top_level_tasks[kNumVersions];
+ PerfTaskImpl::Vector tasks[kNumVersions];
+ PerfTaskImpl::Vector leaf_tasks[kNumVersions];
+ for (size_t i = 0; i < kNumVersions; ++i) {
+ CreateTasks(num_top_level_tasks, &top_level_tasks[i]);
+ CreateTasks(num_tasks, &tasks[i]);
+ CreateTasks(num_leaf_tasks, &leaf_tasks[i]);
+ }
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ internal::TaskGraph graph;
+ internal::Task::Vector completed_tasks;
+
+ size_t count = 0;
timer_.Reset();
do {
- ScheduleTasks(NULL, NULL, max_depth, num_children_per_node);
- task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
- internal::Task::Vector completed_tasks;
- task_graph_runner_->CollectCompletedTasks(namespace_token_,
- &completed_tasks);
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks[count % kNumVersions],
+ tasks[count % kNumVersions],
+ leaf_tasks[count % kNumVersions],
+ &graph);
+ task_graph_runner_->SetTaskGraph(namespace_token_, &graph);
+ CollectCompletedTasks(&completed_tasks);
+ completed_tasks.clear();
+ ++count;
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ internal::TaskGraph empty;
+ task_graph_runner_->SetTaskGraph(namespace_token_, &empty);
+ CollectCompletedTasks(&completed_tasks);
+
+ perf_test::PrintResult("schedule_alternate_tasks",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunScheduleAndExecuteTasksTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ internal::TaskGraph graph;
+ internal::Task::Vector completed_tasks;
+
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ task_graph_runner_->SetTaskGraph(namespace_token_, &graph);
+ while (task_graph_runner_->RunTaskForTesting())
+ continue;
+ CollectCompletedTasks(&completed_tasks);
+ completed_tasks.clear();
+ ResetTasks(&top_level_tasks);
+ ResetTasks(&tasks);
+ ResetTasks(&leaf_tasks);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
}
private:
- void ScheduleTasks(internal::Task* root_task,
- internal::Task* leaf_task,
- unsigned max_depth,
- unsigned num_children_per_node) {
- internal::Task::Vector tasks;
- internal::GraphNode::Map graph;
-
- scoped_ptr<internal::GraphNode> root_node;
- if (root_task)
- root_node = make_scoped_ptr(new internal::GraphNode(root_task, 0u));
-
- scoped_ptr<internal::GraphNode> leaf_node;
- if (leaf_task)
- leaf_node = make_scoped_ptr(new internal::GraphNode(leaf_task, 0u));
-
- if (max_depth) {
- BuildTaskGraph(&tasks,
- &graph,
- root_node.get(),
- leaf_node.get(),
- 0,
- max_depth,
- num_children_per_node);
- }
-
- if (leaf_node)
- graph.set(leaf_task, leaf_node.Pass());
+ void CreateTasks(int num_tasks, PerfTaskImpl::Vector* tasks) {
+ for (int i = 0; i < num_tasks; ++i)
+ tasks->push_back(make_scoped_refptr(new PerfTaskImpl));
+ }
- if (root_node)
- graph.set(root_task, root_node.Pass());
+ void ResetTasks(PerfTaskImpl::Vector* tasks) {
+ for (PerfTaskImpl::Vector::iterator it = tasks->begin(); it != tasks->end();
+ ++it) {
+ PerfTaskImpl* task = it->get();
+ task->Reset();
+ }
+ }
- task_graph_runner_->SetTaskGraph(namespace_token_, &graph);
+ void BuildTaskGraph(const PerfTaskImpl::Vector& top_level_tasks,
+ const PerfTaskImpl::Vector& tasks,
+ const PerfTaskImpl::Vector& leaf_tasks,
+ internal::TaskGraph* graph) {
+ DCHECK(graph->nodes.empty());
+ DCHECK(graph->edges.empty());
+
+ for (PerfTaskImpl::Vector::const_iterator it = leaf_tasks.begin();
+ it != leaf_tasks.end();
+ ++it) {
+ graph->nodes.push_back(internal::TaskGraph::Node(it->get(), 0u, 0u));
+ }
- tasks_.swap(tasks);
- }
+ for (PerfTaskImpl::Vector::const_iterator it = tasks.begin();
+ it != tasks.end();
+ ++it) {
+ graph->nodes.push_back(
+ internal::TaskGraph::Node(it->get(), 0u, leaf_tasks.size()));
+
+ for (PerfTaskImpl::Vector::const_iterator leaf_it = leaf_tasks.begin();
+ leaf_it != leaf_tasks.end();
+ ++leaf_it) {
+ graph->edges.push_back(
+ internal::TaskGraph::Edge(leaf_it->get(), it->get()));
+ }
- void BuildTaskGraph(internal::Task::Vector* tasks,
- internal::GraphNode::Map* graph,
- internal::GraphNode* dependent_node,
- internal::GraphNode* leaf_node,
- unsigned current_depth,
- unsigned max_depth,
- unsigned num_children_per_node) {
- scoped_refptr<PerfTaskImpl> task(new PerfTaskImpl);
- scoped_ptr<internal::GraphNode> node(
- new internal::GraphNode(task.get(), 0u));
-
- if (current_depth < max_depth) {
- for (unsigned i = 0; i < num_children_per_node; ++i) {
- BuildTaskGraph(tasks,
- graph,
- node.get(),
- leaf_node,
- current_depth + 1,
- max_depth,
- num_children_per_node);
+ for (PerfTaskImpl::Vector::const_iterator top_level_it =
+ top_level_tasks.begin();
+ top_level_it != top_level_tasks.end();
+ ++top_level_it) {
+ graph->edges.push_back(
+ internal::TaskGraph::Edge(it->get(), top_level_it->get()));
}
- } else if (leaf_node) {
- leaf_node->add_dependent(node.get());
- node->add_dependency();
}
- if (dependent_node) {
- node->add_dependent(dependent_node);
- dependent_node->add_dependency();
+ for (PerfTaskImpl::Vector::const_iterator it = top_level_tasks.begin();
+ it != top_level_tasks.end();
+ ++it) {
+ graph->nodes.push_back(
+ internal::TaskGraph::Node(it->get(), 0u, tasks.size()));
}
- graph->set(task.get(), node.Pass());
- tasks->push_back(task.get());
+ }
+
+ size_t CollectCompletedTasks(internal::Task::Vector* completed_tasks) {
+ DCHECK(completed_tasks->empty());
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ completed_tasks);
+ return completed_tasks->size();
}
scoped_ptr<internal::TaskGraphRunner> task_graph_runner_;
internal::NamespaceToken namespace_token_;
- internal::Task::Vector tasks_;
LapTimer timer_;
};
+TEST_F(TaskGraphRunnerPerfTest, BuildTaskGraph) {
+ RunBuildTaskGraphTest("0_1_0", 0, 1, 0);
+ RunBuildTaskGraphTest("0_32_0", 0, 32, 0);
+ RunBuildTaskGraphTest("2_1_0", 2, 1, 0);
+ RunBuildTaskGraphTest("2_32_0", 2, 32, 0);
+ RunBuildTaskGraphTest("2_1_1", 2, 1, 1);
+ RunBuildTaskGraphTest("2_32_1", 2, 32, 1);
+}
+
TEST_F(TaskGraphRunnerPerfTest, ScheduleTasks) {
- RunScheduleTasksTest("1_10", 1, 10);
- RunScheduleTasksTest("1_1000", 1, 1000);
- RunScheduleTasksTest("2_10", 2, 10);
- RunScheduleTasksTest("5_5", 5, 5);
- RunScheduleTasksTest("10_2", 10, 2);
- RunScheduleTasksTest("1000_1", 1000, 1);
- RunScheduleTasksTest("10_1", 10, 1);
+ RunScheduleTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleTasksTest("2_32_1", 2, 32, 1);
+}
+
+TEST_F(TaskGraphRunnerPerfTest, ScheduleAlternateTasks) {
+ RunScheduleAlternateTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleAlternateTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleAlternateTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleAlternateTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleAlternateTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleAlternateTasksTest("2_32_1", 2, 32, 1);
}
-TEST_F(TaskGraphRunnerPerfTest, ExecuteTasks) {
- RunExecuteTasksTest("1_10", 1, 10);
- RunExecuteTasksTest("1_1000", 1, 1000);
- RunExecuteTasksTest("2_10", 2, 10);
- RunExecuteTasksTest("5_5", 5, 5);
- RunExecuteTasksTest("10_2", 10, 2);
- RunExecuteTasksTest("1000_1", 1000, 1);
- RunExecuteTasksTest("10_1", 10, 1);
+TEST_F(TaskGraphRunnerPerfTest, ScheduleAndExecuteTasks) {
+ RunScheduleAndExecuteTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleAndExecuteTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleAndExecuteTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleAndExecuteTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleAndExecuteTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleAndExecuteTasksTest("2_32_1", 2, 32, 1);
}
} // namespace