OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "cc/resources/task_graph_runner.h" | |
6 | |
7 #include <vector> | |
8 | |
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" | |
15 | |
16 namespace cc { | |
17 namespace { | |
18 | |
19 static const int kTimeLimitMillis = 2000; | |
20 static const int kWarmupRuns = 5; | |
21 static const int kTimeCheckInterval = 10; | |
22 | |
23 class PerfTaskImpl : public Task { | |
24 public: | |
25 typedef std::vector<scoped_refptr<PerfTaskImpl>> Vector; | |
26 | |
27 PerfTaskImpl() {} | |
28 | |
29 // Overridden from Task: | |
30 void RunOnWorkerThread() override {} | |
31 | |
32 void Reset() { did_run_ = false; } | |
33 | |
34 private: | |
35 ~PerfTaskImpl() override {} | |
36 | |
37 DISALLOW_COPY_AND_ASSIGN(PerfTaskImpl); | |
38 }; | |
39 | |
40 class TaskGraphRunnerPerfTest : public testing::Test { | |
41 public: | |
42 TaskGraphRunnerPerfTest() | |
43 : timer_(kWarmupRuns, | |
44 base::TimeDelta::FromMilliseconds(kTimeLimitMillis), | |
45 kTimeCheckInterval) {} | |
46 | |
47 // Overridden from testing::Test: | |
48 void SetUp() override { | |
49 task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner); | |
50 namespace_token_ = task_graph_runner_->GetNamespaceToken(); | |
51 } | |
52 void TearDown() override { task_graph_runner_ = nullptr; } | |
53 | |
54 void RunBuildTaskGraphTest(const std::string& test_name, | |
55 int num_top_level_tasks, | |
56 int num_tasks, | |
57 int num_leaf_tasks) { | |
58 PerfTaskImpl::Vector top_level_tasks; | |
59 PerfTaskImpl::Vector tasks; | |
60 PerfTaskImpl::Vector leaf_tasks; | |
61 CreateTasks(num_top_level_tasks, &top_level_tasks); | |
62 CreateTasks(num_tasks, &tasks); | |
63 CreateTasks(num_leaf_tasks, &leaf_tasks); | |
64 | |
65 // Avoid unnecessary heap allocations by reusing the same graph. | |
66 TaskGraph graph; | |
67 | |
68 timer_.Reset(); | |
69 do { | |
70 graph.Reset(); | |
71 BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph); | |
72 timer_.NextLap(); | |
73 } while (!timer_.HasTimeLimitExpired()); | |
74 | |
75 perf_test::PrintResult("build_task_graph", | |
76 TestModifierString(), | |
77 test_name, | |
78 timer_.LapsPerSecond(), | |
79 "runs/s", | |
80 true); | |
81 } | |
82 | |
83 void RunScheduleTasksTest(const std::string& test_name, | |
84 int num_top_level_tasks, | |
85 int num_tasks, | |
86 int num_leaf_tasks) { | |
87 PerfTaskImpl::Vector top_level_tasks; | |
88 PerfTaskImpl::Vector tasks; | |
89 PerfTaskImpl::Vector leaf_tasks; | |
90 CreateTasks(num_top_level_tasks, &top_level_tasks); | |
91 CreateTasks(num_tasks, &tasks); | |
92 CreateTasks(num_leaf_tasks, &leaf_tasks); | |
93 | |
94 // Avoid unnecessary heap allocations by reusing the same graph and | |
95 // completed tasks vector. | |
96 TaskGraph graph; | |
97 Task::Vector completed_tasks; | |
98 | |
99 timer_.Reset(); | |
100 do { | |
101 graph.Reset(); | |
102 BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph); | |
103 task_graph_runner_->ScheduleTasks(namespace_token_, &graph); | |
104 // Shouldn't be any tasks to collect as we reschedule the same set | |
105 // of tasks. | |
106 DCHECK_EQ(0u, CollectCompletedTasks(&completed_tasks)); | |
107 timer_.NextLap(); | |
108 } while (!timer_.HasTimeLimitExpired()); | |
109 | |
110 TaskGraph empty; | |
111 task_graph_runner_->ScheduleTasks(namespace_token_, &empty); | |
112 CollectCompletedTasks(&completed_tasks); | |
113 | |
114 perf_test::PrintResult("schedule_tasks", | |
115 TestModifierString(), | |
116 test_name, | |
117 timer_.LapsPerSecond(), | |
118 "runs/s", | |
119 true); | |
120 } | |
121 | |
122 void RunScheduleAlternateTasksTest(const std::string& test_name, | |
123 int num_top_level_tasks, | |
124 int num_tasks, | |
125 int num_leaf_tasks) { | |
126 const size_t kNumVersions = 2; | |
127 PerfTaskImpl::Vector top_level_tasks[kNumVersions]; | |
128 PerfTaskImpl::Vector tasks[kNumVersions]; | |
129 PerfTaskImpl::Vector leaf_tasks[kNumVersions]; | |
130 for (size_t i = 0; i < kNumVersions; ++i) { | |
131 CreateTasks(num_top_level_tasks, &top_level_tasks[i]); | |
132 CreateTasks(num_tasks, &tasks[i]); | |
133 CreateTasks(num_leaf_tasks, &leaf_tasks[i]); | |
134 } | |
135 | |
136 // Avoid unnecessary heap allocations by reusing the same graph and | |
137 // completed tasks vector. | |
138 TaskGraph graph; | |
139 Task::Vector completed_tasks; | |
140 | |
141 size_t count = 0; | |
142 timer_.Reset(); | |
143 do { | |
144 graph.Reset(); | |
145 BuildTaskGraph(top_level_tasks[count % kNumVersions], | |
146 tasks[count % kNumVersions], | |
147 leaf_tasks[count % kNumVersions], | |
148 &graph); | |
149 task_graph_runner_->ScheduleTasks(namespace_token_, &graph); | |
150 CollectCompletedTasks(&completed_tasks); | |
151 completed_tasks.clear(); | |
152 ++count; | |
153 timer_.NextLap(); | |
154 } while (!timer_.HasTimeLimitExpired()); | |
155 | |
156 TaskGraph empty; | |
157 task_graph_runner_->ScheduleTasks(namespace_token_, &empty); | |
158 CollectCompletedTasks(&completed_tasks); | |
159 | |
160 perf_test::PrintResult("schedule_alternate_tasks", | |
161 TestModifierString(), | |
162 test_name, | |
163 timer_.LapsPerSecond(), | |
164 "runs/s", | |
165 true); | |
166 } | |
167 | |
168 void RunScheduleAndExecuteTasksTest(const std::string& test_name, | |
169 int num_top_level_tasks, | |
170 int num_tasks, | |
171 int num_leaf_tasks) { | |
172 PerfTaskImpl::Vector top_level_tasks; | |
173 PerfTaskImpl::Vector tasks; | |
174 PerfTaskImpl::Vector leaf_tasks; | |
175 CreateTasks(num_top_level_tasks, &top_level_tasks); | |
176 CreateTasks(num_tasks, &tasks); | |
177 CreateTasks(num_leaf_tasks, &leaf_tasks); | |
178 | |
179 // Avoid unnecessary heap allocations by reusing the same graph and | |
180 // completed tasks vector. | |
181 TaskGraph graph; | |
182 Task::Vector completed_tasks; | |
183 | |
184 timer_.Reset(); | |
185 do { | |
186 graph.Reset(); | |
187 BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph); | |
188 task_graph_runner_->ScheduleTasks(namespace_token_, &graph); | |
189 task_graph_runner_->RunUntilIdle(); | |
190 CollectCompletedTasks(&completed_tasks); | |
191 completed_tasks.clear(); | |
192 ResetTasks(&top_level_tasks); | |
193 ResetTasks(&tasks); | |
194 ResetTasks(&leaf_tasks); | |
195 timer_.NextLap(); | |
196 } while (!timer_.HasTimeLimitExpired()); | |
197 | |
198 perf_test::PrintResult("execute_tasks", | |
199 TestModifierString(), | |
200 test_name, | |
201 timer_.LapsPerSecond(), | |
202 "runs/s", | |
203 true); | |
204 } | |
205 | |
206 private: | |
207 static std::string TestModifierString() { | |
208 return std::string("_task_graph_runner"); | |
209 } | |
210 | |
211 void CreateTasks(int num_tasks, PerfTaskImpl::Vector* tasks) { | |
212 for (int i = 0; i < num_tasks; ++i) | |
213 tasks->push_back(make_scoped_refptr(new PerfTaskImpl)); | |
214 } | |
215 | |
216 void ResetTasks(PerfTaskImpl::Vector* tasks) { | |
217 for (PerfTaskImpl::Vector::iterator it = tasks->begin(); it != tasks->end(); | |
218 ++it) { | |
219 PerfTaskImpl* task = it->get(); | |
220 task->Reset(); | |
221 } | |
222 } | |
223 | |
224 void BuildTaskGraph(const PerfTaskImpl::Vector& top_level_tasks, | |
225 const PerfTaskImpl::Vector& tasks, | |
226 const PerfTaskImpl::Vector& leaf_tasks, | |
227 TaskGraph* graph) { | |
228 DCHECK(graph->nodes.empty()); | |
229 DCHECK(graph->edges.empty()); | |
230 | |
231 for (PerfTaskImpl::Vector::const_iterator it = leaf_tasks.begin(); | |
232 it != leaf_tasks.end(); | |
233 ++it) { | |
234 graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, 0u)); | |
235 } | |
236 | |
237 for (PerfTaskImpl::Vector::const_iterator it = tasks.begin(); | |
238 it != tasks.end(); | |
239 ++it) { | |
240 graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, leaf_tasks.size())); | |
241 | |
242 for (PerfTaskImpl::Vector::const_iterator leaf_it = leaf_tasks.begin(); | |
243 leaf_it != leaf_tasks.end(); | |
244 ++leaf_it) { | |
245 graph->edges.push_back(TaskGraph::Edge(leaf_it->get(), it->get())); | |
246 } | |
247 | |
248 for (PerfTaskImpl::Vector::const_iterator top_level_it = | |
249 top_level_tasks.begin(); | |
250 top_level_it != top_level_tasks.end(); | |
251 ++top_level_it) { | |
252 graph->edges.push_back(TaskGraph::Edge(it->get(), top_level_it->get())); | |
253 } | |
254 } | |
255 | |
256 for (PerfTaskImpl::Vector::const_iterator it = top_level_tasks.begin(); | |
257 it != top_level_tasks.end(); | |
258 ++it) { | |
259 graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, tasks.size())); | |
260 } | |
261 } | |
262 | |
263 size_t CollectCompletedTasks(Task::Vector* completed_tasks) { | |
264 DCHECK(completed_tasks->empty()); | |
265 task_graph_runner_->CollectCompletedTasks(namespace_token_, | |
266 completed_tasks); | |
267 return completed_tasks->size(); | |
268 } | |
269 | |
270 scoped_ptr<TaskGraphRunner> task_graph_runner_; | |
271 NamespaceToken namespace_token_; | |
272 LapTimer timer_; | |
273 }; | |
274 | |
275 TEST_F(TaskGraphRunnerPerfTest, BuildTaskGraph) { | |
276 RunBuildTaskGraphTest("0_1_0", 0, 1, 0); | |
277 RunBuildTaskGraphTest("0_32_0", 0, 32, 0); | |
278 RunBuildTaskGraphTest("2_1_0", 2, 1, 0); | |
279 RunBuildTaskGraphTest("2_32_0", 2, 32, 0); | |
280 RunBuildTaskGraphTest("2_1_1", 2, 1, 1); | |
281 RunBuildTaskGraphTest("2_32_1", 2, 32, 1); | |
282 } | |
283 | |
284 TEST_F(TaskGraphRunnerPerfTest, ScheduleTasks) { | |
285 RunScheduleTasksTest("0_1_0", 0, 1, 0); | |
286 RunScheduleTasksTest("0_32_0", 0, 32, 0); | |
287 RunScheduleTasksTest("2_1_0", 2, 1, 0); | |
288 RunScheduleTasksTest("2_32_0", 2, 32, 0); | |
289 RunScheduleTasksTest("2_1_1", 2, 1, 1); | |
290 RunScheduleTasksTest("2_32_1", 2, 32, 1); | |
291 } | |
292 | |
293 TEST_F(TaskGraphRunnerPerfTest, ScheduleAlternateTasks) { | |
294 RunScheduleAlternateTasksTest("0_1_0", 0, 1, 0); | |
295 RunScheduleAlternateTasksTest("0_32_0", 0, 32, 0); | |
296 RunScheduleAlternateTasksTest("2_1_0", 2, 1, 0); | |
297 RunScheduleAlternateTasksTest("2_32_0", 2, 32, 0); | |
298 RunScheduleAlternateTasksTest("2_1_1", 2, 1, 1); | |
299 RunScheduleAlternateTasksTest("2_32_1", 2, 32, 1); | |
300 } | |
301 | |
302 TEST_F(TaskGraphRunnerPerfTest, ScheduleAndExecuteTasks) { | |
303 RunScheduleAndExecuteTasksTest("0_1_0", 0, 1, 0); | |
304 RunScheduleAndExecuteTasksTest("0_32_0", 0, 32, 0); | |
305 RunScheduleAndExecuteTasksTest("2_1_0", 2, 1, 0); | |
306 RunScheduleAndExecuteTasksTest("2_32_0", 2, 32, 0); | |
307 RunScheduleAndExecuteTasksTest("2_1_1", 2, 1, 1); | |
308 RunScheduleAndExecuteTasksTest("2_32_1", 2, 32, 1); | |
309 } | |
310 | |
311 } // namespace | |
312 } // namespace cc | |
OLD | NEW |