Commit bf2ac894 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[content]: Add CanExceedIdleDeadlineIfRequired function to RendererScheduler.

Adds an CanExceedIdleDeadlineIfRequired function to RendererScheduler
to enable IdleTasks to estimate the best time for them to exceed their deadline
if they have a large monolithic task which could not be run otherwise.

Long idle task design doc:
https://docs.google.com/a/chromium.org/document/d/1yBlUdYW8VTIfB-DqhvQqUeP0kf-Ap1W4cao2yQq58Do/edit

BUG=455713

Review URL: https://codereview.chromium.org/969373002

Cr-Commit-Position: refs/heads/master@{#320817}
parent c16354c5
......@@ -89,6 +89,10 @@ bool NullRendererScheduler::ShouldYieldForHighPriorityWork() {
return false;
}
bool NullRendererScheduler::CanExceedIdleDeadlineIfRequired() const {
return false;
}
void NullRendererScheduler::AddTaskObserver(
base::MessageLoop::TaskObserver* task_observer) {
base::MessageLoop::current()->AddTaskObserver(task_observer);
......
......@@ -27,6 +27,7 @@ class NullRendererScheduler : public RendererScheduler {
void DidAnimateForInputOnCompositorThread() override;
bool IsHighPriorityWorkAnticipated() override;
bool ShouldYieldForHighPriorityWork() override;
bool CanExceedIdleDeadlineIfRequired() const override;
void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
void RemoveTaskObserver(
base::MessageLoop::TaskObserver* task_observer) override;
......
......@@ -70,6 +70,16 @@ class CONTENT_EXPORT RendererScheduler {
// Must be called from the main thread.
virtual bool ShouldYieldForHighPriorityWork() = 0;
// Returns true if a currently running idle task could exceed its deadline
// without impacting user experience too much. This should only be used if
// there is a task which cannot be pre-empted and is likely to take longer
// than the largest expected idle task deadline. It should NOT be polled to
// check whether more work can be performed on the current idle task after
// its deadline has expired - post a new idle task for the continuation of the
// work in this case.
// Must be called from the main thread.
virtual bool CanExceedIdleDeadlineIfRequired() const = 0;
// Adds or removes a task observer from the scheduler. The observer will be
// notified before and after every executed task. These functions can only be
// called on the main thread.
......
......@@ -519,6 +519,7 @@ void RendererSchedulerImpl::StartIdlePeriod(IdlePeriodState new_state) {
"RendererSchedulerIdlePeriod", this);
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(IsInIdlePeriod(new_state));
renderer_task_queue_selector_->EnableQueue(
IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE);
......@@ -563,6 +564,13 @@ bool RendererSchedulerImpl::IsInIdlePeriod(IdlePeriodState state) {
return state != IdlePeriodState::NOT_IN_IDLE_PERIOD;
}
bool RendererSchedulerImpl::CanExceedIdleDeadlineIfRequired() const {
TRACE_EVENT_BEGIN0("renderer.scheduler", "CanExceedIdleDeadlineIfRequired");
DCHECK(main_thread_checker_.CalledOnValidThread());
return idle_period_state_ ==
IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE;
}
void RendererSchedulerImpl::SetTimeSourceForTesting(
scoped_refptr<cc::TestNowSource> time_source) {
DCHECK(main_thread_checker_.CalledOnValidThread());
......
......@@ -43,6 +43,7 @@ class CONTENT_EXPORT RendererSchedulerImpl : public RendererScheduler {
void DidReceiveInputEventOnCompositorThread(
const blink::WebInputEvent& web_input_event) override;
void DidAnimateForInputOnCompositorThread() override;
bool CanExceedIdleDeadlineIfRequired() const override;
bool IsHighPriorityWorkAnticipated() override;
bool ShouldYieldForHighPriorityWork() override;
void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
......
......@@ -1246,4 +1246,61 @@ TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodInTouchStartPolicy) {
EXPECT_EQ(1, run_count);
}
void TestCanExceedIdleDeadlineIfRequiredTask(RendererScheduler* scheduler,
bool* can_exceed_idle_deadline_out,
int* run_count,
base::TimeTicks deadline) {
*can_exceed_idle_deadline_out = scheduler->CanExceedIdleDeadlineIfRequired();
(*run_count)++;
}
TEST_F(RendererSchedulerImplTest, CanExceedIdleDeadlineIfRequired) {
int run_count = 0;
bool can_exceed_idle_deadline = false;
// Should return false if not in an idle period.
EXPECT_FALSE(scheduler_->CanExceedIdleDeadlineIfRequired());
// Should return false for short idle periods.
idle_task_runner_->PostIdleTask(
FROM_HERE,
base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
&can_exceed_idle_deadline, &run_count));
EnableIdleTasks();
RunUntilIdle();
EXPECT_EQ(1, run_count);
EXPECT_FALSE(can_exceed_idle_deadline);
// Should return false for a long idle period which is shortened due to a
// pending delayed task.
default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
base::TimeDelta::FromMilliseconds(10));
idle_task_runner_->PostIdleTask(
FROM_HERE,
base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
&can_exceed_idle_deadline, &run_count));
scheduler_->BeginFrameNotExpectedSoon();
RunUntilIdle();
EXPECT_EQ(2, run_count);
EXPECT_FALSE(can_exceed_idle_deadline);
// Next long idle period will be for the maximum time, so
// CanExceedIdleDeadlineIfRequired should return true.
clock_->AdvanceNow(maximum_idle_period_duration());
idle_task_runner_->PostIdleTask(
FROM_HERE,
base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
&can_exceed_idle_deadline, &run_count));
RunUntilIdle();
EXPECT_EQ(3, run_count);
EXPECT_TRUE(can_exceed_idle_deadline);
// Next long idle period will be for the maximum time, so
// CanExceedIdleDeadlineIfRequired should return true.
scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, clock_->Now(), base::TimeTicks(),
base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL));
EXPECT_FALSE(scheduler_->CanExceedIdleDeadlineIfRequired());
}
} // namespace content
......@@ -24,6 +24,10 @@ bool WebSchedulerImpl::shouldYieldForHighPriorityWork() {
return renderer_scheduler_->ShouldYieldForHighPriorityWork();
}
bool WebSchedulerImpl::canExceedIdleDeadlineIfRequired() {
return renderer_scheduler_->CanExceedIdleDeadlineIfRequired();
}
void WebSchedulerImpl::runIdleTask(
scoped_ptr<blink::WebScheduler::IdleTask> task,
base::TimeTicks deadline) {
......
......@@ -27,6 +27,7 @@ class CONTENT_EXPORT WebSchedulerImpl : public blink::WebScheduler {
~WebSchedulerImpl() override;
virtual bool shouldYieldForHighPriorityWork();
virtual bool canExceedIdleDeadlineIfRequired();
virtual void postIdleTask(const blink::WebTraceLocation& location,
blink::WebScheduler::IdleTask* task);
virtual void postNonNestableIdleTask(const blink::WebTraceLocation& location,
......
......@@ -56,6 +56,10 @@ bool FakeRendererScheduler::ShouldYieldForHighPriorityWork() {
return false;
}
bool FakeRendererScheduler::CanExceedIdleDeadlineIfRequired() const {
return false;
}
void FakeRendererScheduler::AddTaskObserver(
base::MessageLoop::TaskObserver* task_observer) {
}
......
......@@ -26,6 +26,7 @@ class FakeRendererScheduler : public RendererScheduler {
const blink::WebInputEvent& web_input_event) override;
void DidAnimateForInputOnCompositorThread() override;
bool IsHighPriorityWorkAnticipated() override;
bool CanExceedIdleDeadlineIfRequired() const override;
bool ShouldYieldForHighPriorityWork() override;
void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
void RemoveTaskObserver(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment