Commit c6f13d8b authored by Daniel Vogelheim's avatar Daniel Vogelheim Committed by Commit Bot

Introduce Loading Control Task Queue.

This introduces a separate task queue for 'control' loading tasks. That is,
very short task used to coordinate work between different loading tasks.
These are scheduled separately as these tasks would typically unblock other,
larger tasks.

Bug: 557466
Change-Id: Id2de6b73f24e550fe00efa19f4c898866ed0a1cb
Reviewed-on: https://chromium-review.googlesource.com/500147Reviewed-by: default avatarJochen Eisinger <jochen@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Reviewed-by: default avatarAlex Clarke <alexclarke@chromium.org>
Commit-Queue: Daniel Vogelheim <vogelheim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488623}
parent d706dfca
......@@ -27,6 +27,9 @@ RefPtr<WebTaskRunner> TaskRunnerHelper::Get(TaskType type, LocalFrame* frame) {
case TaskType::kNetworking:
return frame ? frame->FrameScheduler()->LoadingTaskRunner()
: Platform::Current()->CurrentThread()->GetWebTaskRunner();
case TaskType::kNetworkingControl:
return frame ? frame->FrameScheduler()->LoadingControlTaskRunner()
: Platform::Current()->CurrentThread()->GetWebTaskRunner();
// Throttling following tasks may break existing web pages, so tentatively
// these are unthrottled.
// TODO(nhiroki): Throttle them again after we're convinced that it's safe
......@@ -110,6 +113,7 @@ RefPtr<WebTaskRunner> TaskRunnerHelper::Get(TaskType type,
case TaskType::kDOMManipulation:
case TaskType::kUserInteraction:
case TaskType::kNetworking:
case TaskType::kNetworkingControl:
case TaskType::kHistoryTraversal:
case TaskType::kEmbed:
case TaskType::kMediaElementEvent:
......
......@@ -37,6 +37,8 @@ enum class TaskType : unsigned {
// This task source is used for features that trigger in response to network
// activity.
kNetworking,
// This task source is used for control messages between kNetworking tasks.
kNetworkingControl,
// This task source is used to queue calls to history.back() and similar APIs.
kHistoryTraversal,
......
......@@ -75,6 +75,7 @@ class EmptyFrameScheduler : public WebFrameScheduler {
void RemoveThrottlingObserver(ObserverType, Observer*) override {}
void SetFrameVisible(bool) override {}
RefPtr<WebTaskRunner> LoadingTaskRunner() override;
RefPtr<WebTaskRunner> LoadingControlTaskRunner() override;
RefPtr<WebTaskRunner> TimerTaskRunner() override;
RefPtr<WebTaskRunner> UnthrottledTaskRunner() override;
RefPtr<WebTaskRunner> SuspendableTaskRunner() override;
......@@ -85,6 +86,10 @@ RefPtr<WebTaskRunner> EmptyFrameScheduler::LoadingTaskRunner() {
return Platform::Current()->MainThread()->GetWebTaskRunner();
}
RefPtr<WebTaskRunner> EmptyFrameScheduler::LoadingControlTaskRunner() {
return Platform::Current()->MainThread()->GetWebTaskRunner();
}
RefPtr<WebTaskRunner> EmptyFrameScheduler::TimerTaskRunner() {
return Platform::Current()->MainThread()->GetWebTaskRunner();
}
......
......@@ -85,6 +85,12 @@ class WebFrameScheduler {
// suspended or blocked. Should be used only when necessary after
// consulting scheduler-dev@.
// Return a WebTaskRunner for very short control messages between loading
// tasks. Caution is needed when posting tasks to this WebTaskRunner because
// they could starve out other work.
// WebFrameScheduler owns the returned WebTaskRunner.
virtual RefPtr<WebTaskRunner> LoadingControlTaskRunner() = 0;
// Returns the WebTaskRunner for timer tasks.
// WebFrameScheduler owns the returned WebTaskRunner.
virtual RefPtr<WebTaskRunner> TimerTaskRunner() = 0;
......
......@@ -99,6 +99,9 @@ class MockFetchContext : public FetchContext {
void RemoveThrottlingObserver(ObserverType, Observer*) override {}
RefPtr<WebTaskRunner> TimerTaskRunner() override { return runner_; }
RefPtr<WebTaskRunner> LoadingTaskRunner() override { return runner_; }
RefPtr<WebTaskRunner> LoadingControlTaskRunner() override {
return runner_;
}
RefPtr<WebTaskRunner> SuspendableTaskRunner() override { return runner_; }
RefPtr<WebTaskRunner> UnthrottledTaskRunner() override { return runner_; }
RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() override {
......
......@@ -36,6 +36,8 @@ const char* MainThreadTaskQueue::NameForQueueType(
return "idle_tq";
case MainThreadTaskQueue::QueueType::TEST:
return "test_tq";
case MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL:
return "frame_loading_control_tq";
case MainThreadTaskQueue::QueueType::COUNT:
NOTREACHED();
return nullptr;
......@@ -54,6 +56,7 @@ MainThreadTaskQueue::QueueClass MainThreadTaskQueue::QueueClassForQueueType(
return QueueClass::NONE;
case QueueType::DEFAULT_LOADING:
case QueueType::FRAME_LOADING:
case QueueType::FRAME_LOADING_CONTROL:
return QueueClass::LOADING;
case QueueType::DEFAULT_TIMER:
case QueueType::FRAME_TIMER:
......@@ -82,6 +85,7 @@ MainThreadTaskQueue::MainThreadTaskQueue(
can_be_blocked_(params.can_be_blocked),
can_be_throttled_(params.can_be_throttled),
can_be_suspended_(params.can_be_suspended),
used_for_control_tasks_(params.used_for_control_tasks),
renderer_scheduler_(renderer_scheduler) {
GetTaskQueueImpl()->SetOnTaskCompletedHandler(base::Bind(
&MainThreadTaskQueue::OnTaskCompleted, base::Unretained(this)));
......
......@@ -28,8 +28,9 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
COMPOSITOR = 8,
IDLE = 9,
TEST = 10,
FRAME_LOADING_CONTROL = 11,
COUNT = 11
COUNT = 12
};
// Returns name of the given queue type. Returned string has application
......@@ -54,7 +55,8 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
spec(NameForQueueType(queue_type)),
can_be_blocked(false),
can_be_throttled(false),
can_be_suspended(false) {}
can_be_suspended(false),
used_for_control_tasks(false) {}
QueueCreationParams SetCanBeBlocked(bool value) {
can_be_blocked = value;
......@@ -71,6 +73,11 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
return *this;
}
QueueCreationParams SetUsedForControlTasks(bool value) {
used_for_control_tasks = value;
return *this;
}
// Forwarded calls to |spec|.
QueueCreationParams SetShouldMonitorQuiescence(bool should_monitor) {
......@@ -99,6 +106,7 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
bool can_be_blocked;
bool can_be_throttled;
bool can_be_suspended;
bool used_for_control_tasks;
};
~MainThreadTaskQueue() override;
......@@ -113,6 +121,8 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
bool CanBeSuspended() const { return can_be_suspended_; }
bool UsedForControlTasks() const { return used_for_control_tasks_; }
void OnTaskCompleted(const TaskQueue::Task& task,
base::TimeTicks start,
base::TimeTicks end);
......@@ -132,6 +142,7 @@ class PLATFORM_EXPORT MainThreadTaskQueue : public TaskQueue {
const bool can_be_blocked_;
const bool can_be_throttled_;
const bool can_be_suspended_;
const bool used_for_control_tasks_;
// Needed to notify renderer scheduler about completed tasks.
RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED
......
......@@ -383,9 +383,13 @@ scoped_refptr<MainThreadTaskQueue> RendererSchedulerImpl::NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType queue_type) {
DCHECK_EQ(MainThreadTaskQueue::QueueClassForQueueType(queue_type),
MainThreadTaskQueue::QueueClass::LOADING);
return NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(queue_type)
.SetCanBeSuspended(true)
.SetCanBeBlocked(true));
return NewTaskQueue(
MainThreadTaskQueue::QueueCreationParams(queue_type)
.SetCanBeSuspended(true)
.SetCanBeBlocked(true)
.SetUsedForControlTasks(
queue_type ==
MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL));
}
scoped_refptr<MainThreadTaskQueue> RendererSchedulerImpl::NewTimerTaskQueue(
......@@ -1634,7 +1638,8 @@ bool RendererSchedulerImpl::TaskQueuePolicy::IsQueueEnabled(
TaskQueue::QueuePriority RendererSchedulerImpl::TaskQueuePolicy::GetPriority(
MainThreadTaskQueue* task_queue) const {
return priority;
return task_queue->UsedForControlTasks() ? TaskQueue::HIGH_PRIORITY
: priority;
}
RendererSchedulerImpl::TimeDomainType
......
......@@ -158,6 +158,7 @@ class PLATFORM_EXPORT RendererSchedulerImpl
// Returns a new loading task queue. This queue is intended for tasks related
// to resource dispatch, foreground HTML parsing, etc...
// Note: Tasks posted to FRAME_LOADING_CONTROL queues must execute quickly.
scoped_refptr<MainThreadTaskQueue> NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType queue_type);
......
......@@ -290,6 +290,8 @@ class RendererSchedulerImplTest : public ::testing::Test {
default_task_runner_ = scheduler_->DefaultTaskQueue();
compositor_task_runner_ = scheduler_->CompositorTaskQueue();
loading_task_runner_ = scheduler_->LoadingTaskQueue();
loading_control_task_runner_ = scheduler_->NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL);
idle_task_runner_ = scheduler_->IdleTaskRunner();
timer_task_runner_ = scheduler_->TimerTaskQueue();
}
......@@ -592,6 +594,7 @@ class RendererSchedulerImplTest : public ::testing::Test {
// - 'D': Default task
// - 'C': Compositor task
// - 'L': Loading task
// - 'M': Loading Control task
// - 'I': Idle task
// - 'T': Timer task
void PostTestTasks(std::vector<std::string>* run_order,
......@@ -613,6 +616,10 @@ class RendererSchedulerImplTest : public ::testing::Test {
loading_task_runner_->PostTask(
FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
break;
case 'M':
loading_control_task_runner_->PostTask(
FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
break;
case 'I':
idle_task_runner_->PostIdleTask(
FROM_HERE,
......@@ -690,6 +697,7 @@ class RendererSchedulerImplTest : public ::testing::Test {
scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> loading_control_task_runner_;
scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_;
bool simulate_timer_task_ran_;
......@@ -3749,6 +3757,8 @@ TEST_F(RendererSchedulerImplTest, EnableVirtualTime) {
scoped_refptr<MainThreadTaskQueue> loading_tq =
scheduler_->NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType::FRAME_LOADING);
scoped_refptr<TaskQueue> loading_control_tq = scheduler_->NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL);
scoped_refptr<MainThreadTaskQueue> timer_tq = scheduler_->NewTimerTaskQueue(
MainThreadTaskQueue::QueueType::FRAME_TIMER);
scoped_refptr<MainThreadTaskQueue> unthrottled_tq =
......@@ -3771,6 +3781,8 @@ TEST_F(RendererSchedulerImplTest, EnableVirtualTime) {
scheduler_->real_time_domain());
EXPECT_EQ(loading_tq->GetTimeDomain(), scheduler_->GetVirtualTimeDomain());
EXPECT_EQ(loading_control_tq->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
EXPECT_EQ(timer_tq->GetTimeDomain(), scheduler_->GetVirtualTimeDomain());
EXPECT_EQ(unthrottled_tq->GetTimeDomain(),
scheduler_->GetVirtualTimeDomain());
......@@ -4072,5 +4084,18 @@ TEST_F(RendererSchedulerImplTest, DidCommitProvisionalLoad) {
EXPECT_TRUE(scheduler_->waiting_for_meaningful_paint()); // State cleared.
}
TEST_F(RendererSchedulerImplTest, LoadingControlTasks) {
// Expect control loading tasks (M) to jump ahead of any regular loading
// tasks (L).
std::vector<std::string> run_order;
PostTestTasks(&run_order, "L1 L2 M1 L3 L4 M2 L5 L6");
RunUntilIdle();
EXPECT_THAT(run_order,
testing::ElementsAre(std::string("M1"), std::string("M2"),
std::string("L1"), std::string("L2"),
std::string("L3"), std::string("L4"),
std::string("L5"), std::string("L6")));
}
} // namespace scheduler
} // namespace blink
......@@ -54,6 +54,11 @@ WebFrameSchedulerImpl::~WebFrameSchedulerImpl() {
loading_task_queue_->SetBlameContext(nullptr);
}
if (loading_control_task_queue_) {
loading_control_task_queue_->UnregisterTaskQueue();
loading_control_task_queue_->SetBlameContext(nullptr);
}
if (timer_task_queue_) {
RemoveTimerQueueFromBackgroundCPUTimeBudgetPool();
timer_task_queue_->UnregisterTaskQueue();
......@@ -157,6 +162,21 @@ RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::LoadingTaskRunner() {
return loading_web_task_runner_;
}
RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::LoadingControlTaskRunner() {
DCHECK(parent_web_view_scheduler_);
if (!loading_control_web_task_runner_) {
loading_control_task_queue_ = renderer_scheduler_->NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL);
loading_control_task_queue_->SetBlameContext(blame_context_);
loading_control_queue_enabled_voter_ =
loading_control_task_queue_->CreateQueueEnabledVoter();
loading_control_queue_enabled_voter_->SetQueueEnabled(!frame_suspended_);
loading_control_web_task_runner_ =
WebTaskRunnerImpl::Create(loading_control_task_queue_);
}
return loading_control_web_task_runner_;
}
RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::TimerTaskRunner() {
DCHECK(parent_web_view_scheduler_);
if (!timer_web_task_runner_) {
......@@ -296,6 +316,11 @@ void WebFrameSchedulerImpl::AsValueInto(
state->SetString("loading_task_queue",
trace_helper::PointerToString(loading_task_queue_.get()));
}
if (loading_control_task_queue_) {
state->SetString(
"loading_control_task_queue",
trace_helper::PointerToString(loading_control_task_queue_.get()));
}
if (timer_task_queue_)
state->SetString("timer_task_queue",
trace_helper::PointerToString(timer_task_queue_.get()));
......@@ -342,6 +367,8 @@ void WebFrameSchedulerImpl::SetSuspended(bool frame_suspended) {
frame_suspended_ = frame_suspended;
if (loading_queue_enabled_voter_)
loading_queue_enabled_voter_->SetQueueEnabled(!frame_suspended);
if (loading_control_queue_enabled_voter_)
loading_control_queue_enabled_voter_->SetQueueEnabled(!frame_suspended);
if (timer_queue_enabled_voter_)
timer_queue_enabled_voter_->SetQueueEnabled(!frame_suspended);
if (suspendable_queue_enabled_voter_)
......
......@@ -47,6 +47,7 @@ class WebFrameSchedulerImpl : public WebFrameScheduler {
void SetSuspended(bool frame_suspended) override;
void SetCrossOrigin(bool cross_origin) override;
RefPtr<WebTaskRunner> LoadingTaskRunner() override;
RefPtr<WebTaskRunner> LoadingControlTaskRunner() override;
RefPtr<WebTaskRunner> TimerTaskRunner() override;
RefPtr<WebTaskRunner> SuspendableTaskRunner() override;
RefPtr<WebTaskRunner> UnthrottledTaskRunner() override;
......@@ -93,15 +94,19 @@ class WebFrameSchedulerImpl : public WebFrameScheduler {
base::WeakPtr<WebFrameSchedulerImpl> AsWeakPtr();
scoped_refptr<TaskQueue> loading_task_queue_;
scoped_refptr<TaskQueue> loading_control_task_queue_;
scoped_refptr<TaskQueue> timer_task_queue_;
scoped_refptr<TaskQueue> unthrottled_task_queue_;
scoped_refptr<TaskQueue> suspendable_task_queue_;
scoped_refptr<TaskQueue> unthrottled_but_blockable_task_queue_;
std::unique_ptr<TaskQueue::QueueEnabledVoter> loading_queue_enabled_voter_;
std::unique_ptr<TaskQueue::QueueEnabledVoter>
loading_control_queue_enabled_voter_;
std::unique_ptr<TaskQueue::QueueEnabledVoter> timer_queue_enabled_voter_;
std::unique_ptr<TaskQueue::QueueEnabledVoter>
suspendable_queue_enabled_voter_;
RefPtr<WebTaskRunnerImpl> loading_web_task_runner_;
RefPtr<WebTaskRunnerImpl> loading_control_web_task_runner_;
RefPtr<WebTaskRunnerImpl> timer_web_task_runner_;
RefPtr<WebTaskRunnerImpl> unthrottled_web_task_runner_;
RefPtr<WebTaskRunnerImpl> suspendable_web_task_runner_;
......
......@@ -32003,6 +32003,7 @@ from previous Chrome versions.
<int value="8" label="Compositor"/>
<int value="9" label="Idle"/>
<int value="10" label="Test"/>
<int value="11" label="FrameLoadingControl"/>
</enum>
<enum name="RendererType">
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