| 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 |