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

Side by Side Diff: content/renderer/scheduler/renderer_scheduler_impl.cc

Issue 968073003: [content]: Add support for long idle times in the Blink Scheduler. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@long_idle_4
Patch Set: Review comments Created 5 years, 9 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/scheduler/renderer_scheduler_impl.h" 5 #include "content/renderer/scheduler/renderer_scheduler_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop/message_loop_proxy.h" 8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/trace_event/trace_event.h" 9 #include "base/trace_event/trace_event.h"
10 #include "base/trace_event/trace_event_argument.h" 10 #include "base/trace_event/trace_event_argument.h"
(...skipping 23 matching lines...) Expand all
34 current_policy_(Policy::NORMAL), 34 current_policy_(Policy::NORMAL),
35 last_input_type_(blink::WebInputEvent::Undefined), 35 last_input_type_(blink::WebInputEvent::Undefined),
36 input_stream_state_(InputStreamState::INACTIVE), 36 input_stream_state_(InputStreamState::INACTIVE),
37 policy_may_need_update_(&incoming_signals_lock_), 37 policy_may_need_update_(&incoming_signals_lock_),
38 weak_factory_(this) { 38 weak_factory_(this) {
39 weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr(); 39 weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr();
40 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, 40 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
41 weak_renderer_scheduler_ptr_); 41 weak_renderer_scheduler_ptr_);
42 end_idle_period_closure_.Reset(base::Bind( 42 end_idle_period_closure_.Reset(base::Bind(
43 &RendererSchedulerImpl::EndIdlePeriod, weak_renderer_scheduler_ptr_)); 43 &RendererSchedulerImpl::EndIdlePeriod, weak_renderer_scheduler_ptr_));
44 initiate_next_long_idle_period_closure_.Reset(base::Bind(
45 &RendererSchedulerImpl::InitiateLongIdlePeriod,
46 weak_renderer_scheduler_ptr_));
47 after_wakeup_initiate_next_long_idle_period_closure_.Reset(base::Bind(
48 &RendererSchedulerImpl::InitiateLongIdlePeriodAfterWakeup,
49 weak_renderer_scheduler_ptr_));
50
44 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( 51 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner(
45 task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE), 52 task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE),
46 control_task_after_wakeup_runner_, 53 control_task_after_wakeup_runner_,
47 base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback, 54 base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback,
48 weak_renderer_scheduler_ptr_))); 55 weak_renderer_scheduler_ptr_)));
49 56
50 renderer_task_queue_selector_->SetQueuePriority( 57 renderer_task_queue_selector_->SetQueuePriority(
51 CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY); 58 CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY);
52 59
53 renderer_task_queue_selector_->SetQueuePriority( 60 renderer_task_queue_selector_->SetQueuePriority(
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 control_task_runner_->PostDelayedTask(FROM_HERE, 142 control_task_runner_->PostDelayedTask(FROM_HERE,
136 end_idle_period_closure_.callback(), 143 end_idle_period_closure_.callback(),
137 estimated_next_frame_begin_ - now); 144 estimated_next_frame_begin_ - now);
138 } 145 }
139 } 146 }
140 147
141 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { 148 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() {
142 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 149 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
143 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); 150 "RendererSchedulerImpl::BeginFrameNotExpectedSoon");
144 DCHECK(main_thread_checker_.CalledOnValidThread()); 151 DCHECK(main_thread_checker_.CalledOnValidThread());
152 if (!task_queue_manager_)
153 return;
154
145 // TODO(skyostil): Wire up real notification of input events processing 155 // TODO(skyostil): Wire up real notification of input events processing
146 // instead of this approximation. 156 // instead of this approximation.
147 DidProcessInputEvent(base::TimeTicks()); 157 DidProcessInputEvent(base::TimeTicks());
148 // TODO(rmcilroy): Implement long idle times. 158
159 InitiateLongIdlePeriod();
149 } 160 }
150 161
151 void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread( 162 void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread(
152 const blink::WebInputEvent& web_input_event) { 163 const blink::WebInputEvent& web_input_event) {
153 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 164 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
154 "RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread"); 165 "RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread");
155 // We regard MouseMove events with the left mouse button down as a signal 166 // We regard MouseMove events with the left mouse button down as a signal
156 // that the user is doing something requiring a smooth frame rate. 167 // that the user is doing something requiring a smooth frame rate.
157 if (web_input_event.type == blink::WebInputEvent::MouseMove && 168 if (web_input_event.type == blink::WebInputEvent::MouseMove &&
158 (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) { 169 (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) {
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 DCHECK(main_thread_checker_.CalledOnValidThread()); 289 DCHECK(main_thread_checker_.CalledOnValidThread());
279 if (!task_queue_manager_) 290 if (!task_queue_manager_)
280 return; 291 return;
281 292
282 base::AutoLock lock(incoming_signals_lock_); 293 base::AutoLock lock(incoming_signals_lock_);
283 base::TimeTicks now; 294 base::TimeTicks now;
284 policy_may_need_update_.SetWhileLocked(false); 295 policy_may_need_update_.SetWhileLocked(false);
285 296
286 base::TimeDelta new_policy_duration; 297 base::TimeDelta new_policy_duration;
287 Policy new_policy = ComputeNewPolicy(&new_policy_duration); 298 Policy new_policy = ComputeNewPolicy(&new_policy_duration);
288 if (new_policy_duration > base::TimeDelta()) 299 if (new_policy_duration > base::TimeDelta()) {
300 current_policy_expiration_time_ = now + new_policy_duration;
289 PostUpdatePolicyOnControlRunner(new_policy_duration); 301 PostUpdatePolicyOnControlRunner(new_policy_duration);
302 } else {
303 current_policy_expiration_time_ = base::TimeTicks();
304 }
290 305
291 if (new_policy == current_policy_) 306 if (new_policy == current_policy_)
292 return; 307 return;
293 308
294 switch (new_policy) { 309 switch (new_policy) {
295 case Policy::COMPOSITOR_PRIORITY: 310 case Policy::COMPOSITOR_PRIORITY:
296 renderer_task_queue_selector_->SetQueuePriority( 311 renderer_task_queue_selector_->SetQueuePriority(
297 COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY); 312 COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY);
298 // TODO(scheduler-dev): Add a task priority between HIGH and BEST_EFFORT 313 // TODO(scheduler-dev): Add a task priority between HIGH and BEST_EFFORT
299 // that still has some guarantee of running. 314 // that still has some guarantee of running.
(...skipping 29 matching lines...) Expand all
329 base::TimeDelta* new_policy_duration) { 344 base::TimeDelta* new_policy_duration) {
330 DCHECK(main_thread_checker_.CalledOnValidThread()); 345 DCHECK(main_thread_checker_.CalledOnValidThread());
331 incoming_signals_lock_.AssertAcquired(); 346 incoming_signals_lock_.AssertAcquired();
332 347
333 Policy new_policy = Policy::NORMAL; 348 Policy new_policy = Policy::NORMAL;
334 *new_policy_duration = base::TimeDelta(); 349 *new_policy_duration = base::TimeDelta();
335 350
336 if (input_stream_state_ == InputStreamState::INACTIVE) 351 if (input_stream_state_ == InputStreamState::INACTIVE)
337 return new_policy; 352 return new_policy;
338 353
339 base::TimeDelta new_priority_duration =
340 base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis);
341 Policy input_priority_policy = 354 Policy input_priority_policy =
342 input_stream_state_ == 355 input_stream_state_ ==
343 InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE 356 InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE
344 ? Policy::TOUCHSTART_PRIORITY 357 ? Policy::TOUCHSTART_PRIORITY
345 : Policy::COMPOSITOR_PRIORITY; 358 : Policy::COMPOSITOR_PRIORITY;
359 base::TimeDelta time_left_in_policy = TimeLeftInInputEscalatedPolicy();
360 if (time_left_in_policy > base::TimeDelta()) {
361 new_policy = input_priority_policy;
362 *new_policy_duration = time_left_in_policy;
363 } else {
364 // Reset |input_stream_state_| to ensure
365 // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task
366 // when it's next called.
367 input_stream_state_ = InputStreamState::INACTIVE;
368 }
369 return new_policy;
370 }
346 371
347 // If the input event is still pending, go into input prioritized policy 372 base::TimeDelta RendererSchedulerImpl::TimeLeftInInputEscalatedPolicy() const {
348 // and check again later. 373 DCHECK(main_thread_checker_.CalledOnValidThread());
374 // TODO(rmcilroy): Change this to DCHECK_EQ when crbug.com/463869 is fixed.
375 DCHECK(input_stream_state_ != InputStreamState::INACTIVE);
376 incoming_signals_lock_.AssertAcquired();
377
378 base::TimeDelta escalated_priority_duration =
379 base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis);
380 base::TimeDelta time_left_in_policy;
349 if (last_input_process_time_on_main_.is_null() && 381 if (last_input_process_time_on_main_.is_null() &&
350 !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) { 382 !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) {
351 new_policy = input_priority_policy; 383 // If the input event is still pending, go into input prioritized policy
352 *new_policy_duration = new_priority_duration; 384 // and check again later.
385 time_left_in_policy = escalated_priority_duration;
353 } else { 386 } else {
354 // Otherwise make sure the input prioritization policy ends on time. 387 // Otherwise make sure the input prioritization policy ends on time.
355 base::TimeTicks new_priority_end( 388 base::TimeTicks new_priority_end(
356 std::max(last_input_receipt_time_on_compositor_, 389 std::max(last_input_receipt_time_on_compositor_,
357 last_input_process_time_on_main_) + 390 last_input_process_time_on_main_) +
358 new_priority_duration); 391 escalated_priority_duration);
359 base::TimeDelta time_left_in_policy = new_priority_end - Now(); 392 time_left_in_policy = new_priority_end - Now();
393 }
394 return time_left_in_policy;
395 }
360 396
361 if (time_left_in_policy > base::TimeDelta()) { 397 bool RendererSchedulerImpl::ShouldStartLongIdlePeriod(
362 new_policy = input_priority_policy; 398 const base::TimeTicks now,
363 *new_policy_duration = time_left_in_policy; 399 base::TimeDelta* next_long_idle_period_delay_out) {
364 } else { 400 DCHECK(main_thread_checker_.CalledOnValidThread());
365 // Reset |input_stream_state_| to ensure 401
366 // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task 402 MaybeUpdatePolicy();
367 // when it's next called. 403 if (SchedulerPolicy() == Policy::TOUCHSTART_PRIORITY) {
368 input_stream_state_ = InputStreamState::INACTIVE; 404 // Don't start a long idle task in touch start priority, try again when
369 } 405 // the policy is scheduled to end.
406 *next_long_idle_period_delay_out = current_policy_expiration_time_ - now;
407 return false;
370 } 408 }
371 return new_policy; 409
410 base::TimeTicks next_pending_delayed_task =
411 task_queue_manager_->NextPendingDelayedTaskRunTime();
412
413 base::TimeDelta long_idle_period_duration =
414 base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis);
415 if (!next_pending_delayed_task.is_null()) {
416 // Limit the idle period duration to be before the next pending task.
417 long_idle_period_duration = std::min(
418 next_pending_delayed_task - now, long_idle_period_duration);
419 }
420
421 if (long_idle_period_duration > base::TimeDelta()) {
422 *next_long_idle_period_delay_out = long_idle_period_duration;
423 return true;
424 } else {
425 // If we can't start the idle period yet then try again after wakeup.
426 *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds(
427 kRetryInitiateLongIdlePeriodDelayMillis);
428 return false;
429 }
430 }
431
432 void RendererSchedulerImpl::InitiateLongIdlePeriod() {
433 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
434 "InitiateLongIdlePeriod");
435 DCHECK(main_thread_checker_.CalledOnValidThread());
436
437 // End any previous idle period.
438 EndIdlePeriod();
439
440 base::TimeTicks now(Now());
441 base::TimeDelta next_long_idle_period_delay;
442 if (ShouldStartLongIdlePeriod(now, &next_long_idle_period_delay)) {
443 estimated_next_frame_begin_ = now + next_long_idle_period_delay;
444 StartIdlePeriod();
445 }
446
447 if (task_queue_manager_->IsQueueEmpty(IDLE_TASK_QUEUE)) {
448 // If there are no current idle tasks or we need to wait for a pending
449 // delayed task to run then post the call to initiate the next idle for
450 // execution after wakeup (at which point after-wakeup idle tasks might
451 // be eligible to run or more idle tasks posted).
452 control_task_after_wakeup_runner_->PostDelayedTask(
453 FROM_HERE,
454 after_wakeup_initiate_next_long_idle_period_closure_.callback(),
455 next_long_idle_period_delay);
456 } else {
457 // Otherwise post on the normal control task queue.
458 control_task_runner_->PostDelayedTask(
459 FROM_HERE,
460 initiate_next_long_idle_period_closure_.callback(),
461 next_long_idle_period_delay);
462 }
463 }
464
465 void RendererSchedulerImpl::InitiateLongIdlePeriodAfterWakeup() {
466 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
467 "AfterWakeupInitiateLongIdlePeriod");
468 DCHECK(main_thread_checker_.CalledOnValidThread());
469
470 if (in_idle_period_) {
471 // Since we were asleep until now, end the async idle period trace event at
472 // the time when it would have ended were we awake.
473 TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(
474 "renderer.scheduler", "RendererSchedulerIdlePeriod", this,
475 std::min(estimated_next_frame_begin_, Now()).ToInternalValue());
476 }
Sami 2015/03/04 18:26:40 Forgot to reset in_idle_period_? Also in EndIdlePe
Sami 2015/03/05 12:01:51 Missed this comment?
rmcilroy 2015/03/05 12:29:41 opps, yes thanks. Done for EndIdlePeriod but I do
477
478 // Post a task to initiate the next long idle period rather than calling it
479 // directly to allow all pending PostIdleTaskAfterWakeup tasks to get enqueued
480 // on the idle task queue before the next idle period starts so they are
481 // eligible to be run during the new idle period.
482 control_task_runner_->PostTask(
483 FROM_HERE,
484 initiate_next_long_idle_period_closure_.callback());
372 } 485 }
373 486
374 void RendererSchedulerImpl::StartIdlePeriod() { 487 void RendererSchedulerImpl::StartIdlePeriod() {
375 TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler", 488 TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler",
376 "RendererSchedulerIdlePeriod", this); 489 "RendererSchedulerIdlePeriod", this);
377 DCHECK(main_thread_checker_.CalledOnValidThread()); 490 DCHECK(main_thread_checker_.CalledOnValidThread());
378 renderer_task_queue_selector_->EnableQueue( 491 renderer_task_queue_selector_->EnableQueue(
379 IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY); 492 IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
380 task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE); 493 task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE);
494 in_idle_period_ = true;
381 } 495 }
382 496
383 void RendererSchedulerImpl::EndIdlePeriod() { 497 void RendererSchedulerImpl::EndIdlePeriod() {
498 DCHECK(main_thread_checker_.CalledOnValidThread());
499
500 end_idle_period_closure_.Cancel();
501 initiate_next_long_idle_period_closure_.Cancel();
502 after_wakeup_initiate_next_long_idle_period_closure_.Cancel();
503
504 if (!in_idle_period_)
505 return;
506
507 renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE);
384 bool is_tracing; 508 bool is_tracing;
385 TRACE_EVENT_CATEGORY_GROUP_ENABLED("renderer.scheduler", &is_tracing); 509 TRACE_EVENT_CATEGORY_GROUP_ENABLED("renderer.scheduler", &is_tracing);
386 if (is_tracing && !estimated_next_frame_begin_.is_null() && 510 if (is_tracing && !estimated_next_frame_begin_.is_null() &&
387 base::TimeTicks::Now() > estimated_next_frame_begin_) { 511 base::TimeTicks::Now() > estimated_next_frame_begin_) {
388 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( 512 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
389 "renderer.scheduler", 513 "renderer.scheduler",
390 "RendererSchedulerIdlePeriod", 514 "RendererSchedulerIdlePeriod",
391 this, 515 this,
392 "DeadlineOverrun", 516 "DeadlineOverrun",
393 estimated_next_frame_begin_.ToInternalValue()); 517 estimated_next_frame_begin_.ToInternalValue());
394 } 518 }
395 TRACE_EVENT_ASYNC_END0("renderer.scheduler", 519 TRACE_EVENT_ASYNC_END0("renderer.scheduler",
396 "RendererSchedulerIdlePeriod", this); 520 "RendererSchedulerIdlePeriod", this);
397 DCHECK(main_thread_checker_.CalledOnValidThread());
398 end_idle_period_closure_.Cancel();
399 renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE);
400 } 521 }
401 522
402 void RendererSchedulerImpl::SetTimeSourceForTesting( 523 void RendererSchedulerImpl::SetTimeSourceForTesting(
403 scoped_refptr<cc::TestNowSource> time_source) { 524 scoped_refptr<cc::TestNowSource> time_source) {
404 DCHECK(main_thread_checker_.CalledOnValidThread()); 525 DCHECK(main_thread_checker_.CalledOnValidThread());
405 time_source_ = time_source; 526 time_source_ = time_source;
406 task_queue_manager_->SetTimeSourceForTesting(time_source); 527 task_queue_manager_->SetTimeSourceForTesting(time_source);
407 } 528 }
408 529
409 void RendererSchedulerImpl::SetWorkBatchSizeForTesting(size_t work_batch_size) { 530 void RendererSchedulerImpl::SetWorkBatchSizeForTesting(size_t work_batch_size) {
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 } 676 }
556 677
557 void RendererSchedulerImpl::RemoveTaskObserver( 678 void RendererSchedulerImpl::RemoveTaskObserver(
558 base::MessageLoop::TaskObserver* task_observer) { 679 base::MessageLoop::TaskObserver* task_observer) {
559 DCHECK(main_thread_checker_.CalledOnValidThread()); 680 DCHECK(main_thread_checker_.CalledOnValidThread());
560 if (task_queue_manager_) 681 if (task_queue_manager_)
561 task_queue_manager_->RemoveTaskObserver(task_observer); 682 task_queue_manager_->RemoveTaskObserver(task_observer);
562 } 683 }
563 684
564 } // namespace content 685 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698