Commit 4e292920 authored by Francois Doray's avatar Francois Doray Committed by Commit Bot

[blink scheduler] Support interval change at any time in WakeUpBudgetPool.

Before this CL, changing the wake up interval in WakeUpBudgetPool did
not have an immediate effect. With this CL, decreasing the wake up
interval immediately reschedules the next wake up. This change is
required to support the intensive wake up experiment, which will
change the wake up interval from 1 second to 1 minute after 5 minutes
in background.

Bug: 1075553
Change-Id: I4ca1589a1ca810a4109cffc694db8ae1d89293dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2220840
Commit-Queue: François Doray <fdoray@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#774651}
parent b3d60081
...@@ -61,7 +61,7 @@ void BudgetPool::EnableThrottling(base::sequence_manager::LazyNow* lazy_now) { ...@@ -61,7 +61,7 @@ void BudgetPool::EnableThrottling(base::sequence_manager::LazyNow* lazy_now) {
TRACE_EVENT0("renderer.scheduler", "BudgetPool_EnableThrottling"); TRACE_EVENT0("renderer.scheduler", "BudgetPool_EnableThrottling");
BlockThrottledQueues(lazy_now->Now()); UpdateThrottlingStateForAllQueues(lazy_now->Now());
} }
void BudgetPool::DisableThrottling(base::sequence_manager::LazyNow* lazy_now) { void BudgetPool::DisableThrottling(base::sequence_manager::LazyNow* lazy_now) {
...@@ -90,7 +90,7 @@ void BudgetPool::Close() { ...@@ -90,7 +90,7 @@ void BudgetPool::Close() {
budget_pool_controller_->UnregisterBudgetPool(this); budget_pool_controller_->UnregisterBudgetPool(this);
} }
void BudgetPool::BlockThrottledQueues(base::TimeTicks now) { void BudgetPool::UpdateThrottlingStateForAllQueues(base::TimeTicks now) {
for (TaskQueue* queue : associated_task_queues_) for (TaskQueue* queue : associated_task_queues_)
budget_pool_controller_->UpdateQueueSchedulingLifecycleState(now, queue); budget_pool_controller_->UpdateQueueSchedulingLifecycleState(now, queue);
} }
......
...@@ -103,8 +103,10 @@ class PLATFORM_EXPORT BudgetPool { ...@@ -103,8 +103,10 @@ class PLATFORM_EXPORT BudgetPool {
// All queues should be removed before calling Close(). // All queues should be removed before calling Close().
void Close(); void Close();
// Block all associated queues and schedule them to run when appropriate. // Ensures that a pump is scheduled and that a fence is installed for all
void BlockThrottledQueues(base::TimeTicks now); // queues in this pool, based on state of those queues and latest values from
// CanRunTasksAt/GetTimeTasksCanRunUntil/GetNextAllowedRunTime.
void UpdateThrottlingStateForAllQueues(base::TimeTicks now);
protected: protected:
BudgetPool(const char* name, BudgetPoolController* budget_pool_controller); BudgetPool(const char* name, BudgetPoolController* budget_pool_controller);
......
...@@ -132,7 +132,7 @@ TEST_F(BudgetPoolTest, WakeUpBudgetPool) { ...@@ -132,7 +132,7 @@ TEST_F(BudgetPoolTest, WakeUpBudgetPool) {
scheduler_->NewTimerTaskQueue( scheduler_->NewTimerTaskQueue(
MainThreadTaskQueue::QueueType::kFrameThrottleable, nullptr); MainThreadTaskQueue::QueueType::kFrameThrottleable, nullptr);
pool->SetWakeUpInterval(base::TimeDelta::FromSeconds(10)); pool->SetWakeUpInterval(base::TimeTicks(), base::TimeDelta::FromSeconds(10));
pool->SetWakeUpDuration(base::TimeDelta::FromMilliseconds(10)); pool->SetWakeUpDuration(base::TimeDelta::FromMilliseconds(10));
// Can't run tasks until a wake-up. // Can't run tasks until a wake-up.
......
...@@ -116,7 +116,7 @@ void CPUTimeBudgetPool::RecordTaskRunTime(TaskQueue* queue, ...@@ -116,7 +116,7 @@ void CPUTimeBudgetPool::RecordTaskRunTime(TaskQueue* queue,
} }
if (current_budget_level_->InSecondsF() < 0) if (current_budget_level_->InSecondsF() < 0)
BlockThrottledQueues(end_time); UpdateThrottlingStateForAllQueues(end_time);
} }
void CPUTimeBudgetPool::OnQueueNextWakeUpChanged( void CPUTimeBudgetPool::OnQueueNextWakeUpChanged(
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/task/sequence_manager/sequence_manager.h" #include "base/task/sequence_manager/sequence_manager.h"
#include "base/task/sequence_manager/test/sequence_manager_for_test.h" #include "base/task/sequence_manager/test/sequence_manager_for_test.h"
#include "base/test/bind_test_util.h"
#include "base/test/test_mock_time_task_runner.h" #include "base/test/test_mock_time_task_runner.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -1329,7 +1330,8 @@ TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottling_EnableDisableThrottling) { ...@@ -1329,7 +1330,8 @@ TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottling_EnableDisableThrottling) {
constexpr base::TimeDelta kDelay = base::TimeDelta::FromSeconds(10); constexpr base::TimeDelta kDelay = base::TimeDelta::FromSeconds(10);
constexpr base::TimeDelta kTimeBetweenWakeUps = constexpr base::TimeDelta kTimeBetweenWakeUps =
base::TimeDelta::FromMinutes(1); base::TimeDelta::FromMinutes(1);
wake_up_budget_pool_->SetWakeUpInterval(kTimeBetweenWakeUps); wake_up_budget_pool_->SetWakeUpInterval(base::TimeTicks(),
kTimeBetweenWakeUps);
wake_up_budget_pool_->SetWakeUpDuration(base::TimeDelta::FromMilliseconds(1)); wake_up_budget_pool_->SetWakeUpDuration(base::TimeDelta::FromMilliseconds(1));
Vector<base::TimeTicks> run_times; Vector<base::TimeTicks> run_times;
...@@ -1375,6 +1377,138 @@ TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottling_EnableDisableThrottling) { ...@@ -1375,6 +1377,138 @@ TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottling_EnableDisableThrottling) {
base::TimeTicks() + base::TimeDelta::FromSeconds(300))); base::TimeTicks() + base::TimeDelta::FromSeconds(300)));
} }
TEST_F(TaskQueueThrottlerTest,
WakeUpBasedThrottling_IncreaseWakeUpIntervalBeforeWakeUp) {
Vector<base::TimeTicks> run_times;
task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_.get());
// Post 2 delayed tasks when the wake up interval is 1 minute. The delay of
// the 2nd task is such that it won't be ready when the 1st task completes.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromMinutes(1));
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
base::TimeDelta::FromMilliseconds(1));
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
base::TimeDelta::FromMinutes(2));
// Update the wake up interval to 1 hour.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromHours(1));
// The 1st delayed task should run after 1 minute, because increasing the wake
// up interval does not affect already scheduled wake ups. The 2nd task is
// scheduled according to the 1-hour wake up interval.
test_task_runner_->FastForwardUntilNoTasksRemain();
EXPECT_THAT(run_times,
ElementsAre(base::TimeTicks() + base::TimeDelta::FromMinutes(1),
base::TimeTicks() + base::TimeDelta::FromHours(1)));
}
TEST_F(TaskQueueThrottlerTest,
WakeUpBasedThrottling_DecreaseWakeUpIntervalBeforeWakeUp) {
Vector<base::TimeTicks> run_times;
task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_.get());
// Post a delayed task when the wake up interval is 1 hour.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromHours(1));
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindOnce(&TestTask, &run_times, test_task_runner_),
base::TimeDelta::FromMilliseconds(1));
// Update the wake up interval to 1 minute.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromMinutes(1));
// The delayed task should run after 1 minute, which is the most up to date
// wake up interval.
test_task_runner_->FastForwardUntilNoTasksRemain();
EXPECT_THAT(run_times,
ElementsAre(base::TimeTicks() + base::TimeDelta::FromMinutes(1)));
}
TEST_F(TaskQueueThrottlerTest,
WakeUpBasedThrottling_IncreaseWakeUpIntervalDuringWakeUp) {
wake_up_budget_pool_->SetWakeUpDuration(
base::TimeDelta::FromMilliseconds(10));
Vector<base::TimeTicks> run_times;
task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_.get());
// Post a 1st delayed task when the wake up interval is 1 minute.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromMinutes(1));
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
TestTask(&run_times, test_task_runner_);
// Post a 2nd delayed task when the wake up interval is still 1 minute.
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
TestTask(&run_times, test_task_runner_);
// Post a 3rd task when the wake up interval is 1 hour.
timer_task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TestTask, &run_times, test_task_runner_),
base::TimeDelta::FromSeconds(1));
}),
base::TimeDelta::FromSeconds(1));
// Increase the wake up interval. Since the wake up for the 2nd task is
// already scheduled, it isn't affected by this.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromHours(1));
}),
base::TimeDelta::FromSeconds(1));
test_task_runner_->FastForwardUntilNoTasksRemain();
EXPECT_THAT(run_times,
ElementsAre(base::TimeTicks() + base::TimeDelta::FromMinutes(1),
base::TimeTicks() + base::TimeDelta::FromMinutes(2),
base::TimeTicks() + base::TimeDelta::FromHours(1)));
}
TEST_F(TaskQueueThrottlerTest,
WakeUpBasedThrottling_DecreaseWakeUpIntervalDuringWakeUp) {
wake_up_budget_pool_->SetWakeUpDuration(
base::TimeDelta::FromMilliseconds(10));
Vector<base::TimeTicks> run_times;
task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_.get());
// Post a 1st delayed task when the wake up interval is 1 hour.
wake_up_budget_pool_->SetWakeUpInterval(test_task_runner_->NowTicks(),
base::TimeDelta::FromHours(1));
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
TestTask(&run_times, test_task_runner_);
// Post a 2nd delayed task when the wake up interval is still 1 hour.
timer_task_runner_->PostDelayedTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
TestTask(&run_times, test_task_runner_);
// Post a 3rd task when the wake up interval is 1 minute.
timer_task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TestTask, &run_times, test_task_runner_),
base::TimeDelta::FromSeconds(1));
}),
base::TimeDelta::FromSeconds(1));
// Decrease the wake up interval. This immediately reschedules the wake
// up for the 2nd task.
wake_up_budget_pool_->SetWakeUpInterval(
test_task_runner_->NowTicks(), base::TimeDelta::FromMinutes(1));
}),
base::TimeDelta::FromSeconds(1));
test_task_runner_->FastForwardUntilNoTasksRemain();
EXPECT_THAT(run_times,
ElementsAre(base::TimeTicks() + base::TimeDelta::FromHours(1),
base::TimeTicks() + base::TimeDelta::FromHours(1) +
base::TimeDelta::FromMinutes(1),
base::TimeTicks() + base::TimeDelta::FromHours(1) +
base::TimeDelta::FromMinutes(2)));
}
TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottlingWithCPUBudgetThrottling) { TEST_F(TaskQueueThrottlerTest, WakeUpBasedThrottlingWithCPUBudgetThrottling) {
wake_up_budget_pool_->SetWakeUpDuration( wake_up_budget_pool_->SetWakeUpDuration(
base::TimeDelta::FromMilliseconds(10)); base::TimeDelta::FromMilliseconds(10));
......
...@@ -26,8 +26,10 @@ QueueBlockType WakeUpBudgetPool::GetBlockType() const { ...@@ -26,8 +26,10 @@ QueueBlockType WakeUpBudgetPool::GetBlockType() const {
return QueueBlockType::kNewTasksOnly; return QueueBlockType::kNewTasksOnly;
} }
void WakeUpBudgetPool::SetWakeUpInterval(base::TimeDelta interval) { void WakeUpBudgetPool::SetWakeUpInterval(base::TimeTicks now,
base::TimeDelta interval) {
wake_up_interval_ = interval; wake_up_interval_ = interval;
UpdateThrottlingStateForAllQueues(now);
} }
void WakeUpBudgetPool::SetWakeUpDuration(base::TimeDelta duration) { void WakeUpBudgetPool::SetWakeUpDuration(base::TimeDelta duration) {
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
namespace blink { namespace blink {
namespace scheduler { namespace scheduler {
// WakeUpBudgetPool represents a collection of task queues which share a limit // WakeUpBudgetPool represents a collection of task queues which run for a
// on total cpu time. // limited time at regular intervals.
class PLATFORM_EXPORT WakeUpBudgetPool : public BudgetPool { class PLATFORM_EXPORT WakeUpBudgetPool : public BudgetPool {
public: public:
WakeUpBudgetPool(const char* name, WakeUpBudgetPool(const char* name,
...@@ -22,12 +22,14 @@ class PLATFORM_EXPORT WakeUpBudgetPool : public BudgetPool { ...@@ -22,12 +22,14 @@ class PLATFORM_EXPORT WakeUpBudgetPool : public BudgetPool {
base::TimeTicks now); base::TimeTicks now);
~WakeUpBudgetPool() override; ~WakeUpBudgetPool() override;
// Note: this does not have an immediate effect and should be called only // Sets the interval between wake ups. This can be invoked at any time. If a
// during initialization of a WakeUpBudgetPool. // next wake up is already scheduled, it is rescheduled only if the new
void SetWakeUpInterval(base::TimeDelta interval); // |interval| is smaller than the old interval. Wake ups after that will be
// scheduled according to |interval|.
void SetWakeUpInterval(base::TimeTicks now, base::TimeDelta interval);
// Note: this does not have an immediate effect and should be called only // Sets the duration of wake ups. This does not have an immediate effect and
// during initialization of a WakeUpBudgetPool. // should be called only during initialization of a WakeUpBudgetPool.
void SetWakeUpDuration(base::TimeDelta duration); void SetWakeUpDuration(base::TimeDelta duration);
// BudgetPool implementation: // BudgetPool implementation:
......
...@@ -591,7 +591,8 @@ void PageSchedulerImpl::MaybeInitializeWakeUpBudgetPool( ...@@ -591,7 +591,8 @@ void PageSchedulerImpl::MaybeInitializeWakeUpBudgetPool(
main_thread_scheduler_->task_queue_throttler()->CreateWakeUpBudgetPool( main_thread_scheduler_->task_queue_throttler()->CreateWakeUpBudgetPool(
"Page Wake Up Throttling"); "Page Wake Up Throttling");
wake_up_budget_pool_->SetWakeUpInterval(kThrottledWakeUpInterval); wake_up_budget_pool_->SetWakeUpInterval(lazy_now->Now(),
kThrottledWakeUpInterval);
wake_up_budget_pool_->SetWakeUpDuration(kThrottledWakeUpDuration); wake_up_budget_pool_->SetWakeUpDuration(kThrottledWakeUpDuration);
} }
......
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