diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/scheduler/main_thread')
30 files changed, 932 insertions, 589 deletions
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc index 0aacf6d7ce6..5acdacb3058 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h" +#include "third_party/blink/public/common/browser_interface_broker_proxy.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/public/dummy_schedulers.h" @@ -25,19 +26,34 @@ MainThreadTaskQueue::QueueCreationParams DefaultTaskQueueCreationParams( .SetAgentGroupScheduler(agent_group_scheduler_impl); } +MainThreadTaskQueue::QueueCreationParams CompositorTaskRunnerCreationParams( + AgentGroupSchedulerImpl* agent_group_scheduler_impl) { + return MainThreadTaskQueue::QueueCreationParams( + MainThreadTaskQueue::QueueType::kCompositor) + .SetShouldMonitorQuiescence(true) + .SetPrioritisationType( + MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor) + .SetAgentGroupScheduler(agent_group_scheduler_impl); +} + AgentGroupSchedulerImpl::AgentGroupSchedulerImpl( MainThreadSchedulerImpl& main_thread_scheduler) : default_task_queue_(main_thread_scheduler.NewTaskQueue( DefaultTaskQueueCreationParams(this))), default_task_runner_(default_task_queue_->CreateTaskRunner( TaskType::kMainThreadTaskQueueDefault)), + compositor_task_queue_(main_thread_scheduler.NewTaskQueue( + CompositorTaskRunnerCreationParams(this))), + compositor_task_runner_(compositor_task_queue_->CreateTaskRunner( + TaskType::kMainThreadTaskQueueCompositor)), main_thread_scheduler_(main_thread_scheduler) { DCHECK(!default_task_queue_->GetFrameScheduler()); DCHECK_EQ(default_task_queue_->GetAgentGroupScheduler(), this); } AgentGroupSchedulerImpl::~AgentGroupSchedulerImpl() { - default_task_queue_->ShutdownTaskQueue(); + default_task_queue_->DetachFromMainThreadScheduler(); + compositor_task_queue_->DetachFromMainThreadScheduler(); main_thread_scheduler_.RemoveAgentGroupScheduler(this); } @@ -48,9 +64,46 @@ std::unique_ptr<PageScheduler> AgentGroupSchedulerImpl::CreatePageScheduler( return page_scheduler; } +scoped_refptr<base::SingleThreadTaskRunner> +AgentGroupSchedulerImpl::DefaultTaskRunner() { + return default_task_runner_; +} + +scoped_refptr<base::SingleThreadTaskRunner> +AgentGroupSchedulerImpl::CompositorTaskRunner() { + if (main_thread_scheduler_.scheduling_settings() + .mbi_compositor_task_runner_per_agent_scheduling_group) { + return compositor_task_runner_; + } + // We temporarily redirect the per-AGS compositor task runner to the main + // thread's compositor task runner. + return main_thread_scheduler_.CompositorTaskRunner(); +} + +scoped_refptr<MainThreadTaskQueue> +AgentGroupSchedulerImpl::CompositorTaskQueue() { + return compositor_task_queue_; +} + +WebThreadScheduler& AgentGroupSchedulerImpl::GetMainThreadScheduler() { + return main_thread_scheduler_; +} + AgentGroupScheduler& AgentGroupSchedulerImpl::AsAgentGroupScheduler() { return *this; } +void AgentGroupSchedulerImpl::BindInterfaceBroker( + mojo::PendingRemote<mojom::BrowserInterfaceBroker> remote_broker) { + DCHECK(!broker_.is_bound()); + broker_.Bind(std::move(remote_broker), default_task_runner_); +} + +BrowserInterfaceBrokerProxy& +AgentGroupSchedulerImpl::GetBrowserInterfaceBroker() { + DCHECK(broker_.is_bound()); + return broker_; +} + } // namespace scheduler } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h index 01dbd8588ba..7ea89714fdb 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h @@ -6,6 +6,9 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_AGENT_GROUP_SCHEDULER_IMPL_H_ #include "base/memory/scoped_refptr.h" +#include "base/task/sequence_manager/task_queue.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "third_party/blink/public/common/browser_interface_broker_proxy.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h" @@ -17,6 +20,7 @@ namespace blink { namespace scheduler { class MainThreadSchedulerImpl; class MainThreadTaskQueue; +class WebThreadScheduler; // AgentGroupScheduler implementation which schedules per-AgentSchedulingGroup // tasks. @@ -30,18 +34,25 @@ class PLATFORM_EXPORT AgentGroupSchedulerImpl : public AgentGroupScheduler { std::unique_ptr<PageScheduler> CreatePageScheduler( PageScheduler::Delegate*) override; - scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override { - return default_task_runner_; - } - MainThreadSchedulerImpl& GetMainThreadScheduler() { - return main_thread_scheduler_; - } + scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override; + scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override; + scoped_refptr<MainThreadTaskQueue> CompositorTaskQueue(); + WebThreadScheduler& GetMainThreadScheduler() override; AgentGroupScheduler& AsAgentGroupScheduler() override; + void BindInterfaceBroker( + mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker> remote_broker) + override; + BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() override; + private: scoped_refptr<MainThreadTaskQueue> default_task_queue_; scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + scoped_refptr<MainThreadTaskQueue> compositor_task_queue_; + scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_; MainThreadSchedulerImpl& main_thread_scheduler_; // Not owned. + + BrowserInterfaceBrokerProxy broker_; }; } // namespace scheduler diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc index 9a4538263ee..d41bc4ea90e 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc @@ -36,6 +36,7 @@ class AutoAdvancingVirtualTimeDomainTest : public testing::Test { nullptr, test_task_runner_, test_task_runner_->GetMockTickClock()); scheduler_helper_.reset(new NonMainThreadSchedulerHelper( sequence_manager_.get(), nullptr, TaskType::kInternalTest)); + scheduler_helper_->AttachToCurrentThread(); scheduler_helper_->AddTaskTimeObserver(&test_task_time_observer_); task_queue_ = scheduler_helper_->DefaultNonMainThreadTaskQueue(); diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc index 0a455119137..1954d462f81 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc @@ -182,7 +182,7 @@ CompositorPriorityExperiments::CompositorBudgetPoolController:: "CompositorBudgetPool", this, tracing_controller, now)); compositor_budget_pool_->SetMinBudgetLevelToRun(now, min_budget); compositor_budget_pool_->SetTimeBudgetRecoveryRate(now, budget_recovery_rate); - compositor_budget_pool_->AddQueue(now, compositor_queue->GetTaskQueue()); + compositor_queue->AddToBudgetPool(now, compositor_budget_pool_.get()); } CompositorPriorityExperiments::CompositorBudgetPoolController:: 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 ff5aeb81906..1c15019931b 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 @@ -14,10 +14,14 @@ #include "base/task/sequence_manager/lazy_now.h" #include "base/time/time.h" #include "base/trace_event/blame_context.h" +#include "components/power_scheduler/power_mode.h" +#include "components/power_scheduler/power_mode_arbiter.h" +#include "components/power_scheduler/power_mode_voter.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.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/back_forward_cache_utils.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/common/features.h" #include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h" @@ -31,6 +35,7 @@ #include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/web_scheduling_task_queue_impl.h" #include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value.h" namespace blink { @@ -189,7 +194,10 @@ FrameSchedulerImpl::FrameSchedulerImpl( waiting_for_meaningful_paint_(true, "FrameScheduler.WaitingForMeaningfulPaint", &tracing_controller_, - YesNoStateToString) { + YesNoStateToString), + loading_power_mode_voter_( + power_scheduler::PowerModeArbiter::GetInstance()->NewVoter( + "PowerModeVoter.Loading")) { frame_task_queue_controller_.reset( new FrameTaskQueueController(main_thread_scheduler_, this, this)); } @@ -384,18 +392,16 @@ QueueTraits FrameSchedulerImpl::CreateQueueTraitsForTaskType(TaskType type) { QueueTraits::PrioritisationType::kJavaScriptTimer) .SetCanBeIntensivelyThrottled(IsIntensiveWakeUpThrottlingEnabled()); case TaskType::kJavascriptTimerImmediate: { - return DeferrableTaskQueueTraits() - .SetPrioritisationType( - QueueTraits::PrioritisationType::kJavaScriptTimer) - .SetCanBeThrottled(!base::FeatureList::IsEnabled( - features::kOptOutZeroTimeoutTimersFromThrottling)); + // Immediate timers are not throttled. + return DeferrableTaskQueueTraits().SetPrioritisationType( + QueueTraits::PrioritisationType::kJavaScriptTimer); } case TaskType::kInternalLoading: case TaskType::kNetworking: case TaskType::kNetworkingWithURLLoaderAnnotation: return LoadingTaskQueueTraits(); case TaskType::kNetworkingUnfreezable: - return base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable) + return IsInflightNetworkRequestBackForwardCacheSupportEnabled() ? UnfreezableLoadingTaskQueueTraits() : LoadingTaskQueueTraits(); case TaskType::kNetworkingControl: @@ -425,6 +431,7 @@ QueueTraits FrameSchedulerImpl::CreateQueueTraitsForTaskType(TaskType type) { case TaskType::kApplicationLifeCycle: case TaskType::kBackgroundFetch: case TaskType::kPermission: + case TaskType::kWakeLock: // TODO(altimin): Move appropriate tasks to throttleable task queue. return DeferrableTaskQueueTraits(); // PostedMessage can be used for navigation, so we shouldn't defer it @@ -612,9 +619,14 @@ void FrameSchedulerImpl::DidCommitProvisionalLoad( bool is_same_document = navigation_type == NavigationType::kSameDocument; if (!is_same_document) { + loading_power_mode_voter_->VoteFor(power_scheduler::PowerMode::kLoading); + loading_power_mode_voter_->ResetVoteAfterTimeout( + power_scheduler::PowerModeVoter::kLoadingTimeout); + waiting_for_contentful_paint_ = true; waiting_for_meaningful_paint_ = true; } + if (is_main_frame && !is_same_document) { task_time_ = base::TimeDelta(); // Ignore result here, based on the assumption that @@ -670,7 +682,7 @@ void FrameSchedulerImpl::OnStartedUsingFeature( "renderer.scheduler", "ActiveSchedulerTrackedFeature", TRACE_ID_LOCAL(reinterpret_cast<intptr_t>(this) ^ static_cast<int>(feature)), - "feature", FeatureToString(feature)); + "feature", FeatureToHumanReadableString(feature)); } } @@ -773,32 +785,22 @@ void FrameSchedulerImpl::OnRemovedBackForwardCacheOptOut( !back_forward_cache_opt_out_counts_.empty(); } -void FrameSchedulerImpl::AsValueInto( - base::trace_event::TracedValue* state) const { - state->SetBoolean("frame_visible", frame_visible_); - state->SetBoolean("page_visible", parent_page_scheduler_->IsPageVisible()); - state->SetBoolean("cross_origin_to_main_frame", IsCrossOriginToMainFrame()); - state->SetString("frame_type", - frame_type_ == FrameScheduler::FrameType::kMainFrame - ? "MainFrame" - : "Subframe"); - state->SetBoolean( - "disable_background_timer_throttling", - !RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled()); - - { - auto dictionary_scope = - state->BeginDictionaryScoped("frame_task_queue_controller"); - frame_task_queue_controller_->AsValueInto(state); - } +void FrameSchedulerImpl::WriteIntoTracedValue( + perfetto::TracedValue context) const { + auto dict = std::move(context).WriteDictionary(); + dict.Add("frame_visible", frame_visible_); + dict.Add("page_visible", parent_page_scheduler_->IsPageVisible()); + dict.Add("cross_origin_to_main_frame", IsCrossOriginToMainFrame()); + dict.Add("frame_type", frame_type_ == FrameScheduler::FrameType::kMainFrame + ? "MainFrame" + : "Subframe"); + dict.Add("disable_background_timer_throttling", + !RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled()); - if (blame_context_) { - auto dictionary_scope = state->BeginDictionaryScoped("blame_context"); - state->SetString( - "id_ref", - PointerToString(reinterpret_cast<void*>(blame_context_->id()))); - state->SetString("scope", blame_context_->scope()); - } + dict.Add("frame_task_queue_controller", frame_task_queue_controller_); + + if (blame_context_) + dict.Add("blame_context", blame_context_); } void FrameSchedulerImpl::SetPageVisibilityForTracing( @@ -845,12 +847,17 @@ void FrameSchedulerImpl::UpdatePolicy() { bool task_queues_were_throttled = task_queues_throttled_; task_queues_throttled_ = ShouldThrottleTaskQueues(); + if (!task_queues_throttled_) + throttled_task_queue_handles_.clear(); + 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_); + if (task_queues_throttled_ && !task_queues_were_throttled && + task_queue_and_voter.first->CanBeThrottled()) { + MainThreadTaskQueue::ThrottleHandle handle = + task_queue_and_voter.first->Throttle(); + throttled_task_queue_handles_.push_back(std::move(handle)); } } @@ -937,6 +944,8 @@ void FrameSchedulerImpl::OnLoad() { // update. main_thread_scheduler_->OnMainFrameLoad(*this); } + + loading_power_mode_voter_->VoteFor(power_scheduler::PowerMode::kIdle); } bool FrameSchedulerImpl::IsWaitingForContentfulPaint() const { @@ -962,24 +971,14 @@ bool FrameSchedulerImpl::ShouldThrottleTaskQueues() const { return false; if (!parent_page_scheduler_->IsPageVisible()) return true; + if (base::FeatureList::IsEnabled(kThrottleVisibleNotFocusedTimers) && + !parent_page_scheduler_->IsPageFocused()) { + return true; + } return RuntimeEnabledFeatures::TimerThrottlingForHiddenFramesEnabled() && !frame_visible_ && IsCrossOriginToMainFrame(); } -void FrameSchedulerImpl::UpdateTaskQueueThrottling( - MainThreadTaskQueue* task_queue, - bool should_throttle) { - if (!task_queue->CanBeThrottled()) - return; - if (should_throttle) { - main_thread_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount( - task_queue->GetTaskQueue()); - } else { - main_thread_scheduler_->task_queue_throttler()->DecreaseThrottleRefCount( - task_queue->GetTaskQueue()); - } -} - bool FrameSchedulerImpl::IsExemptFromBudgetBasedThrottling() const { return opted_out_from_aggressive_throttling(); } @@ -1214,7 +1213,8 @@ void FrameSchedulerImpl::OnTaskQueueCreated( task_queue, frame_origin_type_, &lazy_now); if (task_queues_throttled_) { - UpdateTaskQueueThrottling(task_queue, true); + MainThreadTaskQueue::ThrottleHandle handle = task_queue->Throttle(); + throttled_task_queue_handles_.push_back(std::move(handle)); } } } @@ -1349,8 +1349,7 @@ MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::DeferrableTaskQueueTraits() { return QueueTraits() .SetCanBeDeferred(true) - .SetCanBeFrozen(base::FeatureList::IsEnabled( - blink::features::kStopNonTimersInBackground)) + .SetCanBeFrozen(true) .SetCanBePaused(true) .SetCanRunWhenVirtualTimePaused(false) .SetCanBePausedForAndroidWebview(true); @@ -1359,8 +1358,7 @@ FrameSchedulerImpl::DeferrableTaskQueueTraits() { // static MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::PausableTaskQueueTraits() { return QueueTraits() - .SetCanBeFrozen(base::FeatureList::IsEnabled( - blink::features::kStopNonTimersInBackground)) + .SetCanBeFrozen(true) .SetCanBePaused(true) .SetCanRunWhenVirtualTimePaused(false) .SetCanBePausedForAndroidWebview(true); diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h index 66abb4e0dc5..f9d874d1b9d 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h @@ -18,6 +18,7 @@ #include "base/single_thread_task_runner.h" #include "base/task/sequence_manager/task_queue.h" #include "base/trace_event/trace_event.h" +#include "components/power_scheduler/power_mode_voter.h" #include "net/base/request_priority.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "third_party/blink/public/platform/task_type.h" @@ -32,6 +33,7 @@ #include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h" #include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" namespace base { namespace sequence_manager { @@ -39,7 +41,6 @@ class TaskQueue; } // namespace sequence_manager namespace trace_event { class BlameContext; -class TracedValue; } // namespace trace_event } // namespace base @@ -132,7 +133,6 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler, // created by an SVGImage). Virtual for testing. virtual bool IsOrdinary() const; - void AsValueInto(base::trace_event::TracedValue* state) const; bool IsExemptFromBudgetBasedThrottling() const override; std::unique_ptr<blink::mojom::blink::PauseSubresourceLoadingHandle> GetPauseSubresourceLoadingHandle() override; @@ -203,6 +203,8 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler, const base::UnguessableToken& GetAgentClusterId() const; + void WriteIntoTracedValue(perfetto::TracedValue context) const; + protected: FrameSchedulerImpl(MainThreadSchedulerImpl* main_thread_scheduler, PageSchedulerImpl* parent_page_scheduler, @@ -258,11 +260,6 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler, void UpdateQueuePolicy( MainThreadTaskQueue* queue, base::sequence_manager::TaskQueue::QueueEnabledVoter* voter); - // Update throttling for |task_queue|. This changes the throttling ref counts - // and should only be called for new queues if throttling is enabled, or if - // the throttling state changes. - void UpdateTaskQueueThrottling(MainThreadTaskQueue* task_queue, - bool should_throttle); void AddPauseSubresourceLoadingHandle(); void RemovePauseSubresourceLoadingHandle(); @@ -341,6 +338,7 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler, TraceableState<bool, TracingCategoryName::kInfo> subresource_loading_paused_; StateTracer<TracingCategoryName::kInfo> url_tracer_; TraceableState<bool, TracingCategoryName::kInfo> task_queues_throttled_; + Vector<MainThreadTaskQueue::ThrottleHandle> throttled_task_queue_handles_; TraceableState<bool, TracingCategoryName::kInfo> preempted_for_cooperative_scheduling_; // TODO(https://crbug.com/827113): Trace the count of opt-outs. @@ -376,6 +374,8 @@ class PLATFORM_EXPORT FrameSchedulerImpl : public FrameScheduler, TraceableState<bool, TracingCategoryName::kInfo> waiting_for_meaningful_paint_; + std::unique_ptr<power_scheduler::PowerModeVoter> loading_power_mode_voter_; + // TODO(altimin): Remove after we have have 1:1 relationship between frames // and documents. base::WeakPtrFactory<FrameSchedulerImpl> document_bound_weak_factory_{this}; diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index e076b0a5b53..6338f29ec7f 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc @@ -27,6 +27,7 @@ #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/switches.h" #include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h" +#include "third_party/blink/public/platform/web_runtime_features.h" #include "third_party/blink/renderer/platform/scheduler/common/features.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h" @@ -143,10 +144,11 @@ constexpr TaskType kAllFrameTaskTypes[] = { TaskType::kInternalTranslation, TaskType::kInternalInspector, TaskType::kInternalNavigationAssociatedUnfreezable, - TaskType::kInternalHighPriorityLocalFrame}; + TaskType::kInternalHighPriorityLocalFrame, + TaskType::kWakeLock}; static_assert( - static_cast<int>(TaskType::kCount) == 76, + static_cast<int>(TaskType::kCount) == 77, "When adding a TaskType, make sure that kAllFrameTaskTypes is updated."); void AppendToVectorTestTask(Vector<String>* vector, String value) { @@ -288,6 +290,52 @@ class FrameSchedulerImplTest : public testing::Test { } } + // Helper for posting several tasks to specific queues. |task_descriptor| is a + // string with space delimited task identifiers. The first letter of each task + // identifier specifies the task queue: + // - 'L': Loading task queue + // - 'T': Throttleable task queue + // - 'P': Pausable task queue + // - 'U': Unpausable task queue + // - 'D': Deferrable task queue + void PostTestTasksToQueuesWithTrait(Vector<String>* run_order, + const String& task_descriptor) { + std::istringstream stream(task_descriptor.Utf8()); + while (!stream.eof()) { + std::string task; + stream >> task; + switch (task[0]) { + case 'L': + LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( + FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order, + String::FromUTF8(task))); + break; + case 'T': + ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( + FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order, + String::FromUTF8(task))); + break; + case 'P': + PausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( + FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order, + String::FromUTF8(task))); + break; + case 'U': + UnpausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( + FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order, + String::FromUTF8(task))); + break; + case 'D': + DeferrableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( + FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order, + String::FromUTF8(task))); + break; + default: + NOTREACHED(); + } + } + } + static void ResetForNavigation(FrameSchedulerImpl* frame_scheduler) { frame_scheduler->ResetForNavigation(); } @@ -390,14 +438,12 @@ class FrameSchedulerImplTest : public testing::Test { bool IsThrottled() { EXPECT_TRUE(throttleable_task_queue()); - return scheduler_->task_queue_throttler()->IsThrottled( - throttleable_task_queue()->GetTaskQueue()); + return throttleable_task_queue()->IsThrottled(); } bool IsTaskTypeThrottled(TaskType task_type) { scoped_refptr<MainThreadTaskQueue> task_queue = GetTaskQueue(task_type); - return scheduler_->task_queue_throttler()->IsThrottled( - task_queue->GetTaskQueue()); + return task_queue->IsThrottled(); } SchedulingLifecycleState CalculateLifecycleState( @@ -430,22 +476,6 @@ class FrameSchedulerImplTest : public testing::Test { scoped_refptr<MainThreadTaskQueue> throttleable_task_queue_; }; -class FrameSchedulerImplStopNonTimersInBackgroundEnabledTest - : public FrameSchedulerImplTest { - public: - FrameSchedulerImplStopNonTimersInBackgroundEnabledTest() - : FrameSchedulerImplTest({blink::features::kStopNonTimersInBackground}, - {}) {} -}; - -class FrameSchedulerImplStopNonTimersInBackgroundDisabledTest - : public FrameSchedulerImplTest { - public: - FrameSchedulerImplStopNonTimersInBackgroundDisabledTest() - : FrameSchedulerImplTest({}, - {blink::features::kStopNonTimersInBackground}) {} -}; - class FrameSchedulerImplStopInBackgroundDisabledTest : public FrameSchedulerImplTest, public ::testing::WithParamInterface<TaskType> { @@ -505,10 +535,6 @@ void IncrementCounter(int* counter) { ++*counter; } -void RecordQueueName(String name, Vector<String>* tasks) { - tasks->push_back(std::move(name)); -} - // Simulate running a task of a particular length by fast forwarding the task // environment clock, which is used to determine the wall time of a task. void RunTaskOfLength(base::test::TaskEnvironment* task_environment, @@ -857,8 +883,7 @@ TEST_F(FrameSchedulerImplTest, FreezeForegroundOnlyTasks) { EXPECT_EQ(1, counter); } -TEST_F(FrameSchedulerImplStopNonTimersInBackgroundEnabledTest, - PageFreezeAndUnfreezeFlagEnabled) { +TEST_F(FrameSchedulerImplTest, PageFreezeAndUnfreeze) { int counter = 0; LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter))); @@ -882,13 +907,13 @@ TEST_F(FrameSchedulerImplStopNonTimersInBackgroundEnabledTest, page_scheduler_->SetPageFrozen(false); EXPECT_EQ(1, counter); - // Same as RunUntilIdle but also advances the clock if necessary. task_environment_.FastForwardUntilNoTasksRemain(); EXPECT_EQ(5, counter); } -TEST_F(FrameSchedulerImplStopNonTimersInBackgroundDisabledTest, - PageFreezeAndUnfreezeFlagDisabled) { +// Similar to PageFreezeAndUnfreeze, but unfreezes task queues by making the +// page visible instead of by invoking SetPageFrozen(false). +TEST_F(FrameSchedulerImplTest, PageFreezeAndPageVisible) { int counter = 0; LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter))); @@ -906,13 +931,13 @@ TEST_F(FrameSchedulerImplStopNonTimersInBackgroundDisabledTest, EXPECT_EQ(0, counter); base::RunLoop().RunUntilIdle(); - // throttleable tasks and loading tasks are frozen, others continue to run. - EXPECT_EQ(3, counter); + // unpausable tasks continue to run. + EXPECT_EQ(1, counter); - page_scheduler_->SetPageFrozen(false); + // Making the page visible should cause frozen queues to resume. + page_scheduler_->SetPageVisible(true); - EXPECT_EQ(3, counter); - // Same as RunUntilIdle but also advances the clock if necessary. + EXPECT_EQ(1, counter); task_environment_.FastForwardUntilNoTasksRemain(); EXPECT_EQ(5, counter); } @@ -980,27 +1005,7 @@ TEST_F(FrameSchedulerImplTest, FramePostsCpuTasksThroughReloadRenavigate) { TEST_F(FrameSchedulerImplTest, PageFreezeWithKeepActive) { Vector<String> tasks; - LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, - base::BindOnce(&RecordQueueName, - LoadingTaskQueue()->GetTaskQueue()->GetName(), &tasks)); - ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, - base::BindOnce(&RecordQueueName, - ThrottleableTaskQueue()->GetTaskQueue()->GetName(), - &tasks)); - DeferrableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, - base::BindOnce(&RecordQueueName, - DeferrableTaskQueue()->GetTaskQueue()->GetName(), &tasks)); - PausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, - base::BindOnce(&RecordQueueName, - PausableTaskQueue()->GetTaskQueue()->GetName(), &tasks)); - UnpausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, - base::BindOnce(&RecordQueueName, - UnpausableTaskQueue()->GetTaskQueue()->GetName(), &tasks)); + PostTestTasksToQueuesWithTrait(&tasks, "L1 T1 D1 P1 U1"); page_scheduler_->SetKeepActive(true); // say we have a Service Worker page_scheduler_->SetPageVisible(false); @@ -1009,30 +1014,19 @@ TEST_F(FrameSchedulerImplTest, PageFreezeWithKeepActive) { EXPECT_THAT(tasks, UnorderedElementsAre()); base::RunLoop().RunUntilIdle(); // Everything runs except throttleable tasks (timers) - EXPECT_THAT(tasks, - UnorderedElementsAre( - String(LoadingTaskQueue()->GetTaskQueue()->GetName()), - String(DeferrableTaskQueue()->GetTaskQueue()->GetName()), - String(PausableTaskQueue()->GetTaskQueue()->GetName()), - String(UnpausableTaskQueue()->GetTaskQueue()->GetName()))); + EXPECT_THAT(tasks, UnorderedElementsAre("L1", "D1", "P1", "U1")); tasks.clear(); - LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, - base::BindOnce(&RecordQueueName, - LoadingTaskQueue()->GetTaskQueue()->GetName(), &tasks)); + PostTestTasksToQueuesWithTrait(&tasks, "L1"); EXPECT_THAT(tasks, UnorderedElementsAre()); base::RunLoop().RunUntilIdle(); // loading task runs - EXPECT_THAT(tasks, UnorderedElementsAre(String( - LoadingTaskQueue()->GetTaskQueue()->GetName()))); + EXPECT_THAT(tasks, UnorderedElementsAre("L1")); tasks.clear(); - LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, - base::BindOnce(&RecordQueueName, - LoadingTaskQueue()->GetTaskQueue()->GetName(), &tasks)); + PostTestTasksToQueuesWithTrait(&tasks, "L1"); + // KeepActive is false when Service Worker stops. page_scheduler_->SetKeepActive(false); EXPECT_THAT(tasks, UnorderedElementsAre()); @@ -1044,37 +1038,7 @@ TEST_F(FrameSchedulerImplTest, PageFreezeWithKeepActive) { EXPECT_THAT(tasks, UnorderedElementsAre()); base::RunLoop().RunUntilIdle(); // loading task runs - EXPECT_THAT(tasks, UnorderedElementsAre(String( - LoadingTaskQueue()->GetTaskQueue()->GetName()))); -} - -TEST_F(FrameSchedulerImplStopNonTimersInBackgroundEnabledTest, - PageFreezeAndPageVisible) { - int counter = 0; - LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter))); - ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter))); - DeferrableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter))); - PausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter))); - UnpausableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask( - FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter))); - - page_scheduler_->SetPageVisible(false); - page_scheduler_->SetPageFrozen(true); - - EXPECT_EQ(0, counter); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, counter); - - // Making the page visible should cause frozen queues to resume. - page_scheduler_->SetPageVisible(true); - - EXPECT_EQ(1, counter); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(5, counter); + EXPECT_THAT(tasks, UnorderedElementsAre("L1")); } class FrameSchedulerImplTestWithUnfreezableLoading @@ -1082,7 +1046,9 @@ class FrameSchedulerImplTestWithUnfreezableLoading public: FrameSchedulerImplTestWithUnfreezableLoading() : FrameSchedulerImplTest({blink::features::kLoadingTasksUnfreezable}, - {}) {} + {}) { + WebRuntimeFeatures::EnableBackForwardCache(true); + } }; TEST_F(FrameSchedulerImplTestWithUnfreezableLoading, @@ -2478,7 +2444,7 @@ TEST_F(FrameSchedulerImplTest, BackForwardCacheOptOut) { auto feature_handle1 = frame_scheduler_->RegisterFeature( SchedulingPolicy::Feature::kWebSocket, - {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + {SchedulingPolicy::DisableBackForwardCache()}); EXPECT_THAT( frame_scheduler_->GetActiveFeaturesTrackedForBackForwardCacheMetrics(), @@ -2489,7 +2455,7 @@ TEST_F(FrameSchedulerImplTest, BackForwardCacheOptOut) { auto feature_handle2 = frame_scheduler_->RegisterFeature( SchedulingPolicy::Feature::kWebRTC, - {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + {SchedulingPolicy::DisableBackForwardCache()}); EXPECT_THAT( frame_scheduler_->GetActiveFeaturesTrackedForBackForwardCacheMetrics(), @@ -2528,7 +2494,7 @@ TEST_F(FrameSchedulerImplTest, BackForwardCacheOptOut_FrameNavigated) { auto feature_handle = frame_scheduler_->RegisterFeature( SchedulingPolicy::Feature::kWebSocket, - {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + {SchedulingPolicy::DisableBackForwardCache()}); EXPECT_THAT( frame_scheduler_->GetActiveFeaturesTrackedForBackForwardCacheMetrics(), @@ -2539,7 +2505,7 @@ TEST_F(FrameSchedulerImplTest, BackForwardCacheOptOut_FrameNavigated) { frame_scheduler_->RegisterStickyFeature( SchedulingPolicy::Feature::kMainResourceHasCacheControlNoStore, - {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + {SchedulingPolicy::DisableBackForwardCache()}); EXPECT_THAT( frame_scheduler_->GetActiveFeaturesTrackedForBackForwardCacheMetrics(), @@ -2596,11 +2562,11 @@ TEST_F(FrameSchedulerImplTest, FeatureUpload) { frame_scheduler->RegisterStickyFeature( SchedulingPolicy::Feature:: kMainResourceHasCacheControlNoStore, - {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + {SchedulingPolicy::DisableBackForwardCache()}); frame_scheduler->RegisterStickyFeature( SchedulingPolicy::Feature:: kMainResourceHasCacheControlNoCache, - {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + {SchedulingPolicy::DisableBackForwardCache()}); // Ensure that the feature upload is delayed. testing::Mock::VerifyAndClearExpectations(delegate); EXPECT_CALL( @@ -2635,7 +2601,7 @@ TEST_F(FrameSchedulerImplTest, FeatureUpload_FrameDestruction) { FeatureHandle* feature_handle) { *feature_handle = frame_scheduler->RegisterFeature( SchedulingPolicy::Feature::kWebSocket, - {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + {SchedulingPolicy::DisableBackForwardCache()}); // Ensure that the feature upload is delayed. testing::Mock::VerifyAndClearExpectations(delegate); EXPECT_CALL(*delegate, diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc index ced5549aa9f..6f161891430 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc @@ -17,6 +17,7 @@ #include "third_party/blink/renderer/platform/scheduler/main_thread/web_scheduling_task_queue_impl.h" #include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value.h" namespace blink { namespace scheduler { @@ -159,21 +160,11 @@ bool FrameTaskQueueController::RemoveResourceLoadingTaskQueue( return true; } -void FrameTaskQueueController::AsValueInto( - base::trace_event::TracedValue* state) const { - { - auto array_scope = state->BeginArrayScoped("task_queues"); - for (const auto& it : task_queues_) { - state->AppendString(PointerToString(it.value.get())); - } - } - - { - auto array_scope = state->BeginArrayScoped("resource_loading_task_queues"); - for (const auto& queue : resource_loading_task_queues_) { - state->AppendString(PointerToString(queue.get())); - } - } +void FrameTaskQueueController::WriteIntoTracedValue( + perfetto::TracedValue context) const { + auto dict = std::move(context).WriteDictionary(); + dict.Add("task_queues", task_queues_.Values()); + dict.Add("resource_loading_task_queues", resource_loading_task_queues_); } // static diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h index 956a65b5967..163434b51b7 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h @@ -18,6 +18,7 @@ #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" namespace base { namespace sequence_manager { @@ -95,7 +96,7 @@ class PLATFORM_EXPORT FrameTaskQueueController { bool RemoveResourceLoadingTaskQueue( const scoped_refptr<MainThreadTaskQueue>&); - void AsValueInto(base::trace_event::TracedValue* state) const; + void WriteIntoTracedValue(perfetto::TracedValue context) const; private: friend class FrameTaskQueueControllerTest; diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc index ad03fa3f884..59211b1c5ad 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.cc @@ -9,23 +9,16 @@ namespace blink { namespace scheduler { -IdleTimeEstimator::IdleTimeEstimator( - const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner, - const base::TickClock* time_source, - int sample_count, - double estimation_percentile) - : compositor_task_queue_(compositor_task_runner), - per_frame_compositor_task_runtime_(sample_count), +IdleTimeEstimator::IdleTimeEstimator(const base::TickClock* time_source, + int sample_count, + double estimation_percentile) + : per_frame_compositor_task_runtime_(sample_count), time_source_(time_source), estimation_percentile_(estimation_percentile), nesting_level_(0), - did_commit_(false) { - compositor_task_queue_->GetTaskQueue()->AddTaskObserver(this); -} + did_commit_(false) {} -IdleTimeEstimator::~IdleTimeEstimator() { - compositor_task_queue_->GetTaskQueue()->RemoveTaskObserver(this); -} +IdleTimeEstimator::~IdleTimeEstimator() = default; base::TimeDelta IdleTimeEstimator::GetExpectedIdleDuration( base::TimeDelta compositor_frame_interval) const { @@ -73,5 +66,15 @@ void IdleTimeEstimator::DidProcessTask(const base::PendingTask& pending_task) { } } +void IdleTimeEstimator::AddCompositorTaskQueue( + scoped_refptr<MainThreadTaskQueue> compositor_task_queue) { + compositor_task_queue->GetTaskQueue()->AddTaskObserver(this); +} + +void IdleTimeEstimator::RemoveCompositorTaskQueue( + scoped_refptr<MainThreadTaskQueue> compositor_task_queue) { + compositor_task_queue->GetTaskQueue()->RemoveTaskObserver(this); +} + } // namespace scheduler } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h index db4b01b4edc..f6a962a4ca9 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h @@ -19,7 +19,6 @@ namespace scheduler { class PLATFORM_EXPORT IdleTimeEstimator : public base::TaskObserver { public: IdleTimeEstimator( - const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner, const base::TickClock* time_source, int sample_count, double estimation_percentile); @@ -40,8 +39,12 @@ class PLATFORM_EXPORT IdleTimeEstimator : public base::TaskObserver { bool was_blocked_or_low_priority) override; void DidProcessTask(const base::PendingTask& pending_task) override; + void AddCompositorTaskQueue( + scoped_refptr<MainThreadTaskQueue> compositor_task_queue); + void RemoveCompositorTaskQueue( + scoped_refptr<MainThreadTaskQueue> compositor_task_queue); + private: - scoped_refptr<MainThreadTaskQueue> compositor_task_queue_; cc::RollingTimeDeltaHistory per_frame_compositor_task_runtime_; const base::TickClock* time_source_; // NOT OWNED double estimation_percentile_; diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc index 47d40f37d25..1023113f744 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc @@ -19,19 +19,6 @@ namespace blink { namespace scheduler { -class IdleTimeEstimatorForTest : public IdleTimeEstimator { - public: - IdleTimeEstimatorForTest( - const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner, - const base::TickClock* clock, - int sample_count, - double estimation_percentile) - : IdleTimeEstimator(compositor_task_runner, - clock, - sample_count, - estimation_percentile) {} -}; - class IdleTimeEstimatorTest : public testing::Test { public: IdleTimeEstimatorTest() @@ -46,24 +33,30 @@ class IdleTimeEstimatorTest : public testing::Test { manager_ = base::sequence_manager::SequenceManagerForTest::Create( nullptr, task_environment_.GetMainThreadTaskRunner(), task_environment_.GetMockTickClock()); - compositor_task_queue_ = - manager_->CreateTaskQueueWithType<MainThreadTaskQueue>( - base::sequence_manager::TaskQueue::Spec("test_tq"), - MainThreadTaskQueue::QueueCreationParams( - MainThreadTaskQueue::QueueType::kCompositor), - nullptr); - estimator_.reset(new IdleTimeEstimatorForTest( - compositor_task_queue_, task_environment_.GetMockTickClock(), 10, 50)); + estimator_ = std::make_unique<IdleTimeEstimator>( + task_environment_.GetMockTickClock(), 10, 50); + compositor_task_queue_1_ = NewTaskQueue(); + compositor_task_queue_2_ = NewTaskQueue(); + compositor_task_runner_1_ = compositor_task_queue_1_->CreateTaskRunner( + TaskType::kMainThreadTaskQueueCompositor); + compositor_task_runner_2_ = compositor_task_queue_2_->CreateTaskRunner( + TaskType::kMainThreadTaskQueueCompositor); + estimator_->AddCompositorTaskQueue(compositor_task_queue_1_); + estimator_->AddCompositorTaskQueue(compositor_task_queue_2_); + } + + scoped_refptr<MainThreadTaskQueue> NewTaskQueue() { + return manager_->CreateTaskQueueWithType<MainThreadTaskQueue>( + base::sequence_manager::TaskQueue::Spec("test_tq"), + MainThreadTaskQueue::QueueCreationParams( + MainThreadTaskQueue::QueueType::kCompositor), + nullptr); } void SimulateFrameWithOneCompositorTask(int compositor_time) { base::TimeDelta non_idle_time = base::TimeDelta::FromMilliseconds(compositor_time); - base::PendingTask task(FROM_HERE, base::OnceClosure()); - estimator_->WillProcessTask(task, /*was_blocked_or_low_priority=*/false); - task_environment_.FastForwardBy(non_idle_time); - estimator_->DidCommitFrameToCompositor(); - estimator_->DidProcessTask(task); + PostTask(compositor_task_runner_1_, compositor_time, /*commit=*/true); if (non_idle_time < frame_length_) task_environment_.FastForwardBy(frame_length_ - non_idle_time); } @@ -74,24 +67,37 @@ class IdleTimeEstimatorTest : public testing::Test { base::TimeDelta::FromMilliseconds(compositor_time1); base::TimeDelta non_idle_time2 = base::TimeDelta::FromMilliseconds(compositor_time2); - base::PendingTask task(FROM_HERE, base::OnceClosure()); - estimator_->WillProcessTask(task, /*was_blocked_or_low_priority=*/false); - task_environment_.FastForwardBy(non_idle_time1); - estimator_->DidProcessTask(task); - - estimator_->WillProcessTask(task, /*was_blocked_or_low_priority=*/false); - task_environment_.FastForwardBy(non_idle_time2); - estimator_->DidCommitFrameToCompositor(); - estimator_->DidProcessTask(task); - + PostTask(compositor_task_runner_1_, compositor_time1, /*commit=*/false); + PostTask(compositor_task_runner_2_, compositor_time2, /*commit=*/true); base::TimeDelta idle_time = frame_length_ - non_idle_time1 - non_idle_time2; task_environment_.FastForwardBy(idle_time); } + void PostTask(scoped_refptr<base::SingleThreadTaskRunner> task_runner, + int compositor_time, + bool commit) { + task_runner->PostTask( + FROM_HERE, + base::BindOnce( + [](base::test::TaskEnvironment* task_environment, + IdleTimeEstimator* estimator, int compositor_time, bool commit) { + base::TimeDelta non_idle_time = + base::TimeDelta::FromMilliseconds(compositor_time); + task_environment->FastForwardBy(non_idle_time); + if (commit) + estimator->DidCommitFrameToCompositor(); + }, + &task_environment_, estimator_.get(), compositor_time, commit)); + task_environment_.RunUntilIdle(); + } + base::test::TaskEnvironment task_environment_; std::unique_ptr<base::sequence_manager::SequenceManager> manager_; - scoped_refptr<MainThreadTaskQueue> compositor_task_queue_; - std::unique_ptr<IdleTimeEstimatorForTest> estimator_; + std::unique_ptr<IdleTimeEstimator> estimator_; + scoped_refptr<MainThreadTaskQueue> compositor_task_queue_1_; + scoped_refptr<MainThreadTaskQueue> compositor_task_queue_2_; + scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_1_; + scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_2_; const base::TimeDelta frame_length_; base::sequence_manager::TestTaskTimeObserver test_task_time_observer_; }; @@ -148,6 +154,16 @@ TEST_F(IdleTimeEstimatorTest, Estimation_MultipleTasks) { estimator_->GetExpectedIdleDuration(frame_length_)); } +TEST_F(IdleTimeEstimatorTest, Estimation_MultipleTasks_WithSingleObserver) { + // Observe only |compositor_task_queue_2_| + estimator_->RemoveCompositorTaskQueue(compositor_task_queue_1_); + SimulateFrameWithTwoCompositorTasks(1, 4); + SimulateFrameWithTwoCompositorTasks(1, 4); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(12), + estimator_->GetExpectedIdleDuration(frame_length_)); +} + TEST_F(IdleTimeEstimatorTest, IgnoresNestedTasks) { SimulateFrameWithOneCompositorTask(5); SimulateFrameWithOneCompositorTask(5); diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc index 39602a63139..be2f8281775 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.cc @@ -12,16 +12,10 @@ namespace blink { namespace scheduler { MainThread::MainThread(MainThreadSchedulerImpl* scheduler) - : task_runner_(scheduler->DefaultTaskRunner()), - scheduler_(scheduler), - thread_id_(base::PlatformThread::CurrentId()) {} + : task_runner_(scheduler->DefaultTaskRunner()), scheduler_(scheduler) {} MainThread::~MainThread() = default; -blink::PlatformThreadId MainThread::ThreadId() const { - return thread_id_; -} - blink::ThreadScheduler* MainThread::Scheduler() { return scheduler_; } diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h index 6a382c287f8..a9054728a56 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h @@ -25,7 +25,6 @@ class PLATFORM_EXPORT MainThread : public Thread { // Thread implementation. ThreadScheduler* Scheduler() override; - PlatformThreadId ThreadId() const override; scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override; void AddTaskTimeObserver(base::sequence_manager::TaskTimeObserver*) override; @@ -35,7 +34,6 @@ class PLATFORM_EXPORT MainThread : public Thread { private: scoped_refptr<base::SingleThreadTaskRunner> task_runner_; MainThreadSchedulerImpl* scheduler_; // Not owned. - PlatformThreadId thread_id_; }; } // namespace scheduler diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc index a15e2a43d85..0a84c72edce 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc @@ -42,7 +42,7 @@ MainThreadSchedulerHelper::DefaultMainThreadTaskQueue() { const scoped_refptr<base::SingleThreadTaskRunner>& MainThreadSchedulerHelper::DefaultTaskRunner() { - return default_task_queue_->GetTaskRunnerWithDefaultTaskType(); + return default_task_runner(); } scoped_refptr<MainThreadTaskQueue> @@ -59,25 +59,11 @@ scoped_refptr<base::SingleThreadTaskRunner> MainThreadSchedulerHelper::DeprecatedDefaultTaskRunner() { // TODO(hajimehoshi): Introduce a different task queue from the default task // queue and return the task runner created from it. - return DefaultTaskRunner(); + return default_task_runner(); } scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerHelper::NewTaskQueue( const MainThreadTaskQueue::QueueCreationParams& params) { -#if DCHECK_IS_ON() - // This check is to ensure that we only create one queue with kCompositor - // prioritisation type, ie one compositor task queue, since elsewhere we - // assume there is only one when making priority decisions. - if (params.queue_traits.prioritisation_type == - MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor) { - DCHECK( - !created_compositor_task_queue_ || - params.queue_traits.prioritisation_type != - MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor); - created_compositor_task_queue_ = true; - } -#endif // DCHECK_IS_ON() - scoped_refptr<MainThreadTaskQueue> task_queue = sequence_manager_->CreateTaskQueueWithType<MainThreadTaskQueue>( params.spec, params, main_thread_scheduler_); diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h index dca77b6a301..9d1c2990a54 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h @@ -46,10 +46,6 @@ class PLATFORM_EXPORT MainThreadSchedulerHelper : public SchedulerHelper { const scoped_refptr<MainThreadTaskQueue> default_task_queue_; const scoped_refptr<MainThreadTaskQueue> control_task_queue_; -#if DCHECK_IS_ON() - bool created_compositor_task_queue_ = false; -#endif // DCHECK_IS_ON() - DISALLOW_COPY_AND_ASSIGN(MainThreadSchedulerHelper); }; diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc index 7089d80e317..cf1ea90760b 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc @@ -25,6 +25,9 @@ #include "base/trace_event/trace_event.h" #include "base/trace_event/traced_value.h" #include "build/build_config.h" +#include "components/power_scheduler/power_mode.h" +#include "components/power_scheduler/power_mode_arbiter.h" +#include "components/power_scheduler/power_mode_voter.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/input/web_input_event_attribution.h" @@ -33,7 +36,6 @@ #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/renderer/platform/bindings/parkable_string_manager.h" #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/common/features.h" @@ -236,8 +238,6 @@ MainThreadSchedulerImpl::MainThreadSchedulerImpl( MainThreadTaskQueue::QueueCreationParams( MainThreadTaskQueue::QueueType::kIPCTrackingForCachedPages) .SetShouldNotifyObservers(false))), - compositor_task_queue_enabled_voter_( - compositor_task_queue_->GetTaskQueue()->CreateQueueEnabledVoter()), memory_purge_task_queue_(helper_.NewTaskQueue( MainThreadTaskQueue::QueueCreationParams( MainThreadTaskQueue::QueueType::kIdle) @@ -252,18 +252,21 @@ MainThreadSchedulerImpl::MainThreadSchedulerImpl( helper_.ControlMainThreadTaskQueue()->CreateTaskRunner( TaskType::kMainThreadTaskQueueControl)), main_thread_only_(this, - compositor_task_queue_, helper_.GetClock(), helper_.NowTicks()), any_thread_(this), policy_may_need_update_(&any_thread_lock_), notify_agent_strategy_task_posted_(&any_thread_lock_) { + helper_.AttachToCurrentThread(); + // Compositor task queue and default task queue should be managed by // WebThreadScheduler. Control task queue should not. task_runners_.emplace(helper_.DefaultMainThreadTaskQueue(), nullptr); task_runners_.emplace( compositor_task_queue_, compositor_task_queue_->GetTaskQueue()->CreateQueueEnabledVoter()); + main_thread_only().idle_time_estimator.AddCompositorTaskQueue( + compositor_task_queue_); back_forward_cache_ipc_tracking_task_runner_ = back_forward_cache_ipc_tracking_task_queue_->CreateTaskRunner( @@ -347,7 +350,7 @@ MainThreadSchedulerImpl::~MainThreadSchedulerImpl() { TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "MainThreadScheduler", this); - for (auto& pair : task_runners_) { + for (const auto& pair : task_runners_) { pair.first->ShutdownTaskQueue(); } @@ -377,11 +380,9 @@ WebThreadScheduler* WebThreadScheduler::MainThreadScheduler() { MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly( MainThreadSchedulerImpl* main_thread_scheduler_impl, - const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner, const base::TickClock* time_source, base::TimeTicks now) - : idle_time_estimator(compositor_task_runner, - time_source, + : idle_time_estimator(time_source, kShortIdlePeriodDurationSampleCount, kShortIdlePeriodDurationPercentile), current_use_case(UseCase::kNone, @@ -494,7 +495,10 @@ MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly( compositor_priority(TaskQueue::QueuePriority::kNormalPriority, "Scheduler.CompositorPriority", &main_thread_scheduler_impl->tracing_controller_, - TaskQueue::PriorityToString) {} + TaskQueue::PriorityToString), + audible_power_mode_voter( + power_scheduler::PowerModeArbiter::GetInstance()->NewVoter( + "PowerModeVoter.Audible")) {} MainThreadSchedulerImpl::MainThreadOnly::~MainThreadOnly() = default; @@ -605,6 +609,13 @@ MainThreadSchedulerImpl::SchedulingSettings::SchedulingSettings() { } } } + + mbi_override_task_runner_handle = + base::FeatureList::IsEnabled(kMbiOverrideTaskRunnerHandle); + + mbi_compositor_task_runner_per_agent_scheduling_group = + base::FeatureList::IsEnabled( + kMbiCompositorTaskRunnerPerAgentSchedulingGroup); } MainThreadSchedulerImpl::AnyThread::~AnyThread() = default; @@ -742,6 +753,13 @@ scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewTaskQueue( voter = task_queue->GetTaskQueue()->CreateQueueEnabledVoter(); } + if (task_queue->GetPrioritisationType() == + MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor) { + DCHECK(!voter); + voter = task_queue->GetTaskQueue()->CreateQueueEnabledVoter(); + main_thread_only().idle_time_estimator.AddCompositorTaskQueue(task_queue); + } + auto insert_result = task_runners_.emplace(task_queue, std::move(voter)); UpdateTaskQueueState(task_queue.get(), insert_result.first->second.get(), @@ -888,9 +906,6 @@ void MainThreadSchedulerImpl::OnShutdownTaskQueue( if (was_shutdown_) return; - if (task_queue_throttler_) - task_queue_throttler_->ShutdownTaskQueue(task_queue->GetTaskQueue()); - task_queue.get()->DetachOnIPCTaskPostedWhileInBackForwardCache(); task_runners_.erase(task_queue.get()); } @@ -1083,7 +1098,6 @@ void MainThreadSchedulerImpl::SetRendererBackgrounded(bool backgrounded) { main_thread_only().metrics_helper.OnRendererForegrounded(now); } - ParkableStringManager::Instance().SetRendererBackgrounded(backgrounded); memory_purge_manager_.SetRendererBackgrounded(backgrounded); } @@ -1125,6 +1139,10 @@ void MainThreadSchedulerImpl::OnAudioStateChanged() { return; main_thread_only().is_audio_playing = is_audio_playing; + + main_thread_only().audible_power_mode_voter->VoteFor( + is_audio_playing ? power_scheduler::PowerMode::kAudible + : power_scheduler::PowerMode::kIdle); } std::unique_ptr<ThreadScheduler::RendererPauseHandle> @@ -1454,9 +1472,14 @@ bool MainThreadSchedulerImpl::ShouldYieldForHighPriorityWork() { case UseCase::kMainThreadGesture: case UseCase::kMainThreadCustomInputHandling: case UseCase::kSynchronizedGesture: - return compositor_task_queue_->GetTaskQueue() - ->HasTaskToRunImmediately() || - main_thread_only().blocking_input_expected_soon; + for (const auto& pair : task_runners_) { + if (pair.first->GetPrioritisationType() == + MainThreadTaskQueue::QueueTraits::PrioritisationType:: + kCompositor && + pair.first->GetTaskQueue()->HasTaskToRunImmediately()) + return true; + } + return main_thread_only().blocking_input_expected_soon; case UseCase::kTouchstart: return true; @@ -1706,8 +1729,6 @@ void MainThreadSchedulerImpl::UpdateStateForAllTaskQueues( UpdateTaskQueueState(pair.first.get(), pair.second.get(), old_policy, current_policy, should_update_priorities); } - compositor_task_queue_enabled_voter_->SetVoteToEnable( - !current_policy.should_freeze_compositor_task_queue()); } void MainThreadSchedulerImpl::UpdateTaskQueueState( @@ -1741,6 +1762,12 @@ void MainThreadSchedulerImpl::UpdateTaskQueueState( task_queue->GetTaskQueue()->SetTimeDomain(real_time_domain()); } } + + if (task_queue->GetPrioritisationType() == + MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor) { + task_queue_enabled_voter->SetVoteToEnable( + !new_policy.should_freeze_compositor_task_queue()); + } } UseCase MainThreadSchedulerImpl::ComputeCurrentUseCase( @@ -1947,7 +1974,7 @@ void MainThreadSchedulerImpl::VirtualTimePaused() { for (const auto& pair : task_runners_) { if (pair.first->CanRunWhenVirtualTimePaused()) continue; - DCHECK(!task_queue_throttler_->IsThrottled(pair.first->GetTaskQueue())); + DCHECK(!pair.first->IsThrottled()); pair.first->GetTaskQueue()->InsertFence( TaskQueue::InsertFencePosition::kNow); } @@ -1957,7 +1984,7 @@ void MainThreadSchedulerImpl::VirtualTimeResumed() { for (const auto& pair : task_runners_) { if (pair.first->CanRunWhenVirtualTimePaused()) continue; - DCHECK(!task_queue_throttler_->IsThrottled(pair.first->GetTaskQueue())); + DCHECK(!pair.first->IsThrottled()); DCHECK(pair.first->GetTaskQueue()->HasActiveFence()); pair.first->GetTaskQueue()->RemoveFence(); } @@ -2046,138 +2073,104 @@ void MainThreadSchedulerImpl::SetMaxVirtualTimeTaskStarvationCount( ApplyVirtualTimePolicy(); } -std::unique_ptr<base::trace_event::ConvertableToTraceFormat> -MainThreadSchedulerImpl::AsValue(base::TimeTicks optional_now) const { - base::AutoLock lock(any_thread_lock_); - return AsValueLocked(optional_now); -} - void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshot() const { TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"), - "MainThreadScheduler", this, AsValue(helper_.NowTicks())); + "MainThreadScheduler", this, [&](perfetto::TracedValue context) { + base::AutoLock lock(any_thread_lock_); + WriteIntoTracedValueLocked(std::move(context), helper_.NowTicks()); + }); } void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshotLocked() const { TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"), - "MainThreadScheduler", this, AsValueLocked(helper_.NowTicks())); -} - -std::unique_ptr<base::trace_event::ConvertableToTraceFormat> -MainThreadSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { - auto state = std::make_unique<base::trace_event::TracedValue>(); - AsValueIntoLocked(state.get(), optional_now); - return std::move(state); + "MainThreadScheduler", this, [&](perfetto::TracedValue context) { + WriteIntoTracedValueLocked(std::move(context), helper_.NowTicks()); + }); } -std::string MainThreadSchedulerImpl::ToString() const { - base::AutoLock lock(any_thread_lock_); - base::trace_event::TracedValueJSON value; - AsValueIntoLocked(&value, base::TimeTicks()); - return value.ToJSON(); -} - -void MainThreadSchedulerImpl::AsValueIntoLocked( - base::trace_event::TracedValue* state, +void MainThreadSchedulerImpl::WriteIntoTracedValueLocked( + perfetto::TracedValue context, base::TimeTicks optional_now) const { helper_.CheckOnValidThread(); any_thread_lock_.AssertAcquired(); + auto dict = std::move(context).WriteDictionary(); + if (optional_now.is_null()) optional_now = helper_.NowTicks(); - state->SetBoolean( - "has_visible_render_widget_with_touch_handler", - main_thread_only().has_visible_render_widget_with_touch_handler); - state->SetString("current_use_case", - UseCaseToString(main_thread_only().current_use_case)); - state->SetBoolean( - "compositor_will_send_main_frame_not_expected", - main_thread_only().compositor_will_send_main_frame_not_expected); - state->SetBoolean("blocking_input_expected_soon", - main_thread_only().blocking_input_expected_soon); - state->SetString("idle_period_state", - IdleHelper::IdlePeriodStateToString( - idle_helper_.SchedulerIdlePeriodState())); - state->SetBoolean("renderer_hidden", main_thread_only().renderer_hidden); - state->SetBoolean("waiting_for_any_main_frame_contentful_paint", - any_thread().waiting_for_any_main_frame_contentful_paint); - state->SetBoolean("waiting_for_any_main_frame_meaningful_paint", - any_thread().waiting_for_any_main_frame_meaningful_paint); - state->SetBoolean("have_seen_input_since_navigation", - any_thread().have_seen_input_since_navigation); - state->SetBoolean( + dict.Add("has_visible_render_widget_with_touch_handler", + main_thread_only().has_visible_render_widget_with_touch_handler); + dict.Add("current_use_case", + UseCaseToString(main_thread_only().current_use_case)); + dict.Add("compositor_will_send_main_frame_not_expected", + main_thread_only().compositor_will_send_main_frame_not_expected); + dict.Add("blocking_input_expected_soon", + main_thread_only().blocking_input_expected_soon); + dict.Add("idle_period_state", IdleHelper::IdlePeriodStateToString( + idle_helper_.SchedulerIdlePeriodState())); + dict.Add("renderer_hidden", main_thread_only().renderer_hidden); + dict.Add("waiting_for_any_main_frame_contentful_paint", + any_thread().waiting_for_any_main_frame_contentful_paint); + dict.Add("waiting_for_any_main_frame_meaningful_paint", + any_thread().waiting_for_any_main_frame_meaningful_paint); + dict.Add("have_seen_input_since_navigation", + any_thread().have_seen_input_since_navigation); + dict.Add( "have_reported_blocking_intervention_in_current_policy", main_thread_only().have_reported_blocking_intervention_in_current_policy); - state->SetBoolean( + dict.Add( "have_reported_blocking_intervention_since_navigation", main_thread_only().have_reported_blocking_intervention_since_navigation); - state->SetBoolean("renderer_backgrounded", - main_thread_only().renderer_backgrounded); - state->SetBoolean("keep_active_fetch_or_worker", - main_thread_only().keep_active_fetch_or_worker); - state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF()); - state->SetDouble( + dict.Add("renderer_backgrounded", main_thread_only().renderer_backgrounded); + dict.Add("keep_active_fetch_or_worker", + main_thread_only().keep_active_fetch_or_worker); + dict.Add("now", (optional_now - base::TimeTicks()).InMillisecondsF()); + dict.Add( "fling_compositor_escalation_deadline", (any_thread().fling_compositor_escalation_deadline - base::TimeTicks()) .InMillisecondsF()); - state->SetDouble("last_idle_period_end_time", - (any_thread().last_idle_period_end_time - base::TimeTicks()) - .InMillisecondsF()); - state->SetBoolean("awaiting_touch_start_response", - any_thread().awaiting_touch_start_response); - state->SetBoolean("begin_main_frame_on_critical_path", - any_thread().begin_main_frame_on_critical_path); - state->SetBoolean("last_gesture_was_compositor_driven", - any_thread().last_gesture_was_compositor_driven); - state->SetBoolean("default_gesture_prevented", - any_thread().default_gesture_prevented); - state->SetBoolean("is_audio_playing", main_thread_only().is_audio_playing); - state->SetBoolean("virtual_time_stopped", - main_thread_only().virtual_time_stopped); - state->SetDouble("virtual_time_pause_count", - main_thread_only().virtual_time_pause_count); - state->SetString( - "virtual_time_policy", - VirtualTimePolicyToString(main_thread_only().virtual_time_policy)); - state->SetBoolean("virtual_time", main_thread_only().use_virtual_time); - - { - auto dictionary_scope = state->BeginDictionaryScoped("page_schedulers"); - for (PageSchedulerImpl* page_scheduler : - main_thread_only().page_schedulers) { - auto inner_dictionary = state->BeginDictionaryScopedWithCopiedName( - PointerToString(page_scheduler)); - page_scheduler->AsValueInto(state); - } - } - - { - auto dictionary_scope = state->BeginDictionaryScoped("policy"); - main_thread_only().current_policy.AsValueInto(state); - } + dict.Add("last_idle_period_end_time", + (any_thread().last_idle_period_end_time - base::TimeTicks()) + .InMillisecondsF()); + dict.Add("awaiting_touch_start_response", + any_thread().awaiting_touch_start_response); + dict.Add("begin_main_frame_on_critical_path", + any_thread().begin_main_frame_on_critical_path); + dict.Add("last_gesture_was_compositor_driven", + any_thread().last_gesture_was_compositor_driven); + dict.Add("default_gesture_prevented", any_thread().default_gesture_prevented); + dict.Add("is_audio_playing", main_thread_only().is_audio_playing); + dict.Add("virtual_time_stopped", main_thread_only().virtual_time_stopped); + dict.Add("virtual_time_pause_count", + main_thread_only().virtual_time_pause_count); + dict.Add("virtual_time_policy", + VirtualTimePolicyToString(main_thread_only().virtual_time_policy)); + dict.Add("virtual_time", main_thread_only().use_virtual_time); + + dict.Add("page_schedulers", main_thread_only().page_schedulers); + + dict.Add("policy", main_thread_only().current_policy); // TODO(skyostil): Can we somehow trace how accurate these estimates were? - state->SetDouble( + dict.Add( "longest_jank_free_task_duration", main_thread_only().longest_jank_free_task_duration->InMillisecondsF()); - state->SetDouble( - "compositor_frame_interval", - main_thread_only().compositor_frame_interval.InMillisecondsF()); - state->SetDouble( - "estimated_next_frame_begin", - (main_thread_only().estimated_next_frame_begin - base::TimeTicks()) - .InMillisecondsF()); - state->SetBoolean("in_idle_period", any_thread().in_idle_period); + dict.Add("compositor_frame_interval", + main_thread_only().compositor_frame_interval.InMillisecondsF()); + dict.Add("estimated_next_frame_begin", + (main_thread_only().estimated_next_frame_begin - base::TimeTicks()) + .InMillisecondsF()); + dict.Add("in_idle_period", any_thread().in_idle_period); - any_thread().user_model.AsValueInto(state); - render_widget_scheduler_signals_.AsValueInto(state); + dict.Add("user_model", any_thread().user_model); + dict.Add("render_widget_scheduler_signals", render_widget_scheduler_signals_); - { - auto dictionary_scope = - state->BeginDictionaryScoped("task_queue_throttler"); - task_queue_throttler_->AsValueInto(state, optional_now); - } + dict.Add("task_queue_throttler", [&](perfetto::TracedValue context) { + task_queue_throttler_->WriteIntoTracedValue(std::move(context), + optional_now); + }); } bool MainThreadSchedulerImpl::Policy::IsQueueEnabled( @@ -2199,17 +2192,18 @@ MainThreadSchedulerImpl::Policy::GetTimeDomainType() const { return TimeDomainType::kReal; } -void MainThreadSchedulerImpl::Policy::AsValueInto( - base::trace_event::TracedValue* state) const { - state->SetString("rail_mode", RAILModeToString(rail_mode())); - state->SetString("use_case", UseCaseToString(use_case())); +void MainThreadSchedulerImpl::Policy::WriteIntoTracedValue( + perfetto::TracedValue context) const { + auto dict = std::move(context).WriteDictionary(); + dict.Add("rail_mode", RAILModeToString(rail_mode())); + dict.Add("use_case", UseCaseToString(use_case())); - state->SetBoolean("should_disable_throttling", should_disable_throttling()); - state->SetBoolean("should_defer_task_queues", should_defer_task_queues()); - state->SetBoolean("should_pause_task_queues", should_pause_task_queues()); - state->SetBoolean("should_pause_task_queues_for_android_webview", - should_pause_task_queues_for_android_webview()); - state->SetBoolean("use_virtual_time", use_virtual_time()); + dict.Add("should_disable_throttling", should_disable_throttling()); + dict.Add("should_defer_task_queues", should_defer_task_queues()); + dict.Add("should_pause_task_queues", should_pause_task_queues()); + dict.Add("should_pause_task_queues_for_android_webview", + should_pause_task_queues_for_android_webview()); + dict.Add("use_virtual_time", use_virtual_time()); } void MainThreadSchedulerImpl::OnIdlePeriodStarted() { @@ -2440,6 +2434,14 @@ MainThreadSchedulerImpl::V8TaskRunner() { scoped_refptr<base::SingleThreadTaskRunner> MainThreadSchedulerImpl::CompositorTaskRunner() { + if (scheduling_settings() + .mbi_compositor_task_runner_per_agent_scheduling_group) { + NOTREACHED() << "When MbiPerAGSCompositorTaskRunner is enabled, " + "MainThreadSchedulerImpl::CompositorTaskRunner() shouldn't " + "be used. We are planning to remove " + "MainThreadSchedulerImpl::CompositorTaskRunner() in the " + "near future."; + } return compositor_task_runner_; } @@ -2467,30 +2469,92 @@ MainThreadSchedulerImpl::GetCurrentAgentGroupScheduler() { return current_agent_group_scheduler_; } -void MainThreadSchedulerImpl::SetCurrentAgentGroupScheduler( - WebAgentGroupScheduler* agent_group_scheduler) { - helper_.CheckOnValidThread(); - if (current_agent_group_scheduler_) { - TRACE_EVENT_NESTABLE_ASYNC_END1( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "scheduler.agent_scope", current_agent_group_scheduler_, - "agent_group_scheduler", current_agent_group_scheduler_); - } else { - TRACE_EVENT_NESTABLE_ASYNC_END0( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "scheduler.thread_scope", this); - } - current_agent_group_scheduler_ = agent_group_scheduler; - if (current_agent_group_scheduler_) { - TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "scheduler.agent_scope", current_agent_group_scheduler_, - "agent_group_scheduler", current_agent_group_scheduler_); +void MainThreadSchedulerImpl::BeginAgentGroupSchedulerScope( + WebAgentGroupScheduler* next_agent_group_scheduler) { + scoped_refptr<base::SingleThreadTaskRunner> next_task_runner; + const char* trace_event_scope_name; + void* trace_event_scope_id; + + if (next_agent_group_scheduler) { + // If the |next_agent_group_scheduler| is not null, it means that a + // per-AgentSchedulingGroup task is about to start. In this case, a + // per-AgentGroupScheduler scope starts. + next_task_runner = next_agent_group_scheduler->DefaultTaskRunner(), + trace_event_scope_name = "scheduler.agent_scope"; + trace_event_scope_id = next_agent_group_scheduler; } else { - TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "scheduler.thread_scope", this); - } + // If the |next_agent_group_scheduler| is null, it means that a + // per-thread task is about to start. In this case, a per-thread scope + // starts. + next_task_runner = helper_.DefaultTaskRunner(); + trace_event_scope_name = "scheduler.thread_scope"; + trace_event_scope_id = this; + } + + TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), trace_event_scope_name, + trace_event_scope_id, "agent_group_scheduler", + static_cast<void*>(next_agent_group_scheduler)); + + WebAgentGroupScheduler* previous_agent_group_scheduler = + current_agent_group_scheduler_; + current_agent_group_scheduler_ = next_agent_group_scheduler; + + scoped_refptr<base::SingleThreadTaskRunner> previous_task_runner = + base::ThreadTaskRunnerHandle::Get(); + std::unique_ptr<base::ThreadTaskRunnerHandleOverride> + thread_task_runner_handle_override; + if (scheduling_settings().mbi_override_task_runner_handle && + next_task_runner != previous_task_runner) { + // per-thread and per-AgentSchedulingGroup task runner allows nested + // runloop. |MainThreadSchedulerImpl| guarantees that + // |ThreadTaskRunnerHandle::Get()| and |SequencedTaskRunnerHandle::Get()| + // return a proper task runner even when a nested runloop is used. Because + // |MainThreadSchedulerImpl::OnTaskStarted()| always overrides + // TTRH/STRH::Get() properly. So there is no concern about returning an + // unexpected task runner from TTRH/STRH::Get() in this specific case. + thread_task_runner_handle_override = + std::unique_ptr<base::ThreadTaskRunnerHandleOverride>( + new base::ThreadTaskRunnerHandleOverride( + next_task_runner, + /*allow_nested_runloop=*/true)); + } + + main_thread_only().agent_group_scheduler_scope_stack.emplace_back( + AgentGroupSchedulerScope{ + std::move(thread_task_runner_handle_override), + previous_agent_group_scheduler, next_agent_group_scheduler, + std::move(previous_task_runner), std::move(next_task_runner), + trace_event_scope_name, trace_event_scope_id}); +} + +void MainThreadSchedulerImpl::EndAgentGroupSchedulerScope() { + AgentGroupSchedulerScope& agent_group_scheduler_scope = + main_thread_only().agent_group_scheduler_scope_stack.back(); + + if (scheduling_settings().mbi_override_task_runner_handle) { + DCHECK_EQ(base::ThreadTaskRunnerHandle::Get(), + agent_group_scheduler_scope.current_task_runner); + DCHECK_EQ(base::SequencedTaskRunnerHandle::Get(), + agent_group_scheduler_scope.current_task_runner); + } + agent_group_scheduler_scope.thread_task_runner_handle_override = nullptr; + DCHECK_EQ(base::ThreadTaskRunnerHandle::Get(), + agent_group_scheduler_scope.previous_task_runner); + DCHECK_EQ(base::SequencedTaskRunnerHandle::Get(), + agent_group_scheduler_scope.previous_task_runner); + + current_agent_group_scheduler_ = + agent_group_scheduler_scope.previous_agent_group_scheduler; + + TRACE_EVENT_NESTABLE_ASYNC_END1( + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + agent_group_scheduler_scope.trace_event_scope_name, + agent_group_scheduler_scope.trace_event_scope_id, "agent_group_scheduler", + static_cast<void*>( + agent_group_scheduler_scope.current_agent_group_scheduler)); + + main_thread_only().agent_group_scheduler_scope_stack.pop_back(); } std::unique_ptr<ThreadScheduler::RendererPauseHandle> @@ -2561,6 +2625,11 @@ void MainThreadSchedulerImpl::RemovePageScheduler( SetOnIPCTaskPostedWhileInBackForwardCacheIfNeeded(); } + if (main_thread_only().is_audio_playing && page_scheduler->IsAudioPlaying()) { + // This page may have been the only one playing audio. + OnAudioStateChanged(); + } + base::AutoLock lock(any_thread_lock_); any_thread().waiting_for_any_main_frame_contentful_paint = IsAnyMainFrameWaitingForFirstContentfulPaint(); @@ -2605,8 +2674,10 @@ void MainThreadSchedulerImpl::OnTaskStarted( MainThreadTaskQueue* queue, const base::sequence_manager::Task& task, const TaskQueue::TaskTiming& task_timing) { - SetCurrentAgentGroupScheduler(queue ? queue->GetAgentGroupScheduler() - : nullptr); + if (scheduling_settings().mbi_override_task_runner_handle) { + BeginAgentGroupSchedulerScope(queue ? queue->GetAgentGroupScheduler() + : nullptr); + } main_thread_only().running_queues.push(queue); if (main_thread_only().nested_runloop) @@ -2642,16 +2713,18 @@ void MainThreadSchedulerImpl::OnTaskCompleted( if (task_timing->has_wall_time() && queue && queue->GetFrameScheduler()) queue->GetFrameScheduler()->AddTaskTime(task_timing->wall_duration()); main_thread_only().running_queues.pop(); + + // The overriding TaskRunnerHandle scope ends here. + if (scheduling_settings().mbi_override_task_runner_handle) + EndAgentGroupSchedulerScope(); + if (main_thread_only().nested_runloop) return; DispatchOnTaskCompletionCallbacks(); - if (queue) { - task_queue_throttler()->OnTaskRunTimeReported(queue->GetTaskQueue(), - task_timing->start_time(), - task_timing->end_time()); - } + if (queue) + queue->OnTaskRunTimeReported(task_timing); // TODO(altimin): Per-page metrics should also be considered. main_thread_only().metrics_helper.RecordTaskMetrics(queue.get(), task, @@ -2668,10 +2741,6 @@ void MainThreadSchedulerImpl::OnTaskCompleted( find_in_page_budget_pool_controller_->OnTaskCompleted(queue.get(), task_timing); - - // GetCurrentAgentGroupScheduler() should return nullptr when - // it's running thread global task runners. - SetCurrentAgentGroupScheduler(nullptr); } void MainThreadSchedulerImpl::RecordTaskUkm( @@ -2900,8 +2969,13 @@ TaskQueue::QueuePriority MainThreadSchedulerImpl::ComputeCompositorPriority() void MainThreadSchedulerImpl::UpdateCompositorTaskQueuePriority() { main_thread_only().compositor_priority = ComputeCompositorPriority(); - CompositorTaskQueue()->GetTaskQueue()->SetQueuePriority( - ComputePriority(CompositorTaskQueue().get())); + for (const auto& pair : task_runners_) { + if (pair.first->GetPrioritisationType() != + MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor) + continue; + pair.first->GetTaskQueue()->SetQueuePriority( + ComputePriority(pair.first.get())); + } } base::Optional<TaskQueue::QueuePriority> diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h index 2ef822df859..89ea3cb1ef9 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h @@ -23,6 +23,7 @@ #include "base/task/sequence_manager/task_time_observer.h" #include "base/trace_event/trace_log.h" #include "build/build_config.h" +#include "components/power_scheduler/power_mode_voter.h" #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h" @@ -50,14 +51,10 @@ #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" namespace base { - class TaskObserver; - -namespace trace_event { -class ConvertableToTraceFormat; -} } // namespace base namespace blink { @@ -143,6 +140,15 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl std::array<base::sequence_manager::TaskQueue::QueuePriority, net::RequestPrioritySize::NUM_PRIORITIES> net_to_blink_priority; + + // If enabled, base::ThreadTaskRunnerHandle::Get() and + // base::SequencedTaskRunnerHandle::Get() returns the current active + // per-ASG task runner instead of the per-thread task runner. + bool mbi_override_task_runner_handle; + + // If enabled, per-AgentGroupScheduler CompositorTaskRunner will be used + // instead of per-MainThreadScheduler CompositorTaskRunner. + bool mbi_compositor_task_runner_per_agent_scheduling_group; }; static const char* UseCaseToString(UseCase use_case); @@ -223,8 +229,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override; std::unique_ptr<WebAgentGroupScheduler> CreateAgentGroupScheduler() override; WebAgentGroupScheduler* GetCurrentAgentGroupScheduler() override; - void SetCurrentAgentGroupScheduler( - WebAgentGroupScheduler* agent_group_scheduler); std::unique_ptr<ThreadScheduler::RendererPauseHandle> PauseScheduler() override; base::TimeTicks MonotonicallyIncreasingVirtualTime() override; @@ -494,6 +498,21 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl void AddAgentGroupScheduler(AgentGroupSchedulerImpl*); + struct AgentGroupSchedulerScope { + std::unique_ptr<base::ThreadTaskRunnerHandleOverride> + thread_task_runner_handle_override; + WebAgentGroupScheduler* previous_agent_group_scheduler; + WebAgentGroupScheduler* current_agent_group_scheduler; + scoped_refptr<base::SingleThreadTaskRunner> previous_task_runner; + scoped_refptr<base::SingleThreadTaskRunner> current_task_runner; + const char* trace_event_scope_name; + void* trace_event_scope_id; + }; + + void BeginAgentGroupSchedulerScope( + WebAgentGroupScheduler* next_agent_group_scheduler); + void EndAgentGroupSchedulerScope(); + bool IsAnyMainFrameWaitingForFirstContentfulPaint() const; bool IsAnyMainFrameWaitingForFirstMeaningfulPaint() const; @@ -573,12 +592,12 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl use_case_ == other.use_case_; } - void AsValueInto(base::trace_event::TracedValue* state) const; - bool IsQueueEnabled(MainThreadTaskQueue* task_queue) const; TimeDomainType GetTimeDomainType() const; + void WriteIntoTracedValue(perfetto::TracedValue context) const; + private: RAILMode rail_mode_{RAILMode::kAnimation}; bool should_disable_throttling_{false}; @@ -632,14 +651,10 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl MainThreadTaskQueue* queue); // Returns the serialized scheduler state for tracing. - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue( - base::TimeTicks optional_now) const; - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValueLocked( - base::TimeTicks optional_now) const; + void WriteIntoTracedValueLocked(perfetto::TracedValue context, + base::TimeTicks optional_now) const; void CreateTraceEventObjectSnapshotLocked() const; - std::string ToString() const; - static bool ShouldPrioritizeInputEvent(const WebInputEvent& web_input_event); // The amount of time which idle periods can continue being scheduled when the @@ -780,9 +795,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl // task. void DispatchOnTaskCompletionCallbacks(); - void AsValueIntoLocked(base::trace_event::TracedValue*, - base::TimeTicks optional_now) const; - bool AllPagesFrozen() const; // Indicates that scheduler has been shutdown. @@ -821,8 +833,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl scoped_refptr<MainThreadTaskQueue> virtual_time_control_task_queue_; scoped_refptr<MainThreadTaskQueue> back_forward_cache_ipc_tracking_task_queue_; - std::unique_ptr<base::sequence_manager::TaskQueue::QueueEnabledVoter> - compositor_task_queue_enabled_voter_; using TaskQueueVoterMap = std::map< scoped_refptr<MainThreadTaskQueue>, @@ -862,7 +872,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl struct MainThreadOnly { MainThreadOnly( MainThreadSchedulerImpl* main_thread_scheduler_impl, - const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner, const base::TickClock* time_source, base::TimeTicks now); ~MainThreadOnly(); @@ -965,6 +974,10 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl // kNormalPriority and is updated via UpdateCompositorTaskQueuePriority(). TraceableState<TaskQueue::QueuePriority, TracingCategoryName::kDefault> compositor_priority; + + WTF::Vector<AgentGroupSchedulerScope> agent_group_scheduler_scope_stack; + + std::unique_ptr<power_scheduler::PowerModeVoter> audible_power_mode_voter; }; struct AnyThread { @@ -1036,7 +1049,8 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl return any_thread_; } - // Don't access compositor_thread_only_, instead use CompositorThreadOnly(). + // Don't access compositor_thread_only_, instead use + // |GetCompositorThreadOnly()|. CompositorThreadOnly compositor_thread_only_; CompositorThreadOnly& GetCompositorThreadOnly() { compositor_thread_only_.CheckOnValidThread(); diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc index 006a901f95a..56a4eb6f6e9 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc @@ -444,13 +444,23 @@ class MainThreadSchedulerImplTest : public testing::Test { default_task_runner_ = scheduler_->DefaultTaskQueue()->GetTaskRunnerWithDefaultTaskType(); - compositor_task_runner_ = - scheduler_->CompositorTaskQueue()->GetTaskRunnerWithDefaultTaskType(); + if (!scheduler_->scheduling_settings() + .mbi_compositor_task_runner_per_agent_scheduling_group) { + compositor_task_runner_ = + scheduler_->CompositorTaskQueue()->GetTaskRunnerWithDefaultTaskType(); + } idle_task_runner_ = scheduler_->IdleTaskRunner(); v8_task_runner_ = scheduler_->V8TaskQueue()->GetTaskRunnerWithDefaultTaskType(); - agent_group_scheduler_ = scheduler_->CreateAgentGroupScheduler(); + agent_group_scheduler_ = std::unique_ptr<AgentGroupSchedulerImpl>( + static_cast<AgentGroupSchedulerImpl*>( + scheduler_->CreateAgentGroupScheduler().release())); + if (scheduler_->scheduling_settings() + .mbi_compositor_task_runner_per_agent_scheduling_group) { + compositor_task_runner_ = agent_group_scheduler_->CompositorTaskQueue() + ->GetTaskRunnerWithDefaultTaskType(); + } page_scheduler_ = std::make_unique<NiceMock<MockPageSchedulerImpl>>( scheduler_.get(), static_cast<AgentGroupSchedulerImpl&>(*agent_group_scheduler_)); @@ -474,6 +484,15 @@ class MainThreadSchedulerImplTest : public testing::Test { blink::TaskType::kInternalHighPriorityLocalFrame); } + MainThreadTaskQueue* compositor_task_queue() { + if (scheduler_->scheduling_settings() + .mbi_compositor_task_runner_per_agent_scheduling_group) { + return agent_group_scheduler_->CompositorTaskQueue().get(); + } else { + return scheduler_->CompositorTaskQueue().get(); + } + } + MainThreadTaskQueue* loading_task_queue() { auto queue_traits = FrameSchedulerImpl::LoadingTaskQueueTraits(); return main_frame_scheduler_->FrameTaskQueueControllerForTest() @@ -946,7 +965,7 @@ class MainThreadSchedulerImplTest : public testing::Test { scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_; std::unique_ptr<MainThreadSchedulerImplForTest> scheduler_; - std::unique_ptr<WebAgentGroupScheduler> agent_group_scheduler_; + std::unique_ptr<AgentGroupSchedulerImpl> agent_group_scheduler_; std::unique_ptr<MockPageSchedulerImpl> page_scheduler_; std::unique_ptr<FrameSchedulerImpl> main_frame_scheduler_; std::unique_ptr<WebWidgetScheduler> widget_scheduler_; @@ -2485,8 +2504,8 @@ TEST_F(MainThreadSchedulerImplTest, StopAndThrottleThrottleableQueue) { auto pause_handle = scheduler_->PauseRenderer(); base::RunLoop().RunUntilIdle(); - scheduler_->task_queue_throttler()->IncreaseThrottleRefCount( - throttleable_task_queue()->GetTaskQueue()); + MainThreadTaskQueue::ThrottleHandle handle = + throttleable_task_queue()->Throttle(); base::RunLoop().RunUntilIdle(); EXPECT_THAT(run_order, testing::ElementsAre()); } @@ -2495,8 +2514,8 @@ TEST_F(MainThreadSchedulerImplTest, ThrottleAndPauseRenderer) { Vector<String> run_order; PostTestTasks(&run_order, "T1 T2"); - scheduler_->task_queue_throttler()->IncreaseThrottleRefCount( - throttleable_task_queue()->GetTaskQueue()); + MainThreadTaskQueue::ThrottleHandle handle = + throttleable_task_queue()->Throttle(); base::RunLoop().RunUntilIdle(); auto pause_handle = scheduler_->PauseRenderer(); base::RunLoop().RunUntilIdle(); @@ -2883,9 +2902,8 @@ TEST_F(MainThreadSchedulerImplTest, SYNCHRONIZED_GESTURE_CompositingExpensive) { // Throttleable tasks should not have been starved by the expensive compositor // tasks. - EXPECT_EQ( - TaskQueue::kNormalPriority, - scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetQueuePriority()); + EXPECT_EQ(TaskQueue::kNormalPriority, + compositor_task_queue()->GetTaskQueue()->GetQueuePriority()); EXPECT_EQ(1000u, run_order.size()); } @@ -2926,9 +2944,8 @@ TEST_F(MainThreadSchedulerImplTest, MAIN_THREAD_CUSTOM_INPUT_HANDLING) { // Throttleable tasks should not have been starved by the expensive compositor // tasks. - EXPECT_EQ( - TaskQueue::kNormalPriority, - scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetQueuePriority()); + EXPECT_EQ(TaskQueue::kNormalPriority, + compositor_task_queue()->GetTaskQueue()->GetQueuePriority()); EXPECT_EQ(1000u, run_order.size()); } @@ -2967,9 +2984,8 @@ TEST_F(MainThreadSchedulerImplTest, MAIN_THREAD_GESTURE) { EXPECT_EQ(UseCase::kMainThreadGesture, CurrentUseCase()) << "i = " << i; } - EXPECT_EQ( - TaskQueue::kHighestPriority, - scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetQueuePriority()); + EXPECT_EQ(TaskQueue::kHighestPriority, + compositor_task_queue()->GetTaskQueue()->GetQueuePriority()); EXPECT_EQ(279u, run_order.size()); } @@ -3140,7 +3156,7 @@ TEST_F(MainThreadSchedulerImplTest, EnableVirtualTime) { EXPECT_EQ(scheduler_->DefaultTaskQueue()->GetTaskQueue()->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); - EXPECT_EQ(scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetTimeDomain(), + EXPECT_EQ(compositor_task_queue()->GetTaskQueue()->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); EXPECT_EQ(loading_task_queue()->GetTaskQueue()->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); @@ -3199,15 +3215,13 @@ TEST_F(MainThreadSchedulerImplTest, EnableVirtualTimeAfterThrottling) { frame_scheduler->SetCrossOriginToMainFrame(true); frame_scheduler->SetFrameVisible(false); - EXPECT_TRUE(scheduler_->task_queue_throttler()->IsThrottled( - throttleable_tq->GetTaskQueue())); + EXPECT_TRUE(throttleable_tq->IsThrottled()); scheduler_->EnableVirtualTime( MainThreadSchedulerImpl::BaseTimeOverridePolicy::DO_NOT_OVERRIDE); EXPECT_EQ(throttleable_tq->GetTaskQueue()->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); - EXPECT_FALSE(scheduler_->task_queue_throttler()->IsThrottled( - throttleable_tq->GetTaskQueue())); + EXPECT_FALSE(throttleable_tq->IsThrottled()); } TEST_F(MainThreadSchedulerImplTest, DisableVirtualTimeForTesting) { @@ -3216,7 +3230,7 @@ TEST_F(MainThreadSchedulerImplTest, DisableVirtualTimeForTesting) { scheduler_->DisableVirtualTimeForTesting(); EXPECT_EQ(scheduler_->DefaultTaskQueue()->GetTaskQueue()->GetTimeDomain(), scheduler_->real_time_domain()); - EXPECT_EQ(scheduler_->CompositorTaskQueue()->GetTaskQueue()->GetTimeDomain(), + EXPECT_EQ(compositor_task_queue()->GetTaskQueue()->GetTimeDomain(), scheduler_->real_time_domain()); EXPECT_EQ(loading_task_queue()->GetTaskQueue()->GetTimeDomain(), scheduler_->real_time_domain()); @@ -3342,7 +3356,7 @@ TEST_F(MainThreadSchedulerImplTest, Tracing) { FROM_HERE, base::BindOnce(NullTask), base::TimeDelta::FromMilliseconds(10)); - EXPECT_FALSE(scheduler_->ToString().empty()); + scheduler_->CreateTraceEventObjectSnapshot(); } TEST_F(MainThreadSchedulerImplTest, @@ -4130,6 +4144,22 @@ TEST_F(BestEffortNonMainQueuesUntilOnFMPTimeoutTest, TaskQueue::QueuePriority::kNormalPriority); } +TEST_F(MainThreadSchedulerImplTest, ThrottleHandleThrottlesQueue) { + EXPECT_FALSE(throttleable_task_queue()->IsThrottled()); + { + MainThreadTaskQueue::ThrottleHandle handle = + throttleable_task_queue()->Throttle(); + EXPECT_TRUE(throttleable_task_queue()->IsThrottled()); + { + MainThreadTaskQueue::ThrottleHandle handle_2 = + throttleable_task_queue()->Throttle(); + EXPECT_TRUE(throttleable_task_queue()->IsThrottled()); + } + EXPECT_TRUE(throttleable_task_queue()->IsThrottled()); + } + EXPECT_FALSE(throttleable_task_queue()->IsThrottled()); +} + } // namespace main_thread_scheduler_impl_unittest } // namespace scheduler } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc index d2f53467c0e..0fba96bd10b 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc @@ -12,6 +12,7 @@ #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/wtf/wtf.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value.h" namespace blink { namespace scheduler { @@ -146,6 +147,12 @@ void MainThreadTaskQueue::OnTaskCompleted( } } +void MainThreadTaskQueue::OnTaskRunTimeReported( + TaskQueue::TaskTiming* task_timing) { + main_thread_scheduler_->task_queue_throttler()->OnTaskRunTimeReported( + task_queue_.get(), task_timing->start_time(), task_timing->end_time()); +} + void MainThreadTaskQueue::DetachFromMainThreadScheduler() { weak_ptr_factory_.InvalidateWeakPtrs(); @@ -203,8 +210,14 @@ WebAgentGroupScheduler* MainThreadTaskQueue::GetAgentGroupScheduler() { } void MainThreadTaskQueue::ClearReferencesToSchedulers() { - if (main_thread_scheduler_) + if (main_thread_scheduler_) { main_thread_scheduler_->OnShutdownTaskQueue(this); + + if (main_thread_scheduler_->task_queue_throttler()) { + main_thread_scheduler_->task_queue_throttler()->ShutdownTaskQueue( + task_queue_.get()); + } + } main_thread_scheduler_ = nullptr; agent_group_scheduler_ = nullptr; frame_scheduler_ = nullptr; @@ -243,5 +256,62 @@ MainThreadTaskQueue::web_scheduling_priority() const { return web_scheduling_priority_; } +bool MainThreadTaskQueue::IsThrottled() const { + if (main_thread_scheduler_) { + return main_thread_scheduler_->task_queue_throttler()->IsThrottled( + task_queue_.get()); + } else { + // When the frame detaches the task queue is removed from the throttler. + return false; + } +} + +MainThreadTaskQueue::ThrottleHandle MainThreadTaskQueue::Throttle() { + DCHECK(CanBeThrottled()); + return ThrottleHandle( + task_queue_.get()->AsWeakPtr(), + main_thread_scheduler_->task_queue_throttler()->AsWeakPtr()); +} + +void MainThreadTaskQueue::AddToBudgetPool(base::TimeTicks now, + BudgetPool* pool) { + pool->AddQueue(now, task_queue_.get()); +} + +void MainThreadTaskQueue::RemoveFromBudgetPool(base::TimeTicks now, + BudgetPool* pool) { + pool->RemoveQueue(now, task_queue_.get()); +} + +void MainThreadTaskQueue::SetImmediateWakeUpForTest() { + if (main_thread_scheduler_) { + main_thread_scheduler_->task_queue_throttler()->OnQueueNextWakeUpChanged( + task_queue_.get(), base::TimeTicks()); + } +} + +void MainThreadTaskQueue::WriteIntoTracedValue( + perfetto::TracedValue context) const { + auto dict = std::move(context).WriteDictionary(); + dict.Add("type", queue_type_); + dict.Add("traits", queue_traits_); +} + +void MainThreadTaskQueue::QueueTraits::WriteIntoTracedValue( + perfetto::TracedValue context) const { + auto dict = std::move(context).WriteDictionary(); + dict.Add("can_be_deferred", can_be_deferred); + dict.Add("can_be_throttled", can_be_throttled); + dict.Add("can_be_intensively_throttled", can_be_intensively_throttled); + dict.Add("can_be_paused", can_be_paused); + dict.Add("can_be_frozen", can_be_frozen); + dict.Add("can_run_in_background", can_run_in_background); + dict.Add("can_run_when_virtual_time_paused", + can_run_when_virtual_time_paused); + dict.Add("can_be_paused_for_android_webview", + can_be_paused_for_android_webview); + dict.Add("prioritisation_type", prioritisation_type); +} + } // namespace scheduler } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h index b9248e18703..7aa393f6e1d 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h @@ -13,9 +13,12 @@ #include "base/task/sequence_manager/task_queue_impl.h" #include "base/task/sequence_manager/time_domain.h" #include "net/base/request_priority.h" +#include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h" +#include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" namespace base { namespace sequence_manager { @@ -36,6 +39,10 @@ namespace agent_interference_recorder_test { class AgentInterferenceRecorderTest; } +namespace task_queue_throttler_unittest { +class TaskQueueThrottlerTest; +} + class FrameSchedulerImpl; class MainThreadSchedulerImpl; @@ -92,6 +99,36 @@ class PLATFORM_EXPORT MainThreadTaskQueue kCount = 27 }; + // The ThrottleHandle controls throttling and unthrottling the queue. When + // a caller requests a queue to be throttled, this handle is returned and + // the queue will remain throttled as long as the handle is alive. + class ThrottleHandle { + public: + ThrottleHandle(base::WeakPtr<TaskQueue> task_queue, + base::WeakPtr<TaskQueueThrottler> throttler) + : task_queue_(std::move(task_queue)), throttler_(std::move(throttler)) { + if (task_queue_ && throttler_) + throttler_->IncreaseThrottleRefCount(task_queue_.get()); + } + ~ThrottleHandle() { + if (task_queue_ && throttler_) + throttler_->DecreaseThrottleRefCount(task_queue_.get()); + } + + // Move-only. + ThrottleHandle(ThrottleHandle&& other) + : task_queue_(std::move(other.task_queue_)), + throttler_(std::move(other.throttler_)) { + other.task_queue_ = nullptr; + other.throttler_ = nullptr; + } + ThrottleHandle& operator=(ThrottleHandle&&); + + private: + base::WeakPtr<TaskQueue> task_queue_; + base::WeakPtr<TaskQueueThrottler> throttler_; + }; + // Returns name of the given queue type. Returned string has application // lifetime. static const char* NameForQueueType(QueueType queue_type); @@ -228,6 +265,8 @@ class PLATFORM_EXPORT MainThreadTaskQueue return key; } + void WriteIntoTracedValue(perfetto::TracedValue context) const; + bool can_be_deferred : 1; bool can_be_throttled : 1; bool can_be_intensively_throttled : 1; @@ -258,6 +297,17 @@ class PLATFORM_EXPORT MainThreadTaskQueue return *this; } + QueueCreationParams SetAgentGroupScheduler( + AgentGroupSchedulerImpl* scheduler) { + agent_group_scheduler = scheduler; + return *this; + } + + QueueCreationParams SetFrameScheduler(FrameSchedulerImpl* scheduler) { + frame_scheduler = scheduler; + return *this; + } + // Forwarded calls to |queue_traits| QueueCreationParams SetCanBeDeferred(bool value) { @@ -311,17 +361,6 @@ class PLATFORM_EXPORT MainThreadTaskQueue // Forwarded calls to |spec|. - QueueCreationParams SetAgentGroupScheduler( - AgentGroupSchedulerImpl* scheduler) { - agent_group_scheduler = scheduler; - return *this; - } - - QueueCreationParams SetFrameScheduler(FrameSchedulerImpl* scheduler) { - frame_scheduler = scheduler; - return *this; - } - QueueCreationParams SetShouldMonitorQuiescence(bool should_monitor) { spec = spec.SetShouldMonitorQuiescence(should_monitor); return *this; @@ -440,13 +479,38 @@ class PLATFORM_EXPORT MainThreadTaskQueue return task_queue_->task_runner(); } + bool IsThrottled() const; + + // Throttles the task queue as long as the handle is kept alive. + MainThreadTaskQueue::ThrottleHandle Throttle(); + + // Called when a task finished running to update cpu-based throttling. + void OnTaskRunTimeReported(TaskQueue::TaskTiming* task_timing); + + // Methods for setting and resetting budget pools for this task queue. + // Note that a task queue can be in multiple budget pools so a pool must + // be specified when resetting. + void AddToBudgetPool(base::TimeTicks now, BudgetPool* pool); + void RemoveFromBudgetPool(base::TimeTicks now, BudgetPool* pool); + + // This method is only used for tests. If this queue is throttled it will + // notify the throttler that this queue should wake immediately. + void SetImmediateWakeUpForTest(); + base::WeakPtr<MainThreadTaskQueue> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } + void WriteIntoTracedValue(perfetto::TracedValue context) const; + protected: void SetFrameSchedulerForTest(FrameSchedulerImpl* frame_scheduler); + // Returns the underlying task queue. Only to be used for tests that need to + // test functionality of the task queue specifically without the wrapping + // MainThreadTaskQueue (ex TaskQueueThrottlerTest). + TaskQueue* GetTaskQueueForTest() { return task_queue_.get(); } + // TODO(kdillon): Remove references to TaskQueueImpl once TaskQueueImpl // inherits from TaskQueue. MainThreadTaskQueue( @@ -463,6 +527,8 @@ class PLATFORM_EXPORT MainThreadTaskQueue friend class blink::scheduler::main_thread_scheduler_impl_unittest:: MainThreadSchedulerImplTest; friend class agent_interference_recorder_test::AgentInterferenceRecorderTest; + friend class blink::scheduler::task_queue_throttler_unittest:: + TaskQueueThrottlerTest; // Clear references to main thread scheduler and frame scheduler and dispatch // appropriate notifications. This is the common part of ShutdownTaskQueue and diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc index 992fe514fdb..559600ee9f0 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_unittest.cc @@ -51,13 +51,13 @@ class MainThreadTest : public testing::Test { void SetUp() override { clock_.Advance(base::TimeDelta::FromMicroseconds(5000)); - scheduler_.reset(new MainThreadSchedulerImpl( + scheduler_ = std::make_unique<MainThreadSchedulerImpl>( base::sequence_manager::CreateSequenceManagerOnCurrentThreadWithPump( base::MessagePump::Create(base::MessagePumpType::DEFAULT), base::sequence_manager::SequenceManager::Settings::Builder() .SetTickClock(&clock_) .Build()), - base::nullopt)); + base::nullopt); scheduler_overrider_ = std::make_unique<ScopedSchedulerOverrider>(scheduler_.get()); thread_ = Thread::Current(); diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc index c1b6afdf5ac..5955efb7baf 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc @@ -28,6 +28,7 @@ #include "third_party/blink/renderer/platform/scheduler/main_thread/use_case.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value.h" namespace blink { namespace scheduler { @@ -170,13 +171,12 @@ constexpr base::TimeDelta PageSchedulerImpl::kDefaultThrottledWakeUpInterval; PageSchedulerImpl::PageSchedulerImpl( PageScheduler::Delegate* delegate, AgentGroupSchedulerImpl& agent_group_scheduler) - : main_thread_scheduler_(&agent_group_scheduler.GetMainThreadScheduler()), + : main_thread_scheduler_(static_cast<MainThreadSchedulerImpl*>( + &agent_group_scheduler.GetMainThreadScheduler())), agent_group_scheduler_(agent_group_scheduler), page_visibility_(kDefaultPageVisibility), page_visibility_changed_time_( - agent_group_scheduler.GetMainThreadScheduler() - .GetTickClock() - ->NowTicks()), + main_thread_scheduler_->GetTickClock()->NowTicks()), audio_state_(AudioState::kSilent), is_frozen_(false), reported_background_throttling_since_navigation_(false), @@ -185,9 +185,9 @@ PageSchedulerImpl::PageSchedulerImpl( is_main_frame_local_(false), is_cpu_time_throttled_(false), are_wake_ups_intensively_throttled_(false), - keep_active_( - agent_group_scheduler.GetMainThreadScheduler().SchedulerKeepActive()), + keep_active_(main_thread_scheduler_->SchedulerKeepActive()), had_recent_title_or_favicon_update_(false), + focused_(delegate ? delegate->IsFocused() : true), delegate_(delegate), delay_for_background_tab_freezing_(GetDelayForBackgroundTabFreezing()), freeze_on_network_idle_enabled_(base::FeatureList::IsEnabled( @@ -362,6 +362,13 @@ void PageSchedulerImpl::SetPageBackForwardCached( } } +void PageSchedulerImpl::OnFocusChanged(bool focused) { + DCHECK_NE(focused_, focused); + + focused_ = focused; + NotifyFrames(); +} + void PageSchedulerImpl::SetUpIPCTaskDetection() { DCHECK(is_stored_in_back_forward_cache_); has_ipc_detection_enabled_ = true; @@ -581,6 +588,10 @@ void PageSchedulerImpl::OnTraceLogEnabled() { } } +bool PageSchedulerImpl::IsPageFocused() const { + return focused_; +} + bool PageSchedulerImpl::IsWaitingForMainFrameContentfulPaint() const { return std::any_of(frame_schedulers_.begin(), frame_schedulers_.end(), [](const FrameSchedulerImpl* fs) { @@ -599,40 +610,33 @@ bool PageSchedulerImpl::IsWaitingForMainFrameMeaningfulPaint() const { }); } -void PageSchedulerImpl::AsValueInto( - base::trace_event::TracedValue* state) const { - state->SetBoolean("page_visible", - page_visibility_ == PageVisibilityState::kVisible); - state->SetBoolean("is_audio_playing", IsAudioPlaying()); - state->SetBoolean("is_frozen", is_frozen_); - state->SetBoolean("reported_background_throttling_since_navigation", - reported_background_throttling_since_navigation_); - state->SetBoolean("is_page_freezable", IsBackgrounded()); +void PageSchedulerImpl::WriteIntoTracedValue( + perfetto::TracedValue context) const { + auto dict = std::move(context).WriteDictionary(); + dict.Add("page_visible", page_visibility_ == PageVisibilityState::kVisible); + dict.Add("is_audio_playing", IsAudioPlaying()); + dict.Add("is_frozen", is_frozen_); + dict.Add("reported_background_throttling_since_navigation", + reported_background_throttling_since_navigation_); + dict.Add("is_page_freezable", IsBackgrounded()); - { - auto dictionary_scope = state->BeginDictionaryScoped("frame_schedulers"); - for (FrameSchedulerImpl* frame_scheduler : frame_schedulers_) { - auto inner_dictionary = state->BeginDictionaryScopedWithCopiedName( - PointerToString(frame_scheduler)); - frame_scheduler->AsValueInto(state); - } - } + dict.Add("frame_schedulers", frame_schedulers_); } void PageSchedulerImpl::AddQueueToWakeUpBudgetPool( MainThreadTaskQueue* task_queue, FrameOriginType frame_origin_type, base::sequence_manager::LazyNow* lazy_now) { - GetWakeUpBudgetPool(task_queue, frame_origin_type) - ->AddQueue(lazy_now->Now(), task_queue->GetTaskQueue()); + task_queue->AddToBudgetPool( + lazy_now->Now(), GetWakeUpBudgetPool(task_queue, frame_origin_type)); } void PageSchedulerImpl::RemoveQueueFromWakeUpBudgetPool( MainThreadTaskQueue* task_queue, FrameOriginType frame_origin_type, base::sequence_manager::LazyNow* lazy_now) { - GetWakeUpBudgetPool(task_queue, frame_origin_type) - ->RemoveQueue(lazy_now->Now(), task_queue->GetTaskQueue()); + task_queue->RemoveFromBudgetPool( + lazy_now->Now(), GetWakeUpBudgetPool(task_queue, frame_origin_type)); } WakeUpBudgetPool* PageSchedulerImpl::GetWakeUpBudgetPool( diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h index 27dfaabae38..5aee3226986 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h @@ -25,11 +25,11 @@ #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" namespace base { namespace trace_event { class BlameContext; -class TracedValue; } // namespace trace_event } // namespace base @@ -63,6 +63,7 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler { void SetPageVisible(bool page_visible) override; void SetPageFrozen(bool) override; void SetPageBackForwardCached(bool) override; + void OnFocusChanged(bool focused) override; void SetKeepActive(bool) override; bool IsMainFrameLocal() const override; void SetIsMainFrameLocal(bool is_local) override; @@ -126,6 +127,8 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler { void OnTraceLogEnabled(); + bool IsPageFocused() const; + // Virtual for testing. virtual bool IsWaitingForMainFrameContentfulPaint() const; virtual bool IsWaitingForMainFrameMeaningfulPaint() const; @@ -148,7 +151,7 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler { // frame it not a local one. FrameSchedulerImpl* SelectFrameForUkmAttribution(); - void AsValueInto(base::trace_event::TracedValue* state) const; + void WriteIntoTracedValue(perfetto::TracedValue context) const; base::WeakPtr<PageSchedulerImpl> GetWeakPtr() { return weak_factory_.GetWeakPtr(); @@ -316,6 +319,7 @@ class PLATFORM_EXPORT PageSchedulerImpl : public PageScheduler { bool are_wake_ups_intensively_throttled_; bool keep_active_; bool had_recent_title_or_favicon_update_; + bool focused_; CPUTimeBudgetPool* cpu_time_budget_pool_ = nullptr; // Wake up budget pools for each throttling scenario: diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc index 508f17c8cb5..534a809e6d3 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc @@ -21,6 +21,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/renderer/platform/scheduler/common/features.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h" @@ -82,6 +83,7 @@ class MockPageSchedulerDelegate : public PageScheduler::Delegate { void SetLocalMainFrameNetworkIsAlmostIdle(bool idle) { idle_ = idle; } bool LocalMainFrameNetworkIsAlmostIdle() const override { return idle_; } + bool IsFocused() const override { return true; } private: void ReportIntervention(const WTF::String&) override {} @@ -285,17 +287,6 @@ class PageSchedulerImplTest : public testing::Test { base::test::ScopedFeatureList feature_list_; }; -class PageSchedulerImplStopNonTimersInBackgroundEnabledTest - : public PageSchedulerImplTest { - public: - PageSchedulerImplStopNonTimersInBackgroundEnabledTest() - : PageSchedulerImplTest({blink::features::kStopInBackground, - blink::features::kStopNonTimersInBackground}, - {}) {} - - ~PageSchedulerImplStopNonTimersInBackgroundEnabledTest() override = default; -}; - TEST_F(PageSchedulerImplTest, TestDestructionOfFrameSchedulersBefore) { std::unique_ptr<blink::FrameScheduler> frame1( page_scheduler_->CreateFrameScheduler( @@ -1318,15 +1309,13 @@ TEST_F(PageSchedulerImplTest, OpenWebSocketExemptsFromBudgetThrottling) { // Verify that freezing a page prevents tasks in its task queues from running. // Then, verify that making the page visible unfreezes it and allows tasks in // its task queues to run. -TEST_F(PageSchedulerImplStopNonTimersInBackgroundEnabledTest, - PageFreezeAndSetVisible) { +TEST_F(PageSchedulerImplTest, PageFreezeAndSetVisible) { TestFreeze(true); } // Same as before, but unfreeze the page explicitly instead of making it // visible. -TEST_F(PageSchedulerImplStopNonTimersInBackgroundEnabledTest, - PageFreezeAndUnfreeze) { +TEST_F(PageSchedulerImplTest, PageFreezeAndUnfreeze) { TestFreeze(false); } @@ -1363,23 +1352,19 @@ TEST_F(PageSchedulerImplTest, PageSchedulerDestroyedWhileAudioChangePending) { TEST_F(PageSchedulerImplTest, AudiblePagesAreNotThrottled) { page_scheduler_->SetPageVisible(false); - EXPECT_TRUE(scheduler_->task_queue_throttler()->IsThrottled( - ThrottleableTaskQueue()->GetTaskQueue())); + EXPECT_TRUE(ThrottleableTaskQueue()->IsThrottled()); // No throttling when the page is audible. page_scheduler_->AudioStateChanged(true); - EXPECT_FALSE(scheduler_->task_queue_throttler()->IsThrottled( - ThrottleableTaskQueue()->GetTaskQueue())); + EXPECT_FALSE(ThrottleableTaskQueue()->IsThrottled()); // No throttling for some time after audio signal disappears. page_scheduler_->AudioStateChanged(false); - EXPECT_FALSE(scheduler_->task_queue_throttler()->IsThrottled( - ThrottleableTaskQueue()->GetTaskQueue())); + EXPECT_FALSE(ThrottleableTaskQueue()->IsThrottled()); // Eventually throttling is reenabled again. test_task_runner_->FastForwardUntilNoTasksRemain(); - EXPECT_TRUE(scheduler_->task_queue_throttler()->IsThrottled( - ThrottleableTaskQueue()->GetTaskQueue())); + EXPECT_TRUE(ThrottleableTaskQueue()->IsThrottled()); } TEST_F(PageSchedulerImplTest, BudgetBasedThrottlingForPageScheduler) { @@ -1762,6 +1747,88 @@ TEST_F(PageSchedulerImplPageTransitionTest, UnorderedElementsAreArray(GetExpectedBuckets())); } +class PageSchedulerImplThrottleVisibleNotFocusedTimersEnabledTest + : public PageSchedulerImplTest { + public: + PageSchedulerImplThrottleVisibleNotFocusedTimersEnabledTest() + : PageSchedulerImplTest( + {blink::features::kStopInBackground, + blink::scheduler::kThrottleVisibleNotFocusedTimers}, + {}) {} +}; + +TEST_F(PageSchedulerImplThrottleVisibleNotFocusedTimersEnabledTest, + PageVisibleWithFocus) { + page_scheduler_->SetPageVisible(true); + if (!page_scheduler_->IsPageFocused()) + page_scheduler_->OnFocusChanged(true); + + int run_count = 0; + ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostDelayedTask( + FROM_HERE, + MakeRepeatingTask( + ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType(), + &run_count, base::TimeDelta::FromMilliseconds(20)), + base::TimeDelta::FromMilliseconds(20)); + + test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(50, run_count); + + // Create a new frame when the page has focus + int frame_run_count = 0; + std::unique_ptr<FrameSchedulerImpl> frame_scheduler2 = + CreateFrameScheduler(page_scheduler_.get(), nullptr, nullptr, + FrameScheduler::FrameType::kSubframe); + ThrottleableTaskQueueForScheduler(frame_scheduler2.get()) + ->GetTaskRunnerWithDefaultTaskType() + ->PostDelayedTask( + FROM_HERE, + MakeRepeatingTask( + ThrottleableTaskQueueForScheduler(frame_scheduler2.get()) + ->GetTaskRunnerWithDefaultTaskType(), + &frame_run_count, base::TimeDelta::FromMilliseconds(20)), + base::TimeDelta::FromMilliseconds(20)); + + test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(50, frame_run_count); +} + +TEST_F(PageSchedulerImplThrottleVisibleNotFocusedTimersEnabledTest, + PageVisibleWithoutFocus) { + page_scheduler_->SetPageVisible(true); + if (page_scheduler_->IsPageFocused()) + page_scheduler_->OnFocusChanged(false); + + int run_count = 0; + ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostDelayedTask( + FROM_HERE, + MakeRepeatingTask( + ThrottleableTaskQueue()->GetTaskRunnerWithDefaultTaskType(), + &run_count, base::TimeDelta::FromMilliseconds(20)), + base::TimeDelta::FromMilliseconds(20)); + + test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(1, run_count); + + // Create a new frame when the page doesn't have focus + int frame_run_count = 0; + std::unique_ptr<FrameSchedulerImpl> frame_scheduler2 = + CreateFrameScheduler(page_scheduler_.get(), nullptr, nullptr, + FrameScheduler::FrameType::kSubframe); + ThrottleableTaskQueueForScheduler(frame_scheduler2.get()) + ->GetTaskRunnerWithDefaultTaskType() + ->PostDelayedTask( + FROM_HERE, + MakeRepeatingTask( + ThrottleableTaskQueueForScheduler(frame_scheduler2.get()) + ->GetTaskRunnerWithDefaultTaskType(), + &frame_run_count, base::TimeDelta::FromMilliseconds(20)), + base::TimeDelta::FromMilliseconds(20)); + + test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(1, frame_run_count); +} + } // namespace page_scheduler_impl_unittest } // namespace scheduler } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc index 4d13b8ad29b..1441803981e 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.cc @@ -7,6 +7,7 @@ #include "base/check_op.h" #include "base/memory/ptr_util.h" #include "third_party/blink/public/platform/scheduler/web_render_widget_scheduling_state.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value.h" namespace blink { namespace scheduler { @@ -51,13 +52,12 @@ void RenderWidgetSignals::DecNumVisibleRenderWidgetsWithTouchHandlers() { observer_->SetHasVisibleRenderWidgetWithTouchHandler(false); } -void RenderWidgetSignals::AsValueInto( - base::trace_event::TracedValue* state) const { - auto dictionary_scope = - state->BeginDictionaryScoped("renderer_widget_signals"); - state->SetInteger("num_visible_render_widgets", num_visible_render_widgets_); - state->SetInteger("num_visible_render_widgets_with_touch_handlers", - num_visible_render_widgets_with_touch_handlers_); +void RenderWidgetSignals::WriteIntoTracedValue( + perfetto::TracedValue context) const { + auto dict = std::move(context).WriteDictionary(); + dict.Add("num_visible_render_widgets", num_visible_render_widgets_); + dict.Add("num_visible_render_widgets_with_touch_handlers", + num_visible_render_widgets_with_touch_handlers_); } } // namespace scheduler diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h index f484d89c8f2..81a2d411ed9 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/render_widget_signals.h @@ -11,6 +11,7 @@ #include "base/trace_event/traced_value.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" namespace blink { namespace scheduler { @@ -43,7 +44,7 @@ class PLATFORM_EXPORT RenderWidgetSignals { std::unique_ptr<WebRenderWidgetSchedulingState> NewRenderWidgetSchedulingState(); - void AsValueInto(base::trace_event::TracedValue* state) const; + void WriteIntoTracedValue(perfetto::TracedValue context) const; private: friend class WebRenderWidgetSchedulingState; diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc index 6084494be0a..a1a5df6aa69 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc @@ -145,6 +145,8 @@ const char* TaskTypeNames::TaskTypeToString(TaskType task_type) { return "InternalHighPriorityLocalFrame"; case TaskType::kMainThreadTaskQueueIPCTracking: return "MainThreadTaskQueueIPCTracking"; + case TaskType::kWakeLock: + return "WakeLock"; case TaskType::kCount: return "Count"; } diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc index 14ed5d50e33..e955335dc93 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "third_party/blink/renderer/platform/scheduler/main_thread/user_model.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value.h" namespace blink { namespace scheduler { @@ -140,25 +141,17 @@ void UserModel::Reset(base::TimeTicks now) { pending_input_event_count_ = 0; } -void UserModel::AsValueInto(base::trace_event::TracedValue* state) const { - auto dictionary_scope = state->BeginDictionaryScoped("user_model"); - state->SetInteger("pending_input_event_count", pending_input_event_count_); - state->SetDouble( - "last_input_signal_time", - (last_input_signal_time_ - base::TimeTicks()).InMillisecondsF()); - state->SetDouble( - "last_gesture_start_time", - (last_gesture_start_time_ - base::TimeTicks()).InMillisecondsF()); - state->SetDouble( - "last_continuous_gesture_time", - (last_continuous_gesture_time_ - base::TimeTicks()).InMillisecondsF()); - state->SetDouble("last_gesture_expected_start_time", - (last_gesture_expected_start_time_ - base::TimeTicks()) - .InMillisecondsF()); - state->SetDouble("last_reset_time", - (last_reset_time_ - base::TimeTicks()).InMillisecondsF()); - state->SetBoolean("is_gesture_expected", is_gesture_expected_); - state->SetBoolean("is_gesture_active", is_gesture_active_); +void UserModel::WriteIntoTracedValue(perfetto::TracedValue context) const { + auto dict = std::move(context).WriteDictionary(); + dict.Add("pending_input_event_count", pending_input_event_count_); + dict.Add("last_input_signal_time", last_input_signal_time_); + dict.Add("last_gesture_start_time", last_gesture_start_time_); + dict.Add("last_continuous_gesture_time", last_continuous_gesture_time_); + dict.Add("last_gesture_expected_start_time", + last_gesture_expected_start_time_); + dict.Add("last_reset_time", last_reset_time_); + dict.Add("is_gesture_expected", is_gesture_expected_); + dict.Add("is_gesture_active", is_gesture_active_); } } // namespace scheduler diff --git a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h index fb7d2b79468..7affc23ce28 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h +++ b/chromium/third_party/blink/renderer/platform/scheduler/main_thread/user_model.h @@ -12,6 +12,7 @@ #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" namespace blink { namespace scheduler { @@ -48,7 +49,7 @@ class PLATFORM_EXPORT UserModel { const base::TimeTicks now, base::TimeDelta* prediction_valid_duration) const; - void AsValueInto(base::trace_event::TracedValue* state) const; + void WriteIntoTracedValue(perfetto::TracedValue context) const; // The time we should stay in a priority-escalated mode after an input event. static const int kGestureEstimationLimitMillis = 100; |