// 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/frame_task_queue_controller.h" #include #include #include #include "base/callback.h" #include "base/logging.h" #include "base/trace_event/traced_value.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.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 { using base::sequence_manager::TaskQueue; using QueueTraits = MainThreadTaskQueue::QueueTraits; using QueueEnabledVoter = base::sequence_manager::TaskQueue::QueueEnabledVoter; FrameTaskQueueController::FrameTaskQueueController( MainThreadSchedulerImpl* main_thread_scheduler_impl, FrameSchedulerImpl* frame_scheduler_impl, Delegate* delegate) : main_thread_scheduler_impl_(main_thread_scheduler_impl), frame_scheduler_impl_(frame_scheduler_impl), delegate_(delegate) { DCHECK(frame_scheduler_impl_); DCHECK(delegate_); } FrameTaskQueueController::~FrameTaskQueueController() = default; scoped_refptr FrameTaskQueueController::LoadingTaskQueue() { if (!loading_task_queue_) CreateLoadingTaskQueue(); DCHECK(loading_task_queue_); return loading_task_queue_; } scoped_refptr FrameTaskQueueController::LoadingControlTaskQueue() { if (!loading_control_task_queue_) CreateLoadingControlTaskQueue(); DCHECK(loading_control_task_queue_); return loading_control_task_queue_; } scoped_refptr FrameTaskQueueController::InspectorTaskQueue() { if (!inspector_task_queue_) { inspector_task_queue_ = main_thread_scheduler_impl_->NewTaskQueue( MainThreadTaskQueue::QueueCreationParams( MainThreadTaskQueue::QueueType::kDefault) .SetFrameScheduler(frame_scheduler_impl_)); TaskQueueCreated(inspector_task_queue_); } return inspector_task_queue_; } scoped_refptr FrameTaskQueueController::ExperimentalWebSchedulingTaskQueue( WebSchedulingTaskQueueType task_queue_type) { if (!web_scheduling_task_queues_[task_queue_type]) CreateWebSchedulingTaskQueue(task_queue_type); DCHECK(web_scheduling_task_queues_[task_queue_type]); return web_scheduling_task_queues_[task_queue_type]; } scoped_refptr FrameTaskQueueController::NonLoadingTaskQueue( MainThreadTaskQueue::QueueTraits queue_traits) { if (!non_loading_task_queues_.Contains(queue_traits.Key())) CreateNonLoadingTaskQueue(queue_traits); auto it = non_loading_task_queues_.find(queue_traits.Key()); DCHECK(it != non_loading_task_queues_.end()); return it->value; } const std::vector& FrameTaskQueueController::GetAllTaskQueuesAndVoters() const { return all_task_queues_and_voters_; } void FrameTaskQueueController::CreateLoadingTaskQueue() { DCHECK(!loading_task_queue_); // |main_thread_scheduler_impl_| can be null in unit tests. DCHECK(main_thread_scheduler_impl_); loading_task_queue_ = main_thread_scheduler_impl_->NewLoadingTaskQueue( MainThreadTaskQueue::QueueType::kFrameLoading, frame_scheduler_impl_); TaskQueueCreated(loading_task_queue_); } void FrameTaskQueueController::CreateWebSchedulingTaskQueue( WebSchedulingTaskQueueType task_queue_type) { DCHECK(RuntimeEnabledFeatures::WorkerTaskQueueEnabled()); DCHECK(!web_scheduling_task_queues_[task_queue_type]); // |main_thread_scheduler_impl_| can be null in unit tests. DCHECK(main_thread_scheduler_impl_); MainThreadTaskQueue::QueueType main_thread_queue_type = MainThreadTaskQueue::QueueType::kDefault; switch (task_queue_type) { case kWebSchedulingUserVisiblePriority: main_thread_queue_type = MainThreadTaskQueue::QueueType::kWebSchedulingUserInteraction; break; case kWebSchedulingBestEffortPriority: main_thread_queue_type = MainThreadTaskQueue::QueueType::kWebSchedulingBestEffort; break; case kWebSchedulingPriorityCount: NOTREACHED(); } scoped_refptr task_queue = main_thread_scheduler_impl_->NewTaskQueue( MainThreadTaskQueue::QueueCreationParams(main_thread_queue_type) .SetCanBePaused(true) .SetCanBeFrozen(true) .SetCanBeDeferred(task_queue_type != kWebSchedulingUserVisiblePriority) .SetCanBeThrottled(true) .SetFrameScheduler(frame_scheduler_impl_)); TaskQueueCreated(task_queue); web_scheduling_task_queues_[task_queue_type] = task_queue; } void FrameTaskQueueController::CreateLoadingControlTaskQueue() { DCHECK(!loading_control_task_queue_); // |main_thread_scheduler_impl_| can be null in unit tests. DCHECK(main_thread_scheduler_impl_); loading_control_task_queue_ = main_thread_scheduler_impl_->NewLoadingTaskQueue( MainThreadTaskQueue::QueueType::kFrameLoadingControl, frame_scheduler_impl_); TaskQueueCreated(loading_control_task_queue_); } scoped_refptr FrameTaskQueueController::NewResourceLoadingTaskQueue() { scoped_refptr task_queue = main_thread_scheduler_impl_->NewLoadingTaskQueue( MainThreadTaskQueue::QueueType::kFrameLoading, frame_scheduler_impl_); TaskQueueCreated(task_queue); resource_loading_task_queues_.insert(task_queue); return task_queue; } void FrameTaskQueueController::CreateNonLoadingTaskQueue( QueueTraits queue_traits) { DCHECK(!non_loading_task_queues_.Contains(queue_traits.Key())); // |main_thread_scheduler_impl_| can be null in unit tests. DCHECK(main_thread_scheduler_impl_); scoped_refptr task_queue = main_thread_scheduler_impl_->NewTaskQueue( MainThreadTaskQueue::QueueCreationParams( QueueTypeFromQueueTraits(queue_traits)) .SetQueueTraits(queue_traits) // Freeze when keep active is currently only set for the // throttleable queue. // TODO(altimin): Figure out how to set this for new queues. // Investigate which tasks must be kept alive, and if possible // move them to an unfreezable queue and remove this override and // the page scheduler KeepActive freezing override. .SetFreezeWhenKeepActive(queue_traits.can_be_throttled) .SetFrameScheduler(frame_scheduler_impl_)); TaskQueueCreated(task_queue); non_loading_task_queues_.insert(queue_traits.Key(), task_queue); } void FrameTaskQueueController::TaskQueueCreated( const scoped_refptr& task_queue) { DCHECK(task_queue); std::unique_ptr voter; // Only create a voter for queues that can be disabled. if (task_queue->CanBePaused() || task_queue->CanBeFrozen()) voter = task_queue->CreateQueueEnabledVoter(); delegate_->OnTaskQueueCreated(task_queue.get(), voter.get()); all_task_queues_and_voters_.push_back( TaskQueueAndEnabledVoterPair(task_queue.get(), voter.get())); if (voter) { DCHECK(task_queue_enabled_voters_.find(task_queue) == task_queue_enabled_voters_.end()); task_queue_enabled_voters_.insert(task_queue, std::move(voter)); } } base::sequence_manager::TaskQueue::QueueEnabledVoter* FrameTaskQueueController::GetQueueEnabledVoter( const scoped_refptr& task_queue) { auto it = task_queue_enabled_voters_.find(task_queue); if (it == task_queue_enabled_voters_.end()) return nullptr; return it->value.get(); } bool FrameTaskQueueController::RemoveResourceLoadingTaskQueue( const scoped_refptr& task_queue) { DCHECK(task_queue); if (!resource_loading_task_queues_.Contains(task_queue)) return false; resource_loading_task_queues_.erase(task_queue); DCHECK(task_queue_enabled_voters_.Contains(task_queue)); task_queue_enabled_voters_.erase(task_queue); bool found_task_queue = false; for (auto it = all_task_queues_and_voters_.begin(); it != all_task_queues_and_voters_.end(); ++it) { if (it->first == task_queue.get()) { found_task_queue = true; all_task_queues_and_voters_.erase(it); break; } } DCHECK(found_task_queue); return true; } void FrameTaskQueueController::AsValueInto( base::trace_event::TracedValue* state) const { 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())); } state->BeginArray("non_loading_task_queues"); for (const auto it : non_loading_task_queues_) { state->AppendString(PointerToString(it.value.get())); } state->EndArray(); state->BeginArray("resource_loading_task_queues"); for (const auto& queue : resource_loading_task_queues_) { state->AppendString(PointerToString(queue.get())); } state->EndArray(); } // static MainThreadTaskQueue::QueueType FrameTaskQueueController::QueueTypeFromQueueTraits(QueueTraits queue_traits) { if (queue_traits.can_be_throttled) return MainThreadTaskQueue::QueueType::kFrameThrottleable; if (queue_traits.can_be_deferred) return MainThreadTaskQueue::QueueType::kFrameDeferrable; if (queue_traits.can_be_paused) return MainThreadTaskQueue::QueueType::kFramePausable; return MainThreadTaskQueue::QueueType::kFrameUnpausable; } } // namespace scheduler } // namespace blink