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

[scheduler] Enabling rendering prioritization by default.

Previously, the blink scheduler would run rendering at the same priority
as most work on the main thread (eg. postMessage, timers, ect.) which
could leave rendering to get starved by other tasks and cause visual
lag.This change periodically prioritizes rendering, targeting a lower
frame rate of 10 fps, in order to prevent rendering starvation
(fixing issues like crbug.com/921335 and crbug.com/943621).
Given good results during experimentation, we have decided to enable
this behavior by default.

This CL also has a small implementation change, using a TickClock to
measure time between compositor tasks instead of posting a delayed task
to serve as a countdown.

Bug: 966177
Change-Id: I4956a9f5dbfb7258d8fdc8ad45e74f62db8917b4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2030124
Commit-Queue: Katie Dillon <kdillon@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarScott Haseley <shaseley@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737132}
parent e4016ef9
......@@ -98,6 +98,8 @@ TEST_F(UserLevelMemoryPressureSignalGeneratorTest, GeneratesWhenOverThreshold) {
mock_memory_usage_monitor.get());
MockUserLevelMemoryPressureSignalGenerator generator;
generator.SetTickClockForTesting(test_task_runner_->GetMockTickClock());
// Ensure we are not loading as no signals are sent during a loading phase.
generator.OnRAILModeChanged(RAILMode::kAnimation);
{
EXPECT_CALL(generator, Generate(_)).Times(0);
MemoryUsage usage;
......@@ -135,6 +137,8 @@ TEST_F(UserLevelMemoryPressureSignalGeneratorTest, GenerationPauses) {
mock_memory_usage_monitor.get());
MockUserLevelMemoryPressureSignalGenerator generator;
generator.SetTickClockForTesting(test_task_runner_->GetMockTickClock());
// Ensure we are not loading as no signals are sent during a loading phase.
generator.OnRAILModeChanged(RAILMode::kAnimation);
{
MemoryUsage usage;
usage.v8_bytes = 0;
......
......@@ -73,7 +73,7 @@ const base::Feature kVeryHighPriorityForCompositingAlternating{
// to kNormalPriority.
const base::Feature kVeryHighPriorityForCompositingAfterDelay{
"BlinkSchedulerVeryHighPriorityForCompositingAfterDelay",
base::FEATURE_DISABLED_BY_DEFAULT};
base::FEATURE_ENABLED_BY_DEFAULT};
// Param for kVeryHighPriorityForCompositingAfterDelay experiment. How long
// in ms the compositor will wait to be prioritized if no compositor tasks run.
......
......@@ -15,17 +15,14 @@ CompositorPriorityExperiments::CompositorPriorityExperiments(
MainThreadSchedulerImpl* scheduler)
: scheduler_(scheduler),
experiment_(GetExperimentFromFeatureList()),
last_compositor_task_time_(scheduler_->GetTickClock()->NowTicks()),
prioritize_compositing_after_delay_length_(
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)));
}
CompositorPriorityExperiments::~CompositorPriorityExperiments() {}
: StopSignalType::kAnyCompositorTask) {}
CompositorPriorityExperiments::~CompositorPriorityExperiments() = default;
CompositorPriorityExperiments::Experiment
CompositorPriorityExperiments::GetExperimentFromFeatureList() {
......@@ -37,12 +34,12 @@ CompositorPriorityExperiments::GetExperimentFromFeatureList() {
} else if (base::FeatureList::IsEnabled(
kVeryHighPriorityForCompositingAlternating)) {
return Experiment::kVeryHighPriorityForCompositingAlternating;
} else if (base::FeatureList::IsEnabled(
kVeryHighPriorityForCompositingAfterDelay)) {
return Experiment::kVeryHighPriorityForCompositingAfterDelay;
} else if (base::FeatureList::IsEnabled(
kVeryHighPriorityForCompositingBudget)) {
return Experiment::kVeryHighPriorityForCompositingBudget;
} else if (base::FeatureList::IsEnabled(
kVeryHighPriorityForCompositingAfterDelay)) {
return Experiment::kVeryHighPriorityForCompositingAfterDelay;
} else {
return Experiment::kNone;
}
......@@ -75,15 +72,7 @@ QueuePriority CompositorPriorityExperiments::GetCompositorPriority() const {
}
}
void CompositorPriorityExperiments::DoPrioritizeCompositingAfterDelay() {
delay_compositor_priority_ = QueuePriority::kVeryHighPriority;
scheduler_->OnCompositorPriorityExperimentUpdateCompositorPriority();
}
void CompositorPriorityExperiments::OnMainThreadSchedulerInitialized() {
if (experiment_ == Experiment::kVeryHighPriorityForCompositingAfterDelay) {
PostPrioritizeCompositingAfterDelayTask();
}
if (experiment_ == Experiment::kVeryHighPriorityForCompositingBudget) {
budget_pool_controller_.reset(new CompositorBudgetPoolController(
this, scheduler_, scheduler_->CompositorTaskQueue().get(),
......@@ -102,14 +91,6 @@ void CompositorPriorityExperiments::OnWillBeginMainFrame() {
will_begin_main_frame_ = true;
}
void CompositorPriorityExperiments::PostPrioritizeCompositingAfterDelayTask() {
DCHECK_EQ(experiment_, Experiment::kVeryHighPriorityForCompositingAfterDelay);
scheduler_->ControlTaskRunner()->PostDelayedTask(
FROM_HERE, do_prioritize_compositing_after_delay_callback_.GetCallback(),
prioritize_compositing_after_delay_length_);
}
void CompositorPriorityExperiments::OnTaskCompleted(
MainThreadTaskQueue* queue,
QueuePriority current_compositor_priority,
......@@ -150,12 +131,15 @@ void CompositorPriorityExperiments::OnTaskCompleted(
case Experiment::kVeryHighPriorityForCompositingAfterDelay:
if (have_seen_stop_signal) {
delay_compositor_priority_ = QueuePriority::kNormalPriority;
do_prioritize_compositing_after_delay_callback_.Cancel();
PostPrioritizeCompositingAfterDelayTask();
if (current_compositor_priority != delay_compositor_priority_)
scheduler_->OnCompositorPriorityExperimentUpdateCompositorPriority();
last_compositor_task_time_ = task_timing->end_time();
} else {
if (task_timing->end_time() - last_compositor_task_time_ >=
prioritize_compositing_after_delay_length_) {
delay_compositor_priority_ = QueuePriority::kVeryHighPriority;
}
}
if (current_compositor_priority != delay_compositor_priority_)
scheduler_->OnCompositorPriorityExperimentUpdateCompositorPriority();
return;
case Experiment::kVeryHighPriorityForCompositingBudget:
budget_pool_controller_->OnTaskCompleted(queue, task_timing,
......@@ -188,7 +172,7 @@ CompositorPriorityExperiments::CompositorBudgetPoolController::
TraceableVariableController* tracing_controller,
base::TimeDelta min_budget,
double budget_recovery_rate)
: experiment_(experiment), tick_clock_(scheduler->GetTickClock()) {
: experiment_(experiment) {
DCHECK_EQ(compositor_queue->queue_type(),
MainThreadTaskQueue::QueueType::kCompositor);
base::TimeTicks now = scheduler->GetTickClock()->NowTicks();
......
......@@ -93,16 +93,10 @@ class PLATFORM_EXPORT CompositorPriorityExperiments {
CompositorPriorityExperiments* experiment_;
std::unique_ptr<CPUTimeBudgetPool> compositor_budget_pool_;
bool is_exhausted_ = false;
const base::TickClock* tick_clock_; // Not owned.
};
static Experiment GetExperimentFromFeatureList();
void DoPrioritizeCompositingAfterDelay();
void PostPrioritizeCompositingAfterDelayTask();
enum class StopSignalType { kAnyCompositorTask, kBeginMainFrameTask };
MainThreadSchedulerImpl* scheduler_; // Not owned.
......@@ -113,7 +107,7 @@ class PLATFORM_EXPORT CompositorPriorityExperiments {
QueuePriority::kVeryHighPriority;
QueuePriority delay_compositor_priority_ = QueuePriority::kNormalPriority;
CancelableClosureHolder do_prioritize_compositing_after_delay_callback_;
base::TimeTicks last_compositor_task_time_;
base::TimeDelta prioritize_compositing_after_delay_length_;
QueuePriority budget_compositor_priority_ = QueuePriority::kVeryHighPriority;
......
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