From 4f6007c09c89433b58986a4c517cc4fa76bcdbf9 Mon Sep 17 00:00:00 2001 From: jdduke Date: Tue, 10 Feb 2015 17:20:40 -0800 Subject: [PATCH] Defer loading tasks when awaiting touch response Initial scroll response latency is highly sensitive to dispatch of touchstart and the first touchmove events. Intervening operations between the touchstart and touchmove can delay scroll event dispatch, increasing real and perceived latency. Introduce a touchstart-specific policy wherein loading tasks are completely deferred. This mode is entered upon observation of a touchstart event, and exited when either 1) actionable events like touch movement or scroll updates are observed, or 2) a 100ms timeout expires. BUG=452051,391005 Review URL: https://codereview.chromium.org/877143003 Cr-Commit-Position: refs/heads/master@{#315701} --- .../renderer/scheduler/renderer_scheduler_impl.cc | 131 +++++++++++++++---- .../renderer/scheduler/renderer_scheduler_impl.h | 25 +++- .../scheduler/renderer_scheduler_impl_unittest.cc | 143 ++++++++++++++++++++- .../scheduler/renderer_task_queue_selector.cc | 23 ++-- .../scheduler/renderer_task_queue_selector.h | 3 + .../renderer_task_queue_selector_unittest.cc | 7 + 6 files changed, 289 insertions(+), 43 deletions(-) diff --git a/content/renderer/scheduler/renderer_scheduler_impl.cc b/content/renderer/scheduler/renderer_scheduler_impl.cc index 26cbd4ee35dc..6d5c8a049ec1 100644 --- a/content/renderer/scheduler/renderer_scheduler_impl.cc +++ b/content/renderer/scheduler/renderer_scheduler_impl.cc @@ -30,6 +30,8 @@ RendererSchedulerImpl::RendererSchedulerImpl( loading_task_runner_( task_queue_manager_->TaskRunnerForQueue(LOADING_TASK_QUEUE)), current_policy_(NORMAL_PRIORITY_POLICY), + last_input_type_(blink::WebInputEvent::Undefined), + input_stream_state_(INPUT_INACTIVE), policy_may_need_update_(&incoming_signals_lock_), weak_factory_(this) { weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr(); @@ -127,7 +129,7 @@ void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread( // that the user is doing something requiring a smooth frame rate. if (web_input_event.type == blink::WebInputEvent::MouseMove && (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) { - UpdateForInputEvent(); + UpdateForInputEvent(web_input_event.type); return; } // Ignore all other mouse events because they probably don't signal user @@ -139,21 +141,28 @@ void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread( blink::WebInputEvent::isKeyboardEventType(web_input_event.type)) { return; } - UpdateForInputEvent(); + UpdateForInputEvent(web_input_event.type); } void RendererSchedulerImpl::DidAnimateForInputOnCompositorThread() { - UpdateForInputEvent(); + UpdateForInputEvent(blink::WebInputEvent::Undefined); } -void RendererSchedulerImpl::UpdateForInputEvent() { +void RendererSchedulerImpl::UpdateForInputEvent( + blink::WebInputEvent::Type type) { base::AutoLock lock(incoming_signals_lock_); - if (last_input_time_.is_null()) { - // Update scheduler policy if should start a new compositor policy mode. + + InputStreamState new_input_stream_state = + ComputeNewInputStreamState(input_stream_state_, type, last_input_type_); + + if (input_stream_state_ != new_input_stream_state) { + // Update scheduler policy if we should start a new policy mode. + input_stream_state_ = new_input_stream_state; policy_may_need_update_.SetLocked(true); PostUpdatePolicyOnControlRunner(base::TimeDelta()); } last_input_time_ = Now(); + last_input_type_ = type; } bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() { @@ -162,7 +171,10 @@ bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() { return false; MaybeUpdatePolicy(); - return SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY; + // The touchstart and compositor policies indicate a strong likelihood of + // high-priority work in the near future. + return SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY || + SchedulerPolicy() == TOUCHSTART_PRIORITY_POLICY; } bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() { @@ -171,13 +183,13 @@ bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() { return false; MaybeUpdatePolicy(); - // We only yield if we are in the compositor priority and there is compositor - // work outstanding. Note: even though the control queue is higher priority - // we don't yield for it since these tasks are not user-provided work and they - // are only intended to run before the next task, not interrupt the tasks. - // Note: This function could conceivably be implemented in terms of - // |IsHighPriorityWorkAnticipated|, but for clarity is not. - return SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY && + // We only yield if we are in the touchstart/compositor priority and there + // is input/compositor work outstanding. Note: even though the control queue + // is higher priority we don't yield for it since these tasks are not + // user-provided work and they are only intended to run before the next task, + // not interrupt the tasks. + return (SchedulerPolicy() == COMPOSITOR_PRIORITY_POLICY || + SchedulerPolicy() == TOUCHSTART_PRIORITY_POLICY) && !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE); } @@ -215,20 +227,22 @@ void RendererSchedulerImpl::UpdatePolicy() { policy_may_need_update_.SetLocked(false); Policy new_policy = NORMAL_PRIORITY_POLICY; - if (!last_input_time_.is_null()) { - base::TimeDelta compositor_priority_duration = - base::TimeDelta::FromMilliseconds(kCompositorPriorityAfterTouchMillis); - base::TimeTicks compositor_priority_end(last_input_time_ + - compositor_priority_duration); - now = Now(); - if (compositor_priority_end > now) { - PostUpdatePolicyOnControlRunner(compositor_priority_end - now); - new_policy = COMPOSITOR_PRIORITY_POLICY; + if (input_stream_state_ != INPUT_INACTIVE) { + base::TimeDelta new_priority_duration = + base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis); + base::TimeTicks new_priority_end(last_input_time_ + new_priority_duration); + base::TimeDelta time_left_in_policy = new_priority_end - Now(); + if (time_left_in_policy > base::TimeDelta()) { + PostUpdatePolicyOnControlRunner(time_left_in_policy); + new_policy = + input_stream_state_ == INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE + ? TOUCHSTART_PRIORITY_POLICY + : COMPOSITOR_PRIORITY_POLICY; } else { - // Null out last_input_time_ to ensure - // DidReceiveInputEventOnCompositorThread will post an - // UpdatePolicy task when it's next called. - last_input_time_ = base::TimeTicks(); + // Reset |input_stream_state_| to ensure + // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task + // when it's next called. + input_stream_state_ = INPUT_INACTIVE; } } @@ -244,6 +258,11 @@ void RendererSchedulerImpl::UpdatePolicy() { renderer_task_queue_selector_->SetQueuePriority( LOADING_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY); break; + case TOUCHSTART_PRIORITY_POLICY: + renderer_task_queue_selector_->SetQueuePriority( + COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY); + renderer_task_queue_selector_->DisableQueue(LOADING_TASK_QUEUE); + break; case NORMAL_PRIORITY_POLICY: renderer_task_queue_selector_->SetQueuePriority( COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::NORMAL_PRIORITY); @@ -251,6 +270,10 @@ void RendererSchedulerImpl::UpdatePolicy() { LOADING_TASK_QUEUE, RendererTaskQueueSelector::NORMAL_PRIORITY); break; } + DCHECK(renderer_task_queue_selector_->IsQueueEnabled(COMPOSITOR_TASK_QUEUE)); + if (new_policy != TOUCHSTART_PRIORITY_POLICY) + DCHECK(renderer_task_queue_selector_->IsQueueEnabled(LOADING_TASK_QUEUE)); + current_policy_ = new_policy; TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( @@ -341,6 +364,23 @@ const char* RendererSchedulerImpl::PolicyToString(Policy policy) { return "normal"; case COMPOSITOR_PRIORITY_POLICY: return "compositor"; + case TOUCHSTART_PRIORITY_POLICY: + return "touchstart"; + default: + NOTREACHED(); + return nullptr; + } +} + +const char* RendererSchedulerImpl::InputStreamStateToString( + InputStreamState state) { + switch (state) { + case INPUT_INACTIVE: + return "inactive"; + case INPUT_ACTIVE: + return "active"; + case INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE: + return "active_and_awaiting_touchstart_response"; default: NOTREACHED(); return nullptr; @@ -358,6 +398,8 @@ RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { new base::trace_event::TracedValue(); state->SetString("current_policy", PolicyToString(current_policy_)); + state->SetString("input_stream_state", + InputStreamStateToString(input_stream_state_)); state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF()); state->SetDouble("last_input_time", (last_input_time_ - base::TimeTicks()).InMillisecondsF()); @@ -368,4 +410,39 @@ RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { return state; } +RendererSchedulerImpl::InputStreamState +RendererSchedulerImpl::ComputeNewInputStreamState( + InputStreamState current_state, + blink::WebInputEvent::Type new_input_type, + blink::WebInputEvent::Type last_input_type) { + switch (new_input_type) { + case blink::WebInputEvent::TouchStart: + return INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE; + + case blink::WebInputEvent::TouchMove: + // Observation of consecutive touchmoves is a strong signal that the page + // is consuming the touch sequence, in which case touchstart response + // prioritization is no longer necessary. Otherwise, the initial touchmove + // should preserve the touchstart response pending state. + if (current_state == INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE) { + return last_input_type == blink::WebInputEvent::TouchMove + ? INPUT_ACTIVE + : INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE; + } + break; + + case blink::WebInputEvent::GestureTapDown: + case blink::WebInputEvent::GestureShowPress: + case blink::WebInputEvent::GestureFlingCancel: + case blink::WebInputEvent::GestureScrollEnd: + // With no observable effect, these meta events do not indicate a + // meaningful touchstart response and should not impact task priority. + return current_state; + + default: + break; + } + return INPUT_ACTIVE; +} + } // namespace content diff --git a/content/renderer/scheduler/renderer_scheduler_impl.h b/content/renderer/scheduler/renderer_scheduler_impl.h index 2b47d667e0dc..15958dcc2f49 100644 --- a/content/renderer/scheduler/renderer_scheduler_impl.h +++ b/content/renderer/scheduler/renderer_scheduler_impl.h @@ -63,6 +63,13 @@ class CONTENT_EXPORT RendererSchedulerImpl : public RendererScheduler { enum Policy { NORMAL_PRIORITY_POLICY, COMPOSITOR_PRIORITY_POLICY, + TOUCHSTART_PRIORITY_POLICY, + }; + + enum InputStreamState { + INPUT_INACTIVE, + INPUT_ACTIVE, + INPUT_ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE }; class PollableNeedsUpdateFlag { @@ -88,9 +95,15 @@ class CONTENT_EXPORT RendererSchedulerImpl : public RendererScheduler { base::TimeTicks optional_now) const; static const char* TaskQueueIdToString(QueueId queue_id); static const char* PolicyToString(Policy policy); + static const char* InputStreamStateToString(InputStreamState state); + + static InputStreamState ComputeNewInputStreamState( + InputStreamState current_state, + blink::WebInputEvent::Type new_input_event, + blink::WebInputEvent::Type last_input_event); - // The time we should stay in CompositorPriority mode for after a touch event. - static const int kCompositorPriorityAfterTouchMillis = 100; + // The time we should stay in a priority-escalated mode after an input event. + static const int kPriorityEscalationAfterInputMillis = 100; // IdleTaskDeadlineSupplier Implementation: void CurrentIdleTaskDeadlineCallback(base::TimeTicks* deadline_out) const; @@ -109,7 +122,7 @@ class CONTENT_EXPORT RendererSchedulerImpl : public RendererScheduler { void UpdatePolicy(); // An input event of some sort happened, the policy may need updating. - void UpdateForInputEvent(); + void UpdateForInputEvent(blink::WebInputEvent::Type type); // Start and end an idle period. void StartIdlePeriod(); @@ -134,10 +147,12 @@ class CONTENT_EXPORT RendererSchedulerImpl : public RendererScheduler { base::TimeTicks estimated_next_frame_begin_; - // The incoming_signals_lock_ mutex protects access to last_input_time_ - // and write access to policy_may_need_update_. + // The incoming_signals_lock_ mutex protects access to all variables in the + // (contiguous) block below. base::Lock incoming_signals_lock_; base::TimeTicks last_input_time_; + blink::WebInputEvent::Type last_input_type_; + InputStreamState input_stream_state_; PollableNeedsUpdateFlag policy_may_need_update_; scoped_refptr time_source_; diff --git a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc index 8d6982951a0e..7fd53e8d3997 100644 --- a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc +++ b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc @@ -52,9 +52,9 @@ class RendererSchedulerImplTest : public testing::Test { } protected: - static base::TimeDelta compositor_priority_after_touch_duration() { + static base::TimeDelta priority_escalation_after_input_duration() { return base::TimeDelta::FromMilliseconds( - RendererSchedulerImpl::kCompositorPriorityAfterTouchMillis); + RendererSchedulerImpl::kPriorityEscalationAfterInputMillis); } scoped_refptr clock_; @@ -400,6 +400,51 @@ TEST_F(RendererSchedulerImplTest, TestCompositorPolicy_DidAnimateForInput) { std::string("I1"))); } +TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy) { + std::vector order; + + loading_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("L1"))); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); + + // Observation of touchstart should defer execution of idle and loading tasks. + scheduler_->DidReceiveInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + RunUntilIdle(); + EXPECT_THAT(order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"))); + + // Meta events like TapDown/FlingCancel shouldn't affect the priority. + order.clear(); + scheduler_->DidReceiveInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingCancel)); + scheduler_->DidReceiveInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureTapDown)); + RunUntilIdle(); + EXPECT_TRUE(order.empty()); + + // Action events like ScrollBegin will kick us back into compositor priority, + // allowing servie of the loading and idle queues. + order.clear(); + scheduler_->DidReceiveInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin)); + RunUntilIdle(); + EXPECT_THAT(order, testing::ElementsAre(std::string("L1"))); +} + TEST_F(RendererSchedulerImplTest, DidReceiveInputEventOnCompositorThread_IgnoresMouseMove_WhenMouseUp) { std::vector order; @@ -592,6 +637,98 @@ TEST_F(RendererSchedulerImplTest, TestCompositorPolicyEnds) { std::string("D2"), std::string("C2"))); } +TEST_F(RendererSchedulerImplTest, TestTouchstartPolicyEndsAfterTimeout) { + std::vector order; + + loading_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("L1"))); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); + + scheduler_->DidReceiveInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + RunUntilIdle(); + EXPECT_THAT(order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"))); + + order.clear(); + clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1000)); + + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); + + // Touchstart policy mode should have ended now that the clock has advanced. + RunUntilIdle(); + EXPECT_THAT(order, testing::ElementsAre(std::string("L1"), std::string("D1"), + std::string("C1"), std::string("D2"), + std::string("C2"))); +} + +TEST_F(RendererSchedulerImplTest, + TestTouchstartPolicyEndsAfterConsecutiveTouchmoves) { + std::vector order; + + loading_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("L1"))); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("D1"))); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("C1"))); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("D2"))); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AppendToVectorTestTask, &order, std::string("C2"))); + + // Observation of touchstart should defer execution of idle and loading tasks. + scheduler_->DidReceiveInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + RunUntilIdle(); + EXPECT_THAT(order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"))); + + // Receiving the first touchmove will not affect scheduler priority. + order.clear(); + scheduler_->DidReceiveInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + RunUntilIdle(); + EXPECT_TRUE(order.empty()); + + // Receiving the second touchmove will kick us back into compositor priority. + order.clear(); + scheduler_->DidReceiveInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + RunUntilIdle(); + EXPECT_THAT(order, testing::ElementsAre(std::string("L1"))); +} + TEST_F(RendererSchedulerImplTest, TestIsHighPriorityWorkAnticipated) { bool is_anticipated_before = false; bool is_anticipated_after = false; @@ -618,7 +755,7 @@ TEST_F(RendererSchedulerImplTest, TestIsHighPriorityWorkAnticipated) { EXPECT_FALSE(is_anticipated_before); EXPECT_TRUE(is_anticipated_after); - clock_->AdvanceNow(compositor_priority_after_touch_duration() * 2); + clock_->AdvanceNow(priority_escalation_after_input_duration() * 2); simulate_input = false; default_task_runner_->PostTask( FROM_HERE, diff --git a/content/renderer/scheduler/renderer_task_queue_selector.cc b/content/renderer/scheduler/renderer_task_queue_selector.cc index 121c777e045e..7191942cd13e 100644 --- a/content/renderer/scheduler/renderer_task_queue_selector.cc +++ b/content/renderer/scheduler/renderer_task_queue_selector.cc @@ -20,11 +20,10 @@ void RendererTaskQueueSelector::RegisterWorkQueues( const std::vector& work_queues) { DCHECK(main_thread_checker_.CalledOnValidThread()); work_queues_ = work_queues; - for (QueuePriority priority = FIRST_QUEUE_PRIORITY; - priority < QUEUE_PRIORITY_COUNT; - priority = NextPriority(priority)) { - queue_priorities_[priority].clear(); + for (auto& queue_priority : queue_priorities_) { + queue_priority.clear(); } + // By default, all work queues are set to normal priority. for (size_t i = 0; i < work_queues.size(); i++) { queue_priorities_[NORMAL_PRIORITY].insert(i); @@ -48,11 +47,19 @@ void RendererTaskQueueSelector::EnableQueue(size_t queue_index, void RendererTaskQueueSelector::DisableQueue(size_t queue_index) { DCHECK(main_thread_checker_.CalledOnValidThread()); DCHECK_LT(queue_index, work_queues_.size()); - for (QueuePriority priority = FIRST_QUEUE_PRIORITY; - priority < QUEUE_PRIORITY_COUNT; - priority = NextPriority(priority)) { - queue_priorities_[priority].erase(queue_index); + for (auto& queue_priority : queue_priorities_) { + queue_priority.erase(queue_index); + } +} + +bool RendererTaskQueueSelector::IsQueueEnabled(size_t queue_index) const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK_LT(queue_index, work_queues_.size()); + for (const auto& queue_priority : queue_priorities_) { + if (queue_priority.find(queue_index) != queue_priority.end()) + return true; } + return false; } bool RendererTaskQueueSelector::IsOlder(const base::TaskQueue* queueA, diff --git a/content/renderer/scheduler/renderer_task_queue_selector.h b/content/renderer/scheduler/renderer_task_queue_selector.h index cfea89f43b25..b032b7bfdbed 100644 --- a/content/renderer/scheduler/renderer_task_queue_selector.h +++ b/content/renderer/scheduler/renderer_task_queue_selector.h @@ -51,6 +51,9 @@ class CONTENT_EXPORT RendererTaskQueueSelector // Disable the |queue_index|. void DisableQueue(size_t queue_index); + // Whether |queue_index| is enabled. + bool IsQueueEnabled(size_t queue_index) const; + // TaskQueueSelector implementation: void RegisterWorkQueues( const std::vector& work_queues) override; diff --git a/content/renderer/scheduler/renderer_task_queue_selector_unittest.cc b/content/renderer/scheduler/renderer_task_queue_selector_unittest.cc index 5f9197ee158a..1112beb6b89a 100644 --- a/content/renderer/scheduler/renderer_task_queue_selector_unittest.cc +++ b/content/renderer/scheduler/renderer_task_queue_selector_unittest.cc @@ -58,6 +58,8 @@ class RendererTaskQueueSelectorTest : public testing::Test { task_queues_.push_back(task_queue.release()); } selector_.RegisterWorkQueues(const_task_queues); + for (size_t i = 0; i < kTaskQueueCount; i++) + EXPECT_TRUE(selector_.IsQueueEnabled(i)) << i; } const size_t kTaskQueueCount = 5; @@ -96,7 +98,9 @@ TEST_F(RendererTaskQueueSelectorTest, TestControlPriority) { size_t queue_order[] = {0, 1, 2, 3, 4}; PushTasks(tasks, queue_order); selector_.SetQueuePriority(4, RendererTaskQueueSelector::CONTROL_PRIORITY); + EXPECT_TRUE(selector_.IsQueueEnabled(4)); selector_.SetQueuePriority(2, RendererTaskQueueSelector::HIGH_PRIORITY); + EXPECT_TRUE(selector_.IsQueueEnabled(2)); EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 2, 0, 1, 3)); } @@ -105,7 +109,9 @@ TEST_F(RendererTaskQueueSelectorTest, TestDisableEnable) { size_t queue_order[] = {0, 1, 2, 3, 4}; PushTasks(tasks, queue_order); selector_.DisableQueue(2); + EXPECT_FALSE(selector_.IsQueueEnabled(2)); selector_.DisableQueue(4); + EXPECT_FALSE(selector_.IsQueueEnabled(4)); EXPECT_THAT(PopTasks(), testing::ElementsAre(0, 1, 3)); selector_.EnableQueue(2, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY); EXPECT_THAT(PopTasks(), testing::ElementsAre(2)); @@ -122,6 +128,7 @@ TEST_F(RendererTaskQueueSelectorTest, TestEmptyQueues) { size_t queue_order[] = {0}; PushTasks(tasks, queue_order); selector_.DisableQueue(0); + EXPECT_FALSE(selector_.IsQueueEnabled(0)); EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_queue_index)); } -- 2.11.4.GIT