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"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/time/time.h"
11 #include "cc/base/completion_event.h"
12 #include "cc/debug/lap_timer.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "testing/perf/perf_test.h"
19 static const int kTimeLimitMillis
= 2000;
20 static const int kWarmupRuns
= 5;
21 static const int kTimeCheckInterval
= 10;
23 class PerfTaskImpl
: public Task
{
25 typedef std::vector
<scoped_refptr
<PerfTaskImpl
>> Vector
;
29 // Overridden from Task:
30 void RunOnWorkerThread() override
{}
32 void Reset() { did_run_
= false; }
35 ~PerfTaskImpl() override
{}
37 DISALLOW_COPY_AND_ASSIGN(PerfTaskImpl
);
40 class TaskGraphRunnerPerfTest
: public testing::Test
{
42 TaskGraphRunnerPerfTest()
44 base::TimeDelta::FromMilliseconds(kTimeLimitMillis
),
45 kTimeCheckInterval
) {}
47 // Overridden from testing::Test:
48 virtual void SetUp() override
{
49 task_graph_runner_
= make_scoped_ptr(new TaskGraphRunner
);
50 namespace_token_
= task_graph_runner_
->GetNamespaceToken();
52 virtual void TearDown() override
{ task_graph_runner_
= nullptr; }
54 void AfterTest(const std::string
& test_name
) {
55 // Format matches chrome/test/perf/perf_test.h:PrintResult
57 "*RESULT %s: %.2f runs/s\n", test_name
.c_str(), timer_
.LapsPerSecond());
60 void RunBuildTaskGraphTest(const std::string
& test_name
,
61 int num_top_level_tasks
,
64 PerfTaskImpl::Vector top_level_tasks
;
65 PerfTaskImpl::Vector tasks
;
66 PerfTaskImpl::Vector leaf_tasks
;
67 CreateTasks(num_top_level_tasks
, &top_level_tasks
);
68 CreateTasks(num_tasks
, &tasks
);
69 CreateTasks(num_leaf_tasks
, &leaf_tasks
);
71 // Avoid unnecessary heap allocations by reusing the same graph.
77 BuildTaskGraph(top_level_tasks
, tasks
, leaf_tasks
, &graph
);
79 } while (!timer_
.HasTimeLimitExpired());
81 perf_test::PrintResult("build_task_graph",
84 timer_
.LapsPerSecond(),
89 void RunScheduleTasksTest(const std::string
& test_name
,
90 int num_top_level_tasks
,
93 PerfTaskImpl::Vector top_level_tasks
;
94 PerfTaskImpl::Vector tasks
;
95 PerfTaskImpl::Vector leaf_tasks
;
96 CreateTasks(num_top_level_tasks
, &top_level_tasks
);
97 CreateTasks(num_tasks
, &tasks
);
98 CreateTasks(num_leaf_tasks
, &leaf_tasks
);
100 // Avoid unnecessary heap allocations by reusing the same graph and
101 // completed tasks vector.
103 Task::Vector completed_tasks
;
108 BuildTaskGraph(top_level_tasks
, tasks
, leaf_tasks
, &graph
);
109 task_graph_runner_
->ScheduleTasks(namespace_token_
, &graph
);
110 // Shouldn't be any tasks to collect as we reschedule the same set
112 DCHECK_EQ(0u, CollectCompletedTasks(&completed_tasks
));
114 } while (!timer_
.HasTimeLimitExpired());
117 task_graph_runner_
->ScheduleTasks(namespace_token_
, &empty
);
118 CollectCompletedTasks(&completed_tasks
);
120 perf_test::PrintResult("schedule_tasks",
121 TestModifierString(),
123 timer_
.LapsPerSecond(),
128 void RunScheduleAlternateTasksTest(const std::string
& test_name
,
129 int num_top_level_tasks
,
131 int num_leaf_tasks
) {
132 const size_t kNumVersions
= 2;
133 PerfTaskImpl::Vector top_level_tasks
[kNumVersions
];
134 PerfTaskImpl::Vector tasks
[kNumVersions
];
135 PerfTaskImpl::Vector leaf_tasks
[kNumVersions
];
136 for (size_t i
= 0; i
< kNumVersions
; ++i
) {
137 CreateTasks(num_top_level_tasks
, &top_level_tasks
[i
]);
138 CreateTasks(num_tasks
, &tasks
[i
]);
139 CreateTasks(num_leaf_tasks
, &leaf_tasks
[i
]);
142 // Avoid unnecessary heap allocations by reusing the same graph and
143 // completed tasks vector.
145 Task::Vector completed_tasks
;
151 BuildTaskGraph(top_level_tasks
[count
% kNumVersions
],
152 tasks
[count
% kNumVersions
],
153 leaf_tasks
[count
% kNumVersions
],
155 task_graph_runner_
->ScheduleTasks(namespace_token_
, &graph
);
156 CollectCompletedTasks(&completed_tasks
);
157 completed_tasks
.clear();
160 } while (!timer_
.HasTimeLimitExpired());
163 task_graph_runner_
->ScheduleTasks(namespace_token_
, &empty
);
164 CollectCompletedTasks(&completed_tasks
);
166 perf_test::PrintResult("schedule_alternate_tasks",
167 TestModifierString(),
169 timer_
.LapsPerSecond(),
174 void RunScheduleAndExecuteTasksTest(const std::string
& test_name
,
175 int num_top_level_tasks
,
177 int num_leaf_tasks
) {
178 PerfTaskImpl::Vector top_level_tasks
;
179 PerfTaskImpl::Vector tasks
;
180 PerfTaskImpl::Vector leaf_tasks
;
181 CreateTasks(num_top_level_tasks
, &top_level_tasks
);
182 CreateTasks(num_tasks
, &tasks
);
183 CreateTasks(num_leaf_tasks
, &leaf_tasks
);
185 // Avoid unnecessary heap allocations by reusing the same graph and
186 // completed tasks vector.
188 Task::Vector completed_tasks
;
193 BuildTaskGraph(top_level_tasks
, tasks
, leaf_tasks
, &graph
);
194 task_graph_runner_
->ScheduleTasks(namespace_token_
, &graph
);
195 task_graph_runner_
->RunUntilIdle();
196 CollectCompletedTasks(&completed_tasks
);
197 completed_tasks
.clear();
198 ResetTasks(&top_level_tasks
);
200 ResetTasks(&leaf_tasks
);
202 } while (!timer_
.HasTimeLimitExpired());
204 perf_test::PrintResult("execute_tasks",
205 TestModifierString(),
207 timer_
.LapsPerSecond(),
213 static std::string
TestModifierString() {
214 return std::string("_task_graph_runner");
217 void CreateTasks(int num_tasks
, PerfTaskImpl::Vector
* tasks
) {
218 for (int i
= 0; i
< num_tasks
; ++i
)
219 tasks
->push_back(make_scoped_refptr(new PerfTaskImpl
));
222 void ResetTasks(PerfTaskImpl::Vector
* tasks
) {
223 for (PerfTaskImpl::Vector::iterator it
= tasks
->begin(); it
!= tasks
->end();
225 PerfTaskImpl
* task
= it
->get();
230 void BuildTaskGraph(const PerfTaskImpl::Vector
& top_level_tasks
,
231 const PerfTaskImpl::Vector
& tasks
,
232 const PerfTaskImpl::Vector
& leaf_tasks
,
234 DCHECK(graph
->nodes
.empty());
235 DCHECK(graph
->edges
.empty());
237 for (PerfTaskImpl::Vector::const_iterator it
= leaf_tasks
.begin();
238 it
!= leaf_tasks
.end();
240 graph
->nodes
.push_back(TaskGraph::Node(it
->get(), 0u, 0u));
243 for (PerfTaskImpl::Vector::const_iterator it
= tasks
.begin();
246 graph
->nodes
.push_back(TaskGraph::Node(it
->get(), 0u, leaf_tasks
.size()));
248 for (PerfTaskImpl::Vector::const_iterator leaf_it
= leaf_tasks
.begin();
249 leaf_it
!= leaf_tasks
.end();
251 graph
->edges
.push_back(TaskGraph::Edge(leaf_it
->get(), it
->get()));
254 for (PerfTaskImpl::Vector::const_iterator top_level_it
=
255 top_level_tasks
.begin();
256 top_level_it
!= top_level_tasks
.end();
258 graph
->edges
.push_back(TaskGraph::Edge(it
->get(), top_level_it
->get()));
262 for (PerfTaskImpl::Vector::const_iterator it
= top_level_tasks
.begin();
263 it
!= top_level_tasks
.end();
265 graph
->nodes
.push_back(TaskGraph::Node(it
->get(), 0u, tasks
.size()));
269 size_t CollectCompletedTasks(Task::Vector
* completed_tasks
) {
270 DCHECK(completed_tasks
->empty());
271 task_graph_runner_
->CollectCompletedTasks(namespace_token_
,
273 return completed_tasks
->size();
276 scoped_ptr
<TaskGraphRunner
> task_graph_runner_
;
277 NamespaceToken namespace_token_
;
281 TEST_F(TaskGraphRunnerPerfTest
, BuildTaskGraph
) {
282 RunBuildTaskGraphTest("0_1_0", 0, 1, 0);
283 RunBuildTaskGraphTest("0_32_0", 0, 32, 0);
284 RunBuildTaskGraphTest("2_1_0", 2, 1, 0);
285 RunBuildTaskGraphTest("2_32_0", 2, 32, 0);
286 RunBuildTaskGraphTest("2_1_1", 2, 1, 1);
287 RunBuildTaskGraphTest("2_32_1", 2, 32, 1);
290 TEST_F(TaskGraphRunnerPerfTest
, ScheduleTasks
) {
291 RunScheduleTasksTest("0_1_0", 0, 1, 0);
292 RunScheduleTasksTest("0_32_0", 0, 32, 0);
293 RunScheduleTasksTest("2_1_0", 2, 1, 0);
294 RunScheduleTasksTest("2_32_0", 2, 32, 0);
295 RunScheduleTasksTest("2_1_1", 2, 1, 1);
296 RunScheduleTasksTest("2_32_1", 2, 32, 1);
299 TEST_F(TaskGraphRunnerPerfTest
, ScheduleAlternateTasks
) {
300 RunScheduleAlternateTasksTest("0_1_0", 0, 1, 0);
301 RunScheduleAlternateTasksTest("0_32_0", 0, 32, 0);
302 RunScheduleAlternateTasksTest("2_1_0", 2, 1, 0);
303 RunScheduleAlternateTasksTest("2_32_0", 2, 32, 0);
304 RunScheduleAlternateTasksTest("2_1_1", 2, 1, 1);
305 RunScheduleAlternateTasksTest("2_32_1", 2, 32, 1);
308 TEST_F(TaskGraphRunnerPerfTest
, ScheduleAndExecuteTasks
) {
309 RunScheduleAndExecuteTasksTest("0_1_0", 0, 1, 0);
310 RunScheduleAndExecuteTasksTest("0_32_0", 0, 32, 0);
311 RunScheduleAndExecuteTasksTest("2_1_0", 2, 1, 0);
312 RunScheduleAndExecuteTasksTest("2_32_0", 2, 32, 0);
313 RunScheduleAndExecuteTasksTest("2_1_1", 2, 1, 1);
314 RunScheduleAndExecuteTasksTest("2_32_1", 2, 32, 1);