From 30e04726874eb3a4b5da0e193d608246e80a5af7 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Wed, 28 Apr 2021 14:39:42 -0500 Subject: [PATCH] Pause dart microtasks while UI thread is processing frame workloads (flutter/engine#25789) --- engine/src/flutter/shell/common/shell_test.cc | 2 +- .../flutter/shell/common/shell_unittests.cc | 1 + .../src/flutter/shell/common/vsync_waiter.cc | 24 +++++++++++++++++-- .../src/flutter/shell/common/vsync_waiter.h | 6 ++++- .../shell/common/vsync_waiter_fallback.cc | 9 ++++--- .../shell/common/vsync_waiter_fallback.h | 4 +++- .../ios/framework/Source/vsync_waiter_ios.mm | 3 ++- .../platform/fuchsia/flutter/vsync_waiter.cc | 2 +- 8 files changed, 41 insertions(+), 10 deletions(-) diff --git a/engine/src/flutter/shell/common/shell_test.cc b/engine/src/flutter/shell/common/shell_test.cc index e763696618..00c12f05ca 100644 --- a/engine/src/flutter/shell/common/shell_test.cc +++ b/engine/src/flutter/shell/common/shell_test.cc @@ -325,7 +325,7 @@ std::unique_ptr ShellTest::CreateShell( std::make_unique(task_runners, vsync_clock)); } else { return static_cast>( - std::make_unique(task_runners)); + std::make_unique(task_runners, true)); } }; diff --git a/engine/src/flutter/shell/common/shell_unittests.cc b/engine/src/flutter/shell/common/shell_unittests.cc index 5a21085446..d31c138fda 100644 --- a/engine/src/flutter/shell/common/shell_unittests.cc +++ b/engine/src/flutter/shell/common/shell_unittests.cc @@ -1335,6 +1335,7 @@ TEST_F(ShellTest, ReportTimingsIsCalledImmediatelyAfterTheFirstFrame) { }; AddNativeCallback("NativeReportTimingsCallback", CREATE_NATIVE_ENTRY(nativeTimingCallback)); + ASSERT_TRUE(configuration.IsValid()); RunEngine(shell.get(), std::move(configuration)); for (int i = 0; i < 10; i += 1) { diff --git a/engine/src/flutter/shell/common/vsync_waiter.cc b/engine/src/flutter/shell/common/vsync_waiter.cc index 886f6724db..40ced727ab 100644 --- a/engine/src/flutter/shell/common/vsync_waiter.cc +++ b/engine/src/flutter/shell/common/vsync_waiter.cc @@ -91,7 +91,8 @@ void VsyncWaiter::ScheduleSecondaryCallback(uintptr_t id, } void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, - fml::TimePoint frame_target_time) { + fml::TimePoint frame_target_time, + bool pause_secondary_tasks) { Callback callback; std::vector secondary_callbacks; @@ -114,6 +115,9 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, if (callback) { auto flow_identifier = fml::tracing::TraceNonce(); + if (pause_secondary_tasks) { + PauseDartMicroTasks(); + } // The base trace ensures that flows have a root to begin from if one does // not exist. The trace viewer will ignore traces that have no base event @@ -124,11 +128,15 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, TRACE_FLOW_BEGIN("flutter", kVsyncFlowName, flow_identifier); task_runners_.GetUITaskRunner()->PostTaskForTime( - [callback, flow_identifier, frame_start_time, frame_target_time]() { + [this, callback, flow_identifier, frame_start_time, frame_target_time, + pause_secondary_tasks]() { FML_TRACE_EVENT("flutter", kVsyncTraceName, "StartTime", frame_start_time, "TargetTime", frame_target_time); callback(frame_start_time, frame_target_time); TRACE_FLOW_END("flutter", kVsyncFlowName, flow_identifier); + if (pause_secondary_tasks) { + ResumeDartMicroTasks(); + } }, frame_start_time); } @@ -139,4 +147,16 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, } } +void VsyncWaiter::PauseDartMicroTasks() { + auto ui_task_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId(); + auto task_queues = fml::MessageLoopTaskQueues::GetInstance(); + task_queues->PauseSecondarySource(ui_task_queue_id); +} + +void VsyncWaiter::ResumeDartMicroTasks() { + auto ui_task_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId(); + auto task_queues = fml::MessageLoopTaskQueues::GetInstance(); + task_queues->ResumeSecondarySource(ui_task_queue_id); +} + } // namespace flutter diff --git a/engine/src/flutter/shell/common/vsync_waiter.h b/engine/src/flutter/shell/common/vsync_waiter.h index 084399011d..d593c7014b 100644 --- a/engine/src/flutter/shell/common/vsync_waiter.h +++ b/engine/src/flutter/shell/common/vsync_waiter.h @@ -49,13 +49,17 @@ class VsyncWaiter : public std::enable_shared_from_this { virtual void AwaitVSync() = 0; void FireCallback(fml::TimePoint frame_start_time, - fml::TimePoint frame_target_time); + fml::TimePoint frame_target_time, + bool pause_secondary_tasks = true); private: std::mutex callback_mutex_; Callback callback_; std::unordered_map secondary_callbacks_; + void PauseDartMicroTasks(); + void ResumeDartMicroTasks(); + FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter); }; diff --git a/engine/src/flutter/shell/common/vsync_waiter_fallback.cc b/engine/src/flutter/shell/common/vsync_waiter_fallback.cc index 514dc02fac..8bf51c5ce2 100644 --- a/engine/src/flutter/shell/common/vsync_waiter_fallback.cc +++ b/engine/src/flutter/shell/common/vsync_waiter_fallback.cc @@ -21,8 +21,11 @@ static fml::TimePoint SnapToNextTick(fml::TimePoint value, } // namespace -VsyncWaiterFallback::VsyncWaiterFallback(TaskRunners task_runners) - : VsyncWaiter(std::move(task_runners)), phase_(fml::TimePoint::Now()) {} +VsyncWaiterFallback::VsyncWaiterFallback(TaskRunners task_runners, + bool for_testing) + : VsyncWaiter(std::move(task_runners)), + phase_(fml::TimePoint::Now()), + for_testing_(for_testing) {} VsyncWaiterFallback::~VsyncWaiterFallback() = default; @@ -36,7 +39,7 @@ void VsyncWaiterFallback::AwaitVSync() { auto next = SnapToNextTick(fml::TimePoint::Now(), phase_, kSingleFrameInterval); - FireCallback(next, next + kSingleFrameInterval); + FireCallback(next, next + kSingleFrameInterval, !for_testing_); } } // namespace flutter diff --git a/engine/src/flutter/shell/common/vsync_waiter_fallback.h b/engine/src/flutter/shell/common/vsync_waiter_fallback.h index 5226dda019..b2ae63f720 100644 --- a/engine/src/flutter/shell/common/vsync_waiter_fallback.h +++ b/engine/src/flutter/shell/common/vsync_waiter_fallback.h @@ -15,12 +15,14 @@ namespace flutter { /// A |VsyncWaiter| that will fire at 60 fps irrespective of the vsync. class VsyncWaiterFallback final : public VsyncWaiter { public: - VsyncWaiterFallback(TaskRunners task_runners); + explicit VsyncWaiterFallback(TaskRunners task_runners, + bool for_testing = false); ~VsyncWaiterFallback() override; private: fml::TimePoint phase_; + const bool for_testing_; // |VsyncWaiter| void AwaitVSync() override; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm index d71ecd7d78..37d9b23c0c 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -23,7 +23,8 @@ VsyncWaiterIOS::VsyncWaiterIOS(flutter::TaskRunners task_runners) callback:std::bind(&VsyncWaiterIOS::FireCallback, this, std::placeholders::_1, - std::placeholders::_2)]) {} + std::placeholders::_2, + true)]) {} VsyncWaiterIOS::~VsyncWaiterIOS() { // This way, we will get no more callbacks from the display link that holds a weak (non-nilling) diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/vsync_waiter.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/vsync_waiter.cc index 5a8fe59be1..fd8f60122a 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/vsync_waiter.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/vsync_waiter.cc @@ -197,7 +197,7 @@ void VsyncWaiter::FireCallbackNow() { } fml::TimePoint previous_vsync = next_vsync - vsync_info.presentation_interval; - FireCallback(previous_vsync, next_vsync); + FireCallback(previous_vsync, next_vsync, false); } } // namespace flutter_runner