• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PerfTaskImpl()27   PerfTaskImpl() {}
28 
29   // Overridden from Task:
RunOnWorkerThread()30   virtual void RunOnWorkerThread() OVERRIDE {}
31 
Reset()32   void Reset() { did_run_ = false; }
33 
34  private:
~PerfTaskImpl()35   virtual ~PerfTaskImpl() {}
36 
37   DISALLOW_COPY_AND_ASSIGN(PerfTaskImpl);
38 };
39 
40 class TaskGraphRunnerPerfTest : public testing::Test {
41  public:
TaskGraphRunnerPerfTest()42   TaskGraphRunnerPerfTest()
43       : timer_(kWarmupRuns,
44                base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
45                kTimeCheckInterval) {}
46 
47   // Overridden from testing::Test:
SetUp()48   virtual void SetUp() OVERRIDE {
49     task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner);
50     namespace_token_ = task_graph_runner_->GetNamespaceToken();
51   }
TearDown()52   virtual void TearDown() OVERRIDE { task_graph_runner_.reset(); }
53 
AfterTest(const std::string & test_name)54   void AfterTest(const std::string& test_name) {
55     // Format matches chrome/test/perf/perf_test.h:PrintResult
56     printf(
57         "*RESULT %s: %.2f runs/s\n", test_name.c_str(), timer_.LapsPerSecond());
58   }
59 
RunBuildTaskGraphTest(const std::string & test_name,int num_top_level_tasks,int num_tasks,int num_leaf_tasks)60   void RunBuildTaskGraphTest(const std::string& test_name,
61                              int num_top_level_tasks,
62                              int num_tasks,
63                              int num_leaf_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);
70 
71     // Avoid unnecessary heap allocations by reusing the same graph.
72     TaskGraph graph;
73 
74     timer_.Reset();
75     do {
76       graph.Reset();
77       BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
78       timer_.NextLap();
79     } while (!timer_.HasTimeLimitExpired());
80 
81     perf_test::PrintResult("build_task_graph",
82                            TestModifierString(),
83                            test_name,
84                            timer_.LapsPerSecond(),
85                            "runs/s",
86                            true);
87   }
88 
RunScheduleTasksTest(const std::string & test_name,int num_top_level_tasks,int num_tasks,int num_leaf_tasks)89   void RunScheduleTasksTest(const std::string& test_name,
90                             int num_top_level_tasks,
91                             int num_tasks,
92                             int num_leaf_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);
99 
100     // Avoid unnecessary heap allocations by reusing the same graph and
101     // completed tasks vector.
102     TaskGraph graph;
103     Task::Vector completed_tasks;
104 
105     timer_.Reset();
106     do {
107       graph.Reset();
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
111       // of tasks.
112       DCHECK_EQ(0u, CollectCompletedTasks(&completed_tasks));
113       timer_.NextLap();
114     } while (!timer_.HasTimeLimitExpired());
115 
116     TaskGraph empty;
117     task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
118     CollectCompletedTasks(&completed_tasks);
119 
120     perf_test::PrintResult("schedule_tasks",
121                            TestModifierString(),
122                            test_name,
123                            timer_.LapsPerSecond(),
124                            "runs/s",
125                            true);
126   }
127 
RunScheduleAlternateTasksTest(const std::string & test_name,int num_top_level_tasks,int num_tasks,int num_leaf_tasks)128   void RunScheduleAlternateTasksTest(const std::string& test_name,
129                                      int num_top_level_tasks,
130                                      int num_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]);
140     }
141 
142     // Avoid unnecessary heap allocations by reusing the same graph and
143     // completed tasks vector.
144     TaskGraph graph;
145     Task::Vector completed_tasks;
146 
147     size_t count = 0;
148     timer_.Reset();
149     do {
150       graph.Reset();
151       BuildTaskGraph(top_level_tasks[count % kNumVersions],
152                      tasks[count % kNumVersions],
153                      leaf_tasks[count % kNumVersions],
154                      &graph);
155       task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
156       CollectCompletedTasks(&completed_tasks);
157       completed_tasks.clear();
158       ++count;
159       timer_.NextLap();
160     } while (!timer_.HasTimeLimitExpired());
161 
162     TaskGraph empty;
163     task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
164     CollectCompletedTasks(&completed_tasks);
165 
166     perf_test::PrintResult("schedule_alternate_tasks",
167                            TestModifierString(),
168                            test_name,
169                            timer_.LapsPerSecond(),
170                            "runs/s",
171                            true);
172   }
173 
RunScheduleAndExecuteTasksTest(const std::string & test_name,int num_top_level_tasks,int num_tasks,int num_leaf_tasks)174   void RunScheduleAndExecuteTasksTest(const std::string& test_name,
175                                       int num_top_level_tasks,
176                                       int num_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);
184 
185     // Avoid unnecessary heap allocations by reusing the same graph and
186     // completed tasks vector.
187     TaskGraph graph;
188     Task::Vector completed_tasks;
189 
190     timer_.Reset();
191     do {
192       graph.Reset();
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);
199       ResetTasks(&tasks);
200       ResetTasks(&leaf_tasks);
201       timer_.NextLap();
202     } while (!timer_.HasTimeLimitExpired());
203 
204     perf_test::PrintResult("execute_tasks",
205                            TestModifierString(),
206                            test_name,
207                            timer_.LapsPerSecond(),
208                            "runs/s",
209                            true);
210   }
211 
212  private:
TestModifierString()213   static std::string TestModifierString() {
214     return std::string("_task_graph_runner");
215   }
216 
CreateTasks(int num_tasks,PerfTaskImpl::Vector * tasks)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));
220   }
221 
ResetTasks(PerfTaskImpl::Vector * tasks)222   void ResetTasks(PerfTaskImpl::Vector* tasks) {
223     for (PerfTaskImpl::Vector::iterator it = tasks->begin(); it != tasks->end();
224          ++it) {
225       PerfTaskImpl* task = it->get();
226       task->Reset();
227     }
228   }
229 
BuildTaskGraph(const PerfTaskImpl::Vector & top_level_tasks,const PerfTaskImpl::Vector & tasks,const PerfTaskImpl::Vector & leaf_tasks,TaskGraph * graph)230   void BuildTaskGraph(const PerfTaskImpl::Vector& top_level_tasks,
231                       const PerfTaskImpl::Vector& tasks,
232                       const PerfTaskImpl::Vector& leaf_tasks,
233                       TaskGraph* graph) {
234     DCHECK(graph->nodes.empty());
235     DCHECK(graph->edges.empty());
236 
237     for (PerfTaskImpl::Vector::const_iterator it = leaf_tasks.begin();
238          it != leaf_tasks.end();
239          ++it) {
240       graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, 0u));
241     }
242 
243     for (PerfTaskImpl::Vector::const_iterator it = tasks.begin();
244          it != tasks.end();
245          ++it) {
246       graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, leaf_tasks.size()));
247 
248       for (PerfTaskImpl::Vector::const_iterator leaf_it = leaf_tasks.begin();
249            leaf_it != leaf_tasks.end();
250            ++leaf_it) {
251         graph->edges.push_back(TaskGraph::Edge(leaf_it->get(), it->get()));
252       }
253 
254       for (PerfTaskImpl::Vector::const_iterator top_level_it =
255                top_level_tasks.begin();
256            top_level_it != top_level_tasks.end();
257            ++top_level_it) {
258         graph->edges.push_back(TaskGraph::Edge(it->get(), top_level_it->get()));
259       }
260     }
261 
262     for (PerfTaskImpl::Vector::const_iterator it = top_level_tasks.begin();
263          it != top_level_tasks.end();
264          ++it) {
265       graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, tasks.size()));
266     }
267   }
268 
CollectCompletedTasks(Task::Vector * completed_tasks)269   size_t CollectCompletedTasks(Task::Vector* completed_tasks) {
270     DCHECK(completed_tasks->empty());
271     task_graph_runner_->CollectCompletedTasks(namespace_token_,
272                                               completed_tasks);
273     return completed_tasks->size();
274   }
275 
276   scoped_ptr<TaskGraphRunner> task_graph_runner_;
277   NamespaceToken namespace_token_;
278   LapTimer timer_;
279 };
280 
TEST_F(TaskGraphRunnerPerfTest,BuildTaskGraph)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);
288 }
289 
TEST_F(TaskGraphRunnerPerfTest,ScheduleTasks)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);
297 }
298 
TEST_F(TaskGraphRunnerPerfTest,ScheduleAlternateTasks)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);
306 }
307 
TEST_F(TaskGraphRunnerPerfTest,ScheduleAndExecuteTasks)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);
315 }
316 
317 }  // namespace
318 }  // namespace cc
319