From 15eadbee14428aaa90d91d8ad7089cb8a6b9f1fe Mon Sep 17 00:00:00 2001 From: Liron Yahdav Date: Wed, 23 Oct 2024 13:15:45 -0700 Subject: [PATCH] batch sync events based on event beats (#47147) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/47147 By batching sync events if multiple events are dispatched during sync rendering this will reduce the number of re-renders. Changelog: [Internal] Reviewed By: yungsters Differential Revision: D64287526 fbshipit-source-id: a5dc3b643ef1853bef9e38ce8c2f5db75e02214b --- .../react/renderer/core/EventBeat.cpp | 14 ++++++++++++- .../react/renderer/core/EventBeat.h | 7 +++++++ .../react/renderer/core/EventDispatcher.cpp | 4 +--- .../react/renderer/core/EventDispatcher.h | 1 - .../react/renderer/core/EventQueue.cpp | 20 +++---------------- .../react/renderer/core/EventQueue.h | 7 +------ .../react/renderer/scheduler/Scheduler.cpp | 1 - 7 files changed, 25 insertions(+), 29 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventBeat.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventBeat.cpp index 9a9fd5266d798a..ecd919898de4a3 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventBeat.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/EventBeat.cpp @@ -21,6 +21,11 @@ void EventBeat::request() const { isRequested_ = true; } +void EventBeat::requestSynchronous() const { + isSynchronousRequested_ = true; + request(); +} + void EventBeat::setBeatCallback(BeatCallback beatCallback) { beatCallback_ = std::move(beatCallback); } @@ -33,7 +38,7 @@ void EventBeat::induce() const { isRequested_ = false; isBeatCallbackScheduled_ = true; - runtimeScheduler_.scheduleWork( + auto beat = std::function( [this, ownerBox = ownerBox_](jsi::Runtime& runtime) { auto owner = ownerBox->owner.lock(); if (!owner) { @@ -45,6 +50,13 @@ void EventBeat::induce() const { beatCallback_(runtime); } }); + + if (isSynchronousRequested_) { + isSynchronousRequested_ = false; + runtimeScheduler_.executeNowOnTheSameThread(std::move(beat)); + } else { + runtimeScheduler_.scheduleWork(std::move(beat)); + } } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventBeat.h b/packages/react-native/ReactCommon/react/renderer/core/EventBeat.h index a03a9f7cb874eb..59fd208e58144d 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventBeat.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventBeat.h @@ -74,6 +74,12 @@ class EventBeat { */ virtual void request() const; + /* + * Communicates to the Beat that a consumer is waiting synchronously for the + * coming beat. + */ + virtual void requestSynchronous() const; + /* * The callback is must be called on the proper thread. */ @@ -93,6 +99,7 @@ class EventBeat { private: RuntimeScheduler& runtimeScheduler_; mutable std::atomic isBeatCallbackScheduled_{false}; + mutable std::atomic isSynchronousRequested_{false}; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp index 10d6d0b46590a8..fb18eea2488826 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp @@ -18,11 +18,9 @@ namespace facebook::react { EventDispatcher::EventDispatcher( const EventQueueProcessor& eventProcessor, std::unique_ptr eventBeat, - RuntimeScheduler& runtimeScheduler, StatePipe statePipe, std::weak_ptr eventLogger) - : eventQueue_( - EventQueue(eventProcessor, std::move(eventBeat), runtimeScheduler)), + : eventQueue_(EventQueue(eventProcessor, std::move(eventBeat))), statePipe_(std::move(statePipe)), eventLogger_(std::move(eventLogger)) {} diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h index 79eab45e12009c..c103e489822821 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h @@ -33,7 +33,6 @@ class EventDispatcher { EventDispatcher( const EventQueueProcessor& eventProcessor, std::unique_ptr eventBeat, - RuntimeScheduler& runtimeScheduler, StatePipe statePipe, std::weak_ptr eventLogger); diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventQueue.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventQueue.cpp index 4643e5dea2706c..9290bcc106c88b 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventQueue.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/EventQueue.cpp @@ -15,11 +15,9 @@ namespace facebook::react { EventQueue::EventQueue( EventQueueProcessor eventProcessor, - std::unique_ptr eventBeat, - RuntimeScheduler& runtimeScheduler) + std::unique_ptr eventBeat) : eventProcessor_(std::move(eventProcessor)), - eventBeat_(std::move(eventBeat)), - runtimeScheduler_(&runtimeScheduler) { + eventBeat_(std::move(eventBeat)) { eventBeat_->setBeatCallback( [this](jsi::Runtime& runtime) { onBeat(runtime); }); } @@ -79,26 +77,14 @@ void EventQueue::enqueueStateUpdate(StateUpdate&& stateUpdate) const { } void EventQueue::onEnqueue() const { - if (synchronousAccessRequested_) { - // Sync flush has been scheduled, no need to request access to the runtime. - return; - } eventBeat_->request(); } void EventQueue::experimental_flushSync() const { - synchronousAccessRequested_ = true; - runtimeScheduler_->executeNowOnTheSameThread([this](jsi::Runtime& runtime) { - synchronousAccessRequested_ = false; - onBeat(runtime); - }); + eventBeat_->requestSynchronous(); } void EventQueue::onBeat(jsi::Runtime& runtime) const { - if (synchronousAccessRequested_) { - // Sync flush has been scheduled, let's yield to it. - return; - } flushStateUpdates(); flushEvents(runtime); } diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventQueue.h b/packages/react-native/ReactCommon/react/renderer/core/EventQueue.h index f82940c431f61e..3578473b76634e 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventQueue.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventQueue.h @@ -29,8 +29,7 @@ class EventQueue { public: EventQueue( EventQueueProcessor eventProcessor, - std::unique_ptr eventBeat, - RuntimeScheduler& runtimeScheduler); + std::unique_ptr eventBeat); /* * Enqueues and (probably later) dispatch a given event. @@ -75,10 +74,6 @@ class EventQueue { mutable std::vector eventQueue_; mutable std::vector stateUpdateQueue_; mutable std::mutex queueMutex_; - - // TODO: T183075253 - RuntimeScheduler* runtimeScheduler_; - mutable std::atomic_bool synchronousAccessRequested_{false}; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp index a80f53afcc14cd..3a956b52b7d009 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -101,7 +101,6 @@ Scheduler::Scheduler( EventQueueProcessor( eventPipe, eventPipeConclusion, statePipe, eventPerformanceLogger_), std::move(eventBeat), - *runtimeScheduler, statePipe, eventPerformanceLogger_);