Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(169)

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper_unittest.cc

Issue 2258133002: [scheduler] Implement time-based cpu throttling. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use double instead of base::TimeTicks Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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 "platform/scheduler/renderer/throttling_helper.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10
11 #include "base/callback.h"
12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/test/simple_test_tick_clock.h"
15 #include "cc/test/ordered_simple_task_runner.h"
16 #include "platform/scheduler/base/test_time_source.h"
17 #include "platform/scheduler/base/real_time_domain.h"
18 #include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h"
19 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h"
20 #include "platform/scheduler/renderer/renderer_scheduler_impl.h"
21 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h"
22 #include "platform/scheduler/renderer/web_view_scheduler_impl.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using testing::ElementsAre;
27
28 namespace blink {
29 namespace scheduler {
30
31 namespace {
32 void RunTenTimesTask(size_t* count, scoped_refptr<TaskQueue> timer_queue) {
33 if (++(*count) < 10) {
34 timer_queue->PostTask(FROM_HERE,
35 base::Bind(&RunTenTimesTask, count, timer_queue));
36 }
37 }
38 }
39
40 class ThrottlingHelperTest : public testing::Test {
41 public:
42 ThrottlingHelperTest() {}
43 ~ThrottlingHelperTest() override {}
44
45 void SetUp() override {
46 clock_.reset(new base::SimpleTestTickClock());
47 clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
48 mock_task_runner_ =
49 make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true));
50 delegate_ = SchedulerTqmDelegateForTest::Create(
51 mock_task_runner_, base::MakeUnique<TestTimeSource>(clock_.get()));
52 scheduler_.reset(new RendererSchedulerImpl(delegate_));
53 throttling_helper_ = scheduler_->throttling_helper();
54 timer_queue_ = scheduler_->NewTimerTaskRunner("test_queue");
55 }
56
57 void TearDown() override {
58 scheduler_->Shutdown();
59 scheduler_.reset();
60 }
61
62 void ExpectThrottled(scoped_refptr<TaskQueue> timer_queue) {
63 size_t count = 0;
64 timer_queue->PostTask(FROM_HERE,
65 base::Bind(&RunTenTimesTask, &count, timer_queue));
66
67 mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
68 EXPECT_LE(count, 1u);
69
70 // Make sure the rest of the tasks run or we risk a UAF on |count|.
71 mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(10));
72 EXPECT_EQ(10u, count);
73 }
74
75 void ExpectUnthrottled(scoped_refptr<TaskQueue> timer_queue) {
76 size_t count = 0;
77 timer_queue->PostTask(FROM_HERE,
78 base::Bind(&RunTenTimesTask, &count, timer_queue));
79
80 mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
81 EXPECT_EQ(10u, count);
82 mock_task_runner_->RunUntilIdle();
83 }
84
85 protected:
86 std::unique_ptr<base::SimpleTestTickClock> clock_;
87 scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
88 scoped_refptr<SchedulerTqmDelegate> delegate_;
89 std::unique_ptr<RendererSchedulerImpl> scheduler_;
90 scoped_refptr<TaskQueue> timer_queue_;
91 ThrottlingHelper* throttling_helper_; // NOT OWNED
92
93 DISALLOW_COPY_AND_ASSIGN(ThrottlingHelperTest);
94 };
95
96 TEST_F(ThrottlingHelperTest, ThrottledRunTime) {
97 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
98 ThrottlingHelper::ThrottledRunTime(
99 base::TimeTicks() + base::TimeDelta::FromSecondsD(0.0)));
100
101 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
102 ThrottlingHelper::ThrottledRunTime(
103 base::TimeTicks() + base::TimeDelta::FromSecondsD(0.1)));
104
105 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
106 ThrottlingHelper::ThrottledRunTime(
107 base::TimeTicks() + base::TimeDelta::FromSecondsD(0.2)));
108
109 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
110 ThrottlingHelper::ThrottledRunTime(
111 base::TimeTicks() + base::TimeDelta::FromSecondsD(0.5)));
112
113 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
114 ThrottlingHelper::ThrottledRunTime(
115 base::TimeTicks() + base::TimeDelta::FromSecondsD(0.8)));
116
117 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
118 ThrottlingHelper::ThrottledRunTime(
119 base::TimeTicks() + base::TimeDelta::FromSecondsD(0.9)));
120
121 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(2.0),
122 ThrottlingHelper::ThrottledRunTime(
123 base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0)));
124
125 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(2.0),
126 ThrottlingHelper::ThrottledRunTime(
127 base::TimeTicks() + base::TimeDelta::FromSecondsD(1.1)));
128
129 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(9.0),
130 ThrottlingHelper::ThrottledRunTime(
131 base::TimeTicks() + base::TimeDelta::FromSecondsD(8.0)));
132
133 EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(9.0),
134 ThrottlingHelper::ThrottledRunTime(
135 base::TimeTicks() + base::TimeDelta::FromSecondsD(8.1)));
136 }
137
138 namespace {
139 void TestTask(std::vector<base::TimeTicks>* run_times,
140 base::SimpleTestTickClock* clock) {
141 run_times->push_back(clock->NowTicks());
142 }
143 } // namespace
144
145 TEST_F(ThrottlingHelperTest, TimerAlignment) {
146 std::vector<base::TimeTicks> run_times;
147 timer_queue_->PostDelayedTask(FROM_HERE,
148 base::Bind(&TestTask, &run_times, clock_.get()),
149 base::TimeDelta::FromMilliseconds(200.0));
150
151 timer_queue_->PostDelayedTask(FROM_HERE,
152 base::Bind(&TestTask, &run_times, clock_.get()),
153 base::TimeDelta::FromMilliseconds(800.0));
154
155 timer_queue_->PostDelayedTask(FROM_HERE,
156 base::Bind(&TestTask, &run_times, clock_.get()),
157 base::TimeDelta::FromMilliseconds(1200.0));
158
159 timer_queue_->PostDelayedTask(FROM_HERE,
160 base::Bind(&TestTask, &run_times, clock_.get()),
161 base::TimeDelta::FromMilliseconds(8300.0));
162
163 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
164
165 mock_task_runner_->RunUntilIdle();
166
167 // Times are aligned to a multipple of 1000 milliseconds.
168 EXPECT_THAT(
169 run_times,
170 ElementsAre(
171 base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
172 base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
173 base::TimeTicks() + base::TimeDelta::FromMilliseconds(2000.0),
174 base::TimeTicks() + base::TimeDelta::FromMilliseconds(9000.0)));
175 }
176
177 TEST_F(ThrottlingHelperTest, TimerAlignment_Unthrottled) {
178 std::vector<base::TimeTicks> run_times;
179 base::TimeTicks start_time = clock_->NowTicks();
180 timer_queue_->PostDelayedTask(FROM_HERE,
181 base::Bind(&TestTask, &run_times, clock_.get()),
182 base::TimeDelta::FromMilliseconds(200.0));
183
184 timer_queue_->PostDelayedTask(FROM_HERE,
185 base::Bind(&TestTask, &run_times, clock_.get()),
186 base::TimeDelta::FromMilliseconds(800.0));
187
188 timer_queue_->PostDelayedTask(FROM_HERE,
189 base::Bind(&TestTask, &run_times, clock_.get()),
190 base::TimeDelta::FromMilliseconds(1200.0));
191
192 timer_queue_->PostDelayedTask(FROM_HERE,
193 base::Bind(&TestTask, &run_times, clock_.get()),
194 base::TimeDelta::FromMilliseconds(8300.0));
195
196 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
197 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
198
199 mock_task_runner_->RunUntilIdle();
200
201 // Times are not aligned.
202 EXPECT_THAT(
203 run_times,
204 ElementsAre(start_time + base::TimeDelta::FromMilliseconds(200.0),
205 start_time + base::TimeDelta::FromMilliseconds(800.0),
206 start_time + base::TimeDelta::FromMilliseconds(1200.0),
207 start_time + base::TimeDelta::FromMilliseconds(8300.0)));
208 }
209
210 TEST_F(ThrottlingHelperTest, Refcount) {
211 ExpectUnthrottled(timer_queue_.get());
212
213 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
214 ExpectThrottled(timer_queue_);
215
216 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
217 ExpectThrottled(timer_queue_);
218
219 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
220 ExpectThrottled(timer_queue_);
221
222 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
223 ExpectUnthrottled(timer_queue_);
224
225 // Should be a NOP.
226 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
227 ExpectUnthrottled(timer_queue_);
228
229 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
230 ExpectThrottled(timer_queue_);
231 }
232
233 TEST_F(ThrottlingHelperTest,
234 ThrotlingAnEmptyQueueDoesNotPostPumpThrottledTasksLocked) {
235 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
236
237 EXPECT_TRUE(throttling_helper_->task_runner()->IsEmpty());
238 }
239
240 TEST_F(ThrottlingHelperTest, WakeUpForNonDelayedTask) {
241 std::vector<base::TimeTicks> run_times;
242
243 // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick.
244 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
245
246 // Posting a task should trigger the pump.
247 timer_queue_->PostTask(FROM_HERE,
248 base::Bind(&TestTask, &run_times, clock_.get()));
249
250 mock_task_runner_->RunUntilIdle();
251 EXPECT_THAT(run_times,
252 ElementsAre(base::TimeTicks() +
253 base::TimeDelta::FromMilliseconds(1000.0)));
254 }
255
256 TEST_F(ThrottlingHelperTest, WakeUpForDelayedTask) {
257 std::vector<base::TimeTicks> run_times;
258
259 // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick.
260 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
261
262 // Posting a task should trigger the pump.
263 timer_queue_->PostDelayedTask(FROM_HERE,
264 base::Bind(&TestTask, &run_times, clock_.get()),
265 base::TimeDelta::FromMilliseconds(1200.0));
266
267 mock_task_runner_->RunUntilIdle();
268 EXPECT_THAT(run_times,
269 ElementsAre(base::TimeTicks() +
270 base::TimeDelta::FromMilliseconds(2000.0)));
271 }
272
273 namespace {
274 bool MessageLoopTaskCounter(size_t* count) {
275 *count = *count + 1;
276 return true;
277 }
278
279 void NopTask() {}
280
281 void AddOneTask(size_t* count) {
282 (*count)++;
283 }
284
285 } // namespace
286
287 TEST_F(ThrottlingHelperTest,
288 SingleThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
289 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
290
291 base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
292 timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay);
293
294 size_t task_count = 0;
295 mock_task_runner_->RunTasksWhile(
296 base::Bind(&MessageLoopTaskCounter, &task_count));
297
298 // Run the task.
299 // TODO(alexclarke): Add a base::RunLoop observer and fix this.
300 EXPECT_EQ(2u, task_count);
301 }
302
303 TEST_F(ThrottlingHelperTest,
304 SingleFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
305 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
306
307 base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5));
308 timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay);
309
310 size_t task_count = 0;
311 mock_task_runner_->RunTasksWhile(
312 base::Bind(&MessageLoopTaskCounter, &task_count));
313
314 // Run the delayed task.
315 // TODO(alexclarke): Add a base::RunLoop observer and fix this.
316 EXPECT_EQ(2u, task_count);
317 }
318
319 TEST_F(ThrottlingHelperTest,
320 TwoFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
321 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
322 std::vector<base::TimeTicks> run_times;
323
324 base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5));
325 timer_queue_->PostDelayedTask(
326 FROM_HERE, base::Bind(&TestTask, &run_times, clock_.get()), delay);
327
328 base::TimeDelta delay2(base::TimeDelta::FromSecondsD(5.5));
329 timer_queue_->PostDelayedTask(
330 FROM_HERE, base::Bind(&TestTask, &run_times, clock_.get()), delay2);
331
332 size_t task_count = 0;
333 mock_task_runner_->RunTasksWhile(
334 base::Bind(&MessageLoopTaskCounter, &task_count));
335
336 // Run both delayed tasks.
337 // TODO(alexclarke): Add a base::RunLoop observer and fix this.
338 EXPECT_EQ(4u, task_count);
339
340 EXPECT_THAT(
341 run_times,
342 ElementsAre(base::TimeTicks() + base::TimeDelta::FromSeconds(6),
343 base::TimeTicks() + base::TimeDelta::FromSeconds(16)));
344 }
345
346 TEST_F(ThrottlingHelperTest, TaskDelayIsBasedOnRealTime) {
347 std::vector<base::TimeTicks> run_times;
348
349 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
350
351 // Post an initial task that should run at the first aligned time period.
352 timer_queue_->PostDelayedTask(FROM_HERE,
353 base::Bind(&TestTask, &run_times, clock_.get()),
354 base::TimeDelta::FromMilliseconds(900.0));
355
356 mock_task_runner_->RunUntilIdle();
357
358 // Advance realtime.
359 clock_->Advance(base::TimeDelta::FromMilliseconds(250));
360
361 // Post a task that due to real time + delay must run in the third aligned
362 // time period.
363 timer_queue_->PostDelayedTask(FROM_HERE,
364 base::Bind(&TestTask, &run_times, clock_.get()),
365 base::TimeDelta::FromMilliseconds(900.0));
366
367 mock_task_runner_->RunUntilIdle();
368
369 EXPECT_THAT(
370 run_times,
371 ElementsAre(
372 base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
373 base::TimeTicks() + base::TimeDelta::FromMilliseconds(3000.0)));
374 }
375
376 TEST_F(ThrottlingHelperTest, ThrottledTasksReportRealTime) {
377 EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks());
378
379 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
380 EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks());
381
382 clock_->Advance(base::TimeDelta::FromMilliseconds(250));
383 // Make sure the throttled time domain's Now() reports the same as the
384 // underlying clock.
385 EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks());
386 }
387
388 TEST_F(ThrottlingHelperTest, TaskQueueDisabledTillPump) {
389 size_t count = 0;
390 timer_queue_->PostTask(FROM_HERE, base::Bind(&AddOneTask, &count));
391
392 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
393 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
394 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
395
396 mock_task_runner_->RunUntilIdle(); // Wait until the pump.
397 EXPECT_EQ(1u, count); // The task got run
398 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
399 }
400
401 TEST_F(ThrottlingHelperTest, TaskQueueUnthrottle_InitiallyEnabled) {
402 timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
403
404 timer_queue_->SetQueueEnabled(true); // NOP
405 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
406 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
407
408 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
409 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
410 }
411
412 TEST_F(ThrottlingHelperTest, TaskQueueUnthrottle_InitiallyDisabled) {
413 timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
414
415 timer_queue_->SetQueueEnabled(false);
416 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
417 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
418
419 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
420 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
421 }
422
423 TEST_F(ThrottlingHelperTest, SetQueueEnabled_Unthrottled) {
424 timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
425
426 throttling_helper_->SetQueueEnabled(timer_queue_.get(), false);
427 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
428
429 throttling_helper_->SetQueueEnabled(timer_queue_.get(), true);
430 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
431 }
432
433 TEST_F(ThrottlingHelperTest, SetQueueEnabled_DisabledWhileThrottled) {
434 timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
435
436 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
437 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
438
439 throttling_helper_->SetQueueEnabled(timer_queue_.get(), false);
440 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
441 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
442 }
443
444 TEST_F(ThrottlingHelperTest, TaskQueueDisabledTillPump_ThenManuallyDisabled) {
445 size_t count = 0;
446 timer_queue_->PostTask(FROM_HERE, base::Bind(&AddOneTask, &count));
447
448 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
449 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
450 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
451
452 mock_task_runner_->RunUntilIdle(); // Wait until the pump.
453 EXPECT_EQ(1u, count); // Task ran
454 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
455
456 throttling_helper_->SetQueueEnabled(timer_queue_.get(), false);
457 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
458 }
459
460 TEST_F(ThrottlingHelperTest, DoubleIncrementDoubleDecrement) {
461 timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
462
463 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
464 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
465 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
466 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
467 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
468 throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
469 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
470 }
471
472 TEST_F(ThrottlingHelperTest, EnableVirtualTimeThenIncrement) {
473 timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
474
475 scheduler_->EnableVirtualTime();
476 EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain());
477
478 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
479 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
480 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
481 EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain());
482 }
483
484 TEST_F(ThrottlingHelperTest, IncrementThenEnableVirtualTime) {
485 timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
486
487 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
488 throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
489 EXPECT_FALSE(timer_queue_->IsQueueEnabled());
490
491 scheduler_->EnableVirtualTime();
492 EXPECT_TRUE(timer_queue_->IsQueueEnabled());
493 EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain());
494 }
495
496 } // namespace scheduler
497 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698