| OLD | NEW |
| 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 "components/scheduler/renderer/renderer_scheduler_impl.h" | 5 #include "components/scheduler/renderer/renderer_scheduler_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/debug/stack_trace.h" | 8 #include "base/debug/stack_trace.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" |
| 11 #include "cc/output/begin_frame_args.h" | 11 #include "cc/output/begin_frame_args.h" |
| 12 #include "components/scheduler/child/scheduler_task_runner_delegate.h" | 12 #include "components/scheduler/child/scheduler_task_runner_delegate.h" |
| 13 #include "components/scheduler/child/task_queue_impl.h" | 13 #include "components/scheduler/child/task_queue_impl.h" |
| 14 #include "components/scheduler/child/task_queue_selector.h" | 14 #include "components/scheduler/child/task_queue_selector.h" |
| 15 | 15 |
| 16 namespace scheduler { | 16 namespace scheduler { |
| 17 namespace { |
| 18 const int kTimerTaskEstimationSampleCount = 4 * 60; |
| 19 const double kTimerTaskEstimationPercentile = 80; |
| 20 const int kShortIdlePeriodDurationSampleCount = 10; |
| 21 const double kShortIdlePeriodDurationPercentile = 20; |
| 22 } |
| 17 | 23 |
| 18 RendererSchedulerImpl::RendererSchedulerImpl( | 24 RendererSchedulerImpl::RendererSchedulerImpl( |
| 19 scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner) | 25 scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner) |
| 20 : helper_(main_task_runner, | 26 : helper_(main_task_runner, |
| 21 "renderer.scheduler", | 27 "renderer.scheduler", |
| 22 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 28 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 23 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")), | 29 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")), |
| 24 idle_helper_(&helper_, | 30 idle_helper_(&helper_, |
| 25 this, | 31 this, |
| 26 "renderer.scheduler", | 32 "renderer.scheduler", |
| (...skipping 14 matching lines...) Expand all Loading... |
| 41 base::Bind(&RendererSchedulerImpl::UpdatePolicy, | 47 base::Bind(&RendererSchedulerImpl::UpdatePolicy, |
| 42 base::Unretained(this)), | 48 base::Unretained(this)), |
| 43 helper_.ControlTaskRunner()), | 49 helper_.ControlTaskRunner()), |
| 44 policy_may_need_update_(&any_thread_lock_), | 50 policy_may_need_update_(&any_thread_lock_), |
| 45 weak_factory_(this) { | 51 weak_factory_(this) { |
| 46 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, | 52 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, |
| 47 weak_factory_.GetWeakPtr()); | 53 weak_factory_.GetWeakPtr()); |
| 48 end_renderer_hidden_idle_period_closure_.Reset(base::Bind( | 54 end_renderer_hidden_idle_period_closure_.Reset(base::Bind( |
| 49 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); | 55 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); |
| 50 | 56 |
| 57 timer_task_runner_->AddTaskObserver( |
| 58 &MainThreadOnly().timer_task_cost_estimator_); |
| 59 |
| 51 TRACE_EVENT_OBJECT_CREATED_WITH_ID( | 60 TRACE_EVENT_OBJECT_CREATED_WITH_ID( |
| 52 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | 61 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", |
| 53 this); | 62 this); |
| 54 } | 63 } |
| 55 | 64 |
| 56 RendererSchedulerImpl::~RendererSchedulerImpl() { | 65 RendererSchedulerImpl::~RendererSchedulerImpl() { |
| 57 TRACE_EVENT_OBJECT_DELETED_WITH_ID( | 66 TRACE_EVENT_OBJECT_DELETED_WITH_ID( |
| 58 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | 67 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", |
| 59 this); | 68 this); |
| 69 timer_task_runner_->RemoveTaskObserver( |
| 70 &MainThreadOnly().timer_task_cost_estimator_); |
| 60 // Ensure the renderer scheduler was shut down explicitly, because otherwise | 71 // Ensure the renderer scheduler was shut down explicitly, because otherwise |
| 61 // we could end up having stale pointers to the Blink heap which has been | 72 // we could end up having stale pointers to the Blink heap which has been |
| 62 // terminated by this point. | 73 // terminated by this point. |
| 63 DCHECK(MainThreadOnly().was_shutdown_); | 74 DCHECK(MainThreadOnly().was_shutdown_); |
| 64 } | 75 } |
| 65 | 76 |
| 66 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly() | 77 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly() |
| 67 : current_policy_(Policy::NORMAL), | 78 : timer_task_cost_estimator_(kTimerTaskEstimationSampleCount, |
| 79 kTimerTaskEstimationPercentile), |
| 80 short_idle_period_duration_(kShortIdlePeriodDurationSampleCount), |
| 81 current_policy_(Policy::NORMAL), |
| 68 timer_queue_suspend_count_(0), | 82 timer_queue_suspend_count_(0), |
| 69 renderer_hidden_(false), | 83 renderer_hidden_(false), |
| 70 was_shutdown_(false) { | 84 was_shutdown_(false) {} |
| 71 } | 85 |
| 86 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} |
| 72 | 87 |
| 73 RendererSchedulerImpl::AnyThread::AnyThread() | 88 RendererSchedulerImpl::AnyThread::AnyThread() |
| 74 : pending_main_thread_input_event_count_(0), | 89 : pending_main_thread_input_event_count_(0), |
| 75 awaiting_touch_start_response_(false), | 90 awaiting_touch_start_response_(false), |
| 76 in_idle_period_(false), | 91 in_idle_period_(false), |
| 77 begin_main_frame_on_critical_path_(false) { | 92 begin_main_frame_on_critical_path_(false), |
| 78 } | 93 timer_tasks_seem_expensive_(false) {} |
| 79 | 94 |
| 80 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() | 95 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() |
| 81 : last_input_type_(blink::WebInputEvent::Undefined) { | 96 : last_input_type_(blink::WebInputEvent::Undefined) { |
| 82 } | 97 } |
| 83 | 98 |
| 84 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() { | 99 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() { |
| 85 } | 100 } |
| 86 | 101 |
| 87 void RendererSchedulerImpl::Shutdown() { | 102 void RendererSchedulerImpl::Shutdown() { |
| 88 helper_.Shutdown(); | 103 helper_.Shutdown(); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 if (helper_.IsShutdown()) | 167 if (helper_.IsShutdown()) |
| 153 return; | 168 return; |
| 154 | 169 |
| 155 base::TimeTicks now(helper_.Now()); | 170 base::TimeTicks now(helper_.Now()); |
| 156 if (now < MainThreadOnly().estimated_next_frame_begin_) { | 171 if (now < MainThreadOnly().estimated_next_frame_begin_) { |
| 157 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of | 172 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of |
| 158 // the next pending delayed tasks (as currently done in for long idle times) | 173 // the next pending delayed tasks (as currently done in for long idle times) |
| 159 idle_helper_.StartIdlePeriod( | 174 idle_helper_.StartIdlePeriod( |
| 160 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, | 175 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, |
| 161 MainThreadOnly().estimated_next_frame_begin_); | 176 MainThreadOnly().estimated_next_frame_begin_); |
| 177 MainThreadOnly().short_idle_period_duration_.InsertSample( |
| 178 MainThreadOnly().estimated_next_frame_begin_ - now); |
| 179 MainThreadOnly().expected_short_idle_period_duration_ = |
| 180 MainThreadOnly().short_idle_period_duration_.Percentile( |
| 181 kShortIdlePeriodDurationPercentile); |
| 162 } | 182 } |
| 163 } | 183 } |
| 164 | 184 |
| 165 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { | 185 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { |
| 166 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 186 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 167 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); | 187 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); |
| 168 helper_.CheckOnValidThread(); | 188 helper_.CheckOnValidThread(); |
| 169 if (helper_.IsShutdown()) | 189 if (helper_.IsShutdown()) |
| 170 return; | 190 return; |
| 171 | 191 |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 | 428 |
| 409 void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { | 429 void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { |
| 410 helper_.CheckOnValidThread(); | 430 helper_.CheckOnValidThread(); |
| 411 any_thread_lock_.AssertAcquired(); | 431 any_thread_lock_.AssertAcquired(); |
| 412 if (helper_.IsShutdown()) | 432 if (helper_.IsShutdown()) |
| 413 return; | 433 return; |
| 414 | 434 |
| 415 base::TimeTicks now = helper_.Now(); | 435 base::TimeTicks now = helper_.Now(); |
| 416 policy_may_need_update_.SetWhileLocked(false); | 436 policy_may_need_update_.SetWhileLocked(false); |
| 417 | 437 |
| 438 AnyThread().timer_tasks_seem_expensive_ = |
| 439 MainThreadOnly().expected_short_idle_period_duration_ > |
| 440 base::TimeDelta() && |
| 441 MainThreadOnly().timer_task_cost_estimator_.expected_task_duration() > |
| 442 MainThreadOnly().expected_short_idle_period_duration_; |
| 443 |
| 418 base::TimeDelta new_policy_duration; | 444 base::TimeDelta new_policy_duration; |
| 419 Policy new_policy = ComputeNewPolicy(now, &new_policy_duration); | 445 Policy new_policy = ComputeNewPolicy(now, &new_policy_duration); |
| 420 if (new_policy_duration > base::TimeDelta()) { | 446 if (new_policy_duration > base::TimeDelta()) { |
| 421 MainThreadOnly().current_policy_expiration_time_ = | 447 MainThreadOnly().current_policy_expiration_time_ = |
| 422 now + new_policy_duration; | 448 now + new_policy_duration; |
| 423 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, | 449 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, |
| 424 now); | 450 now); |
| 425 } else { | 451 } else { |
| 426 MainThreadOnly().current_policy_expiration_time_ = base::TimeTicks(); | 452 MainThreadOnly().current_policy_expiration_time_ = base::TimeTicks(); |
| 427 } | 453 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 new_policy != Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY) { | 500 new_policy != Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY) { |
| 475 DCHECK(loading_task_runner_->IsQueueEnabled()); | 501 DCHECK(loading_task_runner_->IsQueueEnabled()); |
| 476 } | 502 } |
| 477 MainThreadOnly().current_policy_ = new_policy; | 503 MainThreadOnly().current_policy_ = new_policy; |
| 478 | 504 |
| 479 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 505 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 480 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | 506 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", |
| 481 this, AsValueLocked(now)); | 507 this, AsValueLocked(now)); |
| 482 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 508 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 483 "RendererScheduler.policy", MainThreadOnly().current_policy_); | 509 "RendererScheduler.policy", MainThreadOnly().current_policy_); |
| 510 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 511 "RendererScheduler.timer_tasks_seem_expensive", |
| 512 AnyThread().timer_tasks_seem_expensive_); |
| 484 } | 513 } |
| 485 | 514 |
| 486 bool RendererSchedulerImpl::InputSignalsSuggestCompositorPriority( | 515 bool RendererSchedulerImpl::InputSignalsSuggestCompositorPriority( |
| 487 base::TimeTicks now) const { | 516 base::TimeTicks now) const { |
| 488 base::TimeDelta unused_policy_duration; | 517 base::TimeDelta unused_policy_duration; |
| 489 switch (ComputeNewPolicy(now, &unused_policy_duration)) { | 518 switch (ComputeNewPolicy(now, &unused_policy_duration)) { |
| 490 case Policy::TOUCHSTART_PRIORITY: | 519 case Policy::TOUCHSTART_PRIORITY: |
| 491 case Policy::COMPOSITOR_PRIORITY: | 520 case Policy::COMPOSITOR_PRIORITY: |
| 492 case Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY: | 521 case Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY: |
| 493 return true; | 522 return true; |
| 494 | 523 |
| 495 default: | 524 default: |
| 496 break; | 525 break; |
| 497 } | 526 } |
| 498 return false; | 527 return false; |
| 499 } | 528 } |
| 500 | 529 |
| 501 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy( | 530 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy( |
| 502 base::TimeTicks now, | 531 base::TimeTicks now, |
| 503 base::TimeDelta* new_policy_duration) const { | 532 base::TimeDelta* new_policy_duration) const { |
| 504 any_thread_lock_.AssertAcquired(); | 533 any_thread_lock_.AssertAcquired(); |
| 505 // Above all else we want to be responsive to user input. | 534 // Above all else we want to be responsive to user input. |
| 506 *new_policy_duration = TimeLeftInInputEscalatedPolicy(now); | 535 *new_policy_duration = TimeLeftInInputEscalatedPolicy(now); |
| 507 if (*new_policy_duration > base::TimeDelta()) { | 536 if (*new_policy_duration > base::TimeDelta()) { |
| 508 if (AnyThread().awaiting_touch_start_response_) | 537 if (AnyThread().awaiting_touch_start_response_) |
| 509 return Policy::TOUCHSTART_PRIORITY; | 538 return Policy::TOUCHSTART_PRIORITY; |
| 510 // If BeginMainFrame is on the critical path, we want to try and prevent | 539 // If BeginMainFrame is on the critical path, we want to try and prevent |
| 511 // timers and loading tasks from running shortly before BeginMainFrame is | 540 // timers and loading tasks from running if we think they might be |
| 512 // due to be posted from the compositor, because they can delay | 541 // expensive. |
| 513 // BeginMainFrame's execution. We do this by limiting execution of timers to | 542 // TODO(skyostil): Consider removing in_idle_period_ and |
| 514 // idle periods, provided there has been at least one idle period recently. | 543 // HadAnIdlePeriodRecently() unless we need them here. |
| 515 // | 544 if (AnyThread().timer_tasks_seem_expensive_ && |
| 516 // TODO(alexclarke): It's a shame in_idle_period_, | 545 AnyThread().begin_main_frame_on_critical_path_) { |
| 517 // begin_main_frame_on_critical_path_ and last_idle_period_end_time_ are in | |
| 518 // the AnyThread struct. Find a way to migrate them to MainThreadOnly. | |
| 519 if (!AnyThread().in_idle_period_ && | |
| 520 AnyThread().begin_main_frame_on_critical_path_ && | |
| 521 HadAnIdlePeriodRecently(now)) { | |
| 522 return Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY; | 546 return Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY; |
| 523 } | 547 } |
| 524 return Policy::COMPOSITOR_PRIORITY; | 548 return Policy::COMPOSITOR_PRIORITY; |
| 525 } | 549 } |
| 526 | 550 |
| 527 if (AnyThread().rails_loading_priority_deadline_ > now) { | 551 if (AnyThread().rails_loading_priority_deadline_ > now) { |
| 528 *new_policy_duration = AnyThread().rails_loading_priority_deadline_ - now; | 552 *new_policy_duration = AnyThread().rails_loading_priority_deadline_ - now; |
| 529 return Policy::LOADING_PRIORITY; | 553 return Policy::LOADING_PRIORITY; |
| 530 } | 554 } |
| 531 | 555 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 base::TimeTicks()).InMillisecondsF()); | 657 base::TimeTicks()).InMillisecondsF()); |
| 634 state->SetDouble("last_idle_period_end_time", | 658 state->SetDouble("last_idle_period_end_time", |
| 635 (AnyThread().last_idle_period_end_time_ - base::TimeTicks()) | 659 (AnyThread().last_idle_period_end_time_ - base::TimeTicks()) |
| 636 .InMillisecondsF()); | 660 .InMillisecondsF()); |
| 637 state->SetInteger("pending_main_thread_input_event_count", | 661 state->SetInteger("pending_main_thread_input_event_count", |
| 638 AnyThread().pending_main_thread_input_event_count_); | 662 AnyThread().pending_main_thread_input_event_count_); |
| 639 state->SetBoolean("awaiting_touch_start_response", | 663 state->SetBoolean("awaiting_touch_start_response", |
| 640 AnyThread().awaiting_touch_start_response_); | 664 AnyThread().awaiting_touch_start_response_); |
| 641 state->SetBoolean("begin_main_frame_on_critical_path", | 665 state->SetBoolean("begin_main_frame_on_critical_path", |
| 642 AnyThread().begin_main_frame_on_critical_path_); | 666 AnyThread().begin_main_frame_on_critical_path_); |
| 667 state->SetDouble("expected_timer_task_duration", |
| 668 MainThreadOnly() |
| 669 .timer_task_cost_estimator_.expected_task_duration() |
| 670 .InMillisecondsF()); |
| 671 // TODO(skyostil): Can we somehow trace how accurate these estimates were? |
| 672 state->SetDouble( |
| 673 "expected_short_idle_period_duration", |
| 674 MainThreadOnly().expected_short_idle_period_duration_.InMillisecondsF()); |
| 675 state->SetBoolean("timer_tasks_seem_expensive", |
| 676 AnyThread().timer_tasks_seem_expensive_); |
| 643 state->SetDouble("estimated_next_frame_begin", | 677 state->SetDouble("estimated_next_frame_begin", |
| 644 (MainThreadOnly().estimated_next_frame_begin_ - | 678 (MainThreadOnly().estimated_next_frame_begin_ - |
| 645 base::TimeTicks()).InMillisecondsF()); | 679 base::TimeTicks()).InMillisecondsF()); |
| 646 state->SetBoolean("in_idle_period", AnyThread().in_idle_period_); | 680 state->SetBoolean("in_idle_period", AnyThread().in_idle_period_); |
| 647 | 681 |
| 648 return state; | 682 return state; |
| 649 } | 683 } |
| 650 | 684 |
| 651 void RendererSchedulerImpl::OnIdlePeriodStarted() { | 685 void RendererSchedulerImpl::OnIdlePeriodStarted() { |
| 652 base::AutoLock lock(any_thread_lock_); | 686 base::AutoLock lock(any_thread_lock_); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 669 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); | 703 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); |
| 670 } | 704 } |
| 671 | 705 |
| 672 bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const { | 706 bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const { |
| 673 return (now - AnyThread().last_idle_period_end_time_) <= | 707 return (now - AnyThread().last_idle_period_end_time_) <= |
| 674 base::TimeDelta::FromMilliseconds( | 708 base::TimeDelta::FromMilliseconds( |
| 675 kIdlePeriodStarvationThresholdMillis); | 709 kIdlePeriodStarvationThresholdMillis); |
| 676 } | 710 } |
| 677 | 711 |
| 678 } // namespace scheduler | 712 } // namespace scheduler |
| OLD | NEW |