#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include <algorithm>
#include <memory>
#include <optional>
#include <type_traits>
#include <utility>
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/observer_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/common/scoped_defer_task_posting.h"
#include "base/task/common/task_annotator.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
#include "build/build_config.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_input_event_attribution.h"
#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
#include "third_party/blink/public/common/input/web_touch_event.h"
#include "third_party/blink/public/common/page/launching_process_state.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/platform/scheduler/web_renderer_process_type.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h"
#include "third_party/blink/renderer/platform/scheduler/common/auto_advancing_virtual_time_domain.h"
#include "third_party/blink/renderer/platform/scheduler/common/features.h"
#include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
#include "third_party/blink/renderer/platform/scheduler/common/task_priority.h"
#include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.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_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/pending_user_input.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/widget_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.pbzero.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
#include "v8/include/v8.h"
namespace base {
class LazyNow;
}
namespace blink {
namespace scheduler {
TaskQueue;
TaskTimeObserver;
TimeDomain;
namespace {
const int kShortIdlePeriodDurationSampleCount = …;
const double kShortIdlePeriodDurationPercentile = …;
const double kFastCompositingIdleTimeThreshold = …;
const int64_t kSecondsPerMinute = …;
constexpr base::TimeDelta kDefaultPrioritizeCompositingAfterDelay = …;
constexpr base::TimeDelta kRenderBlockingStarvationThreshold = …;
v8::RAILMode RAILModeToV8RAILMode(RAILMode rail_mode) { … }
void AddRAILModeToProto(perfetto::protos::pbzero::TrackEvent* event,
RAILMode mode) { … }
void AddBackgroundedToProto(perfetto::protos::pbzero::TrackEvent* event,
bool is_backgrounded) { … }
void AddHiddenToProto(perfetto::protos::pbzero::TrackEvent* event,
bool is_hidden) { … }
const char* AudioPlayingStateToString(bool is_audio_playing) { … }
const char* RendererProcessTypeToString(WebRendererProcessType process_type) { … }
const char* OptionalTaskDescriptionToString(
std::optional<MainThreadSchedulerImpl::TaskDescriptionForTracing> desc) { … }
const char* OptionalTaskPriorityToString(std::optional<TaskPriority> priority) { … }
bool IsBlockingEvent(const blink::WebInputEvent& web_input_event) { … }
const char* InputEventStateToString(
WidgetScheduler::InputEventState input_event_state) { … }
TaskPriority GetPriorityFromCompositorTQPolicyDuringThreadedScrolling(
CompositorTQPolicyDuringThreadedScroll policy) { … }
const char* RenderingPrioritizationStateToString(
MainThreadSchedulerImpl::RenderingPrioritizationState state) { … }
}
MainThreadSchedulerImpl::MainThreadSchedulerImpl(
std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager)
: … { … }
MainThreadSchedulerImpl::MainThreadSchedulerImpl(
base::sequence_manager::SequenceManager* sequence_manager)
: … { … }
MainThreadSchedulerImpl::~MainThreadSchedulerImpl() { … }
WebThreadScheduler& WebThreadScheduler::MainThreadScheduler() { … }
MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
MainThreadSchedulerImpl* main_thread_scheduler_impl,
const base::TickClock* time_source,
base::TimeTicks now)
: … { … }
MainThreadSchedulerImpl::MainThreadOnly::~MainThreadOnly() = default;
MainThreadSchedulerImpl::AnyThread::AnyThread(
MainThreadSchedulerImpl* main_thread_scheduler_impl)
: … { … }
MainThreadSchedulerImpl::SchedulingSettings::SchedulingSettings() { … }
MainThreadSchedulerImpl::AnyThread::~AnyThread() = default;
MainThreadSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly()
: … { … }
MainThreadSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() =
default;
MainThreadSchedulerImpl::RendererPauseHandleImpl::RendererPauseHandleImpl(
MainThreadSchedulerImpl* scheduler)
: … { … }
MainThreadSchedulerImpl::RendererPauseHandleImpl::~RendererPauseHandleImpl() { … }
void MainThreadSchedulerImpl::ShutdownAllQueues() { … }
bool MainThreadSchedulerImpl::
IsAnyOrdinaryMainFrameWaitingForFirstMeaningfulPaint() const { … }
bool MainThreadSchedulerImpl::IsAnyOrdinaryMainFrameLoading() const { … }
bool MainThreadSchedulerImpl::
IsAnyOrdinaryMainFrameWaitingForFirstContentfulPaint() const { … }
void MainThreadSchedulerImpl::Shutdown() { … }
std::unique_ptr<MainThread> MainThreadSchedulerImpl::CreateMainThread() { … }
scoped_refptr<WidgetScheduler>
MainThreadSchedulerImpl::CreateWidgetScheduler() { … }
scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerImpl::ControlTaskRunner() { … }
scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerImpl::DefaultTaskRunner() { … }
scoped_refptr<SingleThreadIdleTaskRunner>
MainThreadSchedulerImpl::IdleTaskRunner() { … }
scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerImpl::DeprecatedDefaultTaskRunner() { … }
scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::V8TaskQueue() { … }
scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerImpl::CleanupTaskRunner() { … }
scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::ControlTaskQueue() { … }
scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::DefaultTaskQueue() { … }
scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewTaskQueue(
const MainThreadTaskQueue::QueueCreationParams& params) { … }
bool MainThreadSchedulerImpl::IsIpcTrackingEnabledForAllPages() { … }
void MainThreadSchedulerImpl::UpdateIpcTracking() { … }
void MainThreadSchedulerImpl::
SetOnIPCTaskPostedWhileInBackForwardCacheIfNeeded() { … }
void MainThreadSchedulerImpl::OnIPCTaskPostedWhileInAllPagesBackForwardCache(
uint32_t ipc_hash,
const char* ipc_interface_name) { … }
void MainThreadSchedulerImpl::
DetachOnIPCTaskPostedWhileInBackForwardCacheHandler() { … }
void MainThreadSchedulerImpl::ShutdownEmptyDetachedTaskQueues() { … }
scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType queue_type,
FrameSchedulerImpl* frame_scheduler) { … }
scoped_refptr<MainThreadTaskQueue>
MainThreadSchedulerImpl::NewThrottleableTaskQueueForTest(
FrameSchedulerImpl* frame_scheduler) { … }
void MainThreadSchedulerImpl::OnShutdownTaskQueue(
const scoped_refptr<MainThreadTaskQueue>& task_queue) { … }
void MainThreadSchedulerImpl::OnDetachTaskQueue(
MainThreadTaskQueue& task_queue) { … }
void MainThreadSchedulerImpl::AddTaskObserver(
base::TaskObserver* task_observer) { … }
void MainThreadSchedulerImpl::RemoveTaskObserver(
base::TaskObserver* task_observer) { … }
void MainThreadSchedulerImpl::WillBeginFrame(const viz::BeginFrameArgs& args) { … }
void MainThreadSchedulerImpl::DidCommitFrameToCompositor() { … }
void MainThreadSchedulerImpl::BeginFrameNotExpectedSoon() { … }
void MainThreadSchedulerImpl::BeginMainFrameNotExpectedUntil(
base::TimeTicks time) { … }
void MainThreadSchedulerImpl::SetAllRenderWidgetsHidden(bool hidden) { … }
void MainThreadSchedulerImpl::SetRendererHidden(bool hidden) { … }
void MainThreadSchedulerImpl::SetRendererBackgrounded(bool backgrounded) { … }
void MainThreadSchedulerImpl::SetRendererBackgroundedForTesting(
bool backgrounded) { … }
#if BUILDFLAG(IS_ANDROID)
void MainThreadSchedulerImpl::PauseTimersForAndroidWebView() {
main_thread_only().pause_timers_for_webview = true;
UpdatePolicy();
}
void MainThreadSchedulerImpl::ResumeTimersForAndroidWebView() {
main_thread_only().pause_timers_for_webview = false;
UpdatePolicy();
}
#endif
void MainThreadSchedulerImpl::OnAudioStateChanged() { … }
std::unique_ptr<MainThreadScheduler::RendererPauseHandle>
MainThreadSchedulerImpl::PauseScheduler() { … }
void MainThreadSchedulerImpl::PauseRendererImpl() { … }
void MainThreadSchedulerImpl::ResumeRendererImpl() { … }
void MainThreadSchedulerImpl::EndIdlePeriod() { … }
void MainThreadSchedulerImpl::EndIdlePeriodForTesting(
base::TimeTicks time_remaining) { … }
bool MainThreadSchedulerImpl::PolicyNeedsUpdateForTesting() { … }
void MainThreadSchedulerImpl::SetHaveSeenABlockingGestureForTesting(
bool status) { … }
void MainThreadSchedulerImpl::PerformMicrotaskCheckpoint() { … }
bool MainThreadSchedulerImpl::ShouldPrioritizeInputEvent(
const blink::WebInputEvent& web_input_event) { … }
void MainThreadSchedulerImpl::DidHandleInputEventOnCompositorThread(
const blink::WebInputEvent& web_input_event,
WidgetScheduler::InputEventState event_state) { … }
void MainThreadSchedulerImpl::UpdateForInputEventOnCompositorThread(
const blink::WebInputEvent& web_input_event,
WidgetScheduler::InputEventState input_event_state) { … }
void MainThreadSchedulerImpl::WillPostInputEventToMainThread(
WebInputEvent::Type web_input_event_type,
const WebInputEventAttribution& web_input_event_attribution) { … }
void MainThreadSchedulerImpl::WillHandleInputEventOnMainThread(
WebInputEvent::Type web_input_event_type,
const WebInputEventAttribution& web_input_event_attribution) { … }
void MainThreadSchedulerImpl::DidHandleInputEventOnMainThread(
const WebInputEvent& web_input_event,
WebInputEventResult result,
bool frame_requested) { … }
bool MainThreadSchedulerImpl::ShouldYieldForHighPriorityWork() { … }
base::TimeTicks MainThreadSchedulerImpl::CurrentIdleTaskDeadlineForTesting()
const { … }
void MainThreadSchedulerImpl::StartIdlePeriodForTesting() { … }
void MainThreadSchedulerImpl::MaybeUpdatePolicy() { … }
void MainThreadSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread(
const base::Location& from_here) { … }
void MainThreadSchedulerImpl::UpdatePolicy() { … }
void MainThreadSchedulerImpl::ForceUpdatePolicy() { … }
void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { … }
RAILMode MainThreadSchedulerImpl::ComputeCurrentRAILMode(
UseCase use_case) const { … }
void MainThreadSchedulerImpl::UpdateStateForAllTaskQueues(
std::optional<Policy> previous_policy) { … }
void MainThreadSchedulerImpl::UpdateTaskQueueState(
MainThreadTaskQueue* task_queue,
TaskQueue::QueueEnabledVoter* task_queue_enabled_voter,
const Policy& old_policy,
const Policy& new_policy,
bool should_update_priority) const { … }
UseCase MainThreadSchedulerImpl::ComputeCurrentUseCase(
base::TimeTicks now,
base::TimeDelta* expected_use_case_duration) const { … }
bool MainThreadSchedulerImpl::CanEnterLongIdlePeriod(
base::TimeTicks now,
base::TimeDelta* next_long_idle_period_delay_out) { … }
MainThreadSchedulerHelper*
MainThreadSchedulerImpl::GetSchedulerHelperForTesting() { … }
IdleTimeEstimator* MainThreadSchedulerImpl::GetIdleTimeEstimatorForTesting() { … }
base::SequencedTaskRunner* MainThreadSchedulerImpl::GetVirtualTimeTaskRunner() { … }
void MainThreadSchedulerImpl::OnVirtualTimeEnabled() { … }
void MainThreadSchedulerImpl::OnVirtualTimeDisabled() { … }
void MainThreadSchedulerImpl::OnVirtualTimePaused() { … }
void MainThreadSchedulerImpl::OnVirtualTimeResumed() { … }
void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshot() const { … }
void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshotLocked() const { … }
void MainThreadSchedulerImpl::WriteIntoTraceLocked(
perfetto::TracedValue context,
base::TimeTicks optional_now) const { … }
bool MainThreadSchedulerImpl::Policy::IsQueueEnabled(
MainThreadTaskQueue* task_queue,
const SchedulingSettings& settings) const { … }
void MainThreadSchedulerImpl::Policy::WriteIntoTrace(
perfetto::TracedValue context) const { … }
void MainThreadSchedulerImpl::OnIdlePeriodStarted() { … }
void MainThreadSchedulerImpl::OnIdlePeriodEnded() { … }
void MainThreadSchedulerImpl::OnPendingTasksChanged(bool has_tasks) { … }
void MainThreadSchedulerImpl::DispatchRequestBeginMainFrameNotExpected(
bool has_tasks) { … }
void MainThreadSchedulerImpl::DidStartProvisionalLoad(
bool is_outermost_main_frame) { … }
void MainThreadSchedulerImpl::DidCommitProvisionalLoad(
bool is_web_history_inert_commit,
bool is_reload,
bool is_outermost_main_frame) { … }
void MainThreadSchedulerImpl::OnMainFramePaint() { … }
void MainThreadSchedulerImpl::ResetForNavigationLocked() { … }
void MainThreadSchedulerImpl::AddRAILModeObserver(RAILModeObserver* observer) { … }
void MainThreadSchedulerImpl::RemoveRAILModeObserver(
RAILModeObserver const* observer) { … }
void MainThreadSchedulerImpl::ForEachMainThreadIsolate(
base::RepeatingCallback<void(v8::Isolate* isolate)> callback) { … }
void MainThreadSchedulerImpl::SetRendererProcessType(
WebRendererProcessType type) { … }
Vector<WebInputEventAttribution>
MainThreadSchedulerImpl::GetPendingUserInputInfo(
bool include_continuous) const { … }
blink::MainThreadScheduler* MainThreadSchedulerImpl::ToMainThreadScheduler() { … }
void MainThreadSchedulerImpl::RunIdleTask(Thread::IdleTask task,
base::TimeTicks deadline) { … }
void MainThreadSchedulerImpl::PostIdleTask(const base::Location& location,
Thread::IdleTask task) { … }
void MainThreadSchedulerImpl::PostDelayedIdleTask(
const base::Location& location,
base::TimeDelta delay,
Thread::IdleTask task) { … }
void MainThreadSchedulerImpl::PostNonNestableIdleTask(
const base::Location& location,
Thread::IdleTask task) { … }
scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerImpl::V8TaskRunner() { … }
scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerImpl::V8LowPriorityTaskRunner() { … }
scoped_refptr<base::SingleThreadTaskRunner>
MainThreadSchedulerImpl::NonWakingTaskRunner() { … }
AgentGroupScheduler* MainThreadSchedulerImpl::CreateAgentGroupScheduler() { … }
std::unique_ptr<WebAgentGroupScheduler>
MainThreadSchedulerImpl::CreateWebAgentGroupScheduler() { … }
void MainThreadSchedulerImpl::RemoveAgentGroupScheduler(
AgentGroupSchedulerImpl* agent_group_scheduler) { … }
AgentGroupScheduler* MainThreadSchedulerImpl::GetCurrentAgentGroupScheduler() { … }
void MainThreadSchedulerImpl::SetV8Isolate(v8::Isolate* isolate) { … }
v8::Isolate* MainThreadSchedulerImpl::Isolate() { … }
base::TimeTicks MainThreadSchedulerImpl::MonotonicallyIncreasingVirtualTime() { … }
void MainThreadSchedulerImpl::BeginAgentGroupSchedulerScope(
AgentGroupScheduler* next_agent_group_scheduler) { … }
void MainThreadSchedulerImpl::EndAgentGroupSchedulerScope() { … }
WebThreadScheduler* MainThreadSchedulerImpl::ToWebMainThreadScheduler() { … }
const base::TickClock* MainThreadSchedulerImpl::GetTickClock() const { … }
base::TimeTicks MainThreadSchedulerImpl::NowTicks() const { … }
void MainThreadSchedulerImpl::AddAgentGroupScheduler(
AgentGroupSchedulerImpl* agent_group_scheduler) { … }
void MainThreadSchedulerImpl::AddPageScheduler(
PageSchedulerImpl* page_scheduler) { … }
void MainThreadSchedulerImpl::RemovePageScheduler(
PageSchedulerImpl* page_scheduler) { … }
void MainThreadSchedulerImpl::OnPageFrozen(
base::MemoryReductionTaskContext called_from) { … }
void MainThreadSchedulerImpl::OnPageResumed() { … }
void MainThreadSchedulerImpl::OnTaskStarted(
MainThreadTaskQueue* queue,
const base::sequence_manager::Task& task,
const TaskQueue::TaskTiming& task_timing) { … }
void MainThreadSchedulerImpl::OnTaskCompleted(
base::WeakPtr<MainThreadTaskQueue> queue,
const base::sequence_manager::Task& task,
TaskQueue::TaskTiming* task_timing,
base::LazyNow* lazy_now) { … }
void MainThreadSchedulerImpl::RecordTaskUkm(
MainThreadTaskQueue* queue,
const base::sequence_manager::Task& task,
const TaskQueue::TaskTiming& task_timing) { … }
UkmRecordingStatus MainThreadSchedulerImpl::RecordTaskUkmImpl(
MainThreadTaskQueue* queue,
const base::sequence_manager::Task& task,
const TaskQueue::TaskTiming& task_timing,
FrameSchedulerImpl* frame_scheduler,
bool precise_attribution) { … }
TaskPriority MainThreadSchedulerImpl::ComputePriority(
MainThreadTaskQueue* task_queue) const { … }
void MainThreadSchedulerImpl::AddTaskTimeObserver(
TaskTimeObserver* task_time_observer) { … }
void MainThreadSchedulerImpl::RemoveTaskTimeObserver(
TaskTimeObserver* task_time_observer) { … }
std::unique_ptr<CPUTimeBudgetPool>
MainThreadSchedulerImpl::CreateCPUTimeBudgetPoolForTesting(const char* name) { … }
void MainThreadSchedulerImpl::OnTraceLogEnabled() { … }
void MainThreadSchedulerImpl::OnTraceLogDisabled() { … }
base::WeakPtr<MainThreadSchedulerImpl> MainThreadSchedulerImpl::GetWeakPtr() { … }
bool MainThreadSchedulerImpl::IsAudioPlaying() const { … }
bool MainThreadSchedulerImpl::ShouldUpdateTaskQueuePriorities(
Policy old_policy) const { … }
UseCase MainThreadSchedulerImpl::current_use_case() const { … }
const MainThreadSchedulerImpl::SchedulingSettings&
MainThreadSchedulerImpl::scheduling_settings() const { … }
TaskPriority MainThreadSchedulerImpl::ComputeCompositorPriority() const { … }
void MainThreadSchedulerImpl::UpdateCompositorTaskQueuePriority() { … }
void MainThreadSchedulerImpl::MaybeUpdatePolicyOnTaskCompleted(
MainThreadTaskQueue* queue,
const base::sequence_manager::TaskQueue::TaskTiming& task_timing) { … }
void MainThreadSchedulerImpl::UpdateRenderingPrioritizationStateOnTaskCompleted(
MainThreadTaskQueue* queue,
const base::sequence_manager::TaskQueue::TaskTiming& task_timing) { … }
std::optional<TaskPriority>
MainThreadSchedulerImpl::ComputeCompositorPriorityFromUseCase() const { … }
std::optional<TaskPriority>
MainThreadSchedulerImpl::ComputeCompositorPriorityForMainFrame() const { … }
bool MainThreadSchedulerImpl::AllPagesFrozen() const { … }
const char* MainThreadSchedulerImpl::RAILModeToString(RAILMode rail_mode) { … }
const char* MainThreadSchedulerImpl::TimeDomainTypeToString(
TimeDomainType domain_type) { … }
WTF::Vector<base::OnceClosure>&
MainThreadSchedulerImpl::GetOnTaskCompletionCallbacks() { … }
void MainThreadSchedulerImpl::ExecuteAfterCurrentTaskForTesting(
base::OnceClosure on_completion_task,
ExecuteAfterCurrentTaskRestricted) { … }
void MainThreadSchedulerImpl::OnUrgentMessageReceived() { … }
void MainThreadSchedulerImpl::OnUrgentMessageProcessed() { … }
void MainThreadSchedulerImpl::OnWebSchedulingTaskQueuePriorityChanged(
MainThreadTaskQueue* queue) { … }
}
}