Commit 94413732 authored by kdillon's avatar kdillon Committed by Commit Bot

[scheduler] Add feature to compositor priority experiments to prioritize...

[scheduler] Add feature to compositor priority experiments to prioritize compositing until a BeginMainFrame is run.

By default, these experiments will prioritize compositing until a compositor
task has been run and then set the priority back to normal until a condition
is met. This addition will allow us to experiment with prioritizing the
compositor until we actually see a BeginMainFrame, a specific compositing task,
with the goal of prioritizing rendering more specifically.

This feature can be used with three of the five existing approaches. For alternating, compositing
will be prioritized until a BeginMainFrame is run instead of any compositor task. For the delay
approach, a BeginMainFrame will reset the delay, and for the budget approach the budget will
only be exhausted when a BeginMainFrame is run.

Bug: 966177
Change-Id: I1b9e2487cfaf33b1aefe4f949256c064921451b5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1906330
Commit-Queue: Katie Dillon <kdillon@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Reviewed-by: default avatarScott Haseley <shaseley@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718232}
parent e059091a
......@@ -103,6 +103,16 @@ constexpr base::FeatureParam<double> kCompositorBudgetRecoveryRate{
&kVeryHighPriorityForCompositingBudget, "CompositorBudgetRecoveryRate",
0.25};
// This feature functions as an experiment parameter for the
// VeryHighPriorityForCompositing alternating, delay, and budget experiments.
// When enabled, it does nothing unless one of these experiments is also
// enabled. If one of these experiments is enabled it will change the behavior
// of that experiment such that the stop signal for prioritzation of the
// compositor is a BeginMainFrame task instead of any compositor task.
const base::Feature kPrioritizeCompositingUntilBeginMainFrame{
"BlinkSchedulerPrioritizeCompositingUntilBeginMainFrame",
base::FEATURE_DISABLED_BY_DEFAULT};
// LOAD PRIORITY EXPERIMENT CONTROLS
// Enables setting the priority of background (with no audio) pages'
......
......@@ -16,7 +16,11 @@ CompositorPriorityExperiments::CompositorPriorityExperiments(
: scheduler_(scheduler),
experiment_(GetExperimentFromFeatureList()),
prioritize_compositing_after_delay_length_(
base::TimeDelta::FromMilliseconds(kCompositingDelayLength.Get())) {
base::TimeDelta::FromMilliseconds(kCompositingDelayLength.Get())),
stop_signal_(base::FeatureList::IsEnabled(
kPrioritizeCompositingUntilBeginMainFrame)
? StopSignalType::kBeginMainFrameTask
: StopSignalType::kAnyCompositorTask) {
do_prioritize_compositing_after_delay_callback_.Reset(base::BindRepeating(
&CompositorPriorityExperiments::DoPrioritizeCompositingAfterDelay,
base::Unretained(this)));
......@@ -94,6 +98,10 @@ void CompositorPriorityExperiments::OnMainThreadSchedulerShutdown() {
budget_pool_controller_.reset();
}
void CompositorPriorityExperiments::OnWillBeginMainFrame() {
will_begin_main_frame_ = true;
}
void CompositorPriorityExperiments::PostPrioritizeCompositingAfterDelayTask() {
DCHECK_EQ(experiment_, Experiment::kVeryHighPriorityForCompositingAfterDelay);
......@@ -109,6 +117,16 @@ void CompositorPriorityExperiments::OnTaskCompleted(
if (!queue)
return;
bool have_seen_stop_signal = false;
if (queue->queue_type() == MainThreadTaskQueue::QueueType::kCompositor) {
if (stop_signal_ == StopSignalType::kAnyCompositorTask) {
have_seen_stop_signal = true;
} else if (will_begin_main_frame_) {
have_seen_stop_signal = true;
will_begin_main_frame_ = false;
}
}
switch (experiment_) {
case Experiment::kVeryHighPriorityForCompositingAlways:
return;
......@@ -119,9 +137,8 @@ void CompositorPriorityExperiments::OnTaskCompleted(
// compositor if another task has run regardless of its priority. This
// prevents starving the compositor while allowing other work to run
// in-between.
if (queue->queue_type() == MainThreadTaskQueue::QueueType::kCompositor &&
alternating_compositor_priority_ ==
QueuePriority::kVeryHighPriority) {
if (have_seen_stop_signal && alternating_compositor_priority_ ==
QueuePriority::kVeryHighPriority) {
alternating_compositor_priority_ = QueuePriority::kNormalPriority;
scheduler_->OnCompositorPriorityExperimentUpdateCompositorPriority();
} else if (alternating_compositor_priority_ ==
......@@ -131,7 +148,7 @@ void CompositorPriorityExperiments::OnTaskCompleted(
}
return;
case Experiment::kVeryHighPriorityForCompositingAfterDelay:
if (queue->queue_type() == MainThreadTaskQueue::QueueType::kCompositor) {
if (have_seen_stop_signal) {
delay_compositor_priority_ = QueuePriority::kNormalPriority;
do_prioritize_compositing_after_delay_callback_.Cancel();
PostPrioritizeCompositingAfterDelayTask();
......@@ -141,7 +158,8 @@ void CompositorPriorityExperiments::OnTaskCompleted(
}
return;
case Experiment::kVeryHighPriorityForCompositingBudget:
budget_pool_controller_->OnTaskCompleted(queue, task_timing);
budget_pool_controller_->OnTaskCompleted(queue, task_timing,
have_seen_stop_signal);
return;
case Experiment::kNone:
return;
......@@ -207,8 +225,9 @@ void CompositorPriorityExperiments::CompositorBudgetPoolController::
void CompositorPriorityExperiments::CompositorBudgetPoolController::
OnTaskCompleted(MainThreadTaskQueue* queue,
MainThreadTaskQueue::TaskTiming* task_timing) {
if (queue->queue_type() == MainThreadTaskQueue::QueueType::kCompositor) {
MainThreadTaskQueue::TaskTiming* task_timing,
bool have_seen_stop_signal) {
if (have_seen_stop_signal) {
compositor_budget_pool_->RecordTaskRunTime(queue, task_timing->start_time(),
task_timing->end_time());
}
......
......@@ -52,6 +52,8 @@ class PLATFORM_EXPORT CompositorPriorityExperiments {
return alternating_compositor_priority_;
}
void OnWillBeginMainFrame();
void OnMainThreadSchedulerInitialized();
void OnMainThreadSchedulerShutdown();
......@@ -76,7 +78,8 @@ class PLATFORM_EXPORT CompositorPriorityExperiments {
void UpdateCompositorBudgetState(base::TimeTicks now);
void OnTaskCompleted(MainThreadTaskQueue* queue,
MainThreadTaskQueue::TaskTiming* task_timing);
MainThreadTaskQueue::TaskTiming* task_timing,
bool have_seen_stop_signal);
// Unimplemented methods.
void AddQueueToBudgetPool(TaskQueue* queue,
......@@ -94,14 +97,16 @@ class PLATFORM_EXPORT CompositorPriorityExperiments {
const base::TickClock* tick_clock_; // Not owned.
};
MainThreadSchedulerImpl* scheduler_; // Not owned.
static Experiment GetExperimentFromFeatureList();
void DoPrioritizeCompositingAfterDelay();
void PostPrioritizeCompositingAfterDelayTask();
enum class StopSignalType { kAnyCompositorTask, kBeginMainFrameTask };
MainThreadSchedulerImpl* scheduler_; // Not owned.
const Experiment experiment_;
QueuePriority alternating_compositor_priority_ =
......@@ -113,6 +118,9 @@ class PLATFORM_EXPORT CompositorPriorityExperiments {
QueuePriority budget_compositor_priority_ = QueuePriority::kVeryHighPriority;
std::unique_ptr<CompositorBudgetPoolController> budget_pool_controller_;
const StopSignalType stop_signal_;
bool will_begin_main_frame_ = false;
};
} // namespace scheduler
......
......@@ -844,6 +844,7 @@ void MainThreadSchedulerImpl::WillBeginFrame(const viz::BeginFrameArgs& args) {
any_thread().begin_main_frame_on_critical_path = args.on_critical_path;
}
main_thread_only().compositing_experiment.OnWillBeginMainFrame();
main_thread_only().compositor_priority_experiments.OnWillBeginMainFrame();
}
void MainThreadSchedulerImpl::DidCommitFrameToCompositor() {
......
......@@ -3869,7 +3869,7 @@ TEST_P(VeryHighPriorityForCompositingAfterDelayExperimentTest,
TEST_P(VeryHighPriorityForCompositingAfterDelayExperimentTest,
TestCompositorPolicy_FirstCompositorTaskSetToVeryHighPriority) {
// 1.5ms task to complete the countdown and prioritze compositing.
// 150ms task to complete the countdown and prioritze compositing.
AdvanceTimeWithTask(0.15);
Vector<String> run_order;
......@@ -3968,6 +3968,126 @@ TEST_P(VeryHighPriorityForCompositingBudgetExperimentTest,
EXPECT_EQ(UseCase::kNone, CurrentUseCase());
}
class VeryHighPriorityForCompositingAlternatingBeginMainFrameExperimentTest
: public MainThreadSchedulerImplTest {
public:
VeryHighPriorityForCompositingAlternatingBeginMainFrameExperimentTest()
: MainThreadSchedulerImplTest({kVeryHighPriorityForCompositingAlternating,
kPrioritizeCompositingUntilBeginMainFrame},
{}) {}
};
INSTANTIATE_TEST_SUITE_P(
,
VeryHighPriorityForCompositingAlternatingBeginMainFrameExperimentTest,
testing::Values(AntiStarvationLogic::kEnabled,
AntiStarvationLogic::kDisabled),
GetTestNameSuffix);
TEST_P(VeryHighPriorityForCompositingAlternatingBeginMainFrameExperimentTest,
TestCompositorPolicy_AlternatingCompositorTasks) {
Vector<String> run_order;
PostTestTasks(&run_order, "C1 D1 C2 D2");
base::RunLoop().RunUntilIdle();
EXPECT_THAT(run_order, testing::ElementsAre("C1", "C2", "D1", "D2"));
EXPECT_EQ(UseCase::kNone, CurrentUseCase());
// Next compositor task is the BeginMainFrame. Compositor priority is set
// to normal for a single task before being prioritized again.
DoMainFrame();
run_order.clear();
PostTestTasks(&run_order, "C1 D1 D2 C2");
base::RunLoop().RunUntilIdle();
EXPECT_THAT(run_order, testing::ElementsAre("C1", "D1", "C2", "D2"));
EXPECT_EQ(UseCase::kNone, CurrentUseCase());
}
class VeryHighPriorityForCompositingAfterDelayUntilBeginMainFrameExperimentTest
: public MainThreadSchedulerImplTest {
public:
VeryHighPriorityForCompositingAfterDelayUntilBeginMainFrameExperimentTest()
: MainThreadSchedulerImplTest({kVeryHighPriorityForCompositingAfterDelay,
kPrioritizeCompositingUntilBeginMainFrame},
{}) {}
};
INSTANTIATE_TEST_SUITE_P(
,
VeryHighPriorityForCompositingAfterDelayUntilBeginMainFrameExperimentTest,
testing::Values(AntiStarvationLogic::kEnabled,
AntiStarvationLogic::kDisabled),
GetTestNameSuffix);
TEST_P(
VeryHighPriorityForCompositingAfterDelayUntilBeginMainFrameExperimentTest,
TestCompositorPolicy_FirstCompositorTaskSetToVeryHighPriority) {
// 150ms task to complete the countdown and prioritze compositing.
AdvanceTimeWithTask(0.15);
Vector<String> run_order;
PostTestTasks(&run_order, "D1 C1 D2 C2 P1");
base::RunLoop().RunUntilIdle();
EXPECT_THAT(run_order, testing::ElementsAre("P1", "C1", "C2", "D1", "D2"));
EXPECT_EQ(UseCase::kNone, CurrentUseCase());
// Next compositor task is the BeginMainFrame.
DoMainFrame();
run_order.clear();
PostTestTasks(&run_order, "C1 D1 D2 C2 P1");
base::RunLoop().RunUntilIdle();
EXPECT_THAT(run_order, testing::ElementsAre("P1", "C1", "D1", "D2", "C2"));
EXPECT_EQ(UseCase::kNone, CurrentUseCase());
}
class VeryHighPriorityForCompositingBudgetBeginMainFrameExperimentTest
: public MainThreadSchedulerImplTest {
public:
VeryHighPriorityForCompositingBudgetBeginMainFrameExperimentTest()
: MainThreadSchedulerImplTest({kVeryHighPriorityForCompositingBudget,
kPrioritizeCompositingUntilBeginMainFrame},
{}) {}
};
INSTANTIATE_TEST_SUITE_P(
,
VeryHighPriorityForCompositingBudgetBeginMainFrameExperimentTest,
testing::Values(AntiStarvationLogic::kEnabled,
AntiStarvationLogic::kDisabled),
GetTestNameSuffix);
TEST_P(
VeryHighPriorityForCompositingBudgetBeginMainFrameExperimentTest,
TestCompositorPolicy_CompositorPriorityNonBeginMainFrameDoesntExhaustBudget) {
// 1000ms compositor task will not exhaust the budget.
RunSlowCompositorTask();
Vector<String> run_order;
PostTestTasks(&run_order, "D1 C1 D2 C2 P1");
base::RunLoop().RunUntilIdle();
EXPECT_THAT(run_order, testing::ElementsAre("P1", "C1", "C2", "D1", "D2"));
EXPECT_EQ(UseCase::kNone, CurrentUseCase());
}
TEST_P(VeryHighPriorityForCompositingBudgetBeginMainFrameExperimentTest,
TestCompositorPolicy_CompositorPriorityBeginMainFrameExhaustsBudget) {
// 1000ms BeginMainFrame will exhaust the budget.
DoMainFrame();
RunSlowCompositorTask();
Vector<String> run_order;
PostTestTasks(&run_order, "D1 C1 D2 C2 P1");
base::RunLoop().RunUntilIdle();
EXPECT_THAT(run_order, testing::ElementsAre("P1", "D1", "C1", "D2", "C2"));
EXPECT_EQ(UseCase::kNone, CurrentUseCase());
}
} // namespace main_thread_scheduler_impl_unittest
} // namespace scheduler
} // namespace blink
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