diff options
author | alexclarke <alexclarke@chromium.org> | 2015-06-11 09:50:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-11 16:51:04 +0000 |
commit | c067e255c1e47962989bf411d403ca913d2caf9b (patch) | |
tree | fcf57522c0beba2b15a56a2ea7313b67dd83935b | |
parent | d5cf758d16a434ebe0c77b817175bfcd7c8cf6fb (diff) | |
download | chromium_src-c067e255c1e47962989bf411d403ca913d2caf9b.zip chromium_src-c067e255c1e47962989bf411d403ca913d2caf9b.tar.gz chromium_src-c067e255c1e47962989bf411d403ca913d2caf9b.tar.bz2 |
Introduce a loading policy to the renderer scheduler
The idea is to deprioritize compositing tasks for for 1s after a page
load is detected. This has the side effect of prioritizing loading
tasks. Note the signal is not wired up so this patch should have no
effect by itself.
BUG=497761
Review URL: https://codereview.chromium.org/1168473007
Cr-Commit-Position: refs/heads/master@{#333967}
8 files changed, 85 insertions, 7 deletions
diff --git a/components/scheduler/renderer/null_renderer_scheduler.cc b/components/scheduler/renderer/null_renderer_scheduler.cc index e33da0a..e5052ad 100644 --- a/components/scheduler/renderer/null_renderer_scheduler.cc +++ b/components/scheduler/renderer/null_renderer_scheduler.cc @@ -71,6 +71,9 @@ void NullRendererScheduler::OnRendererHidden() { void NullRendererScheduler::OnRendererVisible() { } +void NullRendererScheduler::OnPageLoadStarted() { +} + bool NullRendererScheduler::IsHighPriorityWorkAnticipated() { return false; } diff --git a/components/scheduler/renderer/null_renderer_scheduler.h b/components/scheduler/renderer/null_renderer_scheduler.h index 4267ffc..753bc9a 100644 --- a/components/scheduler/renderer/null_renderer_scheduler.h +++ b/components/scheduler/renderer/null_renderer_scheduler.h @@ -30,6 +30,7 @@ class NullRendererScheduler : public RendererScheduler { const blink::WebInputEvent& web_input_event) override; void OnRendererHidden() override; void OnRendererVisible() override; + void OnPageLoadStarted() override; void DidAnimateForInputOnCompositorThread() override; bool IsHighPriorityWorkAnticipated() override; bool ShouldYieldForHighPriorityWork() override; diff --git a/components/scheduler/renderer/renderer_scheduler.h b/components/scheduler/renderer/renderer_scheduler.h index 7bbe8c5..2348511 100644 --- a/components/scheduler/renderer/renderer_scheduler.h +++ b/components/scheduler/renderer/renderer_scheduler.h @@ -79,6 +79,11 @@ class SCHEDULER_EXPORT RendererScheduler : public ChildScheduler { // Must be called on the main thread. virtual void OnRendererVisible() = 0; + // Tells the scheduler that a page load has started. The scheduler will + // prioritize loading tasks for a short duration afterwards. + // Must be called from the main thread. + virtual void OnPageLoadStarted() = 0; + // Returns true if the scheduler has reason to believe that high priority work // may soon arrive on the main thread, e.g., if gesture events were observed // recently. diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc index 1d49c3f..3b0eb9b 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl.cc +++ b/components/scheduler/renderer/renderer_scheduler_impl.cc @@ -357,6 +357,9 @@ bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() { case Policy::TOUCHSTART_PRIORITY: return true; + case Policy::LOADING_PRIORITY: + return false; + default: NOTREACHED(); return false; @@ -421,6 +424,8 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { return; bool policy_disables_timers = false; + PrioritizingTaskQueueSelector::QueuePriority timer_priority = + PrioritizingTaskQueueSelector::NORMAL_PRIORITY; switch (new_policy) { case Policy::COMPOSITOR_PRIORITY: @@ -444,6 +449,15 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { helper_.SetQueuePriority(LOADING_TASK_QUEUE, PrioritizingTaskQueueSelector::NORMAL_PRIORITY); break; + case Policy::LOADING_PRIORITY: + // We prioritize loading tasks by deprioritizing compositing and timers. + helper_.SetQueuePriority( + COMPOSITOR_TASK_QUEUE, + PrioritizingTaskQueueSelector::BEST_EFFORT_PRIORITY); + timer_priority = PrioritizingTaskQueueSelector::BEST_EFFORT_PRIORITY; + // TODO(alexclarke): See if we can safely mark the loading task queue as + // high priority. + break; default: NOTREACHED(); } @@ -451,8 +465,7 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { policy_disables_timers) { helper_.DisableQueue(TIMER_TASK_QUEUE); } else { - helper_.SetQueuePriority(TIMER_TASK_QUEUE, - PrioritizingTaskQueueSelector::NORMAL_PRIORITY); + helper_.SetQueuePriority(TIMER_TASK_QUEUE, timer_priority); } DCHECK(helper_.IsQueueEnabled(COMPOSITOR_TASK_QUEUE)); if (new_policy != Policy::TOUCHSTART_PRIORITY) @@ -485,14 +498,20 @@ RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy( base::TimeTicks now, base::TimeDelta* new_policy_duration) const { any_thread_lock_.AssertAcquired(); + // Above all else we want to be responsive to user input. *new_policy_duration = TimeLeftInInputEscalatedPolicy(now); + if (*new_policy_duration > base::TimeDelta()) { + return AnyThread().awaiting_touch_start_response_ + ? Policy::TOUCHSTART_PRIORITY + : Policy::COMPOSITOR_PRIORITY; + } - if (*new_policy_duration == base::TimeDelta()) - return Policy::NORMAL; + if (AnyThread().rails_loading_priority_deadline_ > now) { + *new_policy_duration = AnyThread().rails_loading_priority_deadline_ - now; + return Policy::LOADING_PRIORITY; + } - return AnyThread().awaiting_touch_start_response_ - ? Policy::TOUCHSTART_PRIORITY - : Policy::COMPOSITOR_PRIORITY; + return Policy::NORMAL; } base::TimeDelta RendererSchedulerImpl::TimeLeftInInputEscalatedPolicy( @@ -572,6 +591,8 @@ const char* RendererSchedulerImpl::PolicyToString(Policy policy) { return "compositor"; case Policy::TOUCHSTART_PRIORITY: return "touchstart"; + case Policy::LOADING_PRIORITY: + return "loading"; default: NOTREACHED(); return nullptr; @@ -604,6 +625,9 @@ RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { state->SetDouble("last_input_signal_time", (AnyThread().last_input_signal_time_ - base::TimeTicks()) .InMillisecondsF()); + state->SetDouble("rails_loading_priority_deadline", + (AnyThread().rails_loading_priority_deadline_ - + base::TimeTicks()).InMillisecondsF()); state->SetInteger("pending_main_thread_input_event_count", AnyThread().pending_main_thread_input_event_count_); state->SetBoolean("awaiting_touch_start_response", @@ -628,4 +652,12 @@ void RendererSchedulerImpl::OnIdlePeriodEnded() { // TODO(alexclarke): Force update the policy } +void RendererSchedulerImpl::OnPageLoadStarted() { + base::AutoLock lock(any_thread_lock_); + AnyThread().rails_loading_priority_deadline_ = + helper_.Now() + base::TimeDelta::FromMilliseconds( + kRailsInitialLoadingPrioritizationMillis); + UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); +} + } // namespace scheduler diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h index 7eb6ab6..42cdf11 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl.h +++ b/components/scheduler/renderer/renderer_scheduler_impl.h @@ -46,6 +46,7 @@ class SCHEDULER_EXPORT RendererSchedulerImpl : public RendererScheduler, void DidAnimateForInputOnCompositorThread() override; void OnRendererHidden() override; void OnRendererVisible() override; + void OnPageLoadStarted() override; bool IsHighPriorityWorkAnticipated() override; bool ShouldYieldForHighPriorityWork() override; bool CanExceedIdleDeadlineIfRequired() const override; @@ -79,6 +80,7 @@ class SCHEDULER_EXPORT RendererSchedulerImpl : public RendererScheduler, NORMAL, COMPOSITOR_PRIORITY, TOUCHSTART_PRIORITY, + LOADING_PRIORITY, // Must be the last entry. POLICY_COUNT, FIRST_POLICY = NORMAL, @@ -130,6 +132,10 @@ class SCHEDULER_EXPORT RendererSchedulerImpl : public RendererScheduler, // renderer has been hidden, before going to sleep for good. static const int kEndIdleWhenHiddenDelayMillis = 10000; + // The amount of time for which loading tasks will be prioritized over + // other tasks during the initial page load. + static const int kRailsInitialLoadingPrioritizationMillis = 1000; + // Schedules an immediate PolicyUpdate, if there isn't one already pending and // sets |policy_may_need_update_|. Note |any_thread_lock_| must be // locked. @@ -207,6 +213,7 @@ class SCHEDULER_EXPORT RendererSchedulerImpl : public RendererScheduler, AnyThread(); base::TimeTicks last_input_signal_time_; + base::TimeTicks rails_loading_priority_deadline_; int pending_main_thread_input_event_count_; bool awaiting_touch_start_response_; }; diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc index 3090cdf..e6c4b56 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc @@ -698,6 +698,32 @@ TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_MainThread) { std::string("L1"))); } +TEST_F(RendererSchedulerImplTest, LoadingPriorityPolicy) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + scheduler_->OnPageLoadStarted(); + EnableIdleTasks(); + RunUntilIdle(); + // In loading policy compositor tasks are best effort and should be run last. + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"), + std::string("D2"), std::string("I1"), + std::string("C1"), std::string("C2"))); + + // Advance 1.5s and try again, the loading policy should have ended and the + // task order should return to normal. + clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1500)); + run_order.clear(); + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"), + std::string("C1"), std::string("D2"), + std::string("C2"), std::string("I1"))); +} + TEST_F(RendererSchedulerImplTest, EventConsumedOnCompositorThread_IgnoresMouseMove_WhenMouseUp) { std::vector<std::string> run_order; diff --git a/content/test/fake_renderer_scheduler.cc b/content/test/fake_renderer_scheduler.cc index cc21750..2a3fe40 100644 --- a/content/test/fake_renderer_scheduler.cc +++ b/content/test/fake_renderer_scheduler.cc @@ -68,6 +68,9 @@ void FakeRendererScheduler::OnRendererHidden() { void FakeRendererScheduler::OnRendererVisible() { } +void FakeRendererScheduler::OnPageLoadStarted() { +} + bool FakeRendererScheduler::ShouldYieldForHighPriorityWork() { return false; } diff --git a/content/test/fake_renderer_scheduler.h b/content/test/fake_renderer_scheduler.h index a57e0f9..b408276 100644 --- a/content/test/fake_renderer_scheduler.h +++ b/content/test/fake_renderer_scheduler.h @@ -32,6 +32,7 @@ class FakeRendererScheduler : public scheduler::RendererScheduler { void DidAnimateForInputOnCompositorThread() override; void OnRendererHidden() override; void OnRendererVisible() override; + void OnPageLoadStarted() override; bool IsHighPriorityWorkAnticipated() override; bool CanExceedIdleDeadlineIfRequired() const override; bool ShouldYieldForHighPriorityWork() override; |