Chromium Code Reviews| 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.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 { | |
|
Sami
2014/10/24 10:46:13
I wonder if we could just reuse cc/test/ordered_si
rmcilroy
2014/10/24 14:58:29
I'll look into whether this is possible.
| |
| 17 public: | |
| 18 DelaySupportingTestSimpleTaskRunner(base::SimpleTestTickClock* clock) | |
| 19 : clock_(clock) { } | |
| 20 | |
| 21 virtual bool PostDelayedTask( | |
| 22 const tracked_objects::Location& from_here, | |
| 23 const base::Closure& task, | |
| 24 base::TimeDelta delay) override { | |
| 25 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 26 pending_tasks_.push_back( | |
| 27 base::TestPendingTask(from_here, task, clock_->NowTicks(), delay, | |
| 28 base::TestPendingTask::NESTABLE)); | |
| 29 return true; | |
| 30 } | |
| 31 | |
| 32 virtual bool PostNonNestableDelayedTask( | |
| 33 const tracked_objects::Location& from_here, | |
| 34 const base::Closure& task, | |
| 35 base::TimeDelta delay) override { | |
| 36 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 37 pending_tasks_.push_back( | |
| 38 base::TestPendingTask(from_here, task, clock_->NowTicks(), delay, | |
| 39 base::TestPendingTask::NON_NESTABLE)); | |
| 40 return true; | |
| 41 } | |
| 42 | |
| 43 void RunPendingTasksIfNotDelayed() { | |
| 44 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 45 // Swap with a local variable to avoid re-entrancy problems. | |
| 46 std::deque<base::TestPendingTask> tasks_to_run; | |
| 47 tasks_to_run.swap(pending_tasks_); | |
| 48 for (std::deque<base::TestPendingTask>::iterator it = tasks_to_run.begin(); | |
| 49 it != tasks_to_run.end(); ++it) { | |
| 50 if (it->GetTimeToRun() <= clock_->NowTicks()) { | |
| 51 it->task.Run(); | |
| 52 } else { | |
| 53 pending_tasks_.push_front(*it); | |
| 54 } | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 void RunUntilTasksAreAllDelayed() { | |
| 59 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 60 while (!pending_tasks_.empty() && | |
| 61 pending_tasks_.front().GetTimeToRun() <= clock_->NowTicks()) { | |
| 62 RunPendingTasksIfNotDelayed(); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 protected: | |
| 67 virtual ~DelaySupportingTestSimpleTaskRunner() { } | |
| 68 | |
| 69 private: | |
| 70 base::SimpleTestTickClock* clock_; | |
| 71 }; | |
| 72 | |
| 73 class RendererSchedulerForTest : public RendererScheduler { | |
| 74 public: | |
| 75 RendererSchedulerForTest( | |
| 76 scoped_refptr<base::TestSimpleTaskRunner> task_runner, | |
| 77 base::SimpleTestTickClock* clock) | |
| 78 : RendererScheduler(task_runner), | |
| 79 clock_(clock) { } | |
| 80 virtual ~RendererSchedulerForTest() { } | |
| 81 | |
| 82 protected: | |
| 83 virtual base::TimeTicks Now() const override { | |
| 84 return clock_->NowTicks(); | |
| 85 } | |
| 86 | |
| 87 private: | |
| 88 base::SimpleTestTickClock* clock_; | |
| 89 }; | |
| 90 | |
| 91 class RendererSchedulerTest : public testing::Test { | |
| 92 public: | |
| 93 RendererSchedulerTest() | |
| 94 : clock_(new base::SimpleTestTickClock()), | |
| 95 mock_task_runner_(new DelaySupportingTestSimpleTaskRunner(clock_.get())), | |
| 96 scheduler_(new RendererSchedulerForTest(mock_task_runner_, clock_.get())), | |
| 97 default_task_runner_(scheduler_->DefaultTaskRunner()), | |
| 98 compositor_task_runner_(scheduler_->CompositorTaskRunner()), | |
| 99 idle_task_runner_(scheduler_->IdleTaskRunner()) { } | |
| 100 virtual ~RendererSchedulerTest() { } | |
| 101 | |
| 102 void RunUntilIdle() { | |
| 103 mock_task_runner_->RunUntilTasksAreAllDelayed(); | |
| 104 } | |
| 105 | |
| 106 void EnableIdleTasks() { | |
| 107 scheduler_->WillBeginFrame( | |
| 108 cc::BeginFrameArgs::Create(clock_->NowTicks(), | |
| 109 base::TimeTicks(), | |
| 110 base::TimeDelta::FromMilliseconds(1000))); | |
| 111 clock_->Advance(base::TimeDelta::FromMilliseconds(800)); | |
| 112 scheduler_->DidCommitFrameToCompositor(); | |
| 113 } | |
| 114 | |
| 115 protected: | |
| 116 virtual void SetUp() override { | |
| 117 // Ensure clock is non-zero. | |
| 118 clock_->Advance(base::TimeDelta::FromMilliseconds(5000)); | |
| 119 } | |
| 120 | |
| 121 scoped_ptr<base::SimpleTestTickClock> clock_; | |
| 122 scoped_refptr<DelaySupportingTestSimpleTaskRunner> mock_task_runner_; | |
| 123 | |
| 124 scoped_ptr<RendererScheduler> scheduler_; | |
| 125 scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; | |
| 126 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_; | |
| 127 scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; | |
| 128 | |
| 129 DISALLOW_COPY_AND_ASSIGN(RendererSchedulerTest); | |
| 130 }; | |
| 131 | |
| 132 void OrderedTestTask(int value, int* result) { | |
| 133 *result = (*result << 4) | value; | |
| 134 } | |
| 135 | |
| 136 void UnorderedTestTask(int value, int* result) { | |
| 137 *result += value; | |
| 138 } | |
| 139 | |
| 140 void AppendToVectorTestTask( | |
| 141 std::vector<std::string>* vector, std::string value) { | |
| 142 vector->push_back(value); | |
| 143 } | |
| 144 | |
| 145 void AppendToVectorIdleTestTask( | |
| 146 std::vector<std::string>* vector, | |
| 147 std::string value, | |
| 148 base::TimeTicks deadline) { | |
| 149 AppendToVectorTestTask(vector, value); | |
| 150 } | |
| 151 | |
| 152 void IdleTestTask( | |
| 153 bool* task_run, | |
| 154 base::TimeTicks expected_deadline, | |
| 155 base::TimeTicks deadline) { | |
| 156 EXPECT_FALSE(*task_run); | |
| 157 EXPECT_EQ(expected_deadline, deadline); | |
| 158 *task_run = true; | |
| 159 } | |
| 160 | |
| 161 void RepostingIdleTestTask( | |
| 162 scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner, | |
| 163 int* run_count, | |
| 164 base::TimeTicks deadline) { | |
| 165 if (*run_count == 0) | |
| 166 idle_task_runner->PostIdleTask(FROM_HERE, | |
| 167 base::Bind(&RepostingIdleTestTask, idle_task_runner, run_count)); | |
| 168 (*run_count)++; | |
| 169 } | |
| 170 | |
| 171 TEST_F(RendererSchedulerTest, TestPostDefaultTask) { | |
| 172 int result = 0; | |
| 173 default_task_runner_->PostTask(FROM_HERE, | |
| 174 base::Bind(OrderedTestTask, 1, &result)); | |
| 175 default_task_runner_->PostTask(FROM_HERE, | |
| 176 base::Bind(OrderedTestTask, 2, &result)); | |
| 177 default_task_runner_->PostTask(FROM_HERE, | |
| 178 base::Bind(OrderedTestTask, 3, &result)); | |
| 179 default_task_runner_->PostTask(FROM_HERE, | |
| 180 base::Bind(OrderedTestTask, 4, &result)); | |
| 181 RunUntilIdle(); | |
| 182 EXPECT_EQ(0x1234, result); | |
| 183 } | |
| 184 | |
| 185 TEST_F(RendererSchedulerTest, TestPostDefaultAndCompositor) { | |
| 186 int result = 0; | |
| 187 default_task_runner_->PostTask(FROM_HERE, | |
| 188 base::Bind(&UnorderedTestTask, 1, &result)); | |
| 189 compositor_task_runner_->PostTask(FROM_HERE, | |
| 190 base::Bind(&UnorderedTestTask, 2, &result)); | |
| 191 RunUntilIdle(); | |
| 192 EXPECT_EQ(3, result); | |
| 193 } | |
| 194 | |
| 195 TEST_F(RendererSchedulerTest, TestPostIdleTask) { | |
| 196 bool task_run = false; | |
| 197 base::TimeTicks expected_deadline = | |
| 198 clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300); | |
| 199 | |
| 200 clock_->Advance(base::TimeDelta::FromMilliseconds(100)); | |
| 201 idle_task_runner_->PostIdleTask(FROM_HERE, | |
| 202 base::Bind(&IdleTestTask, &task_run, expected_deadline)); | |
| 203 | |
| 204 RunUntilIdle(); | |
| 205 EXPECT_FALSE(task_run); // Shouldn't run yet as no WillBeginFrame. | |
| 206 | |
| 207 scheduler_->WillBeginFrame( | |
| 208 cc::BeginFrameArgs::Create(clock_->NowTicks(), | |
| 209 base::TimeTicks(), | |
| 210 base::TimeDelta::FromMilliseconds(1000))); | |
| 211 RunUntilIdle(); | |
| 212 EXPECT_FALSE(task_run); // Shouldn't run as no didCommitFrameToCompositor. | |
| 213 | |
| 214 clock_->Advance(base::TimeDelta::FromMilliseconds(1200)); | |
| 215 scheduler_->DidCommitFrameToCompositor(); | |
| 216 RunUntilIdle(); | |
| 217 EXPECT_FALSE(task_run); // We missed the deadline. | |
| 218 | |
| 219 scheduler_->WillBeginFrame( | |
| 220 cc::BeginFrameArgs::Create(clock_->NowTicks(), | |
| 221 base::TimeTicks(), | |
| 222 base::TimeDelta::FromMilliseconds(1000))); | |
| 223 clock_->Advance(base::TimeDelta::FromMilliseconds(800)); | |
| 224 scheduler_->DidCommitFrameToCompositor(); | |
| 225 RunUntilIdle(); | |
| 226 EXPECT_TRUE(task_run); | |
| 227 } | |
| 228 | |
| 229 TEST_F(RendererSchedulerTest, TestRepostingIdleTask) { | |
| 230 int run_count = 0; | |
| 231 | |
| 232 idle_task_runner_->PostIdleTask(FROM_HERE, | |
| 233 base::Bind(&RepostingIdleTestTask, idle_task_runner_, &run_count)); | |
| 234 EnableIdleTasks(); | |
| 235 RunUntilIdle(); | |
| 236 EXPECT_EQ(1, run_count); | |
| 237 | |
| 238 // Reposted tasks shouldn't run until next idle period. | |
| 239 RunUntilIdle(); | |
| 240 EXPECT_EQ(1, run_count); | |
| 241 | |
| 242 EnableIdleTasks(); | |
| 243 RunUntilIdle(); | |
| 244 EXPECT_EQ(2, run_count); | |
| 245 } | |
| 246 | |
| 247 TEST_F(RendererSchedulerTest, TestDefaultPolicy) { | |
| 248 std::vector<std::string> order; | |
| 249 | |
| 250 idle_task_runner_->PostIdleTask(FROM_HERE, | |
| 251 base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1"))); | |
| 252 default_task_runner_->PostTask(FROM_HERE, | |
| 253 base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); | |
| 254 compositor_task_runner_->PostTask(FROM_HERE, | |
| 255 base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); | |
| 256 default_task_runner_->PostTask(FROM_HERE, | |
| 257 base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); | |
| 258 compositor_task_runner_->PostTask(FROM_HERE, | |
| 259 base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); | |
| 260 | |
| 261 EnableIdleTasks(); | |
| 262 RunUntilIdle(); | |
| 263 EXPECT_THAT(order, testing::ElementsAre( | |
| 264 std::string("D1"), std::string("C1"), std::string("D2"), | |
| 265 std::string("C2"), std::string("I1"))); | |
| 266 } | |
| 267 | |
| 268 TEST_F(RendererSchedulerTest, TestCompositorPolicy) { | |
| 269 std::vector<std::string> order; | |
| 270 | |
| 271 idle_task_runner_->PostIdleTask(FROM_HERE, | |
| 272 base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1"))); | |
| 273 default_task_runner_->PostTask(FROM_HERE, | |
| 274 base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); | |
| 275 compositor_task_runner_->PostTask(FROM_HERE, | |
| 276 base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); | |
| 277 default_task_runner_->PostTask(FROM_HERE, | |
| 278 base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); | |
| 279 compositor_task_runner_->PostTask(FROM_HERE, | |
| 280 base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); | |
| 281 | |
| 282 scheduler_->DidReceiveInputEvent(); | |
| 283 EnableIdleTasks(); | |
| 284 RunUntilIdle(); | |
| 285 EXPECT_THAT(order, testing::ElementsAre( | |
| 286 std::string("C1"), std::string("C2"), std::string("D1"), | |
| 287 std::string("D2"), std::string("I1"))); | |
| 288 } | |
| 289 | |
| 290 } // namespace content | |
| OLD | NEW |