summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc')
-rw-r--r--chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc532
1 files changed, 288 insertions, 244 deletions
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index f94bcb88e6d..57b546b0536 100644
--- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -5,20 +5,24 @@
#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
#include <memory>
+#include <set>
+#include <string>
+#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/blame_context.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/blame_context.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/child/features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
#include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/page_visibility_state.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.h"
+#include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h"
#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
#include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
@@ -27,6 +31,7 @@ namespace blink {
namespace scheduler {
using base::sequence_manager::TaskQueue;
+using QueueTraits = MainThreadTaskQueue::QueueTraits;
namespace {
@@ -73,6 +78,44 @@ void UpdatePriority(MainThreadTaskQueue* task_queue) {
task_queue->SetQueuePriority(frame_scheduler->ComputePriority(task_queue));
}
+// Extract a substring from |source| from [start to end), trimming leading
+// whitespace.
+std::string ExtractAndTrimString(std::string source, size_t start, size_t end) {
+ DCHECK(start < source.length());
+ DCHECK(end <= source.length());
+ DCHECK(start <= end);
+ // Trim whitespace
+ while (start < end && source[start] == ' ')
+ ++start;
+ if (start < end)
+ return source.substr(start, end - start);
+ return "";
+}
+
+std::set<std::string> TaskTypesFromFieldTrialParam(const char* param) {
+ std::set<std::string> result;
+ std::string task_type_list = base::GetFieldTrialParamValueByFeature(
+ kThrottleAndFreezeTaskTypes, param);
+ if (!task_type_list.length())
+ return result;
+ // Extract the individual names, separated by ",".
+ size_t pos = 0, start = 0;
+ while ((pos = task_type_list.find(',', start)) != std::string::npos) {
+ std::string task_type = ExtractAndTrimString(task_type_list, start, pos);
+ // Not valid to start with "," or have ",," in the list.
+ DCHECK(task_type.length());
+ result.insert(task_type);
+ start = pos + 1;
+ }
+ // Handle the last or only task type name.
+ std::string task_type =
+ ExtractAndTrimString(task_type_list, start, task_type_list.length());
+ DCHECK(task_type.length());
+ result.insert(task_type);
+
+ return result;
+}
+
} // namespace
FrameSchedulerImpl::ActiveConnectionHandleImpl::ActiveConnectionHandleImpl(
@@ -104,11 +147,12 @@ FrameSchedulerImpl::PauseSubresourceLoadingHandleImpl::
std::unique_ptr<FrameSchedulerImpl> FrameSchedulerImpl::Create(
PageSchedulerImpl* parent_page_scheduler,
+ FrameScheduler::Delegate* delegate,
base::trace_event::BlameContext* blame_context,
FrameScheduler::FrameType frame_type) {
- std::unique_ptr<FrameSchedulerImpl> frame_scheduler(
- new FrameSchedulerImpl(parent_page_scheduler->GetMainThreadScheduler(),
- parent_page_scheduler, blame_context, frame_type));
+ std::unique_ptr<FrameSchedulerImpl> frame_scheduler(new FrameSchedulerImpl(
+ parent_page_scheduler->GetMainThreadScheduler(), parent_page_scheduler,
+ delegate, blame_context, frame_type));
parent_page_scheduler->RegisterFrameSchedulerImpl(frame_scheduler.get());
return frame_scheduler;
}
@@ -116,12 +160,14 @@ std::unique_ptr<FrameSchedulerImpl> FrameSchedulerImpl::Create(
FrameSchedulerImpl::FrameSchedulerImpl(
MainThreadSchedulerImpl* main_thread_scheduler,
PageSchedulerImpl* parent_page_scheduler,
+ FrameScheduler::Delegate* delegate,
base::trace_event::BlameContext* blame_context,
FrameScheduler::FrameType frame_type)
: frame_type_(frame_type),
is_ad_frame_(false),
main_thread_scheduler_(main_thread_scheduler),
parent_page_scheduler_(parent_page_scheduler),
+ delegate_(delegate),
blame_context_(blame_context),
throttling_state_(SchedulingLifecycleState::kNotThrottled),
frame_visible_(true,
@@ -147,11 +193,11 @@ FrameSchedulerImpl::FrameSchedulerImpl(
&tracing_controller_,
PausedStateToString),
url_tracer_("FrameScheduler.URL", this),
- task_queue_throttled_(false,
- "FrameScheduler.TaskQueueThrottled",
- this,
- &tracing_controller_,
- YesNoStateToString),
+ task_queues_throttled_(false,
+ "FrameScheduler.TaskQueuesThrottled",
+ this,
+ &tracing_controller_,
+ YesNoStateToString),
active_connection_count_(0),
subresource_loading_pause_count_(0u),
has_active_connection_(false,
@@ -179,16 +225,23 @@ FrameSchedulerImpl::FrameSchedulerImpl(
this,
&tracing_controller_,
KeepActiveStateToString),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ frame_task_queue_controller_.reset(
+ new FrameTaskQueueController(main_thread_scheduler_, this, this));
+}
FrameSchedulerImpl::FrameSchedulerImpl()
- : FrameSchedulerImpl(nullptr, nullptr, nullptr, FrameType::kSubframe) {}
+ : FrameSchedulerImpl(nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ FrameType::kSubframe) {}
namespace {
void CleanUpQueue(MainThreadTaskQueue* queue) {
- if (!queue)
- return;
+ DCHECK(queue);
+
queue->DetachFromMainThreadScheduler();
queue->DetachFromFrameScheduler();
queue->SetBlameContext(nullptr);
@@ -200,17 +253,13 @@ void CleanUpQueue(MainThreadTaskQueue* queue) {
FrameSchedulerImpl::~FrameSchedulerImpl() {
weak_factory_.InvalidateWeakPtrs();
- RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
-
- CleanUpQueue(loading_task_queue_.get());
- CleanUpQueue(loading_control_task_queue_.get());
- CleanUpQueue(throttleable_task_queue_.get());
- CleanUpQueue(deferrable_task_queue_.get());
- CleanUpQueue(pausable_task_queue_.get());
- CleanUpQueue(unpausable_task_queue_.get());
-
- for (const auto& pair : resource_loading_task_queues_) {
- CleanUpQueue(pair.key.get());
+ for (const auto& task_queue_and_voter :
+ frame_task_queue_controller_->GetAllTaskQueuesAndVoters()) {
+ if (task_queue_and_voter.first->CanBeThrottled()) {
+ RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool(
+ task_queue_and_voter.first);
+ }
+ CleanUpQueue(task_queue_and_voter.first);
}
if (parent_page_scheduler_) {
@@ -222,15 +271,21 @@ FrameSchedulerImpl::~FrameSchedulerImpl() {
}
void FrameSchedulerImpl::DetachFromPageScheduler() {
- RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
+ for (const auto& task_queue_and_voter :
+ frame_task_queue_controller_->GetAllTaskQueuesAndVoters()) {
+ if (task_queue_and_voter.first->CanBeThrottled()) {
+ RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool(
+ task_queue_and_voter.first);
+ }
+ }
parent_page_scheduler_ = nullptr;
}
-void FrameSchedulerImpl::
- RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool() {
- if (!throttleable_task_queue_)
- return;
+void FrameSchedulerImpl::RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool(
+ MainThreadTaskQueue* task_queue) {
+ DCHECK(task_queue);
+ DCHECK(task_queue->CanBeThrottled());
if (!parent_page_scheduler_)
return;
@@ -241,9 +296,14 @@ void FrameSchedulerImpl::
if (!time_budget_pool)
return;
- time_budget_pool->RemoveQueue(
- main_thread_scheduler_->tick_clock()->NowTicks(),
- throttleable_task_queue_.get());
+ // On tests, the scheduler helper might already be shut down and tick is not
+ // available.
+ base::TimeTicks now;
+ if (main_thread_scheduler_->tick_clock())
+ now = main_thread_scheduler_->tick_clock()->NowTicks();
+ else
+ now = base::TimeTicks::Now();
+ time_budget_pool->RemoveQueue(now, task_queue);
}
void FrameSchedulerImpl::SetFrameVisible(bool frame_visible) {
@@ -294,18 +354,52 @@ FrameScheduler::FrameType FrameSchedulerImpl::GetFrameType() const {
return frame_type_;
}
-scoped_refptr<base::SingleThreadTaskRunner> FrameSchedulerImpl::GetTaskRunner(
+void FrameSchedulerImpl::InitializeTaskTypeQueueTraitsMap(
+ FrameTaskTypeToQueueTraitsArray& frame_task_types_to_queue_traits) {
+ DCHECK_EQ(frame_task_types_to_queue_traits.size(),
+ static_cast<size_t>(TaskType::kCount));
+ // Using std set and strings here because field trial parameters are std
+ // strings, and we cannot use WTF strings as Blink is not yet initialized.
+ std::set<std::string> throttleable_task_type_names;
+ std::set<std::string> freezable_task_type_names;
+ if (base::FeatureList::IsEnabled(kThrottleAndFreezeTaskTypes)) {
+ throttleable_task_type_names =
+ TaskTypesFromFieldTrialParam(kThrottleableTaskTypesListParam);
+ freezable_task_type_names =
+ TaskTypesFromFieldTrialParam(kFreezableTaskTypesListParam);
+ }
+ for (size_t i = 0; i < static_cast<size_t>(TaskType::kCount); i++) {
+ TaskType type = static_cast<TaskType>(i);
+ base::Optional<QueueTraits> queue_traits =
+ CreateQueueTraitsForTaskType(type);
+ if (queue_traits && (throttleable_task_type_names.size() ||
+ freezable_task_type_names.size())) {
+ const char* task_type_name = TaskTypeNames::TaskTypeToString(type);
+ if (throttleable_task_type_names.erase(task_type_name))
+ queue_traits->SetCanBeThrottled(true);
+ if (freezable_task_type_names.erase(task_type_name))
+ queue_traits->SetCanBeFrozen(true);
+ }
+ frame_task_types_to_queue_traits[i] = queue_traits;
+ }
+ // Protect against configuration errors.
+ DCHECK(throttleable_task_type_names.empty());
+ DCHECK(freezable_task_type_names.empty());
+}
+
+// static
+base::Optional<QueueTraits> FrameSchedulerImpl::CreateQueueTraitsForTaskType(
TaskType type) {
// TODO(haraken): Optimize the mapping from TaskTypes to task runners.
switch (type) {
case TaskType::kJavascriptTimer:
- return TaskQueueWithTaskType::Create(ThrottleableTaskQueue(), type);
+ return ThrottleableTaskQueueTraits();
case TaskType::kInternalLoading:
case TaskType::kNetworking:
case TaskType::kNetworkingWithURLLoaderAnnotation:
- return TaskQueueWithTaskType::Create(LoadingTaskQueue(), type);
case TaskType::kNetworkingControl:
- return TaskQueueWithTaskType::Create(LoadingControlTaskQueue(), type);
+ // Loading task queues are handled separately.
+ return base::nullopt;
// 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
@@ -329,7 +423,7 @@ scoped_refptr<base::SingleThreadTaskRunner> FrameSchedulerImpl::GetTaskRunner(
case TaskType::kInternalDefault:
case TaskType::kMiscPlatformAPI:
// TODO(altimin): Move appropriate tasks to throttleable task queue.
- return TaskQueueWithTaskType::Create(DeferrableTaskQueue(), type);
+ return DeferrableTaskQueueTraits();
// PostedMessage can be used for navigation, so we shouldn't defer it
// when expecting a user gesture.
case TaskType::kPostedMessage:
@@ -346,7 +440,7 @@ scoped_refptr<base::SingleThreadTaskRunner> FrameSchedulerImpl::GetTaskRunner(
case TaskType::kInternalMediaRealTime:
case TaskType::kInternalUserInteraction:
case TaskType::kInternalIntersectionObserver:
- return TaskQueueWithTaskType::Create(PausableTaskQueue(), type);
+ return PausableTaskQueueTraits();
case TaskType::kInternalIPC:
// The TaskType of Inspector tasks needs to be unpausable because they need
// to run even on a paused page.
@@ -355,7 +449,7 @@ scoped_refptr<base::SingleThreadTaskRunner> FrameSchedulerImpl::GetTaskRunner(
// unthrottled and undeferred) not to prevent service workers that may
// control browser navigation on multiple tabs.
case TaskType::kInternalWorker:
- return TaskQueueWithTaskType::Create(UnpausableTaskQueue(), type);
+ return UnpausableTaskQueueTraits();
case TaskType::kDeprecatedNone:
case TaskType::kMainThreadTaskQueueV8:
case TaskType::kMainThreadTaskQueueCompositor:
@@ -364,41 +458,53 @@ scoped_refptr<base::SingleThreadTaskRunner> FrameSchedulerImpl::GetTaskRunner(
case TaskType::kMainThreadTaskQueueIdle:
case TaskType::kMainThreadTaskQueueIPC:
case TaskType::kMainThreadTaskQueueControl:
+ case TaskType::kMainThreadTaskQueueCleanup:
case TaskType::kCompositorThreadTaskQueueDefault:
case TaskType::kCompositorThreadTaskQueueInput:
case TaskType::kWorkerThreadTaskQueueDefault:
case TaskType::kWorkerThreadTaskQueueV8:
case TaskType::kWorkerThreadTaskQueueCompositor:
case TaskType::kCount:
- NOTREACHED();
- break;
+ // Not a valid frame-level TaskType.
+ return base::nullopt;
}
- NOTREACHED();
- return nullptr;
+ // This method is called for all values between 0 and kCount. TaskType,
+ // however, has numbering gaps, so even though all enumerated TaskTypes are
+ // handled in the switch and return a value, we fall through for some values
+ // of |type|.
+ return base::nullopt;
}
-std::pair<scoped_refptr<MainThreadTaskQueue>,
- std::unique_ptr<TaskQueue::QueueEnabledVoter>>
-FrameSchedulerImpl::CreateNewLoadingTaskQueue() {
- // TODO(panicker): Avoid adding this queue in RS task_runners_.
- scoped_refptr<MainThreadTaskQueue> loading_task_queue =
- main_thread_scheduler_->NewLoadingTaskQueue(
- MainThreadTaskQueue::QueueType::kFrameLoading, this);
- loading_task_queue->SetBlameContext(blame_context_);
- std::unique_ptr<TaskQueue::QueueEnabledVoter> voter =
- loading_task_queue->CreateQueueEnabledVoter();
- voter->SetQueueEnabled(!frame_paused_);
- return std::make_pair(loading_task_queue, std::move(voter));
+scoped_refptr<base::SingleThreadTaskRunner> FrameSchedulerImpl::GetTaskRunner(
+ TaskType type) {
+ scoped_refptr<MainThreadTaskQueue> task_queue = GetTaskQueue(type);
+ DCHECK(task_queue);
+ return task_queue->CreateTaskRunner(type);
}
-scoped_refptr<TaskQueue> FrameSchedulerImpl::LoadingTaskQueue() {
- DCHECK(parent_page_scheduler_);
- if (!loading_task_queue_) {
- auto queue_voter_pair = CreateNewLoadingTaskQueue();
- loading_task_queue_ = queue_voter_pair.first;
- loading_queue_enabled_voter_ = std::move(queue_voter_pair.second);
+scoped_refptr<MainThreadTaskQueue> FrameSchedulerImpl::GetTaskQueue(
+ TaskType type) {
+ switch (type) {
+ case TaskType::kInternalLoading:
+ case TaskType::kNetworking:
+ case TaskType::kNetworkingWithURLLoaderAnnotation:
+ return frame_task_queue_controller_->LoadingTaskQueue();
+ case TaskType::kNetworkingControl:
+ return frame_task_queue_controller_->LoadingControlTaskQueue();
+ default:
+ // Non-loading task queue.
+ DCHECK_LT(static_cast<size_t>(type),
+ main_thread_scheduler_->scheduling_settings()
+ .frame_task_types_to_queue_traits.size());
+ base::Optional<QueueTraits> queue_traits =
+ main_thread_scheduler_->scheduling_settings()
+ .frame_task_types_to_queue_traits[static_cast<size_t>(type)];
+ // We don't have a QueueTraits mapping for |task_type| if it is not a
+ // frame-level task type.
+ DCHECK(queue_traits);
+ return frame_task_queue_controller_->NonLoadingTaskQueue(
+ queue_traits.value());
}
- return loading_task_queue_;
}
std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
@@ -413,143 +519,51 @@ FrameSchedulerImpl::CreateResourceLoadingTaskRunnerHandleImpl() {
(parent_page_scheduler_->IsLoading() &&
main_thread_scheduler_->scheduling_settings()
.use_resource_priorities_only_during_loading)) {
- auto queue_voter_pair = CreateNewLoadingTaskQueue();
-
- resource_loading_task_queues_.insert(
- queue_voter_pair.first, ResourceLoadingTaskQueueMetadata(
- queue_voter_pair.first->GetQueuePriority(),
- std::move(queue_voter_pair.second)));
-
- return ResourceLoadingTaskRunnerHandleImpl::WrapTaskRunner(
- queue_voter_pair.first);
+ scoped_refptr<MainThreadTaskQueue> task_queue =
+ frame_task_queue_controller_->NewResourceLoadingTaskQueue();
+ resource_loading_task_queue_priorities_.insert(
+ task_queue, task_queue->GetQueuePriority());
+ return ResourceLoadingTaskRunnerHandleImpl::WrapTaskRunner(task_queue);
}
- // Make sure the loading task queue exists.
- LoadingTaskQueue();
return ResourceLoadingTaskRunnerHandleImpl::WrapTaskRunner(
- loading_task_queue_);
+ frame_task_queue_controller_->LoadingTaskQueue());
}
void FrameSchedulerImpl::DidChangeResourceLoadingPriority(
scoped_refptr<MainThreadTaskQueue> task_queue,
net::RequestPriority priority) {
// This check is done since in some cases (when kUseResourceFetchPriority
- // feature isn't enabled) we use |loading_task_queue_| for resource loading
+ // feature isn't enabled) we use the loading task queue for resource loading
// and the priority of this queue shouldn't be affected by resource
// priorities.
- auto queue_metadata_pair = resource_loading_task_queues_.find(task_queue);
- if (queue_metadata_pair != resource_loading_task_queues_.end()) {
- queue_metadata_pair->value.priority =
- main_thread_scheduler_->scheduling_settings()
- .net_to_blink_priority[priority];
- UpdateQueuePolicy(task_queue.get(), queue_metadata_pair->value.voter.get());
+ auto queue_priority_pair =
+ resource_loading_task_queue_priorities_.find(task_queue);
+ if (queue_priority_pair != resource_loading_task_queue_priorities_.end()) {
+ task_queue->SetNetRequestPriority(priority);
+ queue_priority_pair->value = main_thread_scheduler_->scheduling_settings()
+ .net_to_blink_priority[priority];
+ auto* voter =
+ frame_task_queue_controller_->GetQueueEnabledVoter(task_queue);
+ UpdateQueuePolicy(task_queue.get(), voter);
}
}
void FrameSchedulerImpl::OnShutdownResourceLoadingTaskQueue(
scoped_refptr<MainThreadTaskQueue> task_queue) {
// This check is done since in some cases (when kUseResourceFetchPriority
- // feature isn't enabled) we use |loading_task_queue_| for resource loading,
+ // feature isn't enabled) we use the loading task queue for resource loading,
// and the lifetime of this queue isn't bound to one resource.
- auto iter = resource_loading_task_queues_.find(task_queue);
- if (iter != resource_loading_task_queues_.end()) {
- resource_loading_task_queues_.erase(iter);
+ auto iter = resource_loading_task_queue_priorities_.find(task_queue);
+ if (iter != resource_loading_task_queue_priorities_.end()) {
+ resource_loading_task_queue_priorities_.erase(iter);
+ bool removed = frame_task_queue_controller_->RemoveResourceLoadingTaskQueue(
+ task_queue);
+ DCHECK(removed);
CleanUpQueue(task_queue.get());
}
}
-scoped_refptr<TaskQueue> FrameSchedulerImpl::LoadingControlTaskQueue() {
- DCHECK(parent_page_scheduler_);
- if (!loading_control_task_queue_) {
- loading_control_task_queue_ = main_thread_scheduler_->NewLoadingTaskQueue(
- MainThreadTaskQueue::QueueType::kFrameLoadingControl, this);
- loading_control_task_queue_->SetBlameContext(blame_context_);
- loading_control_queue_enabled_voter_ =
- loading_control_task_queue_->CreateQueueEnabledVoter();
- loading_control_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
- }
- return loading_control_task_queue_;
-}
-
-scoped_refptr<TaskQueue> FrameSchedulerImpl::ThrottleableTaskQueue() {
- DCHECK(parent_page_scheduler_);
- if (!throttleable_task_queue_) {
- // TODO(panicker): Avoid adding this queue in RS task_runners_.
- throttleable_task_queue_ = main_thread_scheduler_->NewTaskQueue(
- MainThreadTaskQueue::QueueCreationParams(
- MainThreadTaskQueue::QueueType::kFrameThrottleable)
- .SetCanBeThrottled(true)
- .SetCanBeFrozen(true)
- .SetFreezeWhenKeepActive(true)
- .SetCanBeDeferred(true)
- .SetCanBePaused(true)
- .SetFrameScheduler(this));
- throttleable_task_queue_->SetBlameContext(blame_context_);
- throttleable_queue_enabled_voter_ =
- throttleable_task_queue_->CreateQueueEnabledVoter();
- throttleable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
-
- CPUTimeBudgetPool* time_budget_pool =
- parent_page_scheduler_->BackgroundCPUTimeBudgetPool();
- if (time_budget_pool) {
- time_budget_pool->AddQueue(
- main_thread_scheduler_->tick_clock()->NowTicks(),
- throttleable_task_queue_.get());
- }
- UpdateThrottling();
- }
- return throttleable_task_queue_;
-}
-
-scoped_refptr<TaskQueue> FrameSchedulerImpl::DeferrableTaskQueue() {
- DCHECK(parent_page_scheduler_);
- if (!deferrable_task_queue_) {
- deferrable_task_queue_ = main_thread_scheduler_->NewTaskQueue(
- MainThreadTaskQueue::QueueCreationParams(
- MainThreadTaskQueue::QueueType::kFrameDeferrable)
- .SetCanBeDeferred(true)
- .SetCanBeFrozen(
- RuntimeEnabledFeatures::StopNonTimersInBackgroundEnabled())
- .SetCanBePaused(true)
- .SetFrameScheduler(this));
- deferrable_task_queue_->SetBlameContext(blame_context_);
- deferrable_queue_enabled_voter_ =
- deferrable_task_queue_->CreateQueueEnabledVoter();
- deferrable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
- }
- return deferrable_task_queue_;
-}
-
-scoped_refptr<TaskQueue> FrameSchedulerImpl::PausableTaskQueue() {
- DCHECK(parent_page_scheduler_);
- if (!pausable_task_queue_) {
- pausable_task_queue_ = main_thread_scheduler_->NewTaskQueue(
- MainThreadTaskQueue::QueueCreationParams(
- MainThreadTaskQueue::QueueType::kFramePausable)
- .SetCanBeFrozen(
- RuntimeEnabledFeatures::StopNonTimersInBackgroundEnabled())
- .SetCanBePaused(true)
- .SetFrameScheduler(this));
- pausable_task_queue_->SetBlameContext(blame_context_);
- pausable_queue_enabled_voter_ =
- pausable_task_queue_->CreateQueueEnabledVoter();
- pausable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
- }
- return pausable_task_queue_;
-}
-
-scoped_refptr<TaskQueue> FrameSchedulerImpl::UnpausableTaskQueue() {
- DCHECK(parent_page_scheduler_);
- if (!unpausable_task_queue_) {
- unpausable_task_queue_ = main_thread_scheduler_->NewTaskQueue(
- MainThreadTaskQueue::QueueCreationParams(
- MainThreadTaskQueue::QueueType::kFrameUnpausable)
- .SetFrameScheduler(this));
- unpausable_task_queue_->SetBlameContext(blame_context_);
- }
- return unpausable_task_queue_;
-}
-
scoped_refptr<base::SingleThreadTaskRunner>
FrameSchedulerImpl::ControlTaskRunner() {
DCHECK(parent_page_scheduler_);
@@ -605,36 +619,10 @@ void FrameSchedulerImpl::AsValueInto(
state->SetBoolean(
"disable_background_timer_throttling",
!RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled());
- if (loading_task_queue_) {
- state->SetString("loading_task_queue",
- PointerToString(loading_task_queue_.get()));
- }
- if (loading_control_task_queue_) {
- state->SetString("loading_control_task_queue",
- PointerToString(loading_control_task_queue_.get()));
- }
- if (throttleable_task_queue_) {
- state->SetString("throttleable_task_queue",
- PointerToString(throttleable_task_queue_.get()));
- }
- if (deferrable_task_queue_) {
- state->SetString("deferrable_task_queue",
- PointerToString(deferrable_task_queue_.get()));
- }
- if (pausable_task_queue_) {
- state->SetString("pausable_task_queue",
- PointerToString(pausable_task_queue_.get()));
- }
- if (unpausable_task_queue_) {
- state->SetString("unpausable_task_queue",
- PointerToString(unpausable_task_queue_.get()));
- }
- state->BeginArray("resource_loading_task_queues");
- for (const auto& queue : resource_loading_task_queues_) {
- state->AppendString(PointerToString(queue.key.get()));
- }
- state->EndArray();
+ state->BeginDictionary("frame_task_queue_controller");
+ frame_task_queue_controller_->AsValueInto(state);
+ state->EndDictionary();
if (blame_context_) {
state->BeginDictionary("blame_context");
@@ -679,37 +667,33 @@ void FrameSchedulerImpl::SetPageKeepActiveForTracing(bool keep_active) {
}
void FrameSchedulerImpl::UpdatePolicy() {
- // Per-frame (stoppable) task queues will be frozen after 5mins in
- // background. They will be resumed when the page is visible.
- UpdateQueuePolicy(throttleable_task_queue_,
- throttleable_queue_enabled_voter_.get());
- UpdateQueuePolicy(loading_task_queue_, loading_queue_enabled_voter_.get());
- UpdateQueuePolicy(loading_control_task_queue_,
- loading_control_queue_enabled_voter_.get());
- UpdateQueuePolicy(deferrable_task_queue_,
- deferrable_queue_enabled_voter_.get());
- UpdateQueuePolicy(pausable_task_queue_, pausable_queue_enabled_voter_.get());
- UpdateQueuePolicy(unpausable_task_queue_, nullptr);
-
- for (const auto& pair : resource_loading_task_queues_) {
- UpdateQueuePolicy(pair.key, pair.value.voter.get());
+ bool task_queues_were_throttled = task_queues_throttled_;
+ task_queues_throttled_ = ShouldThrottleTaskQueues();
+
+ for (const auto& task_queue_and_voter :
+ frame_task_queue_controller_->GetAllTaskQueuesAndVoters()) {
+ UpdateQueuePolicy(task_queue_and_voter.first, task_queue_and_voter.second);
+ if (task_queues_were_throttled != task_queues_throttled_) {
+ UpdateTaskQueueThrottling(task_queue_and_voter.first,
+ task_queues_throttled_);
+ }
}
- UpdateThrottling();
-
NotifyLifecycleObservers();
}
void FrameSchedulerImpl::UpdateQueuePolicy(
- const scoped_refptr<MainThreadTaskQueue>& queue,
+ MainThreadTaskQueue* queue,
TaskQueue::QueueEnabledVoter* voter) {
- if (!queue)
- return;
- UpdatePriority(queue.get());
+ DCHECK(queue);
+ UpdatePriority(queue);
if (!voter)
return;
DCHECK(parent_page_scheduler_);
bool queue_paused = frame_paused_ && queue->CanBePaused();
+ // Per-frame freezable task queues will be frozen after 5 mins in background
+ // on Android, and if the browser freezes the page in the background. They
+ // will be resumed when the page is visible.
bool queue_frozen =
parent_page_scheduler_->IsFrozen() && queue->CanBeFrozen();
// Override freezing if keep-active is true.
@@ -751,7 +735,7 @@ FrameSchedulerImpl::OnActiveConnectionCreated() {
return std::make_unique<FrameSchedulerImpl::ActiveConnectionHandleImpl>(this);
}
-bool FrameSchedulerImpl::ShouldThrottleTimers() const {
+bool FrameSchedulerImpl::ShouldThrottleTaskQueues() const {
if (!RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled())
return false;
if (parent_page_scheduler_ && parent_page_scheduler_->IsAudioPlaying())
@@ -762,24 +746,17 @@ bool FrameSchedulerImpl::ShouldThrottleTimers() const {
!frame_visible_ && IsCrossOrigin();
}
-void FrameSchedulerImpl::UpdateThrottling() {
- // Before we initialize a trottleable task queue, |task_queue_throttled_|
- // stays false and this function ensures it indicates whether are we holding
- // a queue reference for throttler or not.
- // Don't modify that value neither amend the reference counter anywhere else.
- if (!throttleable_task_queue_)
+void FrameSchedulerImpl::UpdateTaskQueueThrottling(
+ MainThreadTaskQueue* task_queue,
+ bool should_throttle) {
+ if (!task_queue->CanBeThrottled())
return;
- bool should_throttle = ShouldThrottleTimers();
- if (task_queue_throttled_ == should_throttle)
- return;
- task_queue_throttled_ = should_throttle;
-
if (should_throttle) {
main_thread_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
- throttleable_task_queue_.get());
+ task_queue);
} else {
main_thread_scheduler_->task_queue_throttler()->DecreaseThrottleRefCount(
- throttleable_task_queue_.get());
+ task_queue);
}
}
@@ -796,10 +773,10 @@ TaskQueue::QueuePriority FrameSchedulerImpl::ComputePriority(
// Checks the task queue is associated with this frame scheduler.
DCHECK_EQ(frame_scheduler, this);
- auto queue_metadata_pair =
- resource_loading_task_queues_.find(base::WrapRefCounted(task_queue));
- if (queue_metadata_pair != resource_loading_task_queues_.end()) {
- return queue_metadata_pair->value.priority;
+ auto queue_priority_pair = resource_loading_task_queue_priorities_.find(
+ base::WrapRefCounted(task_queue));
+ if (queue_priority_pair != resource_loading_task_queue_priorities_.end()) {
+ return queue_priority_pair->value;
}
base::Optional<TaskQueue::QueuePriority> fixed_priority =
@@ -911,5 +888,72 @@ void FrameSchedulerImpl::RemovePauseSubresourceLoadingHandle() {
}
}
+ukm::UkmRecorder* FrameSchedulerImpl::GetUkmRecorder() {
+ if (!delegate_)
+ return nullptr;
+ return delegate_->GetUkmRecorder();
+}
+
+ukm::SourceId FrameSchedulerImpl::GetUkmSourceId() {
+ if (!delegate_)
+ return ukm::kInvalidSourceId;
+ return delegate_->GetUkmSourceId();
+}
+
+void FrameSchedulerImpl::OnTaskQueueCreated(
+ MainThreadTaskQueue* task_queue,
+ base::sequence_manager::TaskQueue::QueueEnabledVoter* voter) {
+ DCHECK(parent_page_scheduler_);
+
+ task_queue->SetBlameContext(blame_context_);
+ UpdateQueuePolicy(task_queue, voter);
+
+ if (task_queue->CanBeThrottled()) {
+ CPUTimeBudgetPool* time_budget_pool =
+ parent_page_scheduler_->BackgroundCPUTimeBudgetPool();
+ if (time_budget_pool) {
+ time_budget_pool->AddQueue(
+ main_thread_scheduler_->tick_clock()->NowTicks(), task_queue);
+ }
+ if (task_queues_throttled_) {
+ UpdateTaskQueueThrottling(task_queue, true);
+ }
+ }
+}
+
+// static
+MainThreadTaskQueue::QueueTraits
+FrameSchedulerImpl::ThrottleableTaskQueueTraits() {
+ return QueueTraits()
+ .SetCanBeThrottled(true)
+ .SetCanBeFrozen(true)
+ .SetCanBeDeferred(true)
+ .SetCanBePaused(true);
+}
+
+// static
+MainThreadTaskQueue::QueueTraits
+FrameSchedulerImpl::DeferrableTaskQueueTraits() {
+ return QueueTraits()
+ .SetCanBeDeferred(true)
+ .SetCanBeFrozen(base::FeatureList::IsEnabled(
+ blink::features::kStopNonTimersInBackground))
+ .SetCanBePaused(true);
+}
+
+// static
+MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::PausableTaskQueueTraits() {
+ return QueueTraits()
+ .SetCanBeFrozen(base::FeatureList::IsEnabled(
+ blink::features::kStopNonTimersInBackground))
+ .SetCanBePaused(true);
+}
+
+// static
+MainThreadTaskQueue::QueueTraits
+FrameSchedulerImpl::UnpausableTaskQueueTraits() {
+ return QueueTraits();
+}
+
} // namespace scheduler
} // namespace blink