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 "content/renderer/scheduler/renderer_scheduler_impl.h" |
| 6 |
| 7 #include "base/callback.h" |
| 8 #include "base/test/simple_test_tick_clock.h" |
| 9 #include "base/test/test_simple_task_runner.h" |
| 10 #include "cc/output/begin_frame_args.h" |
| 11 #include "testing/gmock/include/gmock/gmock.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 |
| 14 namespace content { |
| 15 |
| 16 class DelaySupportingTestSimpleTaskRunner : public base::TestSimpleTaskRunner { |
| 17 public: |
| 18 DelaySupportingTestSimpleTaskRunner(base::SimpleTestTickClock* clock) |
| 19 : clock_(clock) {} |
| 20 |
| 21 virtual bool PostDelayedTask(const tracked_objects::Location& from_here, |
| 22 const base::Closure& task, |
| 23 base::TimeDelta delay) override { |
| 24 DCHECK(thread_checker_.CalledOnValidThread()); |
| 25 pending_tasks_.push_back( |
| 26 base::TestPendingTask(from_here, |
| 27 task, |
| 28 clock_->NowTicks(), |
| 29 delay, |
| 30 base::TestPendingTask::NESTABLE)); |
| 31 return true; |
| 32 } |
| 33 |
| 34 virtual bool PostNonNestableDelayedTask( |
| 35 const tracked_objects::Location& from_here, |
| 36 const base::Closure& task, |
| 37 base::TimeDelta delay) override { |
| 38 DCHECK(thread_checker_.CalledOnValidThread()); |
| 39 pending_tasks_.push_back( |
| 40 base::TestPendingTask(from_here, |
| 41 task, |
| 42 clock_->NowTicks(), |
| 43 delay, |
| 44 base::TestPendingTask::NON_NESTABLE)); |
| 45 return true; |
| 46 } |
| 47 |
| 48 bool HaveRunnablePendingTasks() { |
| 49 for (base::TestPendingTask pending_task : pending_tasks_) { |
| 50 if (pending_task.GetTimeToRun() <= clock_->NowTicks()) { |
| 51 return true; |
| 52 } |
| 53 } |
| 54 return false; |
| 55 } |
| 56 |
| 57 void RunPendingTasksIfNotDelayed() { |
| 58 DCHECK(thread_checker_.CalledOnValidThread()); |
| 59 // Swap with a local variable to avoid re-entrancy problems. |
| 60 std::deque<base::TestPendingTask> tasks_to_run; |
| 61 tasks_to_run.swap(pending_tasks_); |
| 62 for (base::TestPendingTask pending_task : tasks_to_run) { |
| 63 if (pending_task.GetTimeToRun() <= clock_->NowTicks()) { |
| 64 pending_task.task.Run(); |
| 65 } else { |
| 66 pending_tasks_.push_front(pending_task); |
| 67 } |
| 68 } |
| 69 } |
| 70 |
| 71 void RunUntilTasksAreAllDelayed() { |
| 72 DCHECK(thread_checker_.CalledOnValidThread()); |
| 73 while (!pending_tasks_.empty() && HaveRunnablePendingTasks()) { |
| 74 RunPendingTasksIfNotDelayed(); |
| 75 } |
| 76 } |
| 77 |
| 78 protected: |
| 79 virtual ~DelaySupportingTestSimpleTaskRunner() {} |
| 80 |
| 81 private: |
| 82 base::SimpleTestTickClock* clock_; |
| 83 }; |
| 84 |
| 85 class RendererSchedulerImplForTest : public RendererSchedulerImpl { |
| 86 public: |
| 87 RendererSchedulerImplForTest( |
| 88 scoped_refptr<base::TestSimpleTaskRunner> task_runner, |
| 89 base::SimpleTestTickClock* clock) |
| 90 : RendererSchedulerImpl(task_runner), clock_(clock) {} |
| 91 virtual ~RendererSchedulerImplForTest() {} |
| 92 |
| 93 protected: |
| 94 virtual base::TimeTicks Now() const override { return clock_->NowTicks(); } |
| 95 |
| 96 private: |
| 97 base::SimpleTestTickClock* clock_; |
| 98 }; |
| 99 |
| 100 class RendererSchedulerImplTest : public testing::Test { |
| 101 public: |
| 102 RendererSchedulerImplTest() |
| 103 : clock_(new base::SimpleTestTickClock()), |
| 104 mock_task_runner_( |
| 105 new DelaySupportingTestSimpleTaskRunner(clock_.get())), |
| 106 scheduler_( |
| 107 new RendererSchedulerImplForTest(mock_task_runner_, clock_.get())), |
| 108 default_task_runner_(scheduler_->DefaultTaskRunner()), |
| 109 compositor_task_runner_(scheduler_->CompositorTaskRunner()), |
| 110 idle_task_runner_(scheduler_->IdleTaskRunner()) {} |
| 111 virtual ~RendererSchedulerImplTest() {} |
| 112 |
| 113 void RunUntilIdle() { mock_task_runner_->RunUntilTasksAreAllDelayed(); } |
| 114 |
| 115 void EnableIdleTasks() { |
| 116 scheduler_->WillBeginFrame( |
| 117 cc::BeginFrameArgs::Create(clock_->NowTicks(), |
| 118 base::TimeTicks(), |
| 119 base::TimeDelta::FromMilliseconds(1000))); |
| 120 scheduler_->DidCommitFrameToCompositor(); |
| 121 } |
| 122 |
| 123 protected: |
| 124 virtual void SetUp() override { |
| 125 // Ensure clock is non-zero. |
| 126 clock_->Advance(base::TimeDelta::FromMilliseconds(5000)); |
| 127 } |
| 128 |
| 129 scoped_ptr<base::SimpleTestTickClock> clock_; |
| 130 scoped_refptr<DelaySupportingTestSimpleTaskRunner> mock_task_runner_; |
| 131 |
| 132 scoped_ptr<RendererSchedulerImpl> scheduler_; |
| 133 scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; |
| 134 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_; |
| 135 scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; |
| 136 |
| 137 DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest); |
| 138 }; |
| 139 |
| 140 void NullTask() { |
| 141 } |
| 142 |
| 143 void OrderedTestTask(int value, int* result) { |
| 144 *result = (*result << 4) | value; |
| 145 } |
| 146 |
| 147 void UnorderedTestTask(int value, int* result) { |
| 148 *result += value; |
| 149 } |
| 150 |
| 151 void AppendToVectorTestTask(std::vector<std::string>* vector, |
| 152 std::string value) { |
| 153 vector->push_back(value); |
| 154 } |
| 155 |
| 156 void AppendToVectorIdleTestTask(std::vector<std::string>* vector, |
| 157 std::string value, |
| 158 base::TimeTicks deadline) { |
| 159 AppendToVectorTestTask(vector, value); |
| 160 } |
| 161 |
| 162 void AppendToVectorReentrantTask( |
| 163 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 164 std::vector<int>* vector, |
| 165 int* reentrant_count, |
| 166 int max_reentrant_count) { |
| 167 vector->push_back((*reentrant_count)++); |
| 168 if (*reentrant_count < max_reentrant_count) { |
| 169 task_runner->PostTask(FROM_HERE, |
| 170 base::Bind(AppendToVectorReentrantTask, |
| 171 task_runner, |
| 172 vector, |
| 173 reentrant_count, |
| 174 max_reentrant_count)); |
| 175 } |
| 176 } |
| 177 |
| 178 void IdleTestTask(bool* task_run, |
| 179 base::TimeTicks expected_deadline, |
| 180 base::TimeTicks deadline) { |
| 181 EXPECT_FALSE(*task_run); |
| 182 EXPECT_EQ(expected_deadline, deadline); |
| 183 *task_run = true; |
| 184 } |
| 185 |
| 186 void RepostingIdleTestTask( |
| 187 scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner, |
| 188 int* run_count, |
| 189 base::TimeTicks deadline) { |
| 190 if (*run_count == 0) |
| 191 idle_task_runner->PostIdleTask( |
| 192 FROM_HERE, |
| 193 base::Bind(&RepostingIdleTestTask, idle_task_runner, run_count)); |
| 194 (*run_count)++; |
| 195 } |
| 196 |
| 197 TEST_F(RendererSchedulerImplTest, TestPostDefaultTask) { |
| 198 int result = 0; |
| 199 default_task_runner_->PostTask(FROM_HERE, |
| 200 base::Bind(OrderedTestTask, 1, &result)); |
| 201 default_task_runner_->PostTask(FROM_HERE, |
| 202 base::Bind(OrderedTestTask, 2, &result)); |
| 203 default_task_runner_->PostTask(FROM_HERE, |
| 204 base::Bind(OrderedTestTask, 3, &result)); |
| 205 default_task_runner_->PostTask(FROM_HERE, |
| 206 base::Bind(OrderedTestTask, 4, &result)); |
| 207 RunUntilIdle(); |
| 208 EXPECT_EQ(0x1234, result); |
| 209 } |
| 210 |
| 211 TEST_F(RendererSchedulerImplTest, TestPostDefaultAndCompositor) { |
| 212 int result = 0; |
| 213 default_task_runner_->PostTask(FROM_HERE, |
| 214 base::Bind(&UnorderedTestTask, 1, &result)); |
| 215 compositor_task_runner_->PostTask(FROM_HERE, |
| 216 base::Bind(&UnorderedTestTask, 2, &result)); |
| 217 RunUntilIdle(); |
| 218 EXPECT_EQ(3, result); |
| 219 } |
| 220 |
| 221 TEST_F(RendererSchedulerImplTest, TestRentrantTask) { |
| 222 int count = 0; |
| 223 std::vector<int> order; |
| 224 default_task_runner_->PostTask(FROM_HERE, |
| 225 base::Bind(AppendToVectorReentrantTask, |
| 226 default_task_runner_, |
| 227 &order, |
| 228 &count, |
| 229 5)); |
| 230 RunUntilIdle(); |
| 231 |
| 232 EXPECT_THAT(order, testing::ElementsAre(0, 1, 2, 3, 4)); |
| 233 } |
| 234 |
| 235 TEST_F(RendererSchedulerImplTest, TestPostIdleTask) { |
| 236 bool task_run = false; |
| 237 base::TimeTicks expected_deadline = |
| 238 clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300); |
| 239 |
| 240 clock_->Advance(base::TimeDelta::FromMilliseconds(100)); |
| 241 idle_task_runner_->PostIdleTask( |
| 242 FROM_HERE, base::Bind(&IdleTestTask, &task_run, expected_deadline)); |
| 243 |
| 244 RunUntilIdle(); |
| 245 EXPECT_FALSE(task_run); // Shouldn't run yet as no WillBeginFrame. |
| 246 |
| 247 scheduler_->WillBeginFrame( |
| 248 cc::BeginFrameArgs::Create(clock_->NowTicks(), |
| 249 base::TimeTicks(), |
| 250 base::TimeDelta::FromMilliseconds(1000))); |
| 251 RunUntilIdle(); |
| 252 EXPECT_FALSE(task_run); // Shouldn't run as no didCommitFrameToCompositor. |
| 253 |
| 254 clock_->Advance(base::TimeDelta::FromMilliseconds(1200)); |
| 255 scheduler_->DidCommitFrameToCompositor(); |
| 256 RunUntilIdle(); |
| 257 EXPECT_FALSE(task_run); // We missed the deadline. |
| 258 |
| 259 scheduler_->WillBeginFrame( |
| 260 cc::BeginFrameArgs::Create(clock_->NowTicks(), |
| 261 base::TimeTicks(), |
| 262 base::TimeDelta::FromMilliseconds(1000))); |
| 263 clock_->Advance(base::TimeDelta::FromMilliseconds(800)); |
| 264 scheduler_->DidCommitFrameToCompositor(); |
| 265 RunUntilIdle(); |
| 266 EXPECT_TRUE(task_run); |
| 267 } |
| 268 |
| 269 TEST_F(RendererSchedulerImplTest, TestRepostingIdleTask) { |
| 270 int run_count = 0; |
| 271 |
| 272 idle_task_runner_->PostIdleTask( |
| 273 FROM_HERE, |
| 274 base::Bind(&RepostingIdleTestTask, idle_task_runner_, &run_count)); |
| 275 EnableIdleTasks(); |
| 276 RunUntilIdle(); |
| 277 EXPECT_EQ(1, run_count); |
| 278 |
| 279 // Reposted tasks shouldn't run until next idle period. |
| 280 RunUntilIdle(); |
| 281 EXPECT_EQ(1, run_count); |
| 282 |
| 283 EnableIdleTasks(); |
| 284 RunUntilIdle(); |
| 285 EXPECT_EQ(2, run_count); |
| 286 } |
| 287 |
| 288 TEST_F(RendererSchedulerImplTest, TestDefaultPolicy) { |
| 289 std::vector<std::string> order; |
| 290 |
| 291 idle_task_runner_->PostIdleTask( |
| 292 FROM_HERE, |
| 293 base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1"))); |
| 294 default_task_runner_->PostTask( |
| 295 FROM_HERE, |
| 296 base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); |
| 297 compositor_task_runner_->PostTask( |
| 298 FROM_HERE, |
| 299 base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); |
| 300 default_task_runner_->PostTask( |
| 301 FROM_HERE, |
| 302 base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); |
| 303 compositor_task_runner_->PostTask( |
| 304 FROM_HERE, |
| 305 base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); |
| 306 |
| 307 EnableIdleTasks(); |
| 308 RunUntilIdle(); |
| 309 EXPECT_THAT(order, |
| 310 testing::ElementsAre(std::string("D1"), |
| 311 std::string("C1"), |
| 312 std::string("D2"), |
| 313 std::string("C2"), |
| 314 std::string("I1"))); |
| 315 } |
| 316 |
| 317 TEST_F(RendererSchedulerImplTest, TestCompositorPolicy) { |
| 318 std::vector<std::string> order; |
| 319 |
| 320 idle_task_runner_->PostIdleTask( |
| 321 FROM_HERE, |
| 322 base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1"))); |
| 323 default_task_runner_->PostTask( |
| 324 FROM_HERE, |
| 325 base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); |
| 326 compositor_task_runner_->PostTask( |
| 327 FROM_HERE, |
| 328 base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); |
| 329 default_task_runner_->PostTask( |
| 330 FROM_HERE, |
| 331 base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); |
| 332 compositor_task_runner_->PostTask( |
| 333 FROM_HERE, |
| 334 base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); |
| 335 |
| 336 scheduler_->DidReceiveInputEvent(); |
| 337 EnableIdleTasks(); |
| 338 RunUntilIdle(); |
| 339 EXPECT_THAT(order, |
| 340 testing::ElementsAre(std::string("C1"), |
| 341 std::string("C2"), |
| 342 std::string("D1"), |
| 343 std::string("D2"), |
| 344 std::string("I1"))); |
| 345 } |
| 346 |
| 347 TEST_F(RendererSchedulerImplTest, |
| 348 TestCompositorPolicyDoesNotStarveDefaultTasks) { |
| 349 std::vector<std::string> order; |
| 350 |
| 351 default_task_runner_->PostTask( |
| 352 FROM_HERE, |
| 353 base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); |
| 354 compositor_task_runner_->PostTask( |
| 355 FROM_HERE, |
| 356 base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); |
| 357 for (int i = 0; i < 20; i++) { |
| 358 compositor_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); |
| 359 } |
| 360 compositor_task_runner_->PostTask( |
| 361 FROM_HERE, |
| 362 base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); |
| 363 |
| 364 scheduler_->DidReceiveInputEvent(); |
| 365 RunUntilIdle(); |
| 366 // Ensure that the default D1 task gets to run at some point before the final |
| 367 // C2 compositor task. |
| 368 EXPECT_THAT(order, |
| 369 testing::ElementsAre( |
| 370 std::string("C1"), std::string("D1"), std::string("C2"))); |
| 371 } |
| 372 |
| 373 TEST_F(RendererSchedulerImplTest, TestCompositorPolicyEnds) { |
| 374 std::vector<std::string> order; |
| 375 |
| 376 default_task_runner_->PostTask( |
| 377 FROM_HERE, |
| 378 base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); |
| 379 compositor_task_runner_->PostTask( |
| 380 FROM_HERE, |
| 381 base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); |
| 382 default_task_runner_->PostTask( |
| 383 FROM_HERE, |
| 384 base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); |
| 385 compositor_task_runner_->PostTask( |
| 386 FROM_HERE, |
| 387 base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); |
| 388 |
| 389 scheduler_->DidReceiveInputEvent(); |
| 390 RunUntilIdle(); |
| 391 EXPECT_THAT(order, |
| 392 testing::ElementsAre(std::string("C1"), |
| 393 std::string("C2"), |
| 394 std::string("D1"), |
| 395 std::string("D2"))); |
| 396 |
| 397 order.clear(); |
| 398 clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); |
| 399 |
| 400 default_task_runner_->PostTask( |
| 401 FROM_HERE, |
| 402 base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); |
| 403 compositor_task_runner_->PostTask( |
| 404 FROM_HERE, |
| 405 base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); |
| 406 default_task_runner_->PostTask( |
| 407 FROM_HERE, |
| 408 base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); |
| 409 compositor_task_runner_->PostTask( |
| 410 FROM_HERE, |
| 411 base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); |
| 412 |
| 413 // Compositor policy mode should have ended now that the clock has advanced. |
| 414 RunUntilIdle(); |
| 415 EXPECT_THAT(order, |
| 416 testing::ElementsAre(std::string("D1"), |
| 417 std::string("C1"), |
| 418 std::string("D2"), |
| 419 std::string("C2"))); |
| 420 } |
| 421 |
| 422 } // namespace content |
OLD | NEW |