Commit f03480fa authored by Alexander Timin's avatar Alexander Timin Committed by Commit Bot

[scheduler] Prioritise N compositor tasks when processing input.

Support temporarily increased priority for compositor tasks for input:
- Explicit OnMainFrameRequestedForInput signal (new)
- Implicit presence of input tasks.

This patch does not change default behaviour, but add Finch hooks for enabling
these options and controlling the number of tasks N.

R=skyostil@chromium.org,alexclarke@chromium.org
BUG=853771

Change-Id: Id82b712e46108c51a948a66cfd31556e04eb457a
Reviewed-on: https://chromium-review.googlesource.com/1104677Reviewed-by: default avatarAlex Clarke <alexclarke@chromium.org>
Reviewed-by: default avatarDave Tapuska <dtapuska@chromium.org>
Commit-Queue: Alexander Timin <altimin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#570742}
parent c803b897
......@@ -526,6 +526,8 @@ void MainThreadEventQueue::SetNeedsMainFrame() {
}
if (client_)
client_->SetNeedsMainFrame();
if (main_thread_scheduler_)
main_thread_scheduler_->OnMainFrameRequestedForInput();
return;
}
......
......@@ -55,6 +55,7 @@ class FakeRendererScheduler : public WebThreadScheduler {
WebScopedVirtualTimePauser CreateWebScopedVirtualTimePauser(
const char* name,
WebScopedVirtualTimePauser::VirtualTaskDuration duration) override;
void OnMainFrameRequestedForInput() override;
private:
DISALLOW_COPY_AND_ASSIGN(FakeRendererScheduler);
......
......@@ -66,6 +66,7 @@ class MockRendererScheduler : public WebThreadScheduler {
WebScopedVirtualTimePauser(
const char* name,
WebScopedVirtualTimePauser::VirtualTaskDuration));
MOCK_METHOD0(OnMainFrameRequestedForInput, void());
private:
DISALLOW_COPY_AND_ASSIGN(MockRendererScheduler);
......
......@@ -154,6 +154,10 @@ class BLINK_PLATFORM_EXPORT WebThreadScheduler {
// If set to true, then the scheduler should not freeze the renderer.
virtual void SetSchedulerKeepActive(bool keep_active);
// Tells the scheduler when a begin main frame is requested due to input
// handling.
virtual void OnMainFrameRequestedForInput();
#if defined(OS_ANDROID)
// Android WebView has very strange WebView.pauseTimers/resumeTimers API.
// It's very old and very inconsistent. The API promises that this
......
......@@ -89,6 +89,8 @@ blink_platform_sources("scheduler") {
"main_thread/page_scheduler_impl.h",
"main_thread/page_visibility_state.cc",
"main_thread/page_visibility_state.h",
"main_thread/prioritize_compositing_after_input_experiment.cc",
"main_thread/prioritize_compositing_after_input_experiment.h",
"main_thread/queueing_time_estimator.cc",
"main_thread/queueing_time_estimator.h",
"main_thread/render_widget_signals.cc",
......
......@@ -16,6 +16,37 @@ const base::Feature kHighPriorityInput{"BlinkSchedulerHighPriorityInput",
const base::Feature kDedicatedWorkerThrottling{
"BlinkSchedulerWorkerThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
// COMPOSITING PRIORITY EXPERIMENT CONTROLS
// Enables experiment to increase priority of the compositing tasks during
// input handling. Other features in this section do not have any effect
// when this feature is disabled.
const base::Feature kPrioritizeCompositingAfterInput{
"BlinkSchedulerPrioritizeCompositingAfterInput",
base::FEATURE_DISABLED_BY_DEFAULT};
// Use kHighestPriority for compositing tasks during the experiment.
// kHighPriority is used otherwise.
const base::Feature kHighestPriorityForCompositingAfterInput{
"BlinkSchedulerHighestPriorityForCompostingAfterInput",
base::FEATURE_DISABLED_BY_DEFAULT};
// If enabled, MainFrameSchedulerImpl::OnRequestMainFrameForInput is used as
// triggering signal for the experiment. If disabled, the presence of an input
// task is used as trigger.
const base::Feature kUseExplicitSignalForTriggeringCompositingPrioritization{
"BlinkSchedulerUseExplicitSignalForTriggeringCompositingPrioritization",
base::FEATURE_DISABLED_BY_DEFAULT};
// If enabled, the increased priority continues until we get the appropriate
// number of WillBeginMainFrame signals. If disabled, the priority is increased
// for the fixed number of compositing tasks.
const base::Feature kUseWillBeginMainFrameForCompositingPrioritization{
"BlinkSchedulerUseWillBeginMainFrameForCompositingPrioritization",
base::FEATURE_DISABLED_BY_DEFAULT};
// LOAD PRIORITY EXPERIMENT CONTROLS
// Enables setting the priority of background (with no audio) pages'
// task queues to low priority.
const base::Feature kLowPriorityForBackgroundPages{
......
......@@ -168,5 +168,9 @@ WebScopedVirtualTimePauser WebThreadScheduler::CreateWebScopedVirtualTimePauser(
return WebScopedVirtualTimePauser();
}
void WebThreadScheduler::OnMainFrameRequestedForInput() {
NOTREACHED();
}
} // namespace scheduler
} // namespace blink
......@@ -65,7 +65,7 @@ constexpr base::TimeDelta kQueueingTimeWindowDuration =
const double kSamplingRateForTaskUkm = 0.0001;
const int64_t kSecondsPerMinute = 60;
// Field trial name.
// Wake-up throttling trial.
const char kWakeUpThrottlingTrial[] = "RendererSchedulerWakeUpThrottling";
const char kWakeUpDurationParam[] = "wake_up_duration_ms";
......@@ -579,7 +579,9 @@ MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
max_virtual_time_task_starvation_count(0),
virtual_time_stopped(false),
nested_runloop(false),
uniform_distribution(0.0f, 1.0f) {}
uniform_distribution(0.0f, 1.0f),
compositing_experiment(main_thread_scheduler_impl),
should_prioritize_compositing(false) {}
MainThreadSchedulerImpl::MainThreadOnly::~MainThreadOnly() = default;
......@@ -878,6 +880,7 @@ void MainThreadSchedulerImpl::WillBeginFrame(const viz::BeginFrameArgs& args) {
base::AutoLock lock(any_thread_lock_);
any_thread().begin_main_frame_on_critical_path = args.on_critical_path;
}
main_thread_only().compositing_experiment.OnWillBeginMainFrame();
}
void MainThreadSchedulerImpl::DidCommitFrameToCompositor() {
......@@ -1031,6 +1034,10 @@ void MainThreadSchedulerImpl::SetSchedulerKeepActive(bool keep_active) {
}
}
void MainThreadSchedulerImpl::OnMainFrameRequestedForInput() {
main_thread_only().compositing_experiment.OnMainFrameRequestedForInput();
}
bool MainThreadSchedulerImpl::SchedulerKeepActive() {
return main_thread_only().keep_active_fetch_or_worker;
}
......@@ -1601,6 +1608,12 @@ void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
new_policy.should_disable_throttling() = main_thread_only().use_virtual_time;
if (main_thread_only().should_prioritize_compositing) {
new_policy.compositor_priority() =
main_thread_only()
.compositing_experiment.GetIncreasedCompositingPriority();
}
// Tracing is done before the early out check, because it's quite possible we
// will otherwise miss this information in traces.
CreateTraceEventObjectSnapshotLocked();
......@@ -2497,6 +2510,8 @@ void MainThreadSchedulerImpl::OnTaskCompleted(
if (queue)
task_queue_throttler()->OnTaskRunTimeReported(queue, start, end);
main_thread_only().compositing_experiment.OnTaskCompleted(queue);
// TODO(altimin): Per-page metrics should also be considered.
main_thread_only().metrics_helper.RecordTaskMetrics(queue, task, start, end,
thread_time);
......@@ -2782,6 +2797,17 @@ MainThreadSchedulerImpl::scheduling_settings() const {
return scheduling_settings_;
}
void MainThreadSchedulerImpl::SetShouldPrioritizeCompositing(
bool should_prioritize_compositing) {
if (main_thread_only().should_prioritize_compositing ==
should_prioritize_compositing) {
return;
}
main_thread_only().should_prioritize_compositing =
should_prioritize_compositing;
UpdatePolicy();
}
// static
const char* MainThreadSchedulerImpl::UseCaseToString(UseCase use_case) {
switch (use_case) {
......
......@@ -37,6 +37,7 @@
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/task_cost_estimator.h"
......@@ -145,6 +146,7 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
void SetRendererBackgrounded(bool backgrounded) override;
void SetSchedulerKeepActive(bool keep_active) override;
bool SchedulerKeepActive();
void OnMainFrameRequestedForInput() override;
#if defined(OS_ANDROID)
void PauseTimersForAndroidWebView() override;
void ResumeTimersForAndroidWebView() override;
......@@ -346,6 +348,8 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
const SchedulingSettings& scheduling_settings() const;
void SetShouldPrioritizeCompositing(bool should_prioritize_compositing);
base::WeakPtr<MainThreadSchedulerImpl> GetWeakPtr();
protected:
......@@ -567,6 +571,11 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
void EndIdlePeriod();
// Update a policy which increases priority for the next beginMainFrame after
// an input event.
void UpdatePrioritizeCompositingAfterInputAfterTaskCompleted(
MainThreadTaskQueue* queue);
// Returns the serialized scheduler state for tracing.
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue(
base::TimeTicks optional_now) const;
......@@ -703,6 +712,8 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
void InitWakeUpBudgetPoolIfNeeded();
void SetNumberOfCompositingTasksToPrioritize(int number_of_tasks);
// Indicates that scheduler has been shutdown.
// It should be accessed only on the main thread, but couldn't be a member
// of MainThreadOnly struct because last might be destructed before we
......@@ -857,6 +868,10 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
std::mt19937_64 random_generator;
std::uniform_real_distribution<double> uniform_distribution;
// High-priority for compositing events after input experiment.
PrioritizeCompositingAfterInputExperiment compositing_experiment;
bool should_prioritize_compositing;
};
struct AnyThread {
......
......@@ -286,12 +286,17 @@ class MainThreadSchedulerImplForTest : public MainThreadSchedulerImpl {
class MainThreadSchedulerImplTest : public testing::Test {
public:
MainThreadSchedulerImplTest()
MainThreadSchedulerImplTest(std::vector<base::Feature> features_to_enable,
std::vector<base::Feature> features_to_disable)
: fake_task_(TaskQueue::PostedTask(base::BindOnce([] {}), FROM_HERE),
base::TimeTicks()) {
feature_list_.InitAndEnableFeature(kHighPriorityInput);
feature_list_.InitWithFeatures(features_to_enable, features_to_disable);
}
MainThreadSchedulerImplTest()
: MainThreadSchedulerImplTest({kHighPriorityInput},
{kPrioritizeCompositingAfterInput}) {}
~MainThreadSchedulerImplTest() override = default;
void SetUp() override {
......@@ -914,6 +919,8 @@ TEST_F(MainThreadSchedulerImplTest, TestDefaultPolicy) {
EnableIdleTasks();
base::RunLoop().RunUntilIdle();
// High-priority input is enabled and input tasks are processed first.
// One compositing event is prioritized after an input event but still
// has lower priority than input event.
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("P1"), std::string("P2"),
std::string("L1"), std::string("D1"),
......@@ -3867,6 +3874,70 @@ TEST_F(MainThreadSchedulerImplTest, ShouldIgnoreTaskForUkm) {
}
}
class CompositingExperimentWithExplicitSignalsTest
: public MainThreadSchedulerImplTest {
public:
CompositingExperimentWithExplicitSignalsTest()
: MainThreadSchedulerImplTest(
{kHighPriorityInput, kPrioritizeCompositingAfterInput,
kUseExplicitSignalForTriggeringCompositingPrioritization,
kUseWillBeginMainFrameForCompositingPrioritization},
{}) {}
};
TEST_F(CompositingExperimentWithExplicitSignalsTest, CompositingAfterInput) {
std::vector<std::string> run_order;
PostTestTasks(&run_order, "P1 T1 C1");
base::RunLoop().RunUntilIdle();
// Without an explicit signal nothing should be reordered.
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("P1"), std::string("T1"),
std::string("C1")));
run_order.clear();
scheduler_->OnMainFrameRequestedForInput();
PostTestTasks(&run_order, "T2 C2 C3");
base::RunLoop().RunUntilIdle();
// When a signal is present, compositing tasks should be prioritized until
// WillBeginMainFrame is received.
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("C2"), std::string("C3"),
std::string("T2")));
run_order.clear();
scheduler_->WillBeginFrame(viz::BeginFrameArgs());
PostTestTasks(&run_order, "T3 C4 C5");
base::RunLoop().RunUntilIdle();
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("T3"), std::string("C4"),
std::string("C5")));
run_order.clear();
}
class CompositingExperimentWithImplicitSignalsTest
: public MainThreadSchedulerImplTest {
public:
CompositingExperimentWithImplicitSignalsTest()
: MainThreadSchedulerImplTest(
{kHighPriorityInput, kPrioritizeCompositingAfterInput},
{kHighestPriorityForCompositingAfterInput,
kUseExplicitSignalForTriggeringCompositingPrioritization,
kUseWillBeginMainFrameForCompositingPrioritization}) {}
};
TEST_F(CompositingExperimentWithImplicitSignalsTest, CompositingAfterInput) {
std::vector<std::string> run_order;
PostTestTasks(&run_order, "T1 C1 C2 P1 P2");
base::RunLoop().RunUntilIdle();
// One compositing task should be prioritized after input.
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("P1"), std::string("P2"),
std::string("C1"), std::string("T1"),
std::string("C2")));
}
} // namespace main_thread_scheduler_impl_unittest
} // namespace scheduler
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h"
#include "third_party/blink/renderer/platform/scheduler/child/features.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
namespace blink {
namespace scheduler {
namespace {
// Prioritize compositing after input trial.
constexpr const char kPrioritizeCompositingAfterInputTrial[] =
"BlinkSchedulerPrioritizeCompositingAfterInput";
constexpr const char kNumberOfCompositingTasksToPrioritizeAfterInputParam[] =
"number_of_tasks";
constexpr size_t kDefaultNumberOfTasksToPrioritizeAfterInput = 1;
size_t GetNumberOfCompositingTasksToPrioritizeAfterInput() {
if (!base::FeatureList::IsEnabled(kPrioritizeCompositingAfterInput))
return 0;
int number_of_tasks;
if (!base::StringToInt(
base::GetFieldTrialParamValue(
kPrioritizeCompositingAfterInputTrial,
kNumberOfCompositingTasksToPrioritizeAfterInputParam),
&number_of_tasks)) {
return kDefaultNumberOfTasksToPrioritizeAfterInput;
}
return number_of_tasks;
}
} // namespace
PrioritizeCompositingAfterInputExperiment::
PrioritizeCompositingAfterInputExperiment(
MainThreadSchedulerImpl* scheduler)
: scheduler_(scheduler),
increased_compositing_priority_(
base::FeatureList::IsEnabled(kHighestPriorityForCompositingAfterInput)
? base::sequence_manager::TaskQueue::QueuePriority::
kHighestPriority
: base::sequence_manager::TaskQueue::QueuePriority::
kHighPriority),
number_of_tasks_to_prioritize_after_input_(
GetNumberOfCompositingTasksToPrioritizeAfterInput()),
trigger_type_(
base::FeatureList::IsEnabled(
kUseExplicitSignalForTriggeringCompositingPrioritization)
? TriggerType::kExplicitSignal
: TriggerType::kInferredFromInput),
stop_signal_type_(base::FeatureList::IsEnabled(
kUseWillBeginMainFrameForCompositingPrioritization)
? StopSignalType::kWillBeginMainFrameSignal
: StopSignalType::kAllCompositingTasks),
number_of_tasks_to_prioritize_(0) {}
PrioritizeCompositingAfterInputExperiment::
~PrioritizeCompositingAfterInputExperiment() {}
void PrioritizeCompositingAfterInputExperiment::
SetNumberOfCompositingTasksToPrioritize(int number_of_tasks) {
number_of_tasks = std::max(number_of_tasks, 0);
bool did_prioritize_compositing = number_of_tasks_to_prioritize_ > 0;
number_of_tasks_to_prioritize_ = number_of_tasks;
bool should_prioritize_compositing = number_of_tasks_to_prioritize_ > 0;
if (did_prioritize_compositing != should_prioritize_compositing)
scheduler_->SetShouldPrioritizeCompositing(should_prioritize_compositing);
}
base::sequence_manager::TaskQueue::QueuePriority
PrioritizeCompositingAfterInputExperiment::GetIncreasedCompositingPriority() {
return increased_compositing_priority_;
}
void PrioritizeCompositingAfterInputExperiment::OnTaskCompleted(
MainThreadTaskQueue* queue) {
if (!queue)
return;
if (queue->queue_type() == MainThreadTaskQueue::QueueType::kInput &&
trigger_type_ == TriggerType::kInferredFromInput) {
SetNumberOfCompositingTasksToPrioritize(
number_of_tasks_to_prioritize_after_input_);
} else if (queue->queue_type() ==
MainThreadTaskQueue::QueueType::kCompositor &&
stop_signal_type_ == StopSignalType::kAllCompositingTasks) {
SetNumberOfCompositingTasksToPrioritize(number_of_tasks_to_prioritize_ - 1);
}
}
void PrioritizeCompositingAfterInputExperiment::OnWillBeginMainFrame() {
if (stop_signal_type_ != StopSignalType::kWillBeginMainFrameSignal)
return;
SetNumberOfCompositingTasksToPrioritize(number_of_tasks_to_prioritize_ - 1);
}
void PrioritizeCompositingAfterInputExperiment::OnMainFrameRequestedForInput() {
if (trigger_type_ != TriggerType::kExplicitSignal)
return;
SetNumberOfCompositingTasksToPrioritize(
number_of_tasks_to_prioritize_after_input_);
}
} // namespace scheduler
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_PRIORITIZE_COMPOSITING_AFTER_INPUT_EXPERIMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_PRIORITIZE_COMPOSITING_AFTER_INPUT_EXPERIMENT_H_
#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
namespace blink {
namespace scheduler {
class MainThreadSchedulerImpl;
class MainThreadTaskQueue;
class PLATFORM_EXPORT PrioritizeCompositingAfterInputExperiment {
public:
explicit PrioritizeCompositingAfterInputExperiment(
MainThreadSchedulerImpl* scheduler);
~PrioritizeCompositingAfterInputExperiment();
base::sequence_manager::TaskQueue::QueuePriority
GetIncreasedCompositingPriority();
void OnTaskCompleted(MainThreadTaskQueue* queue);
void OnWillBeginMainFrame();
void OnMainFrameRequestedForInput();
private:
enum class TriggerType { kExplicitSignal, kInferredFromInput };
enum class StopSignalType { kAllCompositingTasks, kWillBeginMainFrameSignal };
void SetNumberOfCompositingTasksToPrioritize(int number_of_tasks);
MainThreadSchedulerImpl* scheduler_; // Not owned.
const base::sequence_manager::TaskQueue::QueuePriority
increased_compositing_priority_;
const int number_of_tasks_to_prioritize_after_input_;
const TriggerType trigger_type_;
const StopSignalType stop_signal_type_;
int number_of_tasks_to_prioritize_;
};
} // namespace scheduler
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_PRIORITIZE_COMPOSITING_AFTER_INPUT_EXPERIMENT_H_
......@@ -100,6 +100,8 @@ void FakeRendererScheduler::SetRAILModeObserver(RAILModeObserver* observer) {}
void FakeRendererScheduler::SetRendererProcessType(RendererProcessType type) {}
void FakeRendererScheduler::OnMainFrameRequestedForInput() {}
WebScopedVirtualTimePauser
FakeRendererScheduler::CreateWebScopedVirtualTimePauser(
const char* name,
......
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