Commit f7c0fc53 authored by Farah Charab's avatar Farah Charab Committed by Commit Bot

Scheduler: Introduce a new priority for task queues between high and

normal priority queues.

Modify the task queue selection and starvation logic, and add the
relevent unit tests.

Rename kHighPriority to kHighestPriority, and modify the affected
code. The introduced priority is kHighPriority.

Change-Id: If6d928180e8848f5492a64ce6a3d504219658376
Reviewed-on: https://chromium-review.googlesource.com/978011
Commit-Queue: Farah Charab <farahcharab@chromium.org>
Reviewed-by: default avatarSami Kyöstilä <skyostil@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548728}
parent 98fc2a89
...@@ -21,7 +21,7 @@ namespace base { ...@@ -21,7 +21,7 @@ namespace base {
namespace trace_event { namespace trace_event {
class BlameContext; class BlameContext;
} }
} } // namespace base
namespace blink { namespace blink {
namespace scheduler { namespace scheduler {
...@@ -80,11 +80,15 @@ class PLATFORM_EXPORT TaskQueue : public base::SingleThreadTaskRunner { ...@@ -80,11 +80,15 @@ class PLATFORM_EXPORT TaskQueue : public base::SingleThreadTaskRunner {
// private queues which perform control operations. // private queues which perform control operations.
kControlPriority, kControlPriority,
// The selector will prioritize high over normal and low and normal over // The selector will prioritize highest over high, normal and low; and
// low. However it will ensure neither of the lower priority queues can be // high over normal and low; and normal over low. However it will ensure
// completely starved by higher priority tasks. All three of these queues // neither of the lower priority queues can be completely starved by higher
// will always take priority over and can starve the best effort queue. // priority tasks. All three of these queues will always take priority over
// and can starve the best effort queue.
kHighestPriority,
kHighPriority, kHighPriority,
// Queues with normal priority are the default. // Queues with normal priority are the default.
kNormalPriority, kNormalPriority,
kLowPriority, kLowPriority,
......
...@@ -22,6 +22,8 @@ const char* TaskQueue::PriorityToString(TaskQueue::QueuePriority priority) { ...@@ -22,6 +22,8 @@ const char* TaskQueue::PriorityToString(TaskQueue::QueuePriority priority) {
switch (priority) { switch (priority) {
case kControlPriority: case kControlPriority:
return "control"; return "control";
case kHighestPriority:
return "highest";
case kHighPriority: case kHighPriority:
return "high"; return "high";
case kNormalPriority: case kNormalPriority:
...@@ -251,7 +253,8 @@ TaskQueueImpl::PostTaskResult TaskQueueImpl::PostDelayedTaskImpl( ...@@ -251,7 +253,8 @@ TaskQueueImpl::PostTaskResult TaskQueueImpl::PostDelayedTaskImpl(
} }
void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread(
Task pending_task, base::TimeTicks now) { Task pending_task,
base::TimeTicks now) {
main_thread_only().task_queue_manager->DidQueueTask(pending_task); main_thread_only().task_queue_manager->DidQueueTask(pending_task);
main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
......
...@@ -16,6 +16,7 @@ namespace internal { ...@@ -16,6 +16,7 @@ namespace internal {
TaskQueueSelector::TaskQueueSelector() TaskQueueSelector::TaskQueueSelector()
: prioritizing_selector_(this, "enabled"), : prioritizing_selector_(this, "enabled"),
immediate_starvation_count_(0), immediate_starvation_count_(0),
high_priority_starvation_score_(0),
normal_priority_starvation_score_(0), normal_priority_starvation_score_(0),
low_priority_starvation_score_(0), low_priority_starvation_score_(0),
task_queue_selector_observer_(nullptr) {} task_queue_selector_observer_(nullptr) {}
...@@ -198,6 +199,7 @@ bool TaskQueueSelector::PrioritizingSelector::SelectWorkQueueToService( ...@@ -198,6 +199,7 @@ bool TaskQueueSelector::PrioritizingSelector::SelectWorkQueueToService(
out_work_queue)) { out_work_queue)) {
return true; return true;
} }
// Select from the normal priority queue if we are starving it. // Select from the normal priority queue if we are starving it.
if (max_priority > TaskQueue::kNormalPriority && if (max_priority > TaskQueue::kNormalPriority &&
task_queue_selector_->normal_priority_starvation_score_ >= task_queue_selector_->normal_priority_starvation_score_ >=
...@@ -207,8 +209,19 @@ bool TaskQueueSelector::PrioritizingSelector::SelectWorkQueueToService( ...@@ -207,8 +209,19 @@ bool TaskQueueSelector::PrioritizingSelector::SelectWorkQueueToService(
out_work_queue)) { out_work_queue)) {
return true; return true;
} }
// Select from the high priority queue if we are starving it.
if (max_priority > TaskQueue::kHighPriority &&
task_queue_selector_->high_priority_starvation_score_ >=
kMaxHighPriorityStarvationScore &&
ChooseOldestWithPriority(TaskQueue::kHighPriority,
out_chose_delayed_over_immediate,
out_work_queue)) {
return true;
}
// Otherwise choose in priority order. // Otherwise choose in priority order.
for (TaskQueue::QueuePriority priority = TaskQueue::kHighPriority; for (TaskQueue::QueuePriority priority = TaskQueue::kHighestPriority;
priority < max_priority; priority = NextPriority(priority)) { priority < max_priority; priority = NextPriority(priority)) {
if (ChooseOldestWithPriority(priority, out_chose_delayed_over_immediate, if (ChooseOldestWithPriority(priority, out_chose_delayed_over_immediate,
out_work_queue)) { out_work_queue)) {
...@@ -257,11 +270,20 @@ void TaskQueueSelector::DidSelectQueueWithPriority( ...@@ -257,11 +270,20 @@ void TaskQueueSelector::DidSelectQueueWithPriority(
switch (priority) { switch (priority) {
case TaskQueue::kControlPriority: case TaskQueue::kControlPriority:
break; break;
case TaskQueue::kHighPriority: case TaskQueue::kHighestPriority:
low_priority_starvation_score_ += low_priority_starvation_score_ +=
kSmallScoreIncrementForLowPriorityStarvation; kSmallScoreIncrementForLowPriorityStarvation;
normal_priority_starvation_score_ += normal_priority_starvation_score_ +=
kSmallScoreIncrementForNormalPriorityStarvation; kSmallScoreIncrementForNormalPriorityStarvation;
high_priority_starvation_score_ +=
kSmallScoreIncrementForHighPriorityStarvation;
break;
case TaskQueue::kHighPriority:
low_priority_starvation_score_ +=
kLargeScoreIncrementForLowPriorityStarvation;
normal_priority_starvation_score_ +=
kLargeScoreIncrementForNormalPriorityStarvation;
high_priority_starvation_score_ = 0;
break; break;
case TaskQueue::kNormalPriority: case TaskQueue::kNormalPriority:
low_priority_starvation_score_ += low_priority_starvation_score_ +=
...@@ -271,6 +293,7 @@ void TaskQueueSelector::DidSelectQueueWithPriority( ...@@ -271,6 +293,7 @@ void TaskQueueSelector::DidSelectQueueWithPriority(
case TaskQueue::kLowPriority: case TaskQueue::kLowPriority:
case TaskQueue::kBestEffortPriority: case TaskQueue::kBestEffortPriority:
low_priority_starvation_score_ = 0; low_priority_starvation_score_ = 0;
high_priority_starvation_score_ = 0;
normal_priority_starvation_score_ = 0; normal_priority_starvation_score_ = 0;
break; break;
default: default:
...@@ -286,6 +309,8 @@ void TaskQueueSelector::DidSelectQueueWithPriority( ...@@ -286,6 +309,8 @@ void TaskQueueSelector::DidSelectQueueWithPriority(
void TaskQueueSelector::AsValueInto( void TaskQueueSelector::AsValueInto(
base::trace_event::TracedValue* state) const { base::trace_event::TracedValue* state) const {
DCHECK(main_thread_checker_.CalledOnValidThread()); DCHECK(main_thread_checker_.CalledOnValidThread());
state->SetInteger("high_priority_starvation_score",
high_priority_starvation_score_);
state->SetInteger("normal_priority_starvation_score", state->SetInteger("normal_priority_starvation_score",
normal_priority_starvation_score_); normal_priority_starvation_score_);
state->SetInteger("low_priority_starvation_score", state->SetInteger("low_priority_starvation_score",
......
...@@ -158,28 +158,46 @@ class PLATFORM_EXPORT TaskQueueSelector { ...@@ -158,28 +158,46 @@ class PLATFORM_EXPORT TaskQueueSelector {
void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority, void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority,
bool chose_delayed_over_immediate); bool chose_delayed_over_immediate);
// Maximum score to accumulate before high priority tasks are run even in
// the presence of highest priority tasks.
static const size_t kMaxHighPriorityStarvationScore = 3;
// Increment to be applied to the high priority starvation score when a task
// should have only a small effect on the score. E.g. A number of highest
// priority tasks must run before the high priority queue is considered
// starved.
static const size_t kSmallScoreIncrementForHighPriorityStarvation = 1;
// Maximum score to accumulate before normal priority tasks are run even in // Maximum score to accumulate before normal priority tasks are run even in
// the presence of high priority tasks. // the presence of higher priority tasks i.e. highest and high priority tasks.
static const size_t kMaxNormalPriorityStarvationScore = 5; static const size_t kMaxNormalPriorityStarvationScore = 5;
// Increment to be applied to the normal priority starvation score when a task // Increment to be applied to the normal priority starvation score when a task
// should have only a small effect on the score. E.g. A number of high // should have a large effect on the score. E.g Only a few high priority
// priority tasks must run before the normal priority queue is considered
// starved.
static const size_t kLargeScoreIncrementForNormalPriorityStarvation = 2;
// Increment to be applied to the normal priority starvation score when a task
// should have only a small effect on the score. E.g. A number of highest
// priority tasks must run before the normal priority queue is considered // priority tasks must run before the normal priority queue is considered
// starved. // starved.
static const size_t kSmallScoreIncrementForNormalPriorityStarvation = 1; static const size_t kSmallScoreIncrementForNormalPriorityStarvation = 1;
// Maximum score to accumulate before low priority tasks are run even in the // Maximum score to accumulate before low priority tasks are run even in the
// presence of high or normal priority tasks. // presence of highest, high, or normal priority tasks.
static const size_t kMaxLowPriorityStarvationScore = 25; static const size_t kMaxLowPriorityStarvationScore = 25;
// Increment to be applied to the low priority starvation score when a task // Increment to be applied to the low priority starvation score when a task
// should have a large effect on the score. E.g. Only a few normal priority // should have a large effect on the score. E.g. Only a few normal/high
// tasks must run before the low priority queue is considered starved. // priority tasks must run before the low priority queue is considered
// starved.
static const size_t kLargeScoreIncrementForLowPriorityStarvation = 5; static const size_t kLargeScoreIncrementForLowPriorityStarvation = 5;
// Increment to be applied to the low priority starvation score when a task // Increment to be applied to the low priority starvation score when a task
// should have only a small effect on the score. E.g. A lot of high priority // should have only a small effect on the score. E.g. A lot of highest
// tasks must run before the low priority queue is considered starved. // priority tasks must run before the low priority queue is considered
// starved.
static const size_t kSmallScoreIncrementForLowPriorityStarvation = 1; static const size_t kSmallScoreIncrementForLowPriorityStarvation = 1;
// Maximum number of delayed tasks tasks which can be run while there's a // Maximum number of delayed tasks tasks which can be run while there's a
...@@ -191,6 +209,7 @@ class PLATFORM_EXPORT TaskQueueSelector { ...@@ -191,6 +209,7 @@ class PLATFORM_EXPORT TaskQueueSelector {
PrioritizingSelector prioritizing_selector_; PrioritizingSelector prioritizing_selector_;
size_t immediate_starvation_count_; size_t immediate_starvation_count_;
size_t high_priority_starvation_score_;
size_t normal_priority_starvation_score_; size_t normal_priority_starvation_score_;
size_t low_priority_starvation_score_; size_t low_priority_starvation_score_;
......
...@@ -1428,7 +1428,7 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { ...@@ -1428,7 +1428,7 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE; new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
expensive_task_policy = ExpensiveTaskPolicy::kBlock; expensive_task_policy = ExpensiveTaskPolicy::kBlock;
new_policy.compositor_queue_policy().priority = new_policy.compositor_queue_policy().priority =
TaskQueue::kHighPriority; TaskQueue::kHighestPriority;
} else { } else {
// What we really want to do is priorize loading tasks, but that doesn't // What we really want to do is priorize loading tasks, but that doesn't
// seem to be safe. Instead we do that by proxy by deprioritizing // seem to be safe. Instead we do that by proxy by deprioritizing
...@@ -1440,7 +1440,7 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { ...@@ -1440,7 +1440,7 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
case UseCase::kSynchronizedGesture: case UseCase::kSynchronizedGesture:
new_policy.compositor_queue_policy().priority = new_policy.compositor_queue_policy().priority =
main_thread_compositing_is_fast ? TaskQueue::kHighPriority main_thread_compositing_is_fast ? TaskQueue::kHighestPriority
: TaskQueue::kNormalPriority; : TaskQueue::kNormalPriority;
if (touchstart_expected_soon) { if (touchstart_expected_soon) {
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE; new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
...@@ -1456,7 +1456,7 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { ...@@ -1456,7 +1456,7 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
// block expensive tasks because we don't know whether they were integral // block expensive tasks because we don't know whether they were integral
// to the page's functionality or not. // to the page's functionality or not.
new_policy.compositor_queue_policy().priority = new_policy.compositor_queue_policy().priority =
main_thread_compositing_is_fast ? TaskQueue::kHighPriority main_thread_compositing_is_fast ? TaskQueue::kHighestPriority
: TaskQueue::kNormalPriority; : TaskQueue::kNormalPriority;
break; break;
...@@ -1465,7 +1465,8 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { ...@@ -1465,7 +1465,8 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
// by the main thread. Since we know the established gesture type, we can // by the main thread. Since we know the established gesture type, we can
// be a little more aggressive about prioritizing compositing and input // be a little more aggressive about prioritizing compositing and input
// handling over other tasks. // handling over other tasks.
new_policy.compositor_queue_policy().priority = TaskQueue::kHighPriority; new_policy.compositor_queue_policy().priority =
TaskQueue::kHighestPriority;
if (touchstart_expected_soon) { if (touchstart_expected_soon) {
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE; new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
expensive_task_policy = ExpensiveTaskPolicy::kBlock; expensive_task_policy = ExpensiveTaskPolicy::kBlock;
...@@ -1476,7 +1477,8 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { ...@@ -1476,7 +1477,8 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
case UseCase::kTouchstart: case UseCase::kTouchstart:
new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE; new_policy.rail_mode() = v8::PERFORMANCE_RESPONSE;
new_policy.compositor_queue_policy().priority = TaskQueue::kHighPriority; new_policy.compositor_queue_policy().priority =
TaskQueue::kHighestPriority;
new_policy.loading_queue_policy().is_blocked = true; new_policy.loading_queue_policy().is_blocked = true;
new_policy.timer_queue_policy().is_blocked = true; new_policy.timer_queue_policy().is_blocked = true;
// NOTE this is a nop due to the above. // NOTE this is a nop due to the above.
...@@ -2163,7 +2165,7 @@ bool RendererSchedulerImpl::TaskQueuePolicy::IsQueueEnabled( ...@@ -2163,7 +2165,7 @@ bool RendererSchedulerImpl::TaskQueuePolicy::IsQueueEnabled(
TaskQueue::QueuePriority RendererSchedulerImpl::TaskQueuePolicy::GetPriority( TaskQueue::QueuePriority RendererSchedulerImpl::TaskQueuePolicy::GetPriority(
MainThreadTaskQueue* task_queue) const { MainThreadTaskQueue* task_queue) const {
return task_queue->UsedForImportantTasks() ? TaskQueue::kHighPriority return task_queue->UsedForImportantTasks() ? TaskQueue::kHighestPriority
: priority; : priority;
} }
......
...@@ -3534,7 +3534,7 @@ TEST_F(RendererSchedulerImplTest, MAIN_THREAD_GESTURE) { ...@@ -3534,7 +3534,7 @@ TEST_F(RendererSchedulerImplTest, MAIN_THREAD_GESTURE) {
EXPECT_EQ(UseCase::kMainThreadGesture, CurrentUseCase()) << "i = " << i; EXPECT_EQ(UseCase::kMainThreadGesture, CurrentUseCase()) << "i = " << i;
} }
EXPECT_EQ(TaskQueue::kHighPriority, EXPECT_EQ(TaskQueue::kHighestPriority,
scheduler_->CompositorTaskQueue()->GetQueuePriority()); scheduler_->CompositorTaskQueue()->GetQueuePriority());
EXPECT_EQ(279u, run_order.size()); EXPECT_EQ(279u, run_order.size());
} }
......
...@@ -56,7 +56,7 @@ scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerHelper::NewTaskQueue( ...@@ -56,7 +56,7 @@ scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerHelper::NewTaskQueue(
task_queue_manager_->CreateTaskQueue<MainThreadTaskQueue>( task_queue_manager_->CreateTaskQueue<MainThreadTaskQueue>(
params.spec, params, renderer_scheduler_); params.spec, params, renderer_scheduler_);
if (params.used_for_important_tasks) if (params.used_for_important_tasks)
task_queue->SetQueuePriority(TaskQueue::QueuePriority::kHighPriority); task_queue->SetQueuePriority(TaskQueue::QueuePriority::kHighestPriority);
return task_queue; return task_queue;
} }
......
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