Commit 0ea17649 authored by Shubhie Panicker's avatar Shubhie Panicker Committed by Commit Bot

POC for considering keep-active signal for freezing per-frame task queues.

Bug: 823482
Change-Id: I633fa3fc6be6b04cc9d58a8165fed1bc388f731b
Reviewed-on: https://chromium-review.googlesource.com/981308
Commit-Queue: Shubhie Panicker <panicker@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#547352}
parent 030f1ce4
......@@ -51,6 +51,14 @@ const char* FrozenStateToString(bool is_frozen) {
}
}
const char* KeepActiveStateToString(bool keep_active) {
if (keep_active) {
return "keep_active";
} else {
return "no_keep_active";
}
}
} // namespace
FrameSchedulerImpl::ActiveConnectionHandleImpl::ActiveConnectionHandleImpl(
......@@ -100,6 +108,11 @@ FrameSchedulerImpl::FrameSchedulerImpl(
this,
&tracing_controller_,
FrozenStateToString),
keep_active_(renderer_scheduler->SchedulerKeepActive(),
"FrameScheduler.KeepActive",
this,
&tracing_controller_,
KeepActiveStateToString),
frame_paused_(false,
"FrameScheduler.FramePaused",
this,
......@@ -339,6 +352,7 @@ scoped_refptr<TaskQueue> FrameSchedulerImpl::ThrottleableTaskQueue() {
MainThreadTaskQueue::QueueType::kFrameThrottleable)
.SetCanBeThrottled(true)
.SetCanBeStopped(true)
.SetFreezeWhenKeepActive(true)
.SetCanBeDeferred(true)
.SetCanBePaused(true));
throttleable_task_queue_->SetBlameContext(blame_context_);
......@@ -520,14 +534,17 @@ void FrameSchedulerImpl::SetPaused(bool frame_paused) {
}
void FrameSchedulerImpl::SetPageFrozen(bool frozen) {
if (frozen == page_frozen_)
return;
DCHECK(page_visibility_ == PageVisibilityState::kHidden);
page_frozen_ = frozen;
UpdateTaskQueues();
UpdateThrottlingState();
}
void FrameSchedulerImpl::SetKeepActive(bool keep_active) {
keep_active_ = keep_active;
UpdateTaskQueues();
}
void FrameSchedulerImpl::UpdateTaskQueues() {
// Per-frame (stoppable) task queues will be stopped after 5mins in
// background. They will be resumed when the page is visible.
......@@ -548,6 +565,9 @@ void FrameSchedulerImpl::UpdateTaskQueue(
return;
bool queue_paused = frame_paused_ && queue->CanBePaused();
bool queue_frozen = page_frozen_ && queue->CanBeStopped();
// Override freezing if keep-active is true.
if (queue_frozen && !queue->FreezeWhenKeepActive())
queue_frozen = !keep_active_;
voter->SetQueueEnabled(!queue_paused && !queue_frozen);
}
......
......@@ -64,6 +64,7 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler {
bool IsPageVisible() const override;
void SetPaused(bool frame_paused) override;
void SetPageFrozen(bool) override;
void SetKeepActive(bool) override;
void SetCrossOrigin(bool cross_origin) override;
bool IsCrossOrigin() const override;
......@@ -168,6 +169,7 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler {
TraceableState<PageVisibilityState, kTracingCategoryNameInfo>
page_visibility_;
TraceableState<bool, kTracingCategoryNameInfo> page_frozen_;
TraceableState<bool, kTracingCategoryNameInfo> keep_active_;
TraceableState<bool, kTracingCategoryNameInfo> frame_paused_;
TraceableState<FrameOriginType, kTracingCategoryNameInfo> frame_origin_type_;
StateTracer<kTracingCategoryNameInfo> url_tracer_;
......
......@@ -338,6 +338,51 @@ TEST_F(FrameSchedulerImplTest, PageFreezeAndUnfreezeFlagDisabled) {
EXPECT_EQ(5, counter);
}
TEST_F(FrameSchedulerImplTest, PageFreezeWithKeepActive) {
ScopedStopLoadingInBackgroundForTest stop_loading_enabler(true);
ScopedStopNonTimersInBackgroundForTest stop_non_timers_enabler(false);
int counter = 0;
LoadingTaskQueue()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
ThrottleableTaskQueue()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
DeferrableTaskQueue()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
PausableTaskQueue()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
UnpausableTaskQueue()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
frame_scheduler_->SetKeepActive(true); // say we have a Service Worker
frame_scheduler_->SetPageVisibility(PageVisibilityState::kHidden);
frame_scheduler_->SetPageFrozen(true);
EXPECT_EQ(0, counter);
mock_task_runner_->RunUntilIdle();
// Everything runs except throttleable tasks (timers)
EXPECT_EQ(4, counter);
LoadingTaskQueue()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
EXPECT_EQ(4, counter);
mock_task_runner_->RunUntilIdle();
EXPECT_EQ(5, counter); // loading task runs
LoadingTaskQueue()->PostTask(
FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
// KeepActive is false when Service Worker stops.
frame_scheduler_->SetKeepActive(false);
EXPECT_EQ(5, counter);
mock_task_runner_->RunUntilIdle();
EXPECT_EQ(5, counter); // loading task does not run
frame_scheduler_->SetKeepActive(true);
EXPECT_EQ(5, counter);
mock_task_runner_->RunUntilIdle();
EXPECT_EQ(6, counter); // loading task runs
}
TEST_F(FrameSchedulerImplTest, PageFreezeAndPageVisible) {
ScopedStopLoadingInBackgroundForTest stop_loading_enabler(true);
ScopedStopNonTimersInBackgroundForTest stop_non_timers_enabler(true);
......
......@@ -142,6 +142,11 @@ void PageSchedulerImpl::SetPageFrozen(bool frozen) {
delegate_->SetPageFrozen(frozen);
}
void PageSchedulerImpl::SetKeepActive(bool keep_active) {
for (FrameSchedulerImpl* frame_scheduler : frame_schedulers_)
frame_scheduler->SetKeepActive(keep_active);
}
std::unique_ptr<FrameSchedulerImpl> PageSchedulerImpl::CreateFrameSchedulerImpl(
base::trace_event::BlameContext* blame_context,
FrameScheduler::FrameType frame_type) {
......
......@@ -45,6 +45,8 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler {
// PageScheduler implementation:
void SetPageVisible(bool page_visible) override;
void SetPageFrozen(bool) override;
void SetKeepActive(bool) override;
std::unique_ptr<FrameScheduler> CreateFrameScheduler(
BlameContext*,
FrameScheduler::FrameType) override;
......
......@@ -90,6 +90,11 @@ class FrameScheduler {
// background.
virtual void SetPageFrozen(bool) {}
// Tells the scheduler about "keep-alive" state which can be due to:
// service workers, shared workers, or fetch keep-alive.
// If true, then the scheduler should not freeze relevant task queues.
virtual void SetKeepActive(bool) {}
// Set whether this frame is cross origin w.r.t. the top level frame. Cross
// origin frames may use a different scheduling policy from same origin
// frames.
......
......@@ -31,6 +31,10 @@ class PLATFORM_EXPORT PageScheduler {
virtual void SetPageVisible(bool) = 0;
// The scheduler transitions app to and from STOPPED state in background.
virtual void SetPageFrozen(bool) = 0;
// Tells the scheduler about "keep-alive" state which can be due to:
// service workers, shared workers, or fetch keep-alive.
// If true, then the scheduler should not freeze relevant task queues.
virtual void SetKeepActive(bool) = 0;
// Creates a new FrameScheduler. The caller is responsible for deleting
// it. All tasks executed by the frame scheduler will be attributed to
......
......@@ -100,6 +100,7 @@ MainThreadTaskQueue::MainThreadTaskQueue(
can_be_throttled_(params.can_be_throttled),
can_be_paused_(params.can_be_paused),
can_be_stopped_(params.can_be_stopped),
freeze_when_keep_active_(params.freeze_when_keep_active),
used_for_important_tasks_(params.used_for_important_tasks),
renderer_scheduler_(renderer_scheduler),
frame_scheduler_(nullptr) {
......
......@@ -80,6 +80,7 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
can_be_throttled(false),
can_be_paused(false),
can_be_stopped(false),
freeze_when_keep_active(false),
used_for_important_tasks(false) {}
QueueCreationParams SetCanBeDeferred(bool value) {
......@@ -102,6 +103,11 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
return *this;
}
QueueCreationParams SetFreezeWhenKeepActive(bool value) {
freeze_when_keep_active = value;
return *this;
}
QueueCreationParams SetUsedForImportantTasks(bool value) {
used_for_important_tasks = value;
return *this;
......@@ -131,6 +137,7 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
bool can_be_throttled;
bool can_be_paused;
bool can_be_stopped;
bool freeze_when_keep_active;
bool used_for_important_tasks;
};
......@@ -148,6 +155,8 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
bool CanBeStopped() const { return can_be_stopped_; }
bool FreezeWhenKeepActive() const { return freeze_when_keep_active_; }
bool UsedForImportantTasks() const { return used_for_important_tasks_; }
void OnTaskStarted(const TaskQueue::Task& task, base::TimeTicks start);
......@@ -185,6 +194,7 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
const bool can_be_throttled_;
const bool can_be_paused_;
const bool can_be_stopped_;
const bool freeze_when_keep_active_;
const bool used_for_important_tasks_;
// Needed to notify renderer scheduler about completed tasks.
......
......@@ -942,7 +942,13 @@ void RendererSchedulerImpl::SetRendererBackgrounded(bool backgrounded) {
void RendererSchedulerImpl::SetSchedulerKeepActive(bool keep_active) {
main_thread_only().keep_active_fetch_or_worker = keep_active;
UpdatePolicy();
for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
page_scheduler->SetKeepActive(keep_active);
}
}
bool RendererSchedulerImpl::SchedulerKeepActive() {
return main_thread_only().keep_active_fetch_or_worker;
}
#if defined(OS_ANDROID)
......@@ -1381,8 +1387,7 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
main_thread_only().stopped_when_backgrounded;
bool newly_stopped = false;
if (main_thread_only().renderer_backgrounded &&
main_thread_only().stopping_when_backgrounded_enabled &&
!main_thread_only().keep_active_fetch_or_worker) {
main_thread_only().stopping_when_backgrounded_enabled) {
base::TimeTicks stop_at = main_thread_only().background_status_changed_at +
delay_for_background_tab_stopping_;
......
......@@ -113,6 +113,7 @@ class PLATFORM_EXPORT RendererSchedulerImpl
void SetRendererHidden(bool hidden) override;
void SetRendererBackgrounded(bool backgrounded) override;
void SetSchedulerKeepActive(bool keep_active) override;
bool SchedulerKeepActive();
#if defined(OS_ANDROID)
void PauseTimersForAndroidWebView();
void ResumeTimersForAndroidWebView();
......
......@@ -2627,72 +2627,6 @@ TEST_F(RendererSchedulerImplTest, TestRendererBackgroundedLoadingSuspension) {
EXPECT_THAT(run_order, testing::ElementsAre(std::string("L6")));
}
TEST_F(RendererSchedulerImplTest, TestRendererBackgroundedRendererKeepActive) {
ScopedStopLoadingInBackgroundForTest stop_loading_enabler(true);
scheduler_->SetStoppingWhenBackgroundedEnabled(true);
scheduler_->SetSchedulerKeepActive(true);
std::vector<std::string> run_order;
PostTestTasks(&run_order, "L1 T1");
base::TimeTicks now;
// Keep-alive should prevent suspension of task queues.
// Though this has no effect until requisite time has elapsed.
scheduler_->SetRendererBackgrounded(true);
now += base::TimeDelta::FromMilliseconds(1100);
clock_.SetNowTicks(now);
RunUntilIdle();
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("L1"), std::string("T1")));
run_order.clear();
PostTestTasks(&run_order, "L2 T2");
now += base::TimeDelta::FromSeconds(1);
clock_.SetNowTicks(now);
RunUntilIdle();
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("L2"), std::string("T2")));
// Advance the time until after the scheduled timer queue suspension.
now = base::TimeTicks() + delay_for_background_tab_stopping() +
base::TimeDelta::FromMilliseconds(10);
run_order.clear();
clock_.SetNowTicks(now);
RunUntilIdle();
ASSERT_TRUE(run_order.empty());
// Keep-alive signal prevents suspension of task queues.
PostTestTasks(&run_order, "L3 T3 V1");
now += base::TimeDelta::FromSeconds(10);
clock_.SetNowTicks(now);
RunUntilIdle();
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("L3"), std::string("T3"),
std::string("V1")));
run_order.clear();
clock_.SetNowTicks(now);
RunUntilIdle();
ASSERT_TRUE(run_order.empty());
// Setting Keep-alive to false triggers task queue suspension.
scheduler_->SetSchedulerKeepActive(false);
PostTestTasks(&run_order, "L4 T4");
now += base::TimeDelta::FromSeconds(10);
clock_.SetNowTicks(now);
RunUntilIdle();
ASSERT_TRUE(run_order.empty());
// Setting Keep-alive to true, undoes suspension.
scheduler_->SetSchedulerKeepActive(true);
now += base::TimeDelta::FromSeconds(10);
clock_.SetNowTicks(now);
RunUntilIdle();
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("L4"), std::string("T4")));
}
TEST_F(RendererSchedulerImplTest,
ExpensiveLoadingTasksNotBlockedTillFirstBeginMainFrame) {
std::vector<std::string> run_order;
......
......@@ -50,6 +50,7 @@ class FakePageScheduler final : public PageScheduler {
void SetPageVisible(bool is_page_visible) override {}
void SetPageFrozen(bool is_page_frozen) override {}
void SetKeepActive(bool keep_active) override {}
std::unique_ptr<FrameScheduler> CreateFrameScheduler(
BlameContext* blame_context,
......
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